xref: /openbmc/u-boot/cmd/otp.c (revision 794e27ec2a1afb2b8aa62c8ceff8a5f3ab0257f3)
1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+
269d5fd8fSJohnny Huang /*
3a219f6deSJohnny Huang  * Copyright 2021 Aspeed Technology Inc.
469d5fd8fSJohnny Huang  */
54c1c9b35SJohnny Huang #include <stdlib.h>
669d5fd8fSJohnny Huang #include <common.h>
769d5fd8fSJohnny Huang #include <console.h>
869d5fd8fSJohnny Huang #include <bootretry.h>
969d5fd8fSJohnny Huang #include <cli.h>
1069d5fd8fSJohnny Huang #include <command.h>
1169d5fd8fSJohnny Huang #include <console.h>
124c1c9b35SJohnny Huang #include <malloc.h>
1369d5fd8fSJohnny Huang #include <inttypes.h>
1469d5fd8fSJohnny Huang #include <mapmem.h>
1569d5fd8fSJohnny Huang #include <asm/io.h>
1669d5fd8fSJohnny Huang #include <linux/compiler.h>
17696656c6SJohnny Huang #include <u-boot/sha256.h>
180cee9a95SJohnny Huang #include "otp_info.h"
1969d5fd8fSJohnny Huang 
2069d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR;
2169d5fd8fSJohnny Huang 
2264b66712SJohnny Huang #define OTP_VER				"1.0.3"
23f67375f7SJohnny Huang 
2469d5fd8fSJohnny Huang #define OTP_PASSWD			0x349fe38a
25dacbba92SJohnny Huang #define RETRY				20
267332532cSJohnny Huang #define OTP_REGION_STRAP		BIT(0)
277332532cSJohnny Huang #define OTP_REGION_CONF			BIT(1)
287332532cSJohnny Huang #define OTP_REGION_DATA			BIT(2)
2969d5fd8fSJohnny Huang 
302a856b9aSJohnny Huang #define OTP_USAGE			-1
312a856b9aSJohnny Huang #define OTP_FAILURE			-2
322a856b9aSJohnny Huang #define OTP_SUCCESS			0
332a856b9aSJohnny Huang 
34a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
35a6af4a17SJohnny Huang 
36181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB		1
37181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV		2
38181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES		3
39181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT		4
40181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC		5
419a4fe690SJohnny Huang 
424c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
434c1c9b35SJohnny Huang #define PBWIDTH 60
444c1c9b35SJohnny Huang 
453d3688adSJohnny Huang #define OTP_BASE		0x1e6f2000
463d3688adSJohnny Huang #define OTP_PROTECT_KEY		OTP_BASE
473d3688adSJohnny Huang #define OTP_COMMAND		OTP_BASE + 0x4
483d3688adSJohnny Huang #define OTP_TIMING		OTP_BASE + 0x8
493d3688adSJohnny Huang #define OTP_ADDR		OTP_BASE + 0x10
503d3688adSJohnny Huang #define OTP_STATUS		OTP_BASE + 0x14
513d3688adSJohnny Huang #define OTP_COMPARE_1		OTP_BASE + 0x20
523d3688adSJohnny Huang #define OTP_COMPARE_2		OTP_BASE + 0x24
533d3688adSJohnny Huang #define OTP_COMPARE_3		OTP_BASE + 0x28
543d3688adSJohnny Huang #define OTP_COMPARE_4		OTP_BASE + 0x2c
553d3688adSJohnny Huang 
56696656c6SJohnny Huang #define OTP_MAGIC		"SOCOTP"
57696656c6SJohnny Huang #define CHECKSUM_LEN		32
58a219f6deSJohnny Huang #define OTP_INC_DATA		BIT(31)
59a219f6deSJohnny Huang #define OTP_INC_CONFIG		BIT(30)
60a219f6deSJohnny Huang #define OTP_INC_STRAP		BIT(29)
61a219f6deSJohnny Huang #define OTP_ECC_EN		BIT(28)
62696656c6SJohnny Huang #define OTP_REGION_SIZE(info)	((info >> 16) & 0xffff)
63696656c6SJohnny Huang #define OTP_REGION_OFFSET(info)	(info & 0xffff)
64696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info)	(info & 0xffff)
65696656c6SJohnny Huang 
66696656c6SJohnny Huang #define OTP_AST2600A0		0
67696656c6SJohnny Huang #define OTP_AST2600A1		1
680dae9d52SJohnny Huang #define OTP_AST2600A2		2
6964b66712SJohnny Huang #define OTP_AST2600A3		3
70696656c6SJohnny Huang 
71696656c6SJohnny Huang struct otp_header {
72696656c6SJohnny Huang 	u8	otp_magic[8];
73696656c6SJohnny Huang 	u8	otp_version[8];
74696656c6SJohnny Huang 	u32	image_info;
75696656c6SJohnny Huang 	u32	data_info;
76696656c6SJohnny Huang 	u32	config_info;
77696656c6SJohnny Huang 	u32	strap_info;
78696656c6SJohnny Huang 	u32	checksum_offset;
79a219f6deSJohnny Huang } __packed;
80696656c6SJohnny Huang 
8166f2f8e5SJohnny Huang struct otpstrap_status {
8269d5fd8fSJohnny Huang 	int value;
8369d5fd8fSJohnny Huang 	int option_array[7];
8469d5fd8fSJohnny Huang 	int remain_times;
8569d5fd8fSJohnny Huang 	int writeable_option;
865010032bSJohnny Huang 	int reg_protected;
8769d5fd8fSJohnny Huang 	int protected;
8869d5fd8fSJohnny Huang };
8969d5fd8fSJohnny Huang 
9066f2f8e5SJohnny Huang struct otpconf_parse {
9166f2f8e5SJohnny Huang 	int dw_offset;
9266f2f8e5SJohnny Huang 	int bit;
9366f2f8e5SJohnny Huang 	int length;
9466f2f8e5SJohnny Huang 	int value;
95696656c6SJohnny Huang 	int ignore;
9666f2f8e5SJohnny Huang 	char status[80];
9766f2f8e5SJohnny Huang };
9866f2f8e5SJohnny Huang 
999a4fe690SJohnny Huang struct otpkey_type {
1009a4fe690SJohnny Huang 	int value;
1019a4fe690SJohnny Huang 	int key_type;
1029a4fe690SJohnny Huang 	int need_id;
1039a4fe690SJohnny Huang 	char information[110];
1049a4fe690SJohnny Huang };
1059a4fe690SJohnny Huang 
1069a4fe690SJohnny Huang struct otp_info_cb {
1079a4fe690SJohnny Huang 	int version;
10879e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1099a4fe690SJohnny Huang 	int strap_info_len;
11079e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1119a4fe690SJohnny Huang 	int conf_info_len;
11279e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1139a4fe690SJohnny Huang 	int key_info_len;
1145010032bSJohnny Huang 
1159a4fe690SJohnny Huang };
1169a4fe690SJohnny Huang 
117696656c6SJohnny Huang struct otp_image_layout {
1185010032bSJohnny Huang 	int data_length;
1195010032bSJohnny Huang 	int conf_length;
1205010032bSJohnny Huang 	int strap_length;
121a219f6deSJohnny Huang 	u8 *data;
122a219f6deSJohnny Huang 	u8 *data_ignore;
123a219f6deSJohnny Huang 	u8 *conf;
124a219f6deSJohnny Huang 	u8 *conf_ignore;
125a219f6deSJohnny Huang 	u8 *strap;
126a219f6deSJohnny Huang 	u8 *strap_reg_pro;
127a219f6deSJohnny Huang 	u8 *strap_pro;
128a219f6deSJohnny Huang 	u8 *strap_ignore;
129696656c6SJohnny Huang };
130696656c6SJohnny Huang 
1319a4fe690SJohnny Huang static struct otp_info_cb info_cb;
1329a4fe690SJohnny Huang 
13379e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
1349a4fe690SJohnny Huang 	{0, OTP_KEY_TYPE_AES,   0, "AES-256 as OEM platform key for image encryption/decryption"},
1359a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1369a4fe690SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,  1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
137181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
138181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   0, "RSA-public as SOC public key"},
139181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
140181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as SOC private key"},
141181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1429a4fe690SJohnny Huang };
1439a4fe690SJohnny Huang 
14479e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
1459a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1469a4fe690SJohnny 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"},
147181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
148181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
149181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1509a4fe690SJohnny Huang };
1519a4fe690SJohnny Huang 
1525fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
1535fdde29fSJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1545fdde29fSJohnny 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"},
155181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
156181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
157181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
158181f72d8SJohnny Huang };
159181f72d8SJohnny Huang 
160181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = {
161181f72d8SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
162181f72d8SJohnny 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"},
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,   1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
165181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
166181f72d8SJohnny Huang 	{11, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key(big endian)"},
167181f72d8SJohnny Huang 	{12, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
168181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key(big endian)"},
1695fdde29fSJohnny Huang };
1705fdde29fSJohnny Huang 
171*794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset)
172*794e27ecSJohnny Huang {
173*794e27ecSJohnny Huang 	int bit_offset;
174*794e27ecSJohnny Huang 	int i;
175*794e27ecSJohnny Huang 
176*794e27ecSJohnny Huang 	if (offset < 32) {
177*794e27ecSJohnny Huang 		i = 0;
178*794e27ecSJohnny Huang 		bit_offset = offset;
179*794e27ecSJohnny Huang 	} else {
180*794e27ecSJohnny Huang 		i = 1;
181*794e27ecSJohnny Huang 		bit_offset = offset - 32;
182*794e27ecSJohnny Huang 	}
183*794e27ecSJohnny Huang 	if ((rid[i] >> bit_offset) & 0x1)
184*794e27ecSJohnny Huang 		return 1;
185*794e27ecSJohnny Huang 	else
186*794e27ecSJohnny Huang 		return 0;
187*794e27ecSJohnny Huang }
188*794e27ecSJohnny Huang 
189*794e27ecSJohnny Huang static int get_rid_num(u32 *rid)
190*794e27ecSJohnny Huang {
191*794e27ecSJohnny Huang 	int i;
192*794e27ecSJohnny Huang 	int fz = 0;
193*794e27ecSJohnny Huang 	int rid_num = 0;
194*794e27ecSJohnny Huang 	int ret = 0;
195*794e27ecSJohnny Huang 
196*794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
197*794e27ecSJohnny Huang 		if (get_dw_bit(rid, i) == 0) {
198*794e27ecSJohnny Huang 			if (!fz)
199*794e27ecSJohnny Huang 				fz = 1;
200*794e27ecSJohnny Huang 
201*794e27ecSJohnny Huang 		} else {
202*794e27ecSJohnny Huang 			rid_num++;
203*794e27ecSJohnny Huang 			if (fz)
204*794e27ecSJohnny Huang 				ret = OTP_FAILURE;
205*794e27ecSJohnny Huang 		}
206*794e27ecSJohnny Huang 	}
207*794e27ecSJohnny Huang 	if (ret)
208*794e27ecSJohnny Huang 		return ret;
209*794e27ecSJohnny Huang 
210*794e27ecSJohnny Huang 	return rid_num;
211*794e27ecSJohnny Huang }
212*794e27ecSJohnny Huang 
213*794e27ecSJohnny Huang static void buf_print(u8 *buf, int len)
214*794e27ecSJohnny Huang {
215*794e27ecSJohnny Huang 	int i;
216*794e27ecSJohnny Huang 
217*794e27ecSJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
218*794e27ecSJohnny Huang 	for (i = 0; i < len; i++) {
219*794e27ecSJohnny Huang 		if (i % 16 == 0)
220*794e27ecSJohnny Huang 			printf("%04X: ", i);
221*794e27ecSJohnny Huang 		printf("%02X ", buf[i]);
222*794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
223*794e27ecSJohnny Huang 			printf("\n");
224*794e27ecSJohnny Huang 	}
225*794e27ecSJohnny Huang }
226*794e27ecSJohnny Huang 
227a219f6deSJohnny Huang static u32 chip_version(void)
2289a4fe690SJohnny Huang {
229badd21c2SJohnny Huang 	u64 rev_id;
2309a4fe690SJohnny Huang 
231badd21c2SJohnny Huang 	rev_id = readl(ASPEED_REVISION_ID0);
232badd21c2SJohnny Huang 	rev_id = ((u64)readl(ASPEED_REVISION_ID1) << 32) | rev_id;
2339a4fe690SJohnny Huang 
234badd21c2SJohnny Huang 	if (rev_id == 0x0500030305000303) {
235badd21c2SJohnny Huang 		/* AST2600-A0 */
2360dae9d52SJohnny Huang 		return OTP_AST2600A0;
237badd21c2SJohnny Huang 	} else if (rev_id == 0x0501030305010303) {
238badd21c2SJohnny Huang 		/* AST2600-A1 */
2390dae9d52SJohnny Huang 		return OTP_AST2600A1;
240badd21c2SJohnny Huang 	} else if (rev_id == 0x0501020305010203) {
241badd21c2SJohnny Huang 		/* AST2620-A1 */
242badd21c2SJohnny Huang 		return OTP_AST2600A1;
243badd21c2SJohnny Huang 	} else if (rev_id == 0x0502030305010303) {
244badd21c2SJohnny Huang 		/* AST2600-A2 */
2450dae9d52SJohnny Huang 		return OTP_AST2600A2;
246badd21c2SJohnny Huang 	} else if (rev_id == 0x0502020305010203) {
247badd21c2SJohnny Huang 		/* AST2620-A2 */
248badd21c2SJohnny Huang 		return OTP_AST2600A2;
249badd21c2SJohnny Huang 	} else if (rev_id == 0x0502010305010103) {
250badd21c2SJohnny Huang 		/* AST2605-A2 */
2510dae9d52SJohnny Huang 		return OTP_AST2600A2;
25264b66712SJohnny Huang 	} else if (rev_id == 0x0503030305030303) {
25364b66712SJohnny Huang 		/* AST2600-A3 */
25464b66712SJohnny Huang 		return OTP_AST2600A3;
25564b66712SJohnny Huang 	} else if (rev_id == 0x0503020305030203) {
25664b66712SJohnny Huang 		/* AST2620-A3 */
25764b66712SJohnny Huang 		return OTP_AST2600A3;
2580dae9d52SJohnny Huang 	}
2590dae9d52SJohnny Huang 
2605fdde29fSJohnny Huang 	return -1;
2619a4fe690SJohnny Huang }
2629a4fe690SJohnny Huang 
2633d3688adSJohnny Huang static void wait_complete(void)
2643d3688adSJohnny Huang {
2653d3688adSJohnny Huang 	int reg;
2663d3688adSJohnny Huang 
2673d3688adSJohnny Huang 	do {
2683d3688adSJohnny Huang 		reg = readl(OTP_STATUS);
2693d3688adSJohnny Huang 	} while ((reg & 0x6) != 0x6);
2703d3688adSJohnny Huang }
2713d3688adSJohnny Huang 
272a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data)
273dacbba92SJohnny Huang {
274dacbba92SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
275dacbba92SJohnny Huang 	writel(data, OTP_COMPARE_1); //write data
276dacbba92SJohnny Huang 	writel(0x23b1e362, OTP_COMMAND); //write command
277dacbba92SJohnny Huang 	wait_complete();
278dacbba92SJohnny Huang }
279dacbba92SJohnny Huang 
280dacbba92SJohnny Huang static void otp_soak(int soak)
281dacbba92SJohnny Huang {
28264b66712SJohnny Huang 	if (info_cb.version == OTP_AST2600A2 || info_cb.version == OTP_AST2600A3) {
283dacbba92SJohnny Huang 		switch (soak) {
284dacbba92SJohnny Huang 		case 0: //default
285dacbba92SJohnny Huang 			otp_write(0x3000, 0x0210); // Write MRA
286dacbba92SJohnny Huang 			otp_write(0x5000, 0x2000); // Write MRB
287dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
288dacbba92SJohnny Huang 			break;
289dacbba92SJohnny Huang 		case 1: //normal program
290dacbba92SJohnny Huang 			otp_write(0x3000, 0x1200); // Write MRA
291feea3fdfSJohnny Huang 			otp_write(0x5000, 0x107F); // Write MRB
292dacbba92SJohnny Huang 			otp_write(0x1000, 0x1024); // Write MR
293feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
294dacbba92SJohnny Huang 			break;
295dacbba92SJohnny Huang 		case 2: //soak program
296dacbba92SJohnny Huang 			otp_write(0x3000, 0x1220); // Write MRA
297feea3fdfSJohnny Huang 			otp_write(0x5000, 0x2074); // Write MRB
298dacbba92SJohnny Huang 			otp_write(0x1000, 0x08a4); // Write MR
299feea3fdfSJohnny Huang 			writel(0x04193a98, OTP_TIMING); // 600us
300dacbba92SJohnny Huang 			break;
301dacbba92SJohnny Huang 		}
302dacbba92SJohnny Huang 	} else {
303dacbba92SJohnny Huang 		switch (soak) {
304dacbba92SJohnny Huang 		case 0: //default
305dacbba92SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
306dacbba92SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
307dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
308dacbba92SJohnny Huang 			break;
309dacbba92SJohnny Huang 		case 1: //normal program
310dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
311dacbba92SJohnny Huang 			otp_write(0x5000, 0x302f); // Write MRB
312dacbba92SJohnny Huang 			otp_write(0x1000, 0x4020); // Write MR
313feea3fdfSJohnny Huang 			writel(0x04190760, OTP_TIMING); // 75us
314dacbba92SJohnny Huang 			break;
315dacbba92SJohnny Huang 		case 2: //soak program
316dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
317dacbba92SJohnny Huang 			otp_write(0x5000, 0x1027); // Write MRB
318dacbba92SJohnny Huang 			otp_write(0x1000, 0x4820); // Write MR
319feea3fdfSJohnny Huang 			writel(0x041930d4, OTP_TIMING); // 500us
320dacbba92SJohnny Huang 			break;
321dacbba92SJohnny Huang 		}
322dacbba92SJohnny Huang 	}
323dacbba92SJohnny Huang 
324dacbba92SJohnny Huang 	wait_complete();
325dacbba92SJohnny Huang }
326dacbba92SJohnny Huang 
327a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data)
32869d5fd8fSJohnny Huang {
3293d3688adSJohnny Huang 	writel(offset, OTP_ADDR); //Read address
3303d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3313d3688adSJohnny Huang 	wait_complete();
3323d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
3333d3688adSJohnny Huang 	data[1] = readl(OTP_COMPARE_2);
33469d5fd8fSJohnny Huang }
33569d5fd8fSJohnny Huang 
336a219f6deSJohnny Huang static void otp_read_config(u32 offset, u32 *data)
33769d5fd8fSJohnny Huang {
33869d5fd8fSJohnny Huang 	int config_offset;
33969d5fd8fSJohnny Huang 
34069d5fd8fSJohnny Huang 	config_offset = 0x800;
34169d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
34269d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
34369d5fd8fSJohnny Huang 
3443d3688adSJohnny Huang 	writel(config_offset, OTP_ADDR);  //Read address
3453d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3463d3688adSJohnny Huang 	wait_complete();
3473d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
34869d5fd8fSJohnny Huang }
34969d5fd8fSJohnny Huang 
350a219f6deSJohnny Huang static int otp_print_config(u32 offset, int dw_count)
35169d5fd8fSJohnny Huang {
35269d5fd8fSJohnny Huang 	int i;
353a219f6deSJohnny Huang 	u32 ret[1];
35469d5fd8fSJohnny Huang 
35569d5fd8fSJohnny Huang 	if (offset + dw_count > 32)
3562a856b9aSJohnny Huang 		return OTP_USAGE;
357dacbba92SJohnny Huang 	otp_soak(0);
35869d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i++) {
35969d5fd8fSJohnny Huang 		otp_read_config(i, ret);
360a6af4a17SJohnny Huang 		printf("OTPCFG%X: %08X\n", i, ret[0]);
36169d5fd8fSJohnny Huang 	}
36269d5fd8fSJohnny Huang 	printf("\n");
3632a856b9aSJohnny Huang 	return OTP_SUCCESS;
36469d5fd8fSJohnny Huang }
36569d5fd8fSJohnny Huang 
366a219f6deSJohnny Huang static int otp_print_data(u32 offset, int dw_count)
36769d5fd8fSJohnny Huang {
36869d5fd8fSJohnny Huang 	int i;
369a219f6deSJohnny Huang 	u32 ret[2];
37069d5fd8fSJohnny Huang 
37169d5fd8fSJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
3722a856b9aSJohnny Huang 		return OTP_USAGE;
373dacbba92SJohnny Huang 	otp_soak(0);
37469d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
37569d5fd8fSJohnny Huang 		otp_read_data(i, ret);
37669d5fd8fSJohnny Huang 		if (i % 4 == 0)
37769d5fd8fSJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
37869d5fd8fSJohnny Huang 		else
37969d5fd8fSJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
38069d5fd8fSJohnny Huang 	}
38169d5fd8fSJohnny Huang 	printf("\n");
3822a856b9aSJohnny Huang 	return OTP_SUCCESS;
38369d5fd8fSJohnny Huang }
38469d5fd8fSJohnny Huang 
385a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr)
38669d5fd8fSJohnny Huang {
387a219f6deSJohnny Huang 	u32 ret;
388a219f6deSJohnny Huang 	u32 *buf;
38969d5fd8fSJohnny Huang 
39069d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
39169d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
39269d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
39369d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
39469d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
3953d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
3963d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
3973d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
3983d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
3993d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
4003d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
4013d3688adSJohnny Huang 	wait_complete();
4023d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
40369d5fd8fSJohnny Huang 	if (ret & 0x1)
40469d5fd8fSJohnny Huang 		return 0;
40569d5fd8fSJohnny Huang 	else
40669d5fd8fSJohnny Huang 		return -1;
40769d5fd8fSJohnny Huang }
40869d5fd8fSJohnny Huang 
409a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value)
41069d5fd8fSJohnny Huang {
411a219f6deSJohnny Huang 	u32 ret[2];
41269d5fd8fSJohnny Huang 
41330a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
4143d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
41530a8c590SJohnny Huang 	else
4163d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
41730a8c590SJohnny Huang 
4183d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4193d3688adSJohnny Huang 	wait_complete();
4203d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4213d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
42283655e91SJohnny Huang 
42330a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
42430a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
42569d5fd8fSJohnny Huang 			return 0;
42669d5fd8fSJohnny Huang 		else
42769d5fd8fSJohnny Huang 			return -1;
42830a8c590SJohnny Huang 	} else {
42930a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
43030a8c590SJohnny Huang 			return 0;
43130a8c590SJohnny Huang 		else
43230a8c590SJohnny Huang 			return -1;
43330a8c590SJohnny Huang 	}
43469d5fd8fSJohnny Huang }
43569d5fd8fSJohnny Huang 
436a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size)
4374c1c9b35SJohnny Huang {
438a219f6deSJohnny Huang 	u32 ret[2];
4394c1c9b35SJohnny Huang 
4404c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
4414c1c9b35SJohnny Huang 
4424c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
4433d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
4444c1c9b35SJohnny Huang 	else
4453d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
4463d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4473d3688adSJohnny Huang 	wait_complete();
4483d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4493d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
4504c1c9b35SJohnny Huang 	if (size == 1) {
4514c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
4524c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
453696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
4544c1c9b35SJohnny Huang 				compare[0] = 0;
4554c1c9b35SJohnny Huang 				return 0;
456a219f6deSJohnny Huang 			}
4574c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
4584c1c9b35SJohnny Huang 			return -1;
4594c1c9b35SJohnny Huang 
4604c1c9b35SJohnny Huang 		} else {
4614c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
462696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
4634c1c9b35SJohnny Huang 				compare[0] = ~0;
4644c1c9b35SJohnny Huang 				return 0;
465a219f6deSJohnny Huang 			}
466d90825e2SJohnny Huang 			compare[0] = ~(value[0] ^ ret[1]);
4674c1c9b35SJohnny Huang 			return -1;
4684c1c9b35SJohnny Huang 		}
4694c1c9b35SJohnny Huang 	} else if (size == 2) {
4704c1c9b35SJohnny Huang 		// otp_addr should be even
471696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
4724c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4734c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4744c1c9b35SJohnny Huang 			compare[0] = 0;
4754c1c9b35SJohnny Huang 			compare[1] = ~0;
4764c1c9b35SJohnny Huang 			return 0;
477a219f6deSJohnny Huang 		}
4784c1c9b35SJohnny Huang 		// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4794c1c9b35SJohnny Huang 		// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4804c1c9b35SJohnny Huang 		compare[0] = value[0] ^ ret[0];
4814c1c9b35SJohnny Huang 		compare[1] = ~(value[1] ^ ret[1]);
4824c1c9b35SJohnny Huang 		return -1;
4834c1c9b35SJohnny Huang 	} else {
4844c1c9b35SJohnny Huang 		return -1;
4854c1c9b35SJohnny Huang 	}
4864c1c9b35SJohnny Huang }
4874c1c9b35SJohnny Huang 
488a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit)
48983655e91SJohnny Huang {
49090965bb3SJohnny Huang 	otp_write(0x0, prog_bit);
49183655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
49283655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
49383655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
49483655e91SJohnny Huang 	wait_complete();
49583655e91SJohnny Huang }
49683655e91SJohnny Huang 
497a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
49883655e91SJohnny Huang {
49983655e91SJohnny Huang 	int prog_bit;
50083655e91SJohnny Huang 
50183655e91SJohnny Huang 	if (prog_address % 2 == 0) {
50283655e91SJohnny Huang 		if (value)
50383655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
50483655e91SJohnny Huang 		else
50583655e91SJohnny Huang 			return;
50683655e91SJohnny Huang 	} else {
50764b66712SJohnny Huang 		if (info_cb.version != OTP_AST2600A3)
50883655e91SJohnny Huang 			prog_address |= 1 << 15;
50983655e91SJohnny Huang 		if (!value)
51083655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
51183655e91SJohnny Huang 		else
51283655e91SJohnny Huang 			return;
51383655e91SJohnny Huang 	}
51483655e91SJohnny Huang 	otp_prog(prog_address, prog_bit);
51583655e91SJohnny Huang }
51683655e91SJohnny Huang 
517a219f6deSJohnny Huang static int otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
51883655e91SJohnny Huang {
51983655e91SJohnny Huang 	int pass;
52083655e91SJohnny Huang 	int i;
52183655e91SJohnny Huang 
52283655e91SJohnny Huang 	otp_soak(1);
52383655e91SJohnny Huang 	_otp_prog_bit(value, prog_address, bit_offset);
52483655e91SJohnny Huang 	pass = 0;
52583655e91SJohnny Huang 
52683655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
52783655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
52883655e91SJohnny Huang 			otp_soak(2);
52983655e91SJohnny Huang 			_otp_prog_bit(value, prog_address, bit_offset);
53083655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
53183655e91SJohnny Huang 				otp_soak(1);
53283655e91SJohnny Huang 			} else {
53383655e91SJohnny Huang 				pass = 1;
53483655e91SJohnny Huang 				break;
53583655e91SJohnny Huang 			}
53683655e91SJohnny Huang 		} else {
53783655e91SJohnny Huang 			pass = 1;
53883655e91SJohnny Huang 			break;
53983655e91SJohnny Huang 		}
54083655e91SJohnny Huang 	}
541*794e27ecSJohnny Huang 	if (pass)
542*794e27ecSJohnny Huang 		return OTP_SUCCESS;
54383655e91SJohnny Huang 
544*794e27ecSJohnny Huang 	return OTP_FAILURE;
54583655e91SJohnny Huang }
54683655e91SJohnny Huang 
547a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address)
548d90825e2SJohnny Huang {
549d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
550d90825e2SJohnny Huang 
551d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
552696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
553d90825e2SJohnny Huang 			continue;
554d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
555d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
556d90825e2SJohnny Huang 			if (bit_value)
557d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
558d90825e2SJohnny Huang 			else
559d90825e2SJohnny Huang 				continue;
560d90825e2SJohnny Huang 		} else {
56164b66712SJohnny Huang 			if (info_cb.version != OTP_AST2600A3)
562d90825e2SJohnny Huang 				prog_address |= 1 << 15;
563d90825e2SJohnny Huang 			if (bit_value)
564d90825e2SJohnny Huang 				continue;
565d90825e2SJohnny Huang 			else
566d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
567d90825e2SJohnny Huang 		}
568d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
569d90825e2SJohnny Huang 	}
570d90825e2SJohnny Huang }
571d90825e2SJohnny Huang 
572a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address)
57354552c69SJohnny Huang {
57454552c69SJohnny Huang 	int pass;
57554552c69SJohnny Huang 	int i;
576a219f6deSJohnny Huang 	u32 data0_masked;
577a219f6deSJohnny Huang 	u32 data1_masked;
578a219f6deSJohnny Huang 	u32 buf0_masked;
579a219f6deSJohnny Huang 	u32 buf1_masked;
580a219f6deSJohnny Huang 	u32 compare[2];
58154552c69SJohnny Huang 
58254552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
58354552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
58454552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
58554552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
586a219f6deSJohnny Huang 	if (data0_masked == buf0_masked && data1_masked == buf1_masked)
58754552c69SJohnny Huang 		return 0;
58854552c69SJohnny Huang 
58954552c69SJohnny Huang 	otp_soak(1);
59054552c69SJohnny Huang 	if (data0_masked != buf0_masked)
59154552c69SJohnny Huang 		otp_prog_dw(buf[0], ignore_mask[0], prog_address);
59254552c69SJohnny Huang 	if (data1_masked != buf1_masked)
59354552c69SJohnny Huang 		otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
59454552c69SJohnny Huang 
59554552c69SJohnny Huang 	pass = 0;
59654552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
59754552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
59854552c69SJohnny Huang 			otp_soak(2);
599a219f6deSJohnny Huang 			if (compare[0] != 0)
60054552c69SJohnny Huang 				otp_prog_dw(compare[0], ignore_mask[0], prog_address);
601a219f6deSJohnny Huang 			if (compare[1] != ~0)
6025537bc72SJohnny Huang 				otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
60354552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
60454552c69SJohnny Huang 				otp_soak(1);
60554552c69SJohnny Huang 			} else {
60654552c69SJohnny Huang 				pass = 1;
60754552c69SJohnny Huang 				break;
60854552c69SJohnny Huang 			}
60954552c69SJohnny Huang 		} else {
61054552c69SJohnny Huang 			pass = 1;
61154552c69SJohnny Huang 			break;
61254552c69SJohnny Huang 		}
61354552c69SJohnny Huang 	}
61454552c69SJohnny Huang 
61554552c69SJohnny Huang 	if (!pass) {
61654552c69SJohnny Huang 		otp_soak(0);
61754552c69SJohnny Huang 		return OTP_FAILURE;
61854552c69SJohnny Huang 	}
61954552c69SJohnny Huang 	return OTP_SUCCESS;
62054552c69SJohnny Huang }
62154552c69SJohnny Huang 
622541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
62376d13988SJohnny Huang {
624a219f6deSJohnny Huang 	u32 OTPSTRAP_RAW[2];
6255010032bSJohnny Huang 	int strap_end;
62676d13988SJohnny Huang 	int i, j;
62776d13988SJohnny Huang 
6285010032bSJohnny Huang 	if (info_cb.version == OTP_AST2600A0) {
62976d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
63076d13988SJohnny Huang 			otpstrap[j].value = 0;
63176d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
63276d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
63376d13988SJohnny Huang 			otpstrap[j].protected = 0;
63476d13988SJohnny Huang 		}
6355010032bSJohnny Huang 		strap_end = 30;
6365010032bSJohnny Huang 	} else {
6375010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
6385010032bSJohnny Huang 			otpstrap[j].value = 0;
6395010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
6405010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
6415010032bSJohnny Huang 			otpstrap[j].reg_protected = 0;
6425010032bSJohnny Huang 			otpstrap[j].protected = 0;
6435010032bSJohnny Huang 		}
6445010032bSJohnny Huang 		strap_end = 28;
6455010032bSJohnny Huang 	}
64676d13988SJohnny Huang 
647dacbba92SJohnny Huang 	otp_soak(0);
6485010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
64976d13988SJohnny Huang 		int option = (i - 16) / 2;
650a219f6deSJohnny Huang 
65176d13988SJohnny Huang 		otp_read_config(i, &OTPSTRAP_RAW[0]);
65276d13988SJohnny Huang 		otp_read_config(i + 1, &OTPSTRAP_RAW[1]);
65376d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
65476d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
655a219f6deSJohnny Huang 
656a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
65776d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
65876d13988SJohnny Huang 			if (bit_value == 1)
65976d13988SJohnny Huang 				otpstrap[j].remain_times--;
66076d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
66176d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
66276d13988SJohnny Huang 		}
66376d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
66476d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
665a219f6deSJohnny Huang 
666a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
66776d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
66876d13988SJohnny Huang 			if (bit_value == 1)
66976d13988SJohnny Huang 				otpstrap[j].remain_times--;
67076d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
67176d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
67276d13988SJohnny Huang 		}
67376d13988SJohnny Huang 	}
6745010032bSJohnny Huang 
6755010032bSJohnny Huang 	if (info_cb.version != OTP_AST2600A0) {
6765010032bSJohnny Huang 		otp_read_config(28, &OTPSTRAP_RAW[0]);
6775010032bSJohnny Huang 		otp_read_config(29, &OTPSTRAP_RAW[1]);
6785010032bSJohnny Huang 		for (j = 0; j < 32; j++) {
6795010032bSJohnny Huang 			if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
6805010032bSJohnny Huang 				otpstrap[j].reg_protected = 1;
6815010032bSJohnny Huang 		}
6825010032bSJohnny Huang 		for (j = 32; j < 64; j++) {
6835010032bSJohnny Huang 			if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
6845010032bSJohnny Huang 				otpstrap[j].reg_protected = 1;
6855010032bSJohnny Huang 		}
6865010032bSJohnny Huang 	}
6875010032bSJohnny Huang 
68876d13988SJohnny Huang 	otp_read_config(30, &OTPSTRAP_RAW[0]);
68976d13988SJohnny Huang 	otp_read_config(31, &OTPSTRAP_RAW[1]);
69076d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
69176d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
69276d13988SJohnny Huang 			otpstrap[j].protected = 1;
69376d13988SJohnny Huang 	}
69476d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
69576d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
69676d13988SJohnny Huang 			otpstrap[j].protected = 1;
69776d13988SJohnny Huang 	}
69876d13988SJohnny Huang }
69976d13988SJohnny Huang 
700*794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
701*794e27ecSJohnny Huang {
702*794e27ecSJohnny Huang 	int bit_offset;
703*794e27ecSJohnny Huang 	int i, j;
704*794e27ecSJohnny Huang 
705*794e27ecSJohnny Huang 	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
706*794e27ecSJohnny Huang 	printf("___________________________________________________\n");
707*794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
708*794e27ecSJohnny Huang 		if (i < 32) {
709*794e27ecSJohnny Huang 			j = 0;
710*794e27ecSJohnny Huang 			bit_offset = i;
711*794e27ecSJohnny Huang 		} else {
712*794e27ecSJohnny Huang 			j = 1;
713*794e27ecSJohnny Huang 			bit_offset = i - 32;
714*794e27ecSJohnny Huang 		}
715*794e27ecSJohnny Huang 		if (i % 16 == 0)
716*794e27ecSJohnny Huang 			printf("%2x | ", i);
717*794e27ecSJohnny Huang 		printf("%d  ", (rid[j] >> bit_offset) & 0x1);
718*794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
719*794e27ecSJohnny Huang 			printf("\n");
720*794e27ecSJohnny Huang 	}
721*794e27ecSJohnny Huang }
722*794e27ecSJohnny Huang 
723696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
72469d5fd8fSJohnny Huang {
72579e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
726a219f6deSJohnny Huang 	u32 *OTPCFG = (u32 *)image_layout->conf;
727a219f6deSJohnny Huang 	u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
728a219f6deSJohnny Huang 	u32 mask;
729a219f6deSJohnny Huang 	u32 dw_offset;
730a219f6deSJohnny Huang 	u32 bit_offset;
731a219f6deSJohnny Huang 	u32 otp_value;
732a219f6deSJohnny Huang 	u32 otp_ignore;
733b458cd62SJohnny Huang 	int fail = 0;
734*794e27ecSJohnny Huang 	int rid_num = 0;
73573f11549SJohnny Huang 	char valid_bit[20];
736*794e27ecSJohnny Huang 	int fz;
73766f2f8e5SJohnny Huang 	int i;
73873f11549SJohnny Huang 	int j;
73966f2f8e5SJohnny Huang 
740737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
74166f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
7423cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
7433cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
7443cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
7453cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
746b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
747696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
748b458cd62SJohnny Huang 
749a219f6deSJohnny Huang 		if (otp_ignore == mask)
750b458cd62SJohnny Huang 			continue;
751a219f6deSJohnny Huang 		else if (otp_ignore != 0)
752b458cd62SJohnny Huang 			fail = 1;
753b458cd62SJohnny Huang 
754a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
7553cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
7563cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
7573cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
758b458cd62SJohnny Huang 			continue;
759b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
760b458cd62SJohnny Huang 
7613cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
7623cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
76366f2f8e5SJohnny Huang 		} else {
764b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
7653cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
7663cb28812SJohnny Huang 			       conf_info[i].bit_offset);
76766f2f8e5SJohnny Huang 		}
768b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
769b458cd62SJohnny Huang 
770b458cd62SJohnny Huang 		if (fail) {
771696656c6SJohnny Huang 			printf("Ignore mask error\n");
772a219f6deSJohnny Huang 			continue;
773a219f6deSJohnny Huang 		}
7743cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
775b458cd62SJohnny Huang 			printf("Reserved\n");
7763cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
7773cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
778b458cd62SJohnny Huang 			printf("\n");
7793cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
780b458cd62SJohnny Huang 			if (otp_value != 0) {
78173f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
782a219f6deSJohnny Huang 					if (otp_value == (1 << j))
78373f11549SJohnny Huang 						valid_bit[j * 2] = '1';
784a219f6deSJohnny Huang 					else
78573f11549SJohnny Huang 						valid_bit[j * 2] = '0';
78673f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
78773f11549SJohnny Huang 				}
78873f11549SJohnny Huang 				valid_bit[15] = 0;
78973f11549SJohnny Huang 			} else {
79073f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
791b458cd62SJohnny Huang 			}
7923cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
793b458cd62SJohnny Huang 			printf("\n");
794b458cd62SJohnny Huang 		} else {
7953cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
796b458cd62SJohnny Huang 		}
797b458cd62SJohnny Huang 	}
798b458cd62SJohnny Huang 
799*794e27ecSJohnny Huang 	if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
800*794e27ecSJohnny Huang 		if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
801*794e27ecSJohnny Huang 			printf("OTP revision ID is invalid.\n");
802*794e27ecSJohnny Huang 			fail = 1;
803*794e27ecSJohnny Huang 		} else {
804*794e27ecSJohnny Huang 			fz = 0;
805*794e27ecSJohnny Huang 			for (i = 0; i < 64; i++) {
806*794e27ecSJohnny Huang 				if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
807*794e27ecSJohnny Huang 					if (!fz)
808*794e27ecSJohnny Huang 						fz = 1;
809*794e27ecSJohnny Huang 				} else {
810*794e27ecSJohnny Huang 					rid_num++;
811*794e27ecSJohnny Huang 					if (fz) {
812*794e27ecSJohnny Huang 						printf("OTP revision ID is invalid.\n");
813*794e27ecSJohnny Huang 						fail = 1;
814*794e27ecSJohnny Huang 						break;
815*794e27ecSJohnny Huang 					}
816*794e27ecSJohnny Huang 				}
817*794e27ecSJohnny Huang 			}
818*794e27ecSJohnny Huang 		}
819*794e27ecSJohnny Huang 		if (fail)
820*794e27ecSJohnny Huang 			printf("OTP revision ID\n");
821*794e27ecSJohnny Huang 		else
822*794e27ecSJohnny Huang 			printf("OTP revision ID: 0x%x\n", rid_num);
823*794e27ecSJohnny Huang 		otp_print_revid(&OTPCFG[0xa]);
824*794e27ecSJohnny Huang 	}
825*794e27ecSJohnny Huang 
826b458cd62SJohnny Huang 	if (fail)
827b458cd62SJohnny Huang 		return OTP_FAILURE;
828b458cd62SJohnny Huang 
82966f2f8e5SJohnny Huang 	return OTP_SUCCESS;
83066f2f8e5SJohnny Huang }
83166f2f8e5SJohnny Huang 
8322d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
83366f2f8e5SJohnny Huang {
83479e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
835a219f6deSJohnny Huang 	u32 OTPCFG[16];
836a219f6deSJohnny Huang 	u32 mask;
837a219f6deSJohnny Huang 	u32 dw_offset;
838a219f6deSJohnny Huang 	u32 bit_offset;
839a219f6deSJohnny Huang 	u32 otp_value;
84073f11549SJohnny Huang 	char valid_bit[20];
84166f2f8e5SJohnny Huang 	int i;
84273f11549SJohnny Huang 	int j;
84366f2f8e5SJohnny Huang 
844dacbba92SJohnny Huang 	otp_soak(0);
845bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
84666f2f8e5SJohnny Huang 		otp_read_config(i, &OTPCFG[i]);
84766f2f8e5SJohnny Huang 
848b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
849b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
8503cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
8513cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
8522d4b0742SJohnny Huang 			continue;
8533cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
8543cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
8553cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
856b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
857b458cd62SJohnny Huang 
858a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
8593cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
8603cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
8613cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
862b458cd62SJohnny Huang 			continue;
863b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
864b458cd62SJohnny Huang 
8653cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
8663cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
867b458cd62SJohnny Huang 		} else {
868b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
8693cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
8703cb28812SJohnny Huang 			       conf_info[i].bit_offset);
871b458cd62SJohnny Huang 		}
872b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
873b458cd62SJohnny Huang 
8743cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
875b458cd62SJohnny Huang 			printf("Reserved\n");
8763cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
8773cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
878b458cd62SJohnny Huang 			printf("\n");
8793cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
880b458cd62SJohnny Huang 			if (otp_value != 0) {
88173f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
882a219f6deSJohnny Huang 					if (otp_value == (1 << j))
88373f11549SJohnny Huang 						valid_bit[j * 2] = '1';
884a219f6deSJohnny Huang 					else
88573f11549SJohnny Huang 						valid_bit[j * 2] = '0';
88673f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
88773f11549SJohnny Huang 				}
88873f11549SJohnny Huang 				valid_bit[15] = 0;
88973f11549SJohnny Huang 			} else {
89073f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
891b458cd62SJohnny Huang 			}
8923cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
893b458cd62SJohnny Huang 			printf("\n");
894b458cd62SJohnny Huang 		} else {
8953cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
896b458cd62SJohnny Huang 		}
897b458cd62SJohnny Huang 	}
898b458cd62SJohnny Huang 	return OTP_SUCCESS;
89966f2f8e5SJohnny Huang }
90066f2f8e5SJohnny Huang 
9015010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
90276d13988SJohnny Huang {
90379e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
904a219f6deSJohnny Huang 	u32 *OTPSTRAP;
905a219f6deSJohnny Huang 	u32 *OTPSTRAP_REG_PRO;
906a219f6deSJohnny Huang 	u32 *OTPSTRAP_PRO;
907a219f6deSJohnny Huang 	u32 *OTPSTRAP_IGNORE;
90876d13988SJohnny Huang 	int i;
909a8bd6d8cSJohnny Huang 	int fail = 0;
910a219f6deSJohnny Huang 	u32 bit_offset;
911a219f6deSJohnny Huang 	u32 dw_offset;
912a219f6deSJohnny Huang 	u32 mask;
913a219f6deSJohnny Huang 	u32 otp_value;
914a219f6deSJohnny Huang 	u32 otp_reg_protect;
915a219f6deSJohnny Huang 	u32 otp_protect;
916a219f6deSJohnny Huang 	u32 otp_ignore;
91776d13988SJohnny Huang 
918a219f6deSJohnny Huang 	OTPSTRAP = (u32 *)image_layout->strap;
919a219f6deSJohnny Huang 	OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
920a219f6deSJohnny Huang 	OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
9215010032bSJohnny Huang 	if (info_cb.version == OTP_AST2600A0) {
922696656c6SJohnny Huang 		OTPSTRAP_REG_PRO = NULL;
923a8bd6d8cSJohnny Huang 		printf("BIT(hex)   Value       Protect     Description\n");
924696656c6SJohnny Huang 	} else {
925a219f6deSJohnny Huang 		OTPSTRAP_REG_PRO = (u32 *)image_layout->strap_reg_pro;
926de6b0cc4SJohnny Huang 		printf("BIT(hex)   Value       Reg_Protect Protect     Description\n");
927696656c6SJohnny Huang 	}
928de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
929b458cd62SJohnny Huang 
9303cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
931696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
932a8bd6d8cSJohnny Huang 			dw_offset = 1;
9333cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
934a8bd6d8cSJohnny Huang 		} else {
935a8bd6d8cSJohnny Huang 			dw_offset = 0;
9363cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
937a8bd6d8cSJohnny Huang 		}
93876d13988SJohnny Huang 
9393cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
940a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
941a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
942696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
943a8bd6d8cSJohnny Huang 
9445010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0)
945696656c6SJohnny Huang 			otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask;
9465010032bSJohnny Huang 		else
9475010032bSJohnny Huang 			otp_reg_protect = 0;
948696656c6SJohnny Huang 
949a219f6deSJohnny Huang 		if (otp_ignore == mask)
950a8bd6d8cSJohnny Huang 			continue;
951a219f6deSJohnny Huang 		else if (otp_ignore != 0)
952a8bd6d8cSJohnny Huang 			fail = 1;
953a8bd6d8cSJohnny Huang 
954a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
9553cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
956a8bd6d8cSJohnny Huang 			continue;
957a8bd6d8cSJohnny Huang 
9583cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
9593cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
960a8bd6d8cSJohnny Huang 		} else {
961b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
9623cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
9633cb28812SJohnny Huang 			       strap_info[i].bit_offset);
964a8bd6d8cSJohnny Huang 		}
965a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
9665010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0)
967696656c6SJohnny Huang 			printf("0x%-10x", otp_reg_protect);
968a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
969a8bd6d8cSJohnny Huang 
970a8bd6d8cSJohnny Huang 		if (fail) {
971696656c6SJohnny Huang 			printf("Ignore mask error\n");
972a8bd6d8cSJohnny Huang 		} else {
9733cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
9743cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
975a8bd6d8cSJohnny Huang 			else
976a8bd6d8cSJohnny Huang 				printf("Reserved\n");
977a8bd6d8cSJohnny Huang 		}
978a8bd6d8cSJohnny Huang 	}
979a8bd6d8cSJohnny Huang 
980a8bd6d8cSJohnny Huang 	if (fail)
98176d13988SJohnny Huang 		return OTP_FAILURE;
98276d13988SJohnny Huang 
98376d13988SJohnny Huang 	return OTP_SUCCESS;
98476d13988SJohnny Huang }
98576d13988SJohnny Huang 
986b458cd62SJohnny Huang static int otp_print_strap_info(int view)
98776d13988SJohnny Huang {
98879e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
98976d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
99007baa4e8SJohnny Huang 	int i, j;
991b458cd62SJohnny Huang 	int fail = 0;
992a219f6deSJohnny Huang 	u32 bit_offset;
993a219f6deSJohnny Huang 	u32 length;
994a219f6deSJohnny Huang 	u32 otp_value;
995a219f6deSJohnny Huang 	u32 otp_protect;
99676d13988SJohnny Huang 
997541eb887SJohnny Huang 	otp_strap_status(strap_status);
99876d13988SJohnny Huang 
999b458cd62SJohnny Huang 	if (view) {
100083655e91SJohnny Huang 		if (info_cb.version == OTP_AST2600A0)
100107baa4e8SJohnny Huang 			printf("BIT(hex) Value  Remains  Protect   Description\n");
100283655e91SJohnny Huang 		else
100383655e91SJohnny Huang 			printf("BIT(hex) Value  Remains  Reg_Protect Protect   Description\n");
100407baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
1005b458cd62SJohnny Huang 	} else {
1006b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
1007b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
100876d13988SJohnny Huang 	}
10093cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1010b458cd62SJohnny Huang 		otp_value = 0;
10113cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
10123cb28812SJohnny Huang 		length = strap_info[i].length;
1013b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
1014c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
1015c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
1016b458cd62SJohnny Huang 		}
1017a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
10183cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1019b458cd62SJohnny Huang 			continue;
1020b458cd62SJohnny Huang 		if (view) {
1021b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
10223cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
1023b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
102407baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
102583655e91SJohnny Huang 				if (info_cb.version != OTP_AST2600A0)
1026e1a7245eSJohnny Huang 					printf("0x%-10X", strap_status[bit_offset + j].reg_protected);
1027e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
10283cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
1029b458cd62SJohnny Huang 					printf(" Reserved\n");
1030b458cd62SJohnny Huang 					continue;
1031b458cd62SJohnny Huang 				}
1032b458cd62SJohnny Huang 				if (length == 1) {
10333cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
1034b458cd62SJohnny Huang 					continue;
103576d13988SJohnny Huang 				}
103676d13988SJohnny Huang 
1037b458cd62SJohnny Huang 				if (j == 0)
10383cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
1039b458cd62SJohnny Huang 				else if (j == length - 1)
1040b458cd62SJohnny Huang 					printf("\\ \"\n");
1041b458cd62SJohnny Huang 				else
1042b458cd62SJohnny Huang 					printf("| \"\n");
104376d13988SJohnny Huang 			}
1044b458cd62SJohnny Huang 		} else {
1045c947ef08SJohnny Huang 			if (length == 1) {
10463cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
1047b458cd62SJohnny Huang 			} else {
1048b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
1049b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
1050b458cd62SJohnny Huang 			}
1051b458cd62SJohnny Huang 
1052b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
1053b458cd62SJohnny Huang 
10543cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
10553cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1056b458cd62SJohnny Huang 			else
1057b458cd62SJohnny Huang 				printf("Reserved\n");
1058b458cd62SJohnny Huang 		}
1059b458cd62SJohnny Huang 	}
1060b458cd62SJohnny Huang 
1061b458cd62SJohnny Huang 	if (fail)
1062b458cd62SJohnny Huang 		return OTP_FAILURE;
1063b458cd62SJohnny Huang 
1064b458cd62SJohnny Huang 	return OTP_SUCCESS;
1065b458cd62SJohnny Huang }
1066b458cd62SJohnny Huang 
1067696656c6SJohnny Huang static int otp_print_data_info(struct otp_image_layout *image_layout)
106869d5fd8fSJohnny Huang {
106969d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
107079e42a59SJoel Stanley 	const struct otpkey_type *key_info_array = info_cb.key_info;
10719a4fe690SJohnny Huang 	struct otpkey_type key_info;
1072a219f6deSJohnny Huang 	u32 *buf;
1073a219f6deSJohnny Huang 	u8 *byte_buf;
10749d998018SJohnny Huang 	char empty = 1;
107569d5fd8fSJohnny Huang 	int i = 0, len = 0;
10769a4fe690SJohnny Huang 	int j;
107754552c69SJohnny Huang 
1078696656c6SJohnny Huang 	byte_buf = image_layout->data;
1079a219f6deSJohnny Huang 	buf = (u32 *)byte_buf;
10809d998018SJohnny Huang 
10819d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
1082a219f6deSJohnny Huang 		if (buf[i] != 0)
10839d998018SJohnny Huang 			empty = 0;
10849d998018SJohnny Huang 	}
10859d998018SJohnny Huang 	if (empty)
10869d998018SJohnny Huang 		return 0;
10879d998018SJohnny Huang 
10889d998018SJohnny Huang 	i = 0;
108969d5fd8fSJohnny Huang 	while (1) {
109069d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
109169d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
109269d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
109369d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
109469d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
109569d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
10969a4fe690SJohnny Huang 
10979a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
10989a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
10999a4fe690SJohnny Huang 				key_info = key_info_array[j];
11009a4fe690SJohnny Huang 				break;
11019a4fe690SJohnny Huang 			}
11029a4fe690SJohnny Huang 		}
11039a4fe690SJohnny Huang 
11047f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
110569d5fd8fSJohnny Huang 		printf("Key Type: ");
11069a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
11079a4fe690SJohnny Huang 
11089a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
110969d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
111069d5fd8fSJohnny Huang 			switch (key_length) {
111169d5fd8fSJohnny Huang 			case 0:
111269d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
111369d5fd8fSJohnny Huang 				break;
111469d5fd8fSJohnny Huang 			case 1:
111569d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
111669d5fd8fSJohnny Huang 				break;
111769d5fd8fSJohnny Huang 			case 2:
111869d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
111969d5fd8fSJohnny Huang 				break;
112069d5fd8fSJohnny Huang 			case 3:
112169d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
112269d5fd8fSJohnny Huang 				break;
112369d5fd8fSJohnny Huang 			}
1124181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1125181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
112669d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
112769d5fd8fSJohnny Huang 			switch (key_length) {
112869d5fd8fSJohnny Huang 			case 0:
112969d5fd8fSJohnny Huang 				printf("RSA1024\n");
113069d5fd8fSJohnny Huang 				len = 0x100;
113169d5fd8fSJohnny Huang 				break;
113269d5fd8fSJohnny Huang 			case 1:
113369d5fd8fSJohnny Huang 				printf("RSA2048\n");
113469d5fd8fSJohnny Huang 				len = 0x200;
113569d5fd8fSJohnny Huang 				break;
113669d5fd8fSJohnny Huang 			case 2:
113769d5fd8fSJohnny Huang 				printf("RSA3072\n");
113869d5fd8fSJohnny Huang 				len = 0x300;
113969d5fd8fSJohnny Huang 				break;
114069d5fd8fSJohnny Huang 			case 3:
114169d5fd8fSJohnny Huang 				printf("RSA4096\n");
114269d5fd8fSJohnny Huang 				len = 0x400;
114369d5fd8fSJohnny Huang 				break;
114469d5fd8fSJohnny Huang 			}
114569d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
114669d5fd8fSJohnny Huang 		}
11479a4fe690SJohnny Huang 		if (key_info.need_id)
114869d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
114969d5fd8fSJohnny Huang 		printf("Key Value:\n");
11509a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
115169d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
11529a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
11539a4fe690SJohnny Huang 			printf("AES Key:\n");
11549a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
11555fdde29fSJohnny Huang 			if (info_cb.version == OTP_AST2600A0) {
11569a4fe690SJohnny Huang 				printf("AES IV:\n");
11579a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
11589a4fe690SJohnny Huang 			}
11599a4fe690SJohnny Huang 
11609a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
11615fdde29fSJohnny Huang 			if (info_cb.version == OTP_AST2600A0) {
116269d5fd8fSJohnny Huang 				printf("AES Key:\n");
116369d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
116469d5fd8fSJohnny Huang 				printf("AES IV:\n");
116569d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
11665fdde29fSJohnny Huang 			} else {
11679a4fe690SJohnny Huang 				printf("AES Key 1:\n");
11689a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
11699a4fe690SJohnny Huang 				printf("AES Key 2:\n");
11709a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
11719a4fe690SJohnny Huang 			}
1172181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
117369d5fd8fSJohnny Huang 			printf("RSA mod:\n");
117469d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
117569d5fd8fSJohnny Huang 			printf("RSA exp:\n");
117669d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1177181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1178181f72d8SJohnny Huang 			printf("RSA mod:\n");
1179181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1180181f72d8SJohnny Huang 			printf("RSA exp:\n");
1181a219f6deSJohnny Huang 			buf_print((u8 *)"\x01\x00\x01", 3);
118269d5fd8fSJohnny Huang 		}
118369d5fd8fSJohnny Huang 		if (last)
118469d5fd8fSJohnny Huang 			break;
118569d5fd8fSJohnny Huang 		i++;
118669d5fd8fSJohnny Huang 	}
118769d5fd8fSJohnny Huang 	return 0;
118869d5fd8fSJohnny Huang }
118969d5fd8fSJohnny Huang 
11905010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout)
119169d5fd8fSJohnny Huang {
1192a6d0d645SJohnny Huang 	int i, k;
1193d90825e2SJohnny Huang 	int pass = 0;
1194a219f6deSJohnny Huang 	u32 prog_address;
1195a219f6deSJohnny Huang 	u32 data[16];
1196a219f6deSJohnny Huang 	u32 compare[2];
1197a219f6deSJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1198a219f6deSJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1199a219f6deSJohnny Huang 	u32 data_masked;
1200a219f6deSJohnny Huang 	u32 buf_masked;
120169d5fd8fSJohnny Huang 
1202a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
1203a6d0d645SJohnny Huang 
1204bb34a7bfSJohnny Huang 	for (i = 0; i < 16 ; i++) {
120569d5fd8fSJohnny Huang 		prog_address = 0x800;
1206a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1207a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1208a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
1209a6d0d645SJohnny Huang 	}
1210a6d0d645SJohnny Huang 
1211a6d0d645SJohnny Huang 	printf("Check writable...\n");
1212bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
12135010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
12145010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1215d90825e2SJohnny Huang 		if (data_masked == buf_masked)
121669d5fd8fSJohnny Huang 			continue;
1217d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1218a6d0d645SJohnny Huang 			continue;
1219a6d0d645SJohnny Huang 		} else {
1220a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1221a6af4a17SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, data[i]);
12225010032bSJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
12235010032bSJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
12242a856b9aSJohnny Huang 			return OTP_FAILURE;
1225a6d0d645SJohnny Huang 		}
1226a6d0d645SJohnny Huang 	}
1227a6d0d645SJohnny Huang 
1228a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1229d90825e2SJohnny Huang 	otp_soak(0);
1230bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
12315010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
12325010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1233a6d0d645SJohnny Huang 		prog_address = 0x800;
1234a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1235a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1236bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1237bb34a7bfSJohnny Huang 			pass = 1;
1238a6d0d645SJohnny Huang 			continue;
1239bb34a7bfSJohnny Huang 		}
1240de6fbf1cSJohnny Huang 
1241de6fbf1cSJohnny Huang 		otp_soak(1);
12425010032bSJohnny Huang 		otp_prog_dw(conf[i], conf_ignore[i], prog_address);
1243a6d0d645SJohnny Huang 
124469d5fd8fSJohnny Huang 		pass = 0;
124569d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
12465010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1247de6fbf1cSJohnny Huang 				otp_soak(2);
1248feea3fdfSJohnny Huang 				otp_prog_dw(compare[0], conf_ignore[i], prog_address);
12495010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1250de6fbf1cSJohnny Huang 					otp_soak(1);
1251de6fbf1cSJohnny Huang 				} else {
1252de6fbf1cSJohnny Huang 					pass = 1;
1253de6fbf1cSJohnny Huang 					break;
1254de6fbf1cSJohnny Huang 				}
1255a6d0d645SJohnny Huang 			} else {
125669d5fd8fSJohnny Huang 				pass = 1;
125769d5fd8fSJohnny Huang 				break;
125869d5fd8fSJohnny Huang 			}
125969d5fd8fSJohnny Huang 		}
1260bb34a7bfSJohnny Huang 		if (pass == 0) {
1261bb34a7bfSJohnny Huang 			printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n",
12625010032bSJohnny Huang 			       i, data[i], conf[i], conf_ignore[i]);
1263bb34a7bfSJohnny Huang 			break;
1264bb34a7bfSJohnny Huang 		}
1265a6d0d645SJohnny Huang 	}
1266a6d0d645SJohnny Huang 
1267de6fbf1cSJohnny Huang 	otp_soak(0);
126869d5fd8fSJohnny Huang 	if (!pass)
12692a856b9aSJohnny Huang 		return OTP_FAILURE;
1270a6d0d645SJohnny Huang 
12712a856b9aSJohnny Huang 	return OTP_SUCCESS;
127269d5fd8fSJohnny Huang }
127369d5fd8fSJohnny Huang 
1274eda10d61SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit)
1275eda10d61SJohnny Huang {
12769901d43aSJohnny Huang 	int prog_flag = 0;
12779901d43aSJohnny Huang 
12789901d43aSJohnny Huang 	// ignore this bit
12799901d43aSJohnny Huang 	if (ibit == 1)
1280eda10d61SJohnny Huang 		return OTP_SUCCESS;
1281eda10d61SJohnny Huang 	printf("OTPSTRAP[%X]:\n", offset);
12829901d43aSJohnny Huang 
1283eda10d61SJohnny Huang 	if (bit == otpstrap->value) {
12849901d43aSJohnny Huang 		if (!pbit && !rpbit) {
1285eda10d61SJohnny Huang 			printf("    The value is same as before, skip it.\n");
1286eda10d61SJohnny Huang 			return OTP_PROG_SKIP;
1287eda10d61SJohnny Huang 		}
12889901d43aSJohnny Huang 		printf("    The value is same as before.\n");
12899901d43aSJohnny Huang 	} else {
12909901d43aSJohnny Huang 		prog_flag = 1;
12919901d43aSJohnny Huang 	}
12929901d43aSJohnny Huang 	if (otpstrap->protected == 1 && prog_flag) {
1293eda10d61SJohnny Huang 		printf("    This bit is protected and is not writable\n");
1294eda10d61SJohnny Huang 		return OTP_FAILURE;
1295eda10d61SJohnny Huang 	}
12969901d43aSJohnny Huang 	if (otpstrap->remain_times == 0 && prog_flag) {
1297eda10d61SJohnny Huang 		printf("    This bit is no remaining times to write.\n");
1298eda10d61SJohnny Huang 		return OTP_FAILURE;
1299eda10d61SJohnny Huang 	}
13009901d43aSJohnny Huang 	if (pbit == 1)
1301eda10d61SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
13029901d43aSJohnny Huang 	if (rpbit == 1 && info_cb.version != OTP_AST2600A0)
1303eda10d61SJohnny Huang 		printf("    The relative register will be protected.\n");
13049901d43aSJohnny Huang 	if (prog_flag)
1305eda10d61SJohnny 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);
13069901d43aSJohnny Huang 
1307eda10d61SJohnny Huang 	return OTP_SUCCESS;
1308eda10d61SJohnny Huang }
1309eda10d61SJohnny Huang 
13105010032bSJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout)
131169d5fd8fSJohnny Huang {
131269d5fd8fSJohnny Huang 	int i;
1313a219f6deSJohnny Huang 	u32 *strap;
1314a219f6deSJohnny Huang 	u32 *strap_ignore;
1315a219f6deSJohnny Huang 	u32 *strap_reg_protect;
1316a219f6deSJohnny Huang 	u32 *strap_pro;
1317eda10d61SJohnny Huang 	int bit, pbit, ibit, rpbit;
131869d5fd8fSJohnny Huang 	int fail = 0;
1319eda10d61SJohnny Huang 	int ret;
132066f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
132169d5fd8fSJohnny Huang 
1322a219f6deSJohnny Huang 	strap = (u32 *)image_layout->strap;
1323a219f6deSJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1324a219f6deSJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1325a219f6deSJohnny Huang 	strap_reg_protect = (u32 *)image_layout->strap_reg_pro;
13265010032bSJohnny Huang 
1327541eb887SJohnny Huang 	otp_strap_status(otpstrap);
132869d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
132969d5fd8fSJohnny Huang 		if (i < 32) {
13305010032bSJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1331eda10d61SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
13325010032bSJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
133369d5fd8fSJohnny Huang 		} else {
13345010032bSJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1335eda10d61SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
13365010032bSJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
13375010032bSJohnny Huang 		}
13385010032bSJohnny Huang 
13395010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0) {
1340a219f6deSJohnny Huang 			if (i < 32)
13415010032bSJohnny Huang 				rpbit = (strap_reg_protect[0] >> i) & 0x1;
1342a219f6deSJohnny Huang 			else
13435010032bSJohnny Huang 				rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
13445010032bSJohnny Huang 		} else {
13455010032bSJohnny Huang 			rpbit = 0;
134669d5fd8fSJohnny Huang 		}
1347eda10d61SJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit);
1348eda10d61SJohnny Huang 
1349eda10d61SJohnny Huang 		if (ret == OTP_FAILURE)
135069d5fd8fSJohnny Huang 			fail = 1;
135169d5fd8fSJohnny Huang 	}
135269d5fd8fSJohnny Huang 	if (fail == 1)
1353a6af4a17SJohnny Huang 		return OTP_FAILURE;
13549901d43aSJohnny Huang 	else
1355eda10d61SJohnny Huang 		return OTP_SUCCESS;
135669d5fd8fSJohnny Huang }
135769d5fd8fSJohnny Huang 
13582a856b9aSJohnny Huang static int otp_print_strap(int start, int count)
135969d5fd8fSJohnny Huang {
136069d5fd8fSJohnny Huang 	int i, j;
1361de6b0cc4SJohnny Huang 	int remains;
136266f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
136369d5fd8fSJohnny Huang 
13642a856b9aSJohnny Huang 	if (start < 0 || start > 64)
13652a856b9aSJohnny Huang 		return OTP_USAGE;
13662a856b9aSJohnny Huang 
13672a856b9aSJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
13682a856b9aSJohnny Huang 		return OTP_USAGE;
13692a856b9aSJohnny Huang 
1370541eb887SJohnny Huang 	otp_strap_status(otpstrap);
137169d5fd8fSJohnny Huang 
1372de6b0cc4SJohnny Huang 	if (info_cb.version == OTP_AST2600A0) {
1373de6b0cc4SJohnny Huang 		remains = 7;
137407baa4e8SJohnny Huang 		printf("BIT(hex)  Value  Option           Status\n");
1375de6b0cc4SJohnny Huang 	} else {
1376de6b0cc4SJohnny Huang 		remains = 6;
1377de6b0cc4SJohnny Huang 		printf("BIT(hex)  Value  Option         Reg_Protect Status\n");
1378de6b0cc4SJohnny Huang 	}
1379de6b0cc4SJohnny Huang 	printf("______________________________________________________________________________\n");
1380737ed20bSJohnny Huang 
1381cd1610b4SJohnny Huang 	for (i = start; i < start + count; i++) {
138207baa4e8SJohnny Huang 		printf("0x%-8X", i);
1383737ed20bSJohnny Huang 		printf("%-7d", otpstrap[i].value);
1384de6b0cc4SJohnny Huang 		for (j = 0; j < remains; j++)
1385737ed20bSJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
1386737ed20bSJohnny Huang 		printf("   ");
1387a219f6deSJohnny Huang 		if (info_cb.version != OTP_AST2600A0)
1388de6b0cc4SJohnny Huang 			printf("%d           ", otpstrap[i].reg_protected);
138969d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
1390737ed20bSJohnny Huang 			printf("protected and not writable");
139169d5fd8fSJohnny Huang 		} else {
1392737ed20bSJohnny Huang 			printf("not protected ");
1393a219f6deSJohnny Huang 			if (otpstrap[i].remain_times == 0)
1394737ed20bSJohnny Huang 				printf("and no remaining times to write.");
1395a219f6deSJohnny Huang 			else
1396737ed20bSJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
139769d5fd8fSJohnny Huang 		}
1398737ed20bSJohnny Huang 		printf("\n");
139969d5fd8fSJohnny Huang 	}
14002a856b9aSJohnny Huang 
14012a856b9aSJohnny Huang 	return OTP_SUCCESS;
140269d5fd8fSJohnny Huang }
140369d5fd8fSJohnny Huang 
14048848d5dcSJohnny Huang static int otp_prog_strap_bit(int bit_offset, int value)
14058848d5dcSJohnny Huang {
14068848d5dcSJohnny Huang 	struct otpstrap_status otpstrap[64];
1407a219f6deSJohnny Huang 	u32 prog_address;
14088848d5dcSJohnny Huang 	int offset;
14098848d5dcSJohnny Huang 	int ret;
14108848d5dcSJohnny Huang 
14118848d5dcSJohnny Huang 	otp_strap_status(otpstrap);
14128848d5dcSJohnny Huang 
14138848d5dcSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
14148848d5dcSJohnny Huang 
1415a219f6deSJohnny Huang 	if (ret != OTP_SUCCESS)
14168848d5dcSJohnny Huang 		return ret;
14178848d5dcSJohnny Huang 
14188848d5dcSJohnny Huang 	prog_address = 0x800;
14198848d5dcSJohnny Huang 	if (bit_offset < 32) {
14208848d5dcSJohnny Huang 		offset = bit_offset;
14218848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
14228848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
14238848d5dcSJohnny Huang 
14248848d5dcSJohnny Huang 	} else {
14258848d5dcSJohnny Huang 		offset = (bit_offset - 32);
14268848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
14278848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
14288848d5dcSJohnny Huang 	}
14298848d5dcSJohnny Huang 
143083655e91SJohnny Huang 	return otp_prog_bit(1, prog_address, offset);
14318848d5dcSJohnny Huang }
14328848d5dcSJohnny Huang 
14335010032bSJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout)
143469d5fd8fSJohnny Huang {
1435a219f6deSJohnny Huang 	u32 *strap;
1436a219f6deSJohnny Huang 	u32 *strap_ignore;
1437a219f6deSJohnny Huang 	u32 *strap_pro;
1438a219f6deSJohnny Huang 	u32 *strap_reg_protect;
1439a219f6deSJohnny Huang 	u32 prog_address;
144083655e91SJohnny Huang 	int i;
1441eda10d61SJohnny Huang 	int bit, pbit, ibit, offset, rpbit;
144269d5fd8fSJohnny Huang 	int fail = 0;
144383655e91SJohnny Huang 	int ret;
14449901d43aSJohnny Huang 	int prog_flag = 0;
144566f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
144669d5fd8fSJohnny Huang 
1447a219f6deSJohnny Huang 	strap = (u32 *)image_layout->strap;
1448a219f6deSJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1449a219f6deSJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1450a219f6deSJohnny Huang 	strap_reg_protect = (u32 *)image_layout->strap_reg_pro;
14515010032bSJohnny Huang 
14527f795e57SJohnny Huang 	printf("Read OTP Strap Region:\n");
1453541eb887SJohnny Huang 	otp_strap_status(otpstrap);
145469d5fd8fSJohnny Huang 
14557f795e57SJohnny Huang 	printf("Check writable...\n");
14565010032bSJohnny Huang 	if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) {
14577f795e57SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
14587f795e57SJohnny Huang 		return OTP_FAILURE;
14597f795e57SJohnny Huang 	}
14607e22f42dSJohnny Huang 
146169d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
146269d5fd8fSJohnny Huang 		prog_address = 0x800;
146369d5fd8fSJohnny Huang 		if (i < 32) {
146469d5fd8fSJohnny Huang 			offset = i;
14655010032bSJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1466eda10d61SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
14675010032bSJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
146869d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
146969d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
147069d5fd8fSJohnny Huang 
147169d5fd8fSJohnny Huang 		} else {
147269d5fd8fSJohnny Huang 			offset = (i - 32);
14735010032bSJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1474eda10d61SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
14755010032bSJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
147669d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
147769d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
147869d5fd8fSJohnny Huang 		}
14795010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0) {
1480a219f6deSJohnny Huang 			if (i < 32)
14815010032bSJohnny Huang 				rpbit = (strap_reg_protect[0] >> i) & 0x1;
1482a219f6deSJohnny Huang 			else
14835010032bSJohnny Huang 				rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
14845010032bSJohnny Huang 		} else {
14855010032bSJohnny Huang 			rpbit = 0;
14865010032bSJohnny Huang 		}
148769d5fd8fSJohnny Huang 
1488a219f6deSJohnny Huang 		if (ibit == 1)
148969d5fd8fSJohnny Huang 			continue;
14909901d43aSJohnny Huang 		if (bit == otpstrap[i].value)
14919901d43aSJohnny Huang 			prog_flag = 0;
14929901d43aSJohnny Huang 		else
14939901d43aSJohnny Huang 			prog_flag = 1;
14949901d43aSJohnny Huang 
14959901d43aSJohnny Huang 		if (otpstrap[i].protected == 1 && prog_flag) {
149669d5fd8fSJohnny Huang 			fail = 1;
149769d5fd8fSJohnny Huang 			continue;
149869d5fd8fSJohnny Huang 		}
14999901d43aSJohnny Huang 		if (otpstrap[i].remain_times == 0 && prog_flag) {
150069d5fd8fSJohnny Huang 			fail = 1;
150169d5fd8fSJohnny Huang 			continue;
150269d5fd8fSJohnny Huang 		}
15037e22f42dSJohnny Huang 
15049901d43aSJohnny Huang 		if (prog_flag) {
150583655e91SJohnny Huang 			ret = otp_prog_bit(1, prog_address, offset);
1506*794e27ecSJohnny Huang 			if (ret)
15072a856b9aSJohnny Huang 				return OTP_FAILURE;
15089901d43aSJohnny Huang 		}
150969d5fd8fSJohnny Huang 
15105010032bSJohnny Huang 		if (rpbit == 1 && info_cb.version != OTP_AST2600A0) {
151169d5fd8fSJohnny Huang 			prog_address = 0x800;
151269d5fd8fSJohnny Huang 			if (i < 32)
15135010032bSJohnny Huang 				prog_address |= 0x608;
151469d5fd8fSJohnny Huang 			else
15155010032bSJohnny Huang 				prog_address |= 0x60a;
15167e22f42dSJohnny Huang 
151783655e91SJohnny Huang 			ret = otp_prog_bit(1, prog_address, offset);
1518*794e27ecSJohnny Huang 			if (ret)
15192a856b9aSJohnny Huang 				return OTP_FAILURE;
15205010032bSJohnny Huang 		}
15215010032bSJohnny Huang 
15225010032bSJohnny Huang 		if (pbit != 0) {
15235010032bSJohnny Huang 			prog_address = 0x800;
15245010032bSJohnny Huang 			if (i < 32)
15255010032bSJohnny Huang 				prog_address |= 0x60c;
15265010032bSJohnny Huang 			else
15275010032bSJohnny Huang 				prog_address |= 0x60e;
15285010032bSJohnny Huang 
152983655e91SJohnny Huang 			ret = otp_prog_bit(1, prog_address, offset);
1530*794e27ecSJohnny Huang 			if (ret)
15315010032bSJohnny Huang 				return OTP_FAILURE;
15325010032bSJohnny Huang 		}
153369d5fd8fSJohnny Huang 	}
1534de6fbf1cSJohnny Huang 	otp_soak(0);
153569d5fd8fSJohnny Huang 	if (fail == 1)
15362a856b9aSJohnny Huang 		return OTP_FAILURE;
15372a856b9aSJohnny Huang 	return OTP_SUCCESS;
153869d5fd8fSJohnny Huang }
153969d5fd8fSJohnny Huang 
15405010032bSJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout)
15414c1c9b35SJohnny Huang {
154254552c69SJohnny Huang 	int i;
154354552c69SJohnny Huang 	int ret;
15445010032bSJohnny Huang 	int data_dw;
1545a219f6deSJohnny Huang 	u32 data[2048];
1546a219f6deSJohnny Huang 	u32 *buf;
1547a219f6deSJohnny Huang 	u32 *buf_ignore;
1548a219f6deSJohnny Huang 	u32 data_masked;
1549a219f6deSJohnny Huang 	u32 buf_masked;
15504c1c9b35SJohnny Huang 
1551a219f6deSJohnny Huang 	buf = (u32 *)image_layout->data;
1552a219f6deSJohnny Huang 	buf_ignore = (u32 *)image_layout->data_ignore;
15535010032bSJohnny Huang 
15545010032bSJohnny Huang 	data_dw = image_layout->data_length / 4;
15555010032bSJohnny Huang 
15564c1c9b35SJohnny Huang 	printf("Read OTP Data:\n");
15574c1c9b35SJohnny Huang 
1558a219f6deSJohnny Huang 	for (i = 0; i < data_dw - 2 ; i += 2)
1559d90825e2SJohnny Huang 		otp_read_data(i, &data[i]);
1560d90825e2SJohnny Huang 
15614c1c9b35SJohnny Huang 	printf("Check writable...\n");
156254552c69SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
15635010032bSJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1564696656c6SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1565696656c6SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
156654552c69SJohnny Huang 		if (data_masked == buf_masked)
15674c1c9b35SJohnny Huang 			continue;
1568d90825e2SJohnny Huang 		if (i % 2 == 0) {
156954552c69SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
15704c1c9b35SJohnny Huang 				continue;
15714c1c9b35SJohnny Huang 			} else {
15724c1c9b35SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1573d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
15744c1c9b35SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1575696656c6SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
15762a856b9aSJohnny Huang 				return OTP_FAILURE;
157769d5fd8fSJohnny Huang 			}
1578d90825e2SJohnny Huang 		} else {
157954552c69SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1580d90825e2SJohnny Huang 				continue;
1581d90825e2SJohnny Huang 			} else {
1582d90825e2SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1583d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1584d90825e2SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1585696656c6SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
15862a856b9aSJohnny Huang 				return OTP_FAILURE;
1587d90825e2SJohnny Huang 			}
1588d90825e2SJohnny Huang 		}
1589d90825e2SJohnny Huang 	}
159069d5fd8fSJohnny Huang 
1591d90825e2SJohnny Huang 	printf("Start Programing...\n");
1592d90825e2SJohnny Huang 
159354552c69SJohnny Huang 	// programing ecc region first
159454552c69SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1595696656c6SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
159654552c69SJohnny Huang 		if (ret != OTP_SUCCESS) {
159754552c69SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1598696656c6SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
159954552c69SJohnny Huang 			return ret;
1600d90825e2SJohnny Huang 		}
1601d90825e2SJohnny Huang 	}
1602d90825e2SJohnny Huang 
160354552c69SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1604696656c6SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
160554552c69SJohnny Huang 		if (ret != OTP_SUCCESS) {
160654552c69SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1607696656c6SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
160854552c69SJohnny Huang 			return ret;
1609d90825e2SJohnny Huang 		}
1610de6fbf1cSJohnny Huang 	}
1611de6fbf1cSJohnny Huang 	otp_soak(0);
16122a856b9aSJohnny Huang 	return OTP_SUCCESS;
1613d90825e2SJohnny Huang }
1614d90825e2SJohnny Huang 
1615a219f6deSJohnny Huang static int otp_image_verify(u8 *src_buf, u32 length, u8 *digest_buf)
1616696656c6SJohnny Huang {
1617696656c6SJohnny Huang 	sha256_context ctx;
1618696656c6SJohnny Huang 	u8 digest_ret[CHECKSUM_LEN];
1619696656c6SJohnny Huang 
1620696656c6SJohnny Huang 	sha256_starts(&ctx);
1621696656c6SJohnny Huang 	sha256_update(&ctx, src_buf, length);
1622696656c6SJohnny Huang 	sha256_finish(&ctx, digest_ret);
1623696656c6SJohnny Huang 
1624696656c6SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
1625696656c6SJohnny Huang 		return 0;
1626696656c6SJohnny Huang 	return -1;
1627696656c6SJohnny Huang }
1628696656c6SJohnny Huang 
1629de6b0cc4SJohnny Huang static int do_otp_prog(int addr, int nconfirm)
163069d5fd8fSJohnny Huang {
163169d5fd8fSJohnny Huang 	int ret;
16329a4fe690SJohnny Huang 	int image_version = 0;
1633696656c6SJohnny Huang 	struct otp_header *otp_header;
1634696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1635696656c6SJohnny Huang 	int image_size;
1636a219f6deSJohnny Huang 	u8 *buf;
1637a219f6deSJohnny Huang 	u8 *checksum;
163869d5fd8fSJohnny Huang 
1639696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1640696656c6SJohnny Huang 	if (!otp_header) {
164169d5fd8fSJohnny Huang 		puts("Failed to map physical memory\n");
16422a856b9aSJohnny Huang 		return OTP_FAILURE;
164369d5fd8fSJohnny Huang 	}
1644d90825e2SJohnny Huang 
1645696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1646696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1647696656c6SJohnny Huang 
1648696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1649696656c6SJohnny Huang 
1650696656c6SJohnny Huang 	if (!buf) {
1651696656c6SJohnny Huang 		puts("Failed to map physical memory\n");
1652696656c6SJohnny Huang 		return OTP_FAILURE;
1653696656c6SJohnny Huang 	}
1654696656c6SJohnny Huang 	otp_header = (struct otp_header *)buf;
1655696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1656696656c6SJohnny Huang 
1657696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1658696656c6SJohnny Huang 		puts("Image is invalid\n");
1659696656c6SJohnny Huang 		return OTP_FAILURE;
1660696656c6SJohnny Huang 	}
1661696656c6SJohnny Huang 
16625010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
16635010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
16645010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
16655010032bSJohnny Huang 
16665010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1667696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
16685010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1669696656c6SJohnny Huang 
1670696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
1671696656c6SJohnny Huang 
1672696656c6SJohnny Huang 	if (!strcmp("A0", (char *)otp_header->otp_version)) {
1673696656c6SJohnny Huang 		image_version = OTP_AST2600A0;
16745010032bSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
16755010032bSJohnny Huang 		image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
16765010032bSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
1677696656c6SJohnny Huang 	} else if (!strcmp("A1", (char *)otp_header->otp_version)) {
1678696656c6SJohnny Huang 		image_version = OTP_AST2600A1;
16795010032bSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
16805010032bSJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
16815010032bSJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
16825010032bSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
16835fdde29fSJohnny Huang 	} else if (!strcmp("A2", (char *)otp_header->otp_version)) {
16845fdde29fSJohnny Huang 		image_version = OTP_AST2600A2;
16855fdde29fSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
16865fdde29fSJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
16875fdde29fSJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
16885fdde29fSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
168964b66712SJohnny Huang 	} else if (!strcmp("A3", (char *)otp_header->otp_version)) {
169064b66712SJohnny Huang 		image_version = OTP_AST2600A3;
169164b66712SJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
169264b66712SJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
169364b66712SJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
169464b66712SJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
1695696656c6SJohnny Huang 	} else {
1696696656c6SJohnny Huang 		puts("Version is not supported\n");
1697696656c6SJohnny Huang 		return OTP_FAILURE;
1698696656c6SJohnny Huang 	}
1699696656c6SJohnny Huang 
17009a4fe690SJohnny Huang 	if (image_version != info_cb.version) {
17019a4fe690SJohnny Huang 		puts("Version is not match\n");
17029a4fe690SJohnny Huang 		return OTP_FAILURE;
17039a4fe690SJohnny Huang 	}
17049a4fe690SJohnny Huang 
1705696656c6SJohnny Huang 	if (otp_image_verify(buf, image_size, checksum)) {
1706696656c6SJohnny Huang 		puts("checksum is invalid\n");
1707696656c6SJohnny Huang 		return OTP_FAILURE;
1708d90825e2SJohnny Huang 	}
17097332532cSJohnny Huang 
171069d5fd8fSJohnny Huang 	if (!nconfirm) {
1711696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
17127f795e57SJohnny Huang 			printf("\nOTP data region :\n");
1713696656c6SJohnny Huang 			if (otp_print_data_info(&image_layout) < 0) {
171469d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
17152a856b9aSJohnny Huang 				return OTP_FAILURE;
171669d5fd8fSJohnny Huang 			}
171769d5fd8fSJohnny Huang 		}
1718696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
17197332532cSJohnny Huang 			printf("\nOTP strap region :\n");
17205010032bSJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
17217332532cSJohnny Huang 				printf("OTP strap error, please check.\n");
17227332532cSJohnny Huang 				return OTP_FAILURE;
17237332532cSJohnny Huang 			}
17247332532cSJohnny Huang 		}
1725696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
17267332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
1727696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
17287332532cSJohnny Huang 				printf("OTP config error, please check.\n");
17297332532cSJohnny Huang 				return OTP_FAILURE;
17307332532cSJohnny Huang 			}
17317332532cSJohnny Huang 		}
17327332532cSJohnny Huang 
173369d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
173469d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
173569d5fd8fSJohnny Huang 			printf(" Aborting\n");
17362a856b9aSJohnny Huang 			return OTP_FAILURE;
173769d5fd8fSJohnny Huang 		}
173869d5fd8fSJohnny Huang 	}
17397332532cSJohnny Huang 
17405010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
17415010032bSJohnny Huang 		printf("programing data region ...\n");
17425010032bSJohnny Huang 		ret = otp_prog_data(&image_layout);
17435010032bSJohnny Huang 		if (ret != 0) {
17445010032bSJohnny Huang 			printf("Error\n");
17455010032bSJohnny Huang 			return ret;
17465010032bSJohnny Huang 		}
1747a219f6deSJohnny Huang 		printf("Done\n");
17485010032bSJohnny Huang 	}
17495010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
17505010032bSJohnny Huang 		printf("programing strap region ...\n");
17515010032bSJohnny Huang 		ret = otp_prog_strap(&image_layout);
17525010032bSJohnny Huang 		if (ret != 0) {
17535010032bSJohnny Huang 			printf("Error\n");
17545010032bSJohnny Huang 			return ret;
17555010032bSJohnny Huang 		}
1756a219f6deSJohnny Huang 		printf("Done\n");
17575010032bSJohnny Huang 	}
17585010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
17595010032bSJohnny Huang 		printf("programing configuration region ...\n");
17605010032bSJohnny Huang 		ret = otp_prog_conf(&image_layout);
17615010032bSJohnny Huang 		if (ret != 0) {
17625010032bSJohnny Huang 			printf("Error\n");
17635010032bSJohnny Huang 			return ret;
17645010032bSJohnny Huang 		}
17655010032bSJohnny Huang 		printf("Done\n");
17665010032bSJohnny Huang 	}
1767cd1610b4SJohnny Huang 
17687332532cSJohnny Huang 	return OTP_SUCCESS;
17692a856b9aSJohnny Huang }
17702a856b9aSJohnny Huang 
17712a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1772cd1610b4SJohnny Huang {
1773a219f6deSJohnny Huang 	u32 read[2];
1774a219f6deSJohnny Huang 	u32 prog_address = 0;
177566f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
1776cd1610b4SJohnny Huang 	int otp_bit;
177783655e91SJohnny Huang 	int ret = 0;
1778cd1610b4SJohnny Huang 
1779dacbba92SJohnny Huang 	otp_soak(0);
1780cd1610b4SJohnny Huang 	switch (mode) {
1781a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1782a6af4a17SJohnny Huang 		otp_read_config(otp_dw_offset, read);
1783cd1610b4SJohnny Huang 		prog_address = 0x800;
1784cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1785cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1786a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
1787cd1610b4SJohnny Huang 		if (otp_bit == value) {
1788a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1789cd1610b4SJohnny Huang 			printf("No need to program\n");
17902a856b9aSJohnny Huang 			return OTP_SUCCESS;
1791cd1610b4SJohnny Huang 		}
1792cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1793a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
1794cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
17952a856b9aSJohnny Huang 			return OTP_FAILURE;
1796cd1610b4SJohnny Huang 		}
1797a6af4a17SJohnny Huang 		printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
1798cd1610b4SJohnny Huang 		break;
1799a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1800cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1801cd1610b4SJohnny Huang 
1802cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1803a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
1804a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
1805643b9cfdSJohnny Huang 
1806643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
1807643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1808643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be cleaned\n");
1809643b9cfdSJohnny Huang 				return OTP_FAILURE;
1810643b9cfdSJohnny Huang 			}
1811cd1610b4SJohnny Huang 		} else {
1812a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
1813a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
1814643b9cfdSJohnny Huang 
1815643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
1816643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1817643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be writen\n");
1818643b9cfdSJohnny Huang 				return OTP_FAILURE;
1819643b9cfdSJohnny Huang 			}
1820cd1610b4SJohnny Huang 		}
1821cd1610b4SJohnny Huang 		if (otp_bit == value) {
1822a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1823cd1610b4SJohnny Huang 			printf("No need to program\n");
18242a856b9aSJohnny Huang 			return OTP_SUCCESS;
1825cd1610b4SJohnny Huang 		}
1826643b9cfdSJohnny Huang 
1827a6af4a17SJohnny Huang 		printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
1828cd1610b4SJohnny Huang 		break;
1829a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
18308848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
18318848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
18328848d5dcSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
18338848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
18348848d5dcSJohnny Huang 			return OTP_FAILURE;
18358848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
18368848d5dcSJohnny Huang 			return OTP_SUCCESS;
1837a6af4a17SJohnny Huang 
1838cd1610b4SJohnny Huang 		break;
1839cd1610b4SJohnny Huang 	}
1840cd1610b4SJohnny Huang 
1841cd1610b4SJohnny Huang 	if (!nconfirm) {
1842cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1843cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1844cd1610b4SJohnny Huang 			printf(" Aborting\n");
18452a856b9aSJohnny Huang 			return OTP_FAILURE;
1846cd1610b4SJohnny Huang 		}
1847cd1610b4SJohnny Huang 	}
1848cd1610b4SJohnny Huang 
1849cd1610b4SJohnny Huang 	switch (mode) {
1850a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
185183655e91SJohnny Huang 		ret =  otp_prog_strap_bit(bit_offset, value);
185283655e91SJohnny Huang 		break;
1853a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1854a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
185583655e91SJohnny Huang 		ret = otp_prog_bit(value, prog_address, bit_offset);
1856de6fbf1cSJohnny Huang 		break;
1857de6fbf1cSJohnny Huang 	}
1858de6fbf1cSJohnny Huang 	otp_soak(0);
185983655e91SJohnny Huang 	if (ret) {
1860*794e27ecSJohnny Huang 		printf("OTP cannot be programed\n");
1861*794e27ecSJohnny Huang 		printf("FAILURE\n");
1862*794e27ecSJohnny Huang 		return OTP_FAILURE;
1863*794e27ecSJohnny Huang 	}
1864*794e27ecSJohnny Huang 
18659009c25dSJohnny Huang 	printf("SUCCESS\n");
18662a856b9aSJohnny Huang 	return OTP_SUCCESS;
1867a219f6deSJohnny Huang }
1868a219f6deSJohnny Huang 
1869*794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
1870*794e27ecSJohnny Huang {
1871*794e27ecSJohnny Huang 	u32 otp_rid[2];
1872*794e27ecSJohnny Huang 	int rid_num = 0;
1873*794e27ecSJohnny Huang 	int bit_offset;
1874*794e27ecSJohnny Huang 	int dw_offset;
1875*794e27ecSJohnny Huang 	int i;
1876*794e27ecSJohnny Huang 	int ret;
1877*794e27ecSJohnny Huang 
1878*794e27ecSJohnny Huang 	otp_read_config(10, &otp_rid[0]);
1879*794e27ecSJohnny Huang 	otp_read_config(11, &otp_rid[1]);
1880*794e27ecSJohnny Huang 
1881*794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1882*794e27ecSJohnny Huang 
1883*794e27ecSJohnny Huang 	if (rid_num < 0) {
1884*794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by this command,\n"
1885*794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n");
1886*794e27ecSJohnny Huang 		otp_print_revid(otp_rid);
18879009c25dSJohnny Huang 		return OTP_FAILURE;
18889009c25dSJohnny Huang 	}
1889cd1610b4SJohnny Huang 
1890*794e27ecSJohnny Huang 	printf("current OTP revision ID: 0x%x\n", rid_num);
1891*794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1892*794e27ecSJohnny Huang 	printf("input update number: 0x%x\n", update_num);
1893*794e27ecSJohnny Huang 
1894*794e27ecSJohnny Huang 	if (rid_num >= update_num) {
1895*794e27ecSJohnny Huang 		printf("OTP rev_id is bigger than 0x%x\n", update_num);
1896*794e27ecSJohnny Huang 		printf("Skip\n");
1897*794e27ecSJohnny Huang 		return OTP_FAILURE;
1898*794e27ecSJohnny Huang 	}
1899*794e27ecSJohnny Huang 
1900*794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1901*794e27ecSJohnny Huang 		if (i < 32) {
1902*794e27ecSJohnny Huang 			dw_offset = 0xa;
1903*794e27ecSJohnny Huang 			bit_offset = i;
1904*794e27ecSJohnny Huang 		} else {
1905*794e27ecSJohnny Huang 			dw_offset = 0xb;
1906*794e27ecSJohnny Huang 			bit_offset = i - 32;
1907*794e27ecSJohnny Huang 		}
1908*794e27ecSJohnny Huang 		printf("OTPCFG%X[%d]", dw_offset, bit_offset);
1909*794e27ecSJohnny Huang 		if (i + 1 != update_num)
1910*794e27ecSJohnny Huang 			printf(", ");
1911*794e27ecSJohnny Huang 	}
1912*794e27ecSJohnny Huang 
1913*794e27ecSJohnny Huang 	printf(" will be programmed\n");
1914*794e27ecSJohnny Huang 	if (force == 0) {
1915*794e27ecSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1916*794e27ecSJohnny Huang 		if (!confirm_yesno()) {
1917*794e27ecSJohnny Huang 			printf(" Aborting\n");
1918*794e27ecSJohnny Huang 			return OTP_FAILURE;
1919*794e27ecSJohnny Huang 		}
1920*794e27ecSJohnny Huang 	}
1921*794e27ecSJohnny Huang 
1922*794e27ecSJohnny Huang 	ret = 0;
1923*794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1924*794e27ecSJohnny Huang 		if (i < 32) {
1925*794e27ecSJohnny Huang 			dw_offset = 0xa04;
1926*794e27ecSJohnny Huang 			bit_offset = i;
1927*794e27ecSJohnny Huang 		} else {
1928*794e27ecSJohnny Huang 			dw_offset = 0xa06;
1929*794e27ecSJohnny Huang 			bit_offset = i - 32;
1930*794e27ecSJohnny Huang 		}
1931*794e27ecSJohnny Huang 		if (otp_prog_bit(1, dw_offset, bit_offset)) {
1932*794e27ecSJohnny Huang 			printf("OTPCFG%X[%d] programming failed\n", dw_offset, bit_offset);
1933*794e27ecSJohnny Huang 			ret = OTP_FAILURE;
1934*794e27ecSJohnny Huang 			break;
1935*794e27ecSJohnny Huang 		}
1936*794e27ecSJohnny Huang 	}
1937*794e27ecSJohnny Huang 
1938*794e27ecSJohnny Huang 	otp_read_config(10, &otp_rid[0]);
1939*794e27ecSJohnny Huang 	otp_read_config(11, &otp_rid[1]);
1940*794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1941*794e27ecSJohnny Huang 	if (rid_num >= 0)
1942*794e27ecSJohnny Huang 		printf("OTP revision ID: 0x%x\n", rid_num);
1943*794e27ecSJohnny Huang 	else
1944*794e27ecSJohnny Huang 		printf("OTP revision ID\n");
1945*794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1946*794e27ecSJohnny Huang 	if (!ret)
1947*794e27ecSJohnny Huang 		printf("SUCCESS\n");
1948*794e27ecSJohnny Huang 	else
1949*794e27ecSJohnny Huang 		printf("FAILED\n");
1950*794e27ecSJohnny Huang 	return ret;
1951*794e27ecSJohnny Huang }
1952*794e27ecSJohnny Huang 
19532a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
195469d5fd8fSJohnny Huang {
1955a219f6deSJohnny Huang 	u32 offset, count;
19562a856b9aSJohnny Huang 	int ret;
195769d5fd8fSJohnny Huang 
19582a856b9aSJohnny Huang 	if (argc == 4) {
19592a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
19602a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
19612a856b9aSJohnny Huang 	} else if (argc == 3) {
19622a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
19632a856b9aSJohnny Huang 		count = 1;
19642a856b9aSJohnny Huang 	} else {
196569d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
196669d5fd8fSJohnny Huang 	}
196769d5fd8fSJohnny Huang 
19682a856b9aSJohnny Huang 	if (!strcmp(argv[1], "conf")) {
19693d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19702a856b9aSJohnny Huang 		ret = otp_print_config(offset, count);
19712a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "data")) {
19723d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19732a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
19742a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
19753d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19762a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
19772a856b9aSJohnny Huang 	} else {
19782a856b9aSJohnny Huang 		return CMD_RET_USAGE;
197969d5fd8fSJohnny Huang 	}
198069d5fd8fSJohnny Huang 
19812a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
19822a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
19832a856b9aSJohnny Huang 	return CMD_RET_USAGE;
19842a856b9aSJohnny Huang }
19852a856b9aSJohnny Huang 
19862a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
19872a856b9aSJohnny Huang {
19882a856b9aSJohnny Huang 	phys_addr_t addr;
19892a856b9aSJohnny Huang 	int ret;
19902a856b9aSJohnny Huang 
1991de6b0cc4SJohnny Huang 	if (argc == 3) {
1992ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
19932a856b9aSJohnny Huang 			return CMD_RET_USAGE;
19942a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
19953d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
1996de6b0cc4SJohnny Huang 		ret = do_otp_prog(addr, 1);
1997de6b0cc4SJohnny Huang 	} else if (argc == 2) {
19982a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
19993d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2000de6b0cc4SJohnny Huang 		ret = do_otp_prog(addr, 0);
20012a856b9aSJohnny Huang 	} else {
20022a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20032a856b9aSJohnny Huang 	}
20042a856b9aSJohnny Huang 
20052a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20062a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20072a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
20082a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
20092a856b9aSJohnny Huang 	else
20102a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20112a856b9aSJohnny Huang }
20122a856b9aSJohnny Huang 
20132a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20142a856b9aSJohnny Huang {
20152a856b9aSJohnny Huang 	int mode = 0;
20162a856b9aSJohnny Huang 	int nconfirm = 0;
20172a856b9aSJohnny Huang 	int otp_addr = 0;
20182a856b9aSJohnny Huang 	int bit_offset;
20192a856b9aSJohnny Huang 	int value;
20202a856b9aSJohnny Huang 	int ret;
20212a856b9aSJohnny Huang 
20222a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
20232a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20242a856b9aSJohnny Huang 
20252a856b9aSJohnny Huang 	/* Drop the pb cmd */
20262a856b9aSJohnny Huang 	argc--;
20272a856b9aSJohnny Huang 	argv++;
20282a856b9aSJohnny Huang 
20292a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
2030a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
20312a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
2032a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
20332a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
2034a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
2035cd1610b4SJohnny Huang 	else
20362a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20372a856b9aSJohnny Huang 
20382a856b9aSJohnny Huang 	/* Drop the region cmd */
20392a856b9aSJohnny Huang 	argc--;
20402a856b9aSJohnny Huang 	argv++;
20412a856b9aSJohnny Huang 
2042ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2043cd1610b4SJohnny Huang 		nconfirm = 1;
20442a856b9aSJohnny Huang 		/* Drop the force option */
20452a856b9aSJohnny Huang 		argc--;
20462a856b9aSJohnny Huang 		argv++;
20472a856b9aSJohnny Huang 	}
2048cd1610b4SJohnny Huang 
2049a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
20502a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
20512a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
20520808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
20532a856b9aSJohnny Huang 			return CMD_RET_USAGE;
2054cd1610b4SJohnny Huang 	} else {
20552a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
20562a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
20572a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
20580808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
20592a856b9aSJohnny Huang 			return CMD_RET_USAGE;
20600808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
206178855207SJohnny Huang 			if (otp_addr >= 0x800)
20620808cc55SJohnny Huang 				return CMD_RET_USAGE;
20630808cc55SJohnny Huang 		} else {
206478855207SJohnny Huang 			if (otp_addr >= 0x20)
20650808cc55SJohnny Huang 				return CMD_RET_USAGE;
20660808cc55SJohnny Huang 		}
2067cd1610b4SJohnny Huang 	}
2068cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
20692a856b9aSJohnny Huang 		return CMD_RET_USAGE;
2070cd1610b4SJohnny Huang 
20713d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
20722a856b9aSJohnny Huang 	ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
20732a856b9aSJohnny Huang 
20742a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20752a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20762a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
20772a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
20782a856b9aSJohnny Huang 	else
20792a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20802a856b9aSJohnny Huang }
20812a856b9aSJohnny Huang 
20822a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20832a856b9aSJohnny Huang {
20842a856b9aSJohnny Huang 	phys_addr_t addr;
20852a856b9aSJohnny Huang 	int otp_addr = 0;
20862a856b9aSJohnny Huang 
20872a856b9aSJohnny Huang 	if (argc != 3)
20882a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20892a856b9aSJohnny Huang 
20903d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
20912a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
20922a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
20932a856b9aSJohnny Huang 	if (otp_compare(otp_addr, addr) == 0) {
209469d5fd8fSJohnny Huang 		printf("Compare pass\n");
20952a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
2096a219f6deSJohnny Huang 	}
209769d5fd8fSJohnny Huang 	printf("Compare fail\n");
20982a856b9aSJohnny Huang 	return CMD_RET_FAILURE;
209969d5fd8fSJohnny Huang }
210069d5fd8fSJohnny Huang 
210166f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
210266f2f8e5SJohnny Huang {
2103a8bd6d8cSJohnny Huang 	int view = 0;
21042d4b0742SJohnny Huang 	int input;
2105a8bd6d8cSJohnny Huang 
2106a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
210766f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
210866f2f8e5SJohnny Huang 
21092d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
21103d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
21112d4b0742SJohnny Huang 		if (argc == 3) {
21122d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
21132d4b0742SJohnny Huang 			otp_print_conf_info(input);
21142d4b0742SJohnny Huang 		} else {
21152d4b0742SJohnny Huang 			otp_print_conf_info(-1);
21162d4b0742SJohnny Huang 		}
21172d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
21182d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
2119a8bd6d8cSJohnny Huang 			view = 1;
2120a8bd6d8cSJohnny Huang 			/* Drop the view option */
2121a8bd6d8cSJohnny Huang 			argc--;
2122a8bd6d8cSJohnny Huang 			argv++;
2123a8bd6d8cSJohnny Huang 		}
21243d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2125b458cd62SJohnny Huang 		otp_print_strap_info(view);
212666f2f8e5SJohnny Huang 	} else {
212766f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
212866f2f8e5SJohnny Huang 	}
21292d4b0742SJohnny Huang 
213066f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
213166f2f8e5SJohnny Huang }
213266f2f8e5SJohnny Huang 
2133e14b073cSJohnny Huang static int _do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[], int preg)
2134737ed20bSJohnny Huang {
2135737ed20bSJohnny Huang 	int input;
2136737ed20bSJohnny Huang 	int bit_offset;
2137e14b073cSJohnny Huang 	u32 prog_address;
213883655e91SJohnny Huang 	int ret;
2139e14b073cSJohnny Huang 	char info[10];
2140e14b073cSJohnny Huang 
2141e14b073cSJohnny Huang 	if (preg) {
2142e14b073cSJohnny Huang 		sprintf(info, "register ");
2143e14b073cSJohnny Huang 		prog_address = 0xe08;
2144e14b073cSJohnny Huang 	} else {
2145e14b073cSJohnny Huang 		info[0] = 0;
2146e14b073cSJohnny Huang 		prog_address = 0xe0c;
2147e14b073cSJohnny Huang 	}
2148a219f6deSJohnny Huang 
2149737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
2150737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2151737ed20bSJohnny Huang 
2152e14b073cSJohnny Huang 	if (!strcmp(argv[1], "o")) {
2153737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
2154737ed20bSJohnny Huang 	} else {
2155737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
2156e14b073cSJohnny Huang 		printf("OTPSTRAP[%d] %swill be protected\n", input, info);
2157737ed20bSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2158737ed20bSJohnny Huang 		if (!confirm_yesno()) {
2159737ed20bSJohnny Huang 			printf(" Aborting\n");
2160737ed20bSJohnny Huang 			return CMD_RET_FAILURE;
2161737ed20bSJohnny Huang 		}
2162737ed20bSJohnny Huang 	}
2163737ed20bSJohnny Huang 
2164737ed20bSJohnny Huang 	if (input < 32) {
2165737ed20bSJohnny Huang 		bit_offset = input;
2166737ed20bSJohnny Huang 	} else if (input < 64) {
2167737ed20bSJohnny Huang 		bit_offset = input - 32;
2168e14b073cSJohnny Huang 		prog_address += 2;
2169737ed20bSJohnny Huang 	} else {
2170737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2171737ed20bSJohnny Huang 	}
2172737ed20bSJohnny Huang 
2173e14b073cSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2174e14b073cSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2175e14b073cSJohnny Huang 		printf("OTPSTRAP[%d] %salready protected\n", input, info);
2176e14b073cSJohnny Huang 		return CMD_RET_SUCCESS;
2177e14b073cSJohnny Huang 	}
2178de6fbf1cSJohnny Huang 
217983655e91SJohnny Huang 	ret = otp_prog_bit(1, prog_address, bit_offset);
2180de6fbf1cSJohnny Huang 	otp_soak(0);
218183655e91SJohnny Huang 
218283655e91SJohnny Huang 	if (ret) {
2183e14b073cSJohnny Huang 		printf("Protect OTPSTRAP[%d] %sfail\n", input, info);
2184737ed20bSJohnny Huang 		return CMD_RET_FAILURE;
2185737ed20bSJohnny Huang 	}
21869a4fe690SJohnny Huang 
2187*794e27ecSJohnny Huang 	printf("OTPSTRAP[%d] %sis protected\n", input, info);
2188*794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2189*794e27ecSJohnny Huang }
2190*794e27ecSJohnny Huang 
2191e14b073cSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2192e14b073cSJohnny Huang {
2193e14b073cSJohnny Huang 	return _do_otpprotect(cmdtp, flag, argc, argv, 0);
2194e14b073cSJohnny Huang }
2195e14b073cSJohnny Huang 
2196e14b073cSJohnny Huang static int do_otprprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2197e14b073cSJohnny Huang {
2198e14b073cSJohnny Huang 	return _do_otpprotect(cmdtp, flag, argc, argv, 1);
2199e14b073cSJohnny Huang }
2200e14b073cSJohnny Huang 
2201f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2202f67375f7SJohnny Huang {
2203f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2204f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2205f67375f7SJohnny Huang 
2206f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2207f67375f7SJohnny Huang }
2208f67375f7SJohnny Huang 
2209*794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2210*794e27ecSJohnny Huang {
2211*794e27ecSJohnny Huang 	u32 update_num;
2212*794e27ecSJohnny Huang 	int force = 0;
2213*794e27ecSJohnny Huang 	int ret;
2214*794e27ecSJohnny Huang 
2215*794e27ecSJohnny Huang 	if (argc == 3) {
2216*794e27ecSJohnny Huang 		if (strcmp(argv[1], "o"))
2217*794e27ecSJohnny Huang 			return CMD_RET_USAGE;
2218*794e27ecSJohnny Huang 		force = 1;
2219*794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[2], NULL, 16);
2220*794e27ecSJohnny Huang 	} else if (argc == 2) {
2221*794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[1], NULL, 16);
2222*794e27ecSJohnny Huang 	} else {
2223*794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2224*794e27ecSJohnny Huang 	}
2225*794e27ecSJohnny Huang 
2226*794e27ecSJohnny Huang 	if (update_num > 64)
2227*794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2228*794e27ecSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2229*794e27ecSJohnny Huang 	ret = otp_update_rid(update_num, force);
2230*794e27ecSJohnny Huang 	if (ret)
2231*794e27ecSJohnny Huang 		return CMD_RET_FAILURE;
2232*794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2233*794e27ecSJohnny Huang }
2234*794e27ecSJohnny Huang 
2235*794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2236*794e27ecSJohnny Huang {
2237*794e27ecSJohnny Huang 	u32 otp_rid[2];
2238*794e27ecSJohnny Huang 	int rid_num = 0;
2239*794e27ecSJohnny Huang 	int ret;
2240*794e27ecSJohnny Huang 
2241*794e27ecSJohnny Huang 	if (argc != 1)
2242*794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2243*794e27ecSJohnny Huang 
2244*794e27ecSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2245*794e27ecSJohnny Huang 	otp_read_config(10, &otp_rid[0]);
2246*794e27ecSJohnny Huang 	otp_read_config(11, &otp_rid[1]);
2247*794e27ecSJohnny Huang 
2248*794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2249*794e27ecSJohnny Huang 
2250*794e27ecSJohnny Huang 	if (rid_num >= 0) {
2251*794e27ecSJohnny Huang 		printf("current OTP revision ID: 0x%x\n", rid_num);
2252*794e27ecSJohnny Huang 		ret = CMD_RET_SUCCESS;
2253*794e27ecSJohnny Huang 	} else {
2254*794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by 'otp update',\n"
2255*794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n"
2256*794e27ecSJohnny Huang 		       "current OTP revision ID\n");
2257*794e27ecSJohnny Huang 		ret = CMD_RET_FAILURE;
2258*794e27ecSJohnny Huang 	}
2259*794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2260*794e27ecSJohnny Huang 
2261*794e27ecSJohnny Huang 	return ret;
2262*794e27ecSJohnny Huang }
2263*794e27ecSJohnny Huang 
22642a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2265f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
22662a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2267a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2268de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
22692a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2270737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
2271e14b073cSJohnny Huang 	U_BOOT_CMD_MKENT(rprotect, 3, 0, do_otprprotect, "", ""),
22722a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
2273*794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
2274*794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
22752a856b9aSJohnny Huang };
22762a856b9aSJohnny Huang 
22772a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
22782a856b9aSJohnny Huang {
22792a856b9aSJohnny Huang 	cmd_tbl_t *cp;
2280a219f6deSJohnny Huang 	u32 ver;
2281e14b073cSJohnny Huang 	int ret;
22822a856b9aSJohnny Huang 
22832a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
22842a856b9aSJohnny Huang 
2285737ed20bSJohnny Huang 	/* Drop the otp command */
22862a856b9aSJohnny Huang 	argc--;
22872a856b9aSJohnny Huang 	argv++;
22882a856b9aSJohnny Huang 
2289a219f6deSJohnny Huang 	if (!cp || argc > cp->maxargs)
22902a856b9aSJohnny Huang 		return CMD_RET_USAGE;
22912a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
22922a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
22932a856b9aSJohnny Huang 
22940dae9d52SJohnny Huang 	ver = chip_version();
22950dae9d52SJohnny Huang 	switch (ver) {
22960dae9d52SJohnny Huang 	case OTP_AST2600A0:
2297696656c6SJohnny Huang 		info_cb.version = OTP_AST2600A0;
22989a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
22999a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
23009a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
23019a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
23029a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
23039a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
23040dae9d52SJohnny Huang 		break;
23050dae9d52SJohnny Huang 	case OTP_AST2600A1:
2306696656c6SJohnny Huang 		info_cb.version = OTP_AST2600A1;
23073cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
23083cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
23093cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
23103cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
23119a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
23129a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
23130dae9d52SJohnny Huang 		break;
23140dae9d52SJohnny Huang 	case OTP_AST2600A2:
23155fdde29fSJohnny Huang 		info_cb.version = OTP_AST2600A2;
23165fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
23175fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
23185fdde29fSJohnny Huang 		info_cb.strap_info = a2_strap_info;
23195fdde29fSJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info);
23205fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
23215fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
23220dae9d52SJohnny Huang 		break;
232364b66712SJohnny Huang 	case OTP_AST2600A3:
232464b66712SJohnny Huang 		info_cb.version = OTP_AST2600A3;
232564b66712SJohnny Huang 		info_cb.conf_info = a2_conf_info;
232664b66712SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
232764b66712SJohnny Huang 		info_cb.strap_info = a2_strap_info;
232864b66712SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info);
2329181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
2330181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
233164b66712SJohnny Huang 		break;
23320dae9d52SJohnny Huang 	default:
2333f1be5099SJohnny Huang 		printf("SOC is not supported\n");
23340dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
23359a4fe690SJohnny Huang 	}
23369a4fe690SJohnny Huang 
2337e14b073cSJohnny Huang 	ret = cp->cmd(cmdtp, flag, argc, argv);
2338e14b073cSJohnny Huang 	writel(1, OTP_PROTECT_KEY); //password
2339e14b073cSJohnny Huang 
2340e14b073cSJohnny Huang 	return ret;
234169d5fd8fSJohnny Huang }
234269d5fd8fSJohnny Huang 
2343a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0,  do_ast_otp,
234469d5fd8fSJohnny Huang 	   "ASPEED One-Time-Programmable sub-system",
2345f67375f7SJohnny Huang 	   "version\n"
2346f67375f7SJohnny Huang 	   "otp read conf|data <otp_dw_offset> <dw_count>\n"
23472a856b9aSJohnny Huang 	   "otp read strap <strap_bit_offset> <bit_count>\n"
23482d4b0742SJohnny Huang 	   "otp info strap [v]\n"
23492d4b0742SJohnny Huang 	   "otp info conf [otp_dw_offset]\n"
2350de6b0cc4SJohnny Huang 	   "otp prog [o] <addr>\n"
2351ed071a2bSJohnny Huang 	   "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2352ed071a2bSJohnny Huang 	   "otp pb strap [o] <bit_offset> <value>\n"
2353ed071a2bSJohnny Huang 	   "otp protect [o] <bit_offset>\n"
2354e14b073cSJohnny Huang 	   "otp rprotect [o] <bit_offset>\n"
2355*794e27ecSJohnny Huang 	   "otp update [o] <revision_id>\n"
2356*794e27ecSJohnny Huang 	   "otp rid\n"
235769d5fd8fSJohnny Huang 	  );
2358