xref: /openbmc/u-boot/cmd/otp.c (revision 2a856b9a4b048528c866c068d4a1e210d1cea0a1)
169d5fd8fSJohnny Huang /*
269d5fd8fSJohnny Huang  *  This program is distributed in the hope that it will be useful,
369d5fd8fSJohnny Huang  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
469d5fd8fSJohnny Huang  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
569d5fd8fSJohnny Huang  *  GNU General Public License for more details.
669d5fd8fSJohnny Huang  *
769d5fd8fSJohnny Huang  *  You should have received a copy of the GNU General Public License
869d5fd8fSJohnny Huang  *  along with this program; if not, write to the Free Software
969d5fd8fSJohnny Huang  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1069d5fd8fSJohnny Huang  */
114c1c9b35SJohnny Huang #include <stdlib.h>
1269d5fd8fSJohnny Huang #include <common.h>
1369d5fd8fSJohnny Huang #include <console.h>
1469d5fd8fSJohnny Huang #include <bootretry.h>
1569d5fd8fSJohnny Huang #include <cli.h>
1669d5fd8fSJohnny Huang #include <command.h>
1769d5fd8fSJohnny Huang #include <console.h>
184c1c9b35SJohnny Huang #include <malloc.h>
1969d5fd8fSJohnny Huang #include <inttypes.h>
2069d5fd8fSJohnny Huang #include <mapmem.h>
2169d5fd8fSJohnny Huang #include <asm/io.h>
2269d5fd8fSJohnny Huang #include <linux/compiler.h>
2369d5fd8fSJohnny Huang 
2469d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR;
2569d5fd8fSJohnny Huang 
2669d5fd8fSJohnny Huang #define OTP_PASSWD			0x349fe38a
2769d5fd8fSJohnny Huang #define RETRY				3
28a6d0d645SJohnny Huang #define OTP_REGION_STRAP		1
29a6d0d645SJohnny Huang #define OTP_REGION_CONF			2
30a6d0d645SJohnny Huang #define OTP_REGION_DATA			3
31a6d0d645SJohnny Huang #define OTP_REGION_ALL			4
3269d5fd8fSJohnny Huang 
33*2a856b9aSJohnny Huang #define OTP_USAGE			-1
34*2a856b9aSJohnny Huang #define OTP_FAILURE			-2
35*2a856b9aSJohnny Huang #define OTP_SUCCESS			0
36*2a856b9aSJohnny Huang 
37e1f9e54eSJohnny Huang #define DISABLE_SECREG_PROG		BIT(0)
38e1f9e54eSJohnny Huang #define ENABLE_SEC_BOOT			BIT(1)
39e1f9e54eSJohnny Huang #define INIT_PROG_DONE			BIT(2)
40e1f9e54eSJohnny Huang #define ENABLE_USERREG_ECC		BIT(3)
41e1f9e54eSJohnny Huang #define ENABLE_SECREG_ECC		BIT(4)
42e1f9e54eSJohnny Huang #define DISABLE_LOW_SEC_KEY		BIT(5)
43e1f9e54eSJohnny Huang #define IGNORE_SEC_BOOT_HWSTRAP		BIT(6)
44e1f9e54eSJohnny Huang #define SEC_BOOT_MDOES(x)		(x >> 7)
45e1f9e54eSJohnny Huang #define   SEC_MODE1			0x0
46e1f9e54eSJohnny Huang #define   SEC_MODE2			0x1
47e1f9e54eSJohnny Huang #define OTP_BIT_CELL_MODES(x)		((x >> 8) & 0x3)
48e1f9e54eSJohnny Huang #define   SINGLE_CELL_MODE		0x0
49e1f9e54eSJohnny Huang #define   DIFFERENTIAL_MODE		0x1
50e1f9e54eSJohnny Huang #define   DIFFERENTIAL_REDUDANT_MODE	0x2
51e1f9e54eSJohnny Huang #define CRYPTO_MODES(x)			((x >> 10) & 0x3)
52e1f9e54eSJohnny Huang #define   CRYPTO_RSA1024		0x0
53e1f9e54eSJohnny Huang #define   CRYPTO_RSA2048		0x1
54e1f9e54eSJohnny Huang #define   CRYPTO_RSA3072		0x2
55e1f9e54eSJohnny Huang #define   CRYPTO_RSA4096		0x3
56e1f9e54eSJohnny Huang #define HASH_MODES(x)			((x >> 12) & 0x3)
57e1f9e54eSJohnny Huang #define   HASH_SAH224			0x0
58e1f9e54eSJohnny Huang #define   HASH_SAH256			0x1
59e1f9e54eSJohnny Huang #define   HASH_SAH384			0x2
60e1f9e54eSJohnny Huang #define   HASH_SAH512			0x3
61e1f9e54eSJohnny Huang #define SECREG_SIZE(x)			((x >> 16) & 0x3f)
62e1f9e54eSJohnny Huang #define WRITE_PROTECT_SECREG		BIT(22)
63e1f9e54eSJohnny Huang #define WRITE_PROTECT_USERREG		BIT(23)
64e1f9e54eSJohnny Huang #define WRITE_PROTECT_CONFREG		BIT(24)
65e1f9e54eSJohnny Huang #define WRITE_PROTECT_STRAPREG		BIT(25)
66e1f9e54eSJohnny Huang #define ENABLE_COPY_TO_SRAM		BIT(26)
67e1f9e54eSJohnny Huang #define ENABLE_IMAGE_ENC		BIT(27)
68e1f9e54eSJohnny Huang #define WRITE_PROTECT_KEY_RETIRE	BIT(29)
69e1f9e54eSJohnny Huang #define ENABLE_SIPROM_RED		BIT(30)
70e1f9e54eSJohnny Huang #define ENABLE_SIPROM_MLOCK		BIT(31)
71e1f9e54eSJohnny Huang 
72e1f9e54eSJohnny Huang #define VENDER_ID(x) 			(x & 0xFFFF)
73e1f9e54eSJohnny Huang #define KEY_REVISION(x)			((x >> 16) & 0xFFFF)
74e1f9e54eSJohnny Huang 
75e1f9e54eSJohnny Huang #define SEC_BOOT_HEADER_OFFSET(x)	(x & 0xFFFF)
76e1f9e54eSJohnny Huang 
77e1f9e54eSJohnny Huang #define KEYS_VALID_BITS(x)		(x & 0xff)
78e1f9e54eSJohnny Huang #define KEYS_RETIRE_BITS(x)		((x >> 16) & 0xff)
794c1c9b35SJohnny Huang 
804c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
814c1c9b35SJohnny Huang #define PBWIDTH 60
824c1c9b35SJohnny Huang 
834c1c9b35SJohnny Huang void printProgress(int numerator, int denominator, char *format, ...)
844c1c9b35SJohnny Huang {
854c1c9b35SJohnny Huang 	int val = numerator * 100 / denominator;
864c1c9b35SJohnny Huang 	int lpad = numerator * PBWIDTH / denominator;
874c1c9b35SJohnny Huang 	int rpad = PBWIDTH - lpad;
884c1c9b35SJohnny Huang 	char buffer[256];
894c1c9b35SJohnny Huang 	va_list aptr;
904c1c9b35SJohnny Huang 
914c1c9b35SJohnny Huang 	va_start(aptr, format);
924c1c9b35SJohnny Huang 	vsprintf(buffer, format, aptr);
934c1c9b35SJohnny Huang 	va_end(aptr);
944c1c9b35SJohnny Huang 
954c1c9b35SJohnny Huang 	printf("\r%3d%% [%.*s%*s] %s", val, lpad, PBSTR, rpad, "", buffer);
964c1c9b35SJohnny Huang 	if (numerator == denominator)
974c1c9b35SJohnny Huang 		printf("\n");
984c1c9b35SJohnny Huang }
994c1c9b35SJohnny Huang 
10069d5fd8fSJohnny Huang struct otpstrap {
10169d5fd8fSJohnny Huang 	int value;
10269d5fd8fSJohnny Huang 	int option_array[7];
10369d5fd8fSJohnny Huang 	int remain_times;
10469d5fd8fSJohnny Huang 	int writeable_option;
10569d5fd8fSJohnny Huang 	int protected;
10669d5fd8fSJohnny Huang };
10769d5fd8fSJohnny Huang 
108*2a856b9aSJohnny Huang static void otp_read_data(uint32_t offset, uint32_t *data)
10969d5fd8fSJohnny Huang {
11069d5fd8fSJohnny Huang 	writel(offset, 0x1e6f2010); //Read address
11169d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
11269d5fd8fSJohnny Huang 	udelay(2);
11369d5fd8fSJohnny Huang 	data[0] = readl(0x1e6f2020);
11469d5fd8fSJohnny Huang 	data[1] = readl(0x1e6f2024);
11569d5fd8fSJohnny Huang }
11669d5fd8fSJohnny Huang 
117*2a856b9aSJohnny Huang static void otp_read_config(uint32_t offset, uint32_t *data)
11869d5fd8fSJohnny Huang {
11969d5fd8fSJohnny Huang 	int config_offset;
12069d5fd8fSJohnny Huang 
12169d5fd8fSJohnny Huang 	config_offset = 0x800;
12269d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
12369d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
12469d5fd8fSJohnny Huang 
12569d5fd8fSJohnny Huang 	writel(config_offset, 0x1e6f2010);  //Read address
12669d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
12769d5fd8fSJohnny Huang 	udelay(2);
12869d5fd8fSJohnny Huang 	data[0] = readl(0x1e6f2020);
12969d5fd8fSJohnny Huang }
13069d5fd8fSJohnny Huang 
13169d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count)
13269d5fd8fSJohnny Huang {
13369d5fd8fSJohnny Huang 	int i;
13469d5fd8fSJohnny Huang 	uint32_t ret[1];
13569d5fd8fSJohnny Huang 
13669d5fd8fSJohnny Huang 	if (offset + dw_count > 32)
137*2a856b9aSJohnny Huang 		return OTP_USAGE;
13869d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i ++) {
13969d5fd8fSJohnny Huang 		otp_read_config(i, ret);
14069d5fd8fSJohnny Huang 		printf("OTPCFG%d: %08X\n", i, ret[0]);
14169d5fd8fSJohnny Huang 	}
14269d5fd8fSJohnny Huang 	printf("\n");
143*2a856b9aSJohnny Huang 	return OTP_SUCCESS;
14469d5fd8fSJohnny Huang }
14569d5fd8fSJohnny Huang 
14669d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count)
14769d5fd8fSJohnny Huang {
14869d5fd8fSJohnny Huang 	int i;
14969d5fd8fSJohnny Huang 	uint32_t ret[2];
15069d5fd8fSJohnny Huang 
15169d5fd8fSJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
152*2a856b9aSJohnny Huang 		return OTP_USAGE;
15369d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
15469d5fd8fSJohnny Huang 		otp_read_data(i, ret);
15569d5fd8fSJohnny Huang 		if (i % 4 == 0)
15669d5fd8fSJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
15769d5fd8fSJohnny Huang 		else
15869d5fd8fSJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
15969d5fd8fSJohnny Huang 
16069d5fd8fSJohnny Huang 	}
16169d5fd8fSJohnny Huang 	printf("\n");
162*2a856b9aSJohnny Huang 	return OTP_SUCCESS;
16369d5fd8fSJohnny Huang }
16469d5fd8fSJohnny Huang 
16569d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr)
16669d5fd8fSJohnny Huang {
16769d5fd8fSJohnny Huang 	uint32_t ret;
16869d5fd8fSJohnny Huang 	uint32_t *buf;
16969d5fd8fSJohnny Huang 
17069d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
17169d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
17269d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
17369d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
17469d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
17569d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //Compare address
17669d5fd8fSJohnny Huang 	writel(buf[0], 0x1e6f2020); //Compare data 1
17769d5fd8fSJohnny Huang 	writel(buf[1], 0x1e6f2024); //Compare data 2
17869d5fd8fSJohnny Huang 	writel(buf[2], 0x1e6f2028); //Compare data 3
17969d5fd8fSJohnny Huang 	writel(buf[3], 0x1e6f202c); //Compare data 4
18069d5fd8fSJohnny Huang 	writel(0x23b1e363, 0x1e6f2004); //Compare command
18169d5fd8fSJohnny Huang 	udelay(10);
18269d5fd8fSJohnny Huang 	ret = readl(0x1e6f2014); //Compare command
18369d5fd8fSJohnny Huang 	if (ret & 0x1)
18469d5fd8fSJohnny Huang 		return 0;
18569d5fd8fSJohnny Huang 	else
18669d5fd8fSJohnny Huang 		return -1;
18769d5fd8fSJohnny Huang }
18869d5fd8fSJohnny Huang 
18969d5fd8fSJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data)
19069d5fd8fSJohnny Huang {
19169d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //write address
19269d5fd8fSJohnny Huang 	writel(data, 0x1e6f2020); //write data
19369d5fd8fSJohnny Huang 	writel(0x23b1e362, 0x1e6f2004); //write command
19469d5fd8fSJohnny Huang 	udelay(100);
19569d5fd8fSJohnny Huang }
19669d5fd8fSJohnny Huang 
19769d5fd8fSJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit)
19869d5fd8fSJohnny Huang {
19969d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //write address
20069d5fd8fSJohnny Huang 	writel(prog_bit, 0x1e6f2020); //write data
20169d5fd8fSJohnny Huang 	writel(0x23b1e364, 0x1e6f2004); //write command
20269d5fd8fSJohnny Huang 	udelay(85);
20369d5fd8fSJohnny Huang }
20469d5fd8fSJohnny Huang 
205a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value)
20669d5fd8fSJohnny Huang {
20769d5fd8fSJohnny Huang 	int ret;
20869d5fd8fSJohnny Huang 
20969d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //Read address
21069d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
21169d5fd8fSJohnny Huang 	udelay(2);
21269d5fd8fSJohnny Huang 	ret = readl(0x1e6f2020);
213a6d0d645SJohnny Huang 	// printf("verify_bit = %x\n", ret);
21469d5fd8fSJohnny Huang 	if (((ret >> bit_offset) & 1) == value)
21569d5fd8fSJohnny Huang 		return 0;
21669d5fd8fSJohnny Huang 	else
21769d5fd8fSJohnny Huang 		return -1;
21869d5fd8fSJohnny Huang }
21969d5fd8fSJohnny Huang 
220d90825e2SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *keep, uint32_t *compare, int size)
2214c1c9b35SJohnny Huang {
2224c1c9b35SJohnny Huang 	uint32_t ret[2];
2234c1c9b35SJohnny Huang 
2244c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
2254c1c9b35SJohnny Huang 
2264c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
2274c1c9b35SJohnny Huang 		writel(otp_addr, 0x1e6f2010); //Read address
2284c1c9b35SJohnny Huang 	else
2294c1c9b35SJohnny Huang 		writel(otp_addr - 1, 0x1e6f2010); //Read address
2304c1c9b35SJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
2314c1c9b35SJohnny Huang 	udelay(2);
2324c1c9b35SJohnny Huang 	ret[0] = readl(0x1e6f2020);
2334c1c9b35SJohnny Huang 	ret[1] = readl(0x1e6f2024);
2344c1c9b35SJohnny Huang 	if (size == 1) {
2354c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
2364c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
237d90825e2SJohnny Huang 			if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0])) {
2384c1c9b35SJohnny Huang 				compare[0] = 0;
2394c1c9b35SJohnny Huang 				return 0;
2404c1c9b35SJohnny Huang 			} else {
2414c1c9b35SJohnny Huang 				compare[0] = value[0] ^ ret[0];
2424c1c9b35SJohnny Huang 				return -1;
2434c1c9b35SJohnny Huang 			}
2444c1c9b35SJohnny Huang 
2454c1c9b35SJohnny Huang 		} else {
2464c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
247d90825e2SJohnny Huang 			if ((value[0] & ~keep[0]) == (ret[1] & ~keep[0])) {
2484c1c9b35SJohnny Huang 				compare[0] = ~0;
2494c1c9b35SJohnny Huang 				return 0;
2504c1c9b35SJohnny Huang 			} else {
251d90825e2SJohnny Huang 				compare[0] = ~(value[0] ^ ret[1]);
2524c1c9b35SJohnny Huang 				return -1;
2534c1c9b35SJohnny Huang 			}
2544c1c9b35SJohnny Huang 		}
2554c1c9b35SJohnny Huang 	} else if (size == 2) {
2564c1c9b35SJohnny Huang 		// otp_addr should be even
257d90825e2SJohnny Huang 		if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0]) && (value[1] & ~keep[1]) == (ret[1] & ~keep[1])) {
2584c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
2594c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
2604c1c9b35SJohnny Huang 			compare[0] = 0;
2614c1c9b35SJohnny Huang 			compare[1] = ~0;
2624c1c9b35SJohnny Huang 			return 0;
2634c1c9b35SJohnny Huang 		} else {
2644c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
2654c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
2664c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
2674c1c9b35SJohnny Huang 			compare[1] = ~(value[1] ^ ret[1]);
2684c1c9b35SJohnny Huang 			return -1;
2694c1c9b35SJohnny Huang 		}
2704c1c9b35SJohnny Huang 	} else {
2714c1c9b35SJohnny Huang 		return -1;
2724c1c9b35SJohnny Huang 	}
2734c1c9b35SJohnny Huang }
2744c1c9b35SJohnny Huang 
275d90825e2SJohnny Huang void otp_soak(int soak)
276d90825e2SJohnny Huang {
277d90825e2SJohnny Huang 	if (soak) {
278d90825e2SJohnny Huang 		otp_write(0x3000, 0x4021); // Write MRA
279d90825e2SJohnny Huang 		otp_write(0x5000, 0x1027); // Write MRB
280d90825e2SJohnny Huang 		otp_write(0x1000, 0x4820); // Write MR
281d90825e2SJohnny Huang 		writel(0x041930d4, 0x1e602008); //soak program
282d90825e2SJohnny Huang 	} else {
283d90825e2SJohnny Huang 		otp_write(0x3000, 0x4061); // Write MRA
284d90825e2SJohnny Huang 		otp_write(0x5000, 0x302f); // Write MRB
285d90825e2SJohnny Huang 		otp_write(0x1000, 0x4020); // Write MR
286d90825e2SJohnny Huang 		writel(0x04190760, 0x1e602008); //normal program
287d90825e2SJohnny Huang 	}
288d90825e2SJohnny Huang }
289d90825e2SJohnny Huang 
290d90825e2SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t keep, uint32_t prog_address)
291d90825e2SJohnny Huang {
292d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
293d90825e2SJohnny Huang 
294d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
295d90825e2SJohnny Huang 		if ((keep >> j) & 0x1)
296d90825e2SJohnny Huang 			continue;
297d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
298d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
299d90825e2SJohnny Huang 			if (bit_value)
300d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
301d90825e2SJohnny Huang 			else
302d90825e2SJohnny Huang 				continue;
303d90825e2SJohnny Huang 		} else {
304d90825e2SJohnny Huang 			prog_address |= 1 << 15;
305d90825e2SJohnny Huang 			if (bit_value)
306d90825e2SJohnny Huang 				continue;
307d90825e2SJohnny Huang 			else
308d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
309d90825e2SJohnny Huang 		}
310d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
311d90825e2SJohnny Huang 	}
312d90825e2SJohnny Huang }
313d90825e2SJohnny Huang 
31469d5fd8fSJohnny Huang static int otp_conf_parse(uint32_t *OTPCFG)
31569d5fd8fSJohnny Huang {
3164c1c9b35SJohnny Huang 	int tmp, i;
3174c1c9b35SJohnny Huang 	int pass = 0;
318442839bbSJohnny Huang 	uint32_t *OTPCFG_KEEP = &OTPCFG[12];
31969d5fd8fSJohnny Huang 
320442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & DISABLE_SECREG_PROG) {
321442839bbSJohnny Huang 		printf("OTPCFG0-D[0]\n");
322442839bbSJohnny Huang 		printf("  Skip\n");
323442839bbSJohnny Huang 	} else {
32469d5fd8fSJohnny Huang 		printf("OTPCFG0-D[0]\n");
325e1f9e54eSJohnny Huang 		if (OTPCFG[0] & DISABLE_SECREG_PROG)
32669d5fd8fSJohnny Huang 			printf("  Disable Secure Region programming\n");
32769d5fd8fSJohnny Huang 		else
32869d5fd8fSJohnny Huang 			printf("  Enable Secure Region programming\n");
329442839bbSJohnny Huang 	}
330442839bbSJohnny Huang 
331442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_SEC_BOOT) {
332442839bbSJohnny Huang 		printf("OTPCFG0-D[1]\n");
333442839bbSJohnny Huang 		printf("  Skip\n");
334442839bbSJohnny Huang 	} else {
335442839bbSJohnny Huang 
33669d5fd8fSJohnny Huang 		printf("OTPCFG0-D[1]\n");
337e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_SEC_BOOT)
33869d5fd8fSJohnny Huang 			printf("  Enable Secure Boot\n");
33969d5fd8fSJohnny Huang 		else
34069d5fd8fSJohnny Huang 			printf("  Disable Secure Boot\n");
341442839bbSJohnny Huang 	}
342442839bbSJohnny Huang 
343442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_USERREG_ECC) {
344442839bbSJohnny Huang 		printf("OTPCFG0-D[3]\n");
345442839bbSJohnny Huang 		printf("  Skip\n");
346442839bbSJohnny Huang 	} else {
34769d5fd8fSJohnny Huang 		printf("OTPCFG0-D[3]\n");
348e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_USERREG_ECC)
34969d5fd8fSJohnny Huang 			printf("  User region ECC enable\n");
35069d5fd8fSJohnny Huang 		else
35169d5fd8fSJohnny Huang 			printf("  User region ECC disable\n");
352442839bbSJohnny Huang 	}
353442839bbSJohnny Huang 
354442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_SECREG_ECC) {
355442839bbSJohnny Huang 		printf("OTPCFG0-D[4]\n");
356442839bbSJohnny Huang 		printf("  Skip\n");
357442839bbSJohnny Huang 	} else {
35869d5fd8fSJohnny Huang 		printf("OTPCFG0-D[4]\n");
359e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_SECREG_ECC)
36069d5fd8fSJohnny Huang 			printf("  Secure Region ECC enable\n");
36169d5fd8fSJohnny Huang 		else
36269d5fd8fSJohnny Huang 			printf("  Secure Region ECC disable\n");
363442839bbSJohnny Huang 	}
364442839bbSJohnny Huang 
365442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & DISABLE_LOW_SEC_KEY) {
366442839bbSJohnny Huang 		printf("OTPCFG0-D[5]\n");
367442839bbSJohnny Huang 		printf("  Skip\n");
368442839bbSJohnny Huang 	} else {
36969d5fd8fSJohnny Huang 		printf("OTPCFG0-D[5]\n");
370e1f9e54eSJohnny Huang 		if (OTPCFG[0] & DISABLE_LOW_SEC_KEY)
37169d5fd8fSJohnny Huang 			printf("  Disable low security key\n");
37269d5fd8fSJohnny Huang 		else
37369d5fd8fSJohnny Huang 			printf("  Enable low security key\n");
374442839bbSJohnny Huang 	}
375442839bbSJohnny Huang 
376442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & IGNORE_SEC_BOOT_HWSTRAP) {
377442839bbSJohnny Huang 		printf("OTPCFG0-D[6]\n");
378442839bbSJohnny Huang 		printf("  Skip\n");
379442839bbSJohnny Huang 	} else {
38069d5fd8fSJohnny Huang 		printf("OTPCFG0-D[6]\n");
381e1f9e54eSJohnny Huang 		if (OTPCFG[0] & IGNORE_SEC_BOOT_HWSTRAP)
38269d5fd8fSJohnny Huang 			printf("  Ignore Secure Boot hardware strap\n");
38369d5fd8fSJohnny Huang 		else
38469d5fd8fSJohnny Huang 			printf("  Do not ignore Secure Boot hardware strap\n");
385442839bbSJohnny Huang 	}
386442839bbSJohnny Huang 
387442839bbSJohnny Huang 	if (SEC_BOOT_MDOES(OTPCFG_KEEP[0]) == 0x1) {
388442839bbSJohnny Huang 		printf("OTPCFG0-D[7]\n");
389442839bbSJohnny Huang 		printf("  Skip\n");
390442839bbSJohnny Huang 	} else {
39169d5fd8fSJohnny Huang 		printf("OTPCFG0-D[7]\n");
392e1f9e54eSJohnny Huang 		if (SEC_BOOT_MDOES(OTPCFG[0]) == SEC_MODE1)
393e1f9e54eSJohnny Huang 			printf("  Secure Boot Mode: 1\n");
394e1f9e54eSJohnny Huang 		else
395e1f9e54eSJohnny Huang 			printf("  Secure Boot Mode: 2\n");
396442839bbSJohnny Huang 	}
397442839bbSJohnny Huang 
398442839bbSJohnny Huang 	if (OTP_BIT_CELL_MODES(OTPCFG_KEEP[0]) == 0x3) {
399442839bbSJohnny Huang 		printf("OTPCFG0-D[9:8]\n");
400442839bbSJohnny Huang 		printf("  Skip\n");
401442839bbSJohnny Huang 	} else {
40269d5fd8fSJohnny Huang 		printf("OTPCFG0-D[9:8]\n");
40369d5fd8fSJohnny Huang 		printf("  OTP bit cell mode : ");
404e1f9e54eSJohnny Huang 		tmp = OTP_BIT_CELL_MODES(OTPCFG[0]);
405e1f9e54eSJohnny Huang 		if (tmp == SINGLE_CELL_MODE) {
40669d5fd8fSJohnny Huang 			printf("Single cell mode (recommended)\n");
407e1f9e54eSJohnny Huang 		} else if (tmp == DIFFERENTIAL_MODE) {
40869d5fd8fSJohnny Huang 			printf("Differnetial mode\n");
409e1f9e54eSJohnny Huang 		} else if (tmp == DIFFERENTIAL_REDUDANT_MODE) {
41069d5fd8fSJohnny Huang 			printf("Differential-redundant mode\n");
41169d5fd8fSJohnny Huang 		} else {
41269d5fd8fSJohnny Huang 			printf("Value error\n");
41369d5fd8fSJohnny Huang 			return -1;
41469d5fd8fSJohnny Huang 		}
415442839bbSJohnny Huang 	}
416442839bbSJohnny Huang 	if (CRYPTO_MODES(OTPCFG_KEEP[0]) == 0x3) {
417442839bbSJohnny Huang 		printf("OTPCFG0-D[11:10]\n");
418442839bbSJohnny Huang 		printf("  Skip\n");
419442839bbSJohnny Huang 	} else {
42069d5fd8fSJohnny Huang 		printf("OTPCFG0-D[11:10]\n");
42169d5fd8fSJohnny Huang 		printf("  RSA mode : ");
422e1f9e54eSJohnny Huang 		tmp = CRYPTO_MODES(OTPCFG[0]);
423e1f9e54eSJohnny Huang 		if (tmp == CRYPTO_RSA1024) {
42469d5fd8fSJohnny Huang 			printf("RSA1024\n");
425e1f9e54eSJohnny Huang 		} else if (tmp == CRYPTO_RSA2048) {
42669d5fd8fSJohnny Huang 			printf("RSA2048\n");
427e1f9e54eSJohnny Huang 		} else if (tmp == CRYPTO_RSA3072) {
42869d5fd8fSJohnny Huang 			printf("RSA3072\n");
42969d5fd8fSJohnny Huang 		} else {
43069d5fd8fSJohnny Huang 			printf("RSA4096\n");
43169d5fd8fSJohnny Huang 		}
432442839bbSJohnny Huang 	}
433442839bbSJohnny Huang 	if (HASH_MODES(OTPCFG_KEEP[0]) == 0x3) {
434442839bbSJohnny Huang 		printf("OTPCFG0-D[13:12]\n");
435442839bbSJohnny Huang 		printf("  Skip\n");
436442839bbSJohnny Huang 	} else {
43769d5fd8fSJohnny Huang 		printf("OTPCFG0-D[13:12]\n");
43869d5fd8fSJohnny Huang 		printf("  SHA mode : ");
439e1f9e54eSJohnny Huang 		tmp = HASH_MODES(OTPCFG[0]);
440e1f9e54eSJohnny Huang 		if (tmp == HASH_SAH224) {
44169d5fd8fSJohnny Huang 			printf("SHA224\n");
442e1f9e54eSJohnny Huang 		} else if (tmp == HASH_SAH256) {
44369d5fd8fSJohnny Huang 			printf("SHA256\n");
444e1f9e54eSJohnny Huang 		} else if (tmp == HASH_SAH384) {
44569d5fd8fSJohnny Huang 			printf("SHA384\n");
44669d5fd8fSJohnny Huang 		} else {
44769d5fd8fSJohnny Huang 			printf("SHA512\n");
44869d5fd8fSJohnny Huang 		}
449442839bbSJohnny Huang 	}
45069d5fd8fSJohnny Huang 
451442839bbSJohnny Huang 	if (SECREG_SIZE(OTPCFG_KEEP[0]) == 0x3f) {
452442839bbSJohnny Huang 		printf("OTPCFG0-D[21:16]\n");
453442839bbSJohnny Huang 		printf("  Skip\n");
454442839bbSJohnny Huang 	} else {
45569d5fd8fSJohnny Huang 		printf("OTPCFG0-D[21:16]\n");
456e1f9e54eSJohnny Huang 		printf("  Secure Region size (DW): %x\n", SECREG_SIZE(OTPCFG[0]));
457442839bbSJohnny Huang 	}
45869d5fd8fSJohnny Huang 
459442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & WRITE_PROTECT_SECREG) {
460442839bbSJohnny Huang 		printf("OTPCFG0-D[22]\n");
461442839bbSJohnny Huang 		printf("  Skip\n");
462442839bbSJohnny Huang 	} else {
46369d5fd8fSJohnny Huang 		printf("OTPCFG0-D[22]\n");
464e1f9e54eSJohnny Huang 		if (OTPCFG[0] & WRITE_PROTECT_SECREG)
46569d5fd8fSJohnny Huang 			printf("  Secure Region : Write Protect\n");
46669d5fd8fSJohnny Huang 		else
46769d5fd8fSJohnny Huang 			printf("  Secure Region : Writable\n");
468442839bbSJohnny Huang 	}
469442839bbSJohnny Huang 
470442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & WRITE_PROTECT_USERREG) {
471442839bbSJohnny Huang 		printf("OTPCFG0-D[23]\n");
472442839bbSJohnny Huang 		printf("  Skip\n");
473442839bbSJohnny Huang 	} else {
47469d5fd8fSJohnny Huang 		printf("OTPCFG0-D[23]\n");
475e1f9e54eSJohnny Huang 		if (OTPCFG[0] & WRITE_PROTECT_USERREG)
47669d5fd8fSJohnny Huang 			printf("  User Region : Write Protect\n");
47769d5fd8fSJohnny Huang 		else
47869d5fd8fSJohnny Huang 			printf("  User Region : Writable\n");
479442839bbSJohnny Huang 	}
480442839bbSJohnny Huang 
481442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & WRITE_PROTECT_CONFREG) {
482442839bbSJohnny Huang 		printf("OTPCFG0-D[24]\n");
483442839bbSJohnny Huang 		printf("  Skip\n");
484442839bbSJohnny Huang 	} else {
48569d5fd8fSJohnny Huang 		printf("OTPCFG0-D[24]\n");
486e1f9e54eSJohnny Huang 		if (OTPCFG[0] & WRITE_PROTECT_CONFREG)
48769d5fd8fSJohnny Huang 			printf("  Configure Region : Write Protect\n");
48869d5fd8fSJohnny Huang 		else
48969d5fd8fSJohnny Huang 			printf("  Configure Region : Writable\n");
490442839bbSJohnny Huang 	}
491442839bbSJohnny Huang 
492442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & WRITE_PROTECT_STRAPREG) {
493442839bbSJohnny Huang 		printf("OTPCFG0-D[25]\n");
494442839bbSJohnny Huang 		printf("  Skip\n");
495442839bbSJohnny Huang 	} else {
49669d5fd8fSJohnny Huang 		printf("OTPCFG0-D[25]\n");
497e1f9e54eSJohnny Huang 		if (OTPCFG[0] & WRITE_PROTECT_STRAPREG)
49869d5fd8fSJohnny Huang 			printf("  OTP strap Region : Write Protect\n");
49969d5fd8fSJohnny Huang 		else
50069d5fd8fSJohnny Huang 			printf("  OTP strap Region : Writable\n");
501442839bbSJohnny Huang 	}
502442839bbSJohnny Huang 
503442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_COPY_TO_SRAM) {
504442839bbSJohnny Huang 		printf("OTPCFG0-D[25]\n");
505442839bbSJohnny Huang 		printf("  Skip\n");
506442839bbSJohnny Huang 	} else {
50769d5fd8fSJohnny Huang 		printf("OTPCFG0-D[26]\n");
508e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_COPY_TO_SRAM)
50969d5fd8fSJohnny Huang 			printf("  Copy Boot Image to Internal SRAM\n");
51069d5fd8fSJohnny Huang 		else
51169d5fd8fSJohnny Huang 			printf("  Disable Copy Boot Image to Internal SRAM\n");
512442839bbSJohnny Huang 	}
513442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_IMAGE_ENC) {
514442839bbSJohnny Huang 		printf("OTPCFG0-D[27]\n");
515442839bbSJohnny Huang 		printf("  Skip\n");
516442839bbSJohnny Huang 	} else {
51769d5fd8fSJohnny Huang 		printf("OTPCFG0-D[27]\n");
518e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_IMAGE_ENC)
51969d5fd8fSJohnny Huang 			printf("  Enable image encryption\n");
52069d5fd8fSJohnny Huang 		else
52169d5fd8fSJohnny Huang 			printf("  Disable image encryption\n");
522442839bbSJohnny Huang 	}
523442839bbSJohnny Huang 
524442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & WRITE_PROTECT_KEY_RETIRE) {
525442839bbSJohnny Huang 		printf("OTPCFG0-D[29]\n");
526442839bbSJohnny Huang 		printf("  Skip\n");
527442839bbSJohnny Huang 	} else {
52869d5fd8fSJohnny Huang 		printf("OTPCFG0-D[29]\n");
529e1f9e54eSJohnny Huang 		if (OTPCFG[0] & WRITE_PROTECT_KEY_RETIRE)
53069d5fd8fSJohnny Huang 			printf("  OTP key retire Region : Write Protect\n");
53169d5fd8fSJohnny Huang 		else
53269d5fd8fSJohnny Huang 			printf("  OTP key retire Region : Writable\n");
533442839bbSJohnny Huang 	}
534442839bbSJohnny Huang 
535442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_SIPROM_RED) {
536442839bbSJohnny Huang 		printf("OTPCFG0-D[30]\n");
537442839bbSJohnny Huang 		printf("  Skip\n");
538442839bbSJohnny Huang 	} else {
53969d5fd8fSJohnny Huang 		printf("OTPCFG0-D[30]\n");
540e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_SIPROM_RED)
54169d5fd8fSJohnny Huang 			printf("  SIPROM RED_EN redundancy repair enable\n");
54269d5fd8fSJohnny Huang 		else
54369d5fd8fSJohnny Huang 			printf("  SIPROM RED_EN redundancy repair disable\n");
544442839bbSJohnny Huang 	}
545442839bbSJohnny Huang 
546442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_SIPROM_MLOCK) {
547442839bbSJohnny Huang 		printf("OTPCFG0-D[31]\n");
548442839bbSJohnny Huang 		printf("  Skip\n");
549442839bbSJohnny Huang 	} else {
55069d5fd8fSJohnny Huang 		printf("OTPCFG0-D[31]\n");
551e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_SIPROM_MLOCK)
55269d5fd8fSJohnny Huang 			printf("  SIPROM Mlock memory lock enable\n");
55369d5fd8fSJohnny Huang 		else
55469d5fd8fSJohnny Huang 			printf("  SIPROM Mlock memory lock disable\n");
555442839bbSJohnny Huang 	}
556442839bbSJohnny Huang 	if (SECREG_SIZE(OTPCFG_KEEP[2]) == 0xFFFF) {
557442839bbSJohnny Huang 		printf("OTPCFG2-D[15:0]\n");
558442839bbSJohnny Huang 		printf("  Skip\n");
559442839bbSJohnny Huang 	} else {
56069d5fd8fSJohnny Huang 		printf("OTPCFG2-D[15:0]\n");
561e1f9e54eSJohnny Huang 		printf("  Vender ID : %x\n", VENDER_ID(OTPCFG[2]));
562442839bbSJohnny Huang 	}
56369d5fd8fSJohnny Huang 
564442839bbSJohnny Huang 	if (SECREG_SIZE(OTPCFG_KEEP[2]) == 0xFFFF) {
565442839bbSJohnny Huang 		printf("OTPCFG2-D[31:16]\n");
566442839bbSJohnny Huang 		printf("  Skip\n");
567442839bbSJohnny Huang 	} else {
56869d5fd8fSJohnny Huang 		printf("OTPCFG2-D[31:16]\n");
569e1f9e54eSJohnny Huang 		printf("  Key Revision : %x\n", KEY_REVISION(OTPCFG[2]));
570442839bbSJohnny Huang 	}
57169d5fd8fSJohnny Huang 
572442839bbSJohnny Huang 	if (SEC_BOOT_HEADER_OFFSET(OTPCFG_KEEP[3]) == 0xFFFF) {
573442839bbSJohnny Huang 		printf("OTPCFG3-D[15:0]\n");
574442839bbSJohnny Huang 		printf("  Skip\n");
575442839bbSJohnny Huang 	} else {
57669d5fd8fSJohnny Huang 		printf("OTPCFG3-D[15:0]\n");
577e1f9e54eSJohnny Huang 		printf("  Secure boot header offset : %x\n",
578e1f9e54eSJohnny Huang 		       SEC_BOOT_HEADER_OFFSET(OTPCFG[3]));
579442839bbSJohnny Huang 	}
58069d5fd8fSJohnny Huang 
581442839bbSJohnny Huang 	if (KEYS_VALID_BITS(OTPCFG_KEEP[4]) == 0xFF) {
582442839bbSJohnny Huang 		printf("OTPCFG4-D[7:0]\n");
583442839bbSJohnny Huang 		printf("  Skip\n");
584442839bbSJohnny Huang 	} else {
58569d5fd8fSJohnny Huang 		printf("OTPCFG4-D[7:0]\n");
586e1f9e54eSJohnny Huang 		tmp = KEYS_VALID_BITS(OTPCFG[4]);
587e1f9e54eSJohnny Huang 		if (tmp != 0) {
58869d5fd8fSJohnny Huang 			for (i = 0; i < 7; i++) {
58969d5fd8fSJohnny Huang 				if (tmp == (1 << i)) {
590e1f9e54eSJohnny Huang 					pass = i + 1;
59169d5fd8fSJohnny Huang 				}
59269d5fd8fSJohnny Huang 			}
593e1f9e54eSJohnny Huang 		} else {
594e1f9e54eSJohnny Huang 			pass = 0;
595e1f9e54eSJohnny Huang 		}
596e1f9e54eSJohnny Huang 		printf("  Keys valid  : %d\n", pass);
597442839bbSJohnny Huang 	}
598442839bbSJohnny Huang 	if (KEYS_RETIRE_BITS(OTPCFG_KEEP[4]) == 0xFF) {
599442839bbSJohnny Huang 		printf("OTPCFG4-D[23:16]\n");
600442839bbSJohnny Huang 		printf("  Skip\n");
601442839bbSJohnny Huang 	} else {
60269d5fd8fSJohnny Huang 		printf("OTPCFG4-D[23:16]\n");
603e1f9e54eSJohnny Huang 		tmp = KEYS_RETIRE_BITS(OTPCFG[4]);
604e1f9e54eSJohnny Huang 		if (tmp != 0) {
60569d5fd8fSJohnny Huang 			for (i = 0; i < 7; i++) {
60669d5fd8fSJohnny Huang 				if (tmp == (1 << i)) {
607e1f9e54eSJohnny Huang 					pass = i + 1;
60869d5fd8fSJohnny Huang 				}
60969d5fd8fSJohnny Huang 			}
610e1f9e54eSJohnny Huang 		} else {
611e1f9e54eSJohnny Huang 			pass = 0;
61269d5fd8fSJohnny Huang 		}
61369d5fd8fSJohnny Huang 		printf("  Keys Retire ID : %d\n", pass);
614442839bbSJohnny Huang 	}
615442839bbSJohnny Huang 	if (OTPCFG_KEEP[5] == 0xFFFFFFFF) {
616442839bbSJohnny Huang 		printf("OTPCFG5-D[31:0]\n");
617442839bbSJohnny Huang 		printf("  Skip\n");
618442839bbSJohnny Huang 	} else {
61969d5fd8fSJohnny Huang 		printf("OTPCFG5-D[31:0]\n");
62069d5fd8fSJohnny Huang 		printf("  User define data, random number low : %x\n", OTPCFG[5]);
621442839bbSJohnny Huang 	}
62269d5fd8fSJohnny Huang 
623442839bbSJohnny Huang 	if (OTPCFG_KEEP[6] == 0xFFFFFFFF) {
624442839bbSJohnny Huang 		printf("OTPCFG6-D[31:0]\n");
625442839bbSJohnny Huang 		printf("  Skip\n");
626442839bbSJohnny Huang 	} else {
62769d5fd8fSJohnny Huang 		printf("OTPCFG6-D[31:0]\n");
62869d5fd8fSJohnny Huang 		printf("  User define data, random number high : %x\n", OTPCFG[6]);
629442839bbSJohnny Huang 	}
63069d5fd8fSJohnny Huang 
631442839bbSJohnny Huang 	if (OTPCFG_KEEP[8] == 0xFFFFFFFF) {
632442839bbSJohnny Huang 		printf("OTPCFG8-D[31:0]\n");
633442839bbSJohnny Huang 		printf("  Skip\n");
634442839bbSJohnny Huang 	} else {
63569d5fd8fSJohnny Huang 		printf("OTPCFG8-D[31:0]\n");
63669d5fd8fSJohnny Huang 		printf("  Redundancy Repair : %x\n", OTPCFG[8]);
637442839bbSJohnny Huang 	}
63869d5fd8fSJohnny Huang 
639442839bbSJohnny Huang 	if (OTPCFG_KEEP[10] == 0xFFFFFFFF) {
640442839bbSJohnny Huang 		printf("OTPCFG10-D[31:0]\n");
641442839bbSJohnny Huang 		printf("  Skip\n");
642442839bbSJohnny Huang 	} else {
64369d5fd8fSJohnny Huang 		printf("OTPCFG10-D[31:0]\n");
64469d5fd8fSJohnny Huang 		printf("  Manifest ID low : %x\n", OTPCFG[10]);
645442839bbSJohnny Huang 	}
64669d5fd8fSJohnny Huang 
647442839bbSJohnny Huang 	if (OTPCFG_KEEP[11] == 0xFFFFFFFF) {
648442839bbSJohnny Huang 		printf("OTPCFG11-D[31:0]\n");
649442839bbSJohnny Huang 		printf("  Skip\n");
650442839bbSJohnny Huang 	} else {
65169d5fd8fSJohnny Huang 		printf("OTPCFG11-D[31:0]\n");
65269d5fd8fSJohnny Huang 		printf("  Manifest ID high : %x\n", OTPCFG[11]);
653442839bbSJohnny Huang 	}
654442839bbSJohnny Huang 
65569d5fd8fSJohnny Huang 	return 0;
65669d5fd8fSJohnny Huang 
65769d5fd8fSJohnny Huang }
65869d5fd8fSJohnny Huang 
65969d5fd8fSJohnny Huang static void buf_print(char *buf, int len)
66069d5fd8fSJohnny Huang {
66169d5fd8fSJohnny Huang 	int i;
66269d5fd8fSJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
66369d5fd8fSJohnny Huang 	for (i = 0; i < len; i++) {
66469d5fd8fSJohnny Huang 		if (i % 16 == 0) {
66569d5fd8fSJohnny Huang 			printf("%04X: ", i);
66669d5fd8fSJohnny Huang 		}
66769d5fd8fSJohnny Huang 		printf("%02X ", buf[i]);
66869d5fd8fSJohnny Huang 		if ((i + 1) % 16 == 0) {
66969d5fd8fSJohnny Huang 			printf("\n");
67069d5fd8fSJohnny Huang 		}
67169d5fd8fSJohnny Huang 	}
67269d5fd8fSJohnny Huang }
67369d5fd8fSJohnny Huang 
674d90825e2SJohnny Huang static int otp_data_parse(uint32_t *buf)
67569d5fd8fSJohnny Huang {
67669d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
67769d5fd8fSJohnny Huang 	char *byte_buf;
67869d5fd8fSJohnny Huang 	int i = 0, len = 0;
67969d5fd8fSJohnny Huang 	byte_buf = (char *)buf;
68069d5fd8fSJohnny Huang 	while (1) {
68169d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
68269d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
68369d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
68469d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
68569d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
68669d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
68769d5fd8fSJohnny Huang 		printf("Key[%d]:\n", i);
68869d5fd8fSJohnny Huang 		printf("Key Type: ");
68969d5fd8fSJohnny Huang 		switch (key_type) {
69069d5fd8fSJohnny Huang 		case 0:
69169d5fd8fSJohnny Huang 			printf("AES-256 as OEM platform key for image encryption/decryption\n");
69269d5fd8fSJohnny Huang 			break;
69369d5fd8fSJohnny Huang 		case 1:
69469d5fd8fSJohnny Huang 			printf("AES-256 as secret vault key\n");
69569d5fd8fSJohnny Huang 			break;
69669d5fd8fSJohnny Huang 		case 4:
69769d5fd8fSJohnny Huang 			printf("HMAC as encrypted OEM HMAC keys in Mode 1\n");
69869d5fd8fSJohnny Huang 			break;
69969d5fd8fSJohnny Huang 		case 8:
70069d5fd8fSJohnny Huang 			printf("RSA-public as OEM DSS public keys in Mode 2\n");
70169d5fd8fSJohnny Huang 			break;
70269d5fd8fSJohnny Huang 		case 9:
70369d5fd8fSJohnny Huang 			printf("RSA-public as SOC public key\n");
70469d5fd8fSJohnny Huang 			break;
70569d5fd8fSJohnny Huang 		case 10:
70669d5fd8fSJohnny Huang 			printf("RSA-public as AES key decryption key\n");
70769d5fd8fSJohnny Huang 			break;
70869d5fd8fSJohnny Huang 		case 13:
70969d5fd8fSJohnny Huang 			printf("RSA-private as SOC private key\n");
71069d5fd8fSJohnny Huang 			break;
71169d5fd8fSJohnny Huang 		case 14:
71269d5fd8fSJohnny Huang 			printf("RSA-private as AES key decryption key\n");
71369d5fd8fSJohnny Huang 			break;
71469d5fd8fSJohnny Huang 		default:
71569d5fd8fSJohnny Huang 			printf("key_type error: %x\n", key_type);
71669d5fd8fSJohnny Huang 			return -1;
71769d5fd8fSJohnny Huang 		}
71869d5fd8fSJohnny Huang 		if (key_type == 4) {
71969d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
72069d5fd8fSJohnny Huang 			switch (key_length) {
72169d5fd8fSJohnny Huang 			case 0:
72269d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
72369d5fd8fSJohnny Huang 				break;
72469d5fd8fSJohnny Huang 			case 1:
72569d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
72669d5fd8fSJohnny Huang 				break;
72769d5fd8fSJohnny Huang 			case 2:
72869d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
72969d5fd8fSJohnny Huang 				break;
73069d5fd8fSJohnny Huang 			case 3:
73169d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
73269d5fd8fSJohnny Huang 				break;
73369d5fd8fSJohnny Huang 			}
734cd1610b4SJohnny Huang 		} else if (key_type != 0 && key_type != 1) {
73569d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
73669d5fd8fSJohnny Huang 			switch (key_length) {
73769d5fd8fSJohnny Huang 			case 0:
73869d5fd8fSJohnny Huang 				printf("RSA1024\n");
73969d5fd8fSJohnny Huang 				len = 0x100;
74069d5fd8fSJohnny Huang 				break;
74169d5fd8fSJohnny Huang 			case 1:
74269d5fd8fSJohnny Huang 				printf("RSA2048\n");
74369d5fd8fSJohnny Huang 				len = 0x200;
74469d5fd8fSJohnny Huang 				break;
74569d5fd8fSJohnny Huang 			case 2:
74669d5fd8fSJohnny Huang 				printf("RSA3072\n");
74769d5fd8fSJohnny Huang 				len = 0x300;
74869d5fd8fSJohnny Huang 				break;
74969d5fd8fSJohnny Huang 			case 3:
75069d5fd8fSJohnny Huang 				printf("RSA4096\n");
75169d5fd8fSJohnny Huang 				len = 0x400;
75269d5fd8fSJohnny Huang 				break;
75369d5fd8fSJohnny Huang 			}
75469d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
75569d5fd8fSJohnny Huang 		}
75669d5fd8fSJohnny Huang 		if (key_type == 4 || key_type == 8)
75769d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
75869d5fd8fSJohnny Huang 		printf("Key Value:\n");
75969d5fd8fSJohnny Huang 		if (key_type == 4) {
76069d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
76169d5fd8fSJohnny Huang 		} else if (key_type == 0 || key_type == 1) {
76269d5fd8fSJohnny Huang 			printf("AES Key:\n");
76369d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
76469d5fd8fSJohnny Huang 			printf("AES IV:\n");
76569d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + 0x20], 0x10);
76669d5fd8fSJohnny Huang 
76769d5fd8fSJohnny Huang 		} else {
76869d5fd8fSJohnny Huang 			printf("RSA mod:\n");
76969d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
77069d5fd8fSJohnny Huang 			printf("RSA exp:\n");
77169d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
77269d5fd8fSJohnny Huang 		}
77369d5fd8fSJohnny Huang 		if (last)
77469d5fd8fSJohnny Huang 			break;
77569d5fd8fSJohnny Huang 		i++;
77669d5fd8fSJohnny Huang 	}
77769d5fd8fSJohnny Huang 	return 0;
77869d5fd8fSJohnny Huang }
77969d5fd8fSJohnny Huang 
780a6d0d645SJohnny Huang static int otp_prog_conf(uint32_t *buf)
78169d5fd8fSJohnny Huang {
782a6d0d645SJohnny Huang 	int i, k;
783d90825e2SJohnny Huang 	int pass = 0;
784d90825e2SJohnny Huang 	int soak = 0;
785a6d0d645SJohnny Huang 	uint32_t prog_address;
786a6d0d645SJohnny Huang 	uint32_t data[12];
787a6d0d645SJohnny Huang 	uint32_t compare[2];
788d90825e2SJohnny Huang 	uint32_t *buf_keep = &buf[12];
789d90825e2SJohnny Huang 	uint32_t data_masked;
790d90825e2SJohnny Huang 	uint32_t buf_masked;
79169d5fd8fSJohnny Huang 
792a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
793a6d0d645SJohnny Huang 
794a6d0d645SJohnny Huang 	printProgress(0, 12, "");
795a6d0d645SJohnny Huang 	for (i = 0; i < 12 ; i ++) {
796a6d0d645SJohnny Huang 		printProgress(i + 1, 12, "");
79769d5fd8fSJohnny Huang 		prog_address = 0x800;
798a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
799a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
800a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
801a6d0d645SJohnny Huang 	}
802a6d0d645SJohnny Huang 
803a6d0d645SJohnny Huang 	printf("Check writable...\n");
804a6d0d645SJohnny Huang 	for (i = 0; i < 12; i++) {
805d90825e2SJohnny Huang 		data_masked = data[i]  & ~buf_keep[i];
806d90825e2SJohnny Huang 		buf_masked  = buf[i] & ~buf_keep[i];
807d90825e2SJohnny Huang 		if (data_masked == buf_masked)
80869d5fd8fSJohnny Huang 			continue;
809d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
810a6d0d645SJohnny Huang 			continue;
811a6d0d645SJohnny Huang 		} else {
812a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
813a6d0d645SJohnny Huang 			printf("OTPCFG[%d] = %x\n", i, data[i]);
814a6d0d645SJohnny Huang 			printf("Input [%d] = %x\n", i, buf[i]);
815d90825e2SJohnny Huang 			printf("Mask  [%x] = %x\n", i, ~buf_keep[i]);
816*2a856b9aSJohnny Huang 			return OTP_FAILURE;
817a6d0d645SJohnny Huang 		}
818a6d0d645SJohnny Huang 	}
819a6d0d645SJohnny Huang 
820a6d0d645SJohnny Huang 	printf("Start Programing...\n");
821a6d0d645SJohnny Huang 	printProgress(0, 12, "");
822d90825e2SJohnny Huang 	otp_soak(0);
823a6d0d645SJohnny Huang 	for (i = 0; i < 12; i++) {
824d90825e2SJohnny Huang 		data_masked = data[i]  & ~buf_keep[i];
825d90825e2SJohnny Huang 		buf_masked  = buf[i] & ~buf_keep[i];
826a6d0d645SJohnny Huang 		prog_address = 0x800;
827a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
828a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
829d90825e2SJohnny Huang 		if (data_masked == buf_masked) {
830a6d0d645SJohnny Huang 			printProgress(i + 1, 12, "[%03X]=%08X HIT", prog_address, buf[i]);
831a6d0d645SJohnny Huang 			continue;
832a6d0d645SJohnny Huang 		}
833d90825e2SJohnny Huang 		if (soak) {
834d90825e2SJohnny Huang 			soak = 0;
835d90825e2SJohnny Huang 			otp_soak(0);
836d90825e2SJohnny Huang 		}
837a6d0d645SJohnny Huang 		printProgress(i + 1, 12, "[%03X]=%08X    ", prog_address, buf[i]);
838a6d0d645SJohnny Huang 
839d90825e2SJohnny Huang 		otp_prog_dw(buf[i], buf_keep[i], prog_address);
840a6d0d645SJohnny Huang 
84169d5fd8fSJohnny Huang 		pass = 0;
84269d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
843d90825e2SJohnny Huang 			if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 1) != 0) {
844d90825e2SJohnny Huang 				if (soak == 0) {
845d90825e2SJohnny Huang 					soak = 1;
846d90825e2SJohnny Huang 					otp_soak(1);
847d90825e2SJohnny Huang 				}
848a6d0d645SJohnny Huang 				otp_prog_dw(compare[0], prog_address, 1);
849a6d0d645SJohnny Huang 			} else {
85069d5fd8fSJohnny Huang 				pass = 1;
85169d5fd8fSJohnny Huang 				break;
85269d5fd8fSJohnny Huang 			}
85369d5fd8fSJohnny Huang 		}
854a6d0d645SJohnny Huang 	}
855a6d0d645SJohnny Huang 
85669d5fd8fSJohnny Huang 	if (!pass)
857*2a856b9aSJohnny Huang 		return OTP_FAILURE;
858a6d0d645SJohnny Huang 
859*2a856b9aSJohnny Huang 	return OTP_SUCCESS;
860d90825e2SJohnny Huang 
86169d5fd8fSJohnny Huang }
86269d5fd8fSJohnny Huang 
86369d5fd8fSJohnny Huang static void otp_strp_status(struct otpstrap *otpstrap)
86469d5fd8fSJohnny Huang {
86569d5fd8fSJohnny Huang 	uint32_t OTPSTRAP_RAW[2];
86669d5fd8fSJohnny Huang 	int i, j;
86769d5fd8fSJohnny Huang 
86869d5fd8fSJohnny Huang 	for (j = 0; j < 64; j++) {
86969d5fd8fSJohnny Huang 		otpstrap[j].value = 0;
87069d5fd8fSJohnny Huang 		otpstrap[j].remain_times = 7;
87169d5fd8fSJohnny Huang 		otpstrap[j].writeable_option = -1;
87269d5fd8fSJohnny Huang 		otpstrap[j].protected = 0;
87369d5fd8fSJohnny Huang 	}
87469d5fd8fSJohnny Huang 
87569d5fd8fSJohnny Huang 	for (i = 16; i < 30; i += 2) {
87669d5fd8fSJohnny Huang 		int option = (i - 16) / 2;
87769d5fd8fSJohnny Huang 		otp_read_config(i, &OTPSTRAP_RAW[0]);
87869d5fd8fSJohnny Huang 		otp_read_config(i + 1, &OTPSTRAP_RAW[1]);
87969d5fd8fSJohnny Huang 		for (j = 0; j < 32; j++) {
88069d5fd8fSJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
88169d5fd8fSJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
88269d5fd8fSJohnny Huang 				otpstrap[j].writeable_option = option;
88369d5fd8fSJohnny Huang 			}
88469d5fd8fSJohnny Huang 			if (bit_value == 1)
88569d5fd8fSJohnny Huang 				otpstrap[j].remain_times --;
88669d5fd8fSJohnny Huang 			otpstrap[j].value ^= bit_value;
88769d5fd8fSJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
88869d5fd8fSJohnny Huang 		}
88969d5fd8fSJohnny Huang 		for (j = 32; j < 64; j++) {
89069d5fd8fSJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
89169d5fd8fSJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
89269d5fd8fSJohnny Huang 				otpstrap[j].writeable_option = option;
89369d5fd8fSJohnny Huang 			}
89469d5fd8fSJohnny Huang 			if (bit_value == 1)
89569d5fd8fSJohnny Huang 				otpstrap[j].remain_times --;
89669d5fd8fSJohnny Huang 			otpstrap[j].value ^= bit_value;
89769d5fd8fSJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
89869d5fd8fSJohnny Huang 		}
89969d5fd8fSJohnny Huang 	}
90069d5fd8fSJohnny Huang 	otp_read_config(30, &OTPSTRAP_RAW[0]);
90169d5fd8fSJohnny Huang 	otp_read_config(31, &OTPSTRAP_RAW[1]);
90269d5fd8fSJohnny Huang 	for (j = 0; j < 32; j++) {
90369d5fd8fSJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
90469d5fd8fSJohnny Huang 			otpstrap[j].protected = 1;
90569d5fd8fSJohnny Huang 	}
90669d5fd8fSJohnny Huang 	for (j = 32; j < 64; j++) {
90769d5fd8fSJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
90869d5fd8fSJohnny Huang 			otpstrap[j].protected = 1;
90969d5fd8fSJohnny Huang 	}
91069d5fd8fSJohnny Huang }
91169d5fd8fSJohnny Huang 
91269d5fd8fSJohnny Huang static int otp_strap_parse(uint32_t *buf)
91369d5fd8fSJohnny Huang {
91469d5fd8fSJohnny Huang 	int i;
91569d5fd8fSJohnny Huang 	uint32_t *strap_keep = buf + 2;
91669d5fd8fSJohnny Huang 	uint32_t *strap_protect = buf + 4;
91769d5fd8fSJohnny Huang 	int bit, pbit, kbit;
91869d5fd8fSJohnny Huang 	int fail = 0;
91969d5fd8fSJohnny Huang 	struct otpstrap otpstrap[64];
92069d5fd8fSJohnny Huang 
92169d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
92269d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
92369d5fd8fSJohnny Huang 		if (i < 32) {
92469d5fd8fSJohnny Huang 			bit = (buf[0] >> i) & 0x1;
92569d5fd8fSJohnny Huang 			kbit = (strap_keep[0] >> i) & 0x1;
92669d5fd8fSJohnny Huang 			pbit = (strap_protect[0] >> i) & 0x1;
92769d5fd8fSJohnny Huang 		} else {
92869d5fd8fSJohnny Huang 			bit = (buf[1] >> (i - 32)) & 0x1;
92969d5fd8fSJohnny Huang 			kbit = (strap_keep[1] >> (i - 32)) & 0x1;
93069d5fd8fSJohnny Huang 			pbit = (strap_protect[1] >> (i - 32)) & 0x1;
93169d5fd8fSJohnny Huang 		}
93269d5fd8fSJohnny Huang 
93369d5fd8fSJohnny Huang 		if (kbit == 1) {
93469d5fd8fSJohnny Huang 			continue;
93569d5fd8fSJohnny Huang 		} else {
93669d5fd8fSJohnny Huang 			printf("OTPSTRAP[%d]:\n", i);
93769d5fd8fSJohnny Huang 		}
93869d5fd8fSJohnny Huang 		if (bit == otpstrap[i].value) {
93969d5fd8fSJohnny Huang 			printf("    The value is same as before, skip it.\n");
94069d5fd8fSJohnny Huang 			continue;
94169d5fd8fSJohnny Huang 		}
94269d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
94369d5fd8fSJohnny Huang 			printf("    This bit is protected and is not writable\n");
94469d5fd8fSJohnny Huang 			fail = 1;
94569d5fd8fSJohnny Huang 			continue;
94669d5fd8fSJohnny Huang 		}
94769d5fd8fSJohnny Huang 		if (otpstrap[i].remain_times == 0) {
94869d5fd8fSJohnny Huang 			printf("    This bit is no remaining number of times to write.\n");
94969d5fd8fSJohnny Huang 			fail = 1;
95069d5fd8fSJohnny Huang 			continue;
95169d5fd8fSJohnny Huang 		}
95269d5fd8fSJohnny Huang 		if (pbit == 1) {
95369d5fd8fSJohnny Huang 			printf("    This bit will be protected and become non-writable.\n");
95469d5fd8fSJohnny Huang 		}
955cd1610b4SJohnny Huang 		printf("    Write 1 to OTPSTRAP[%d] OPTION[%d], that value becomes from %d to %d.\n", i, otpstrap[i].writeable_option + 1, otpstrap[i].value, otpstrap[i].value ^ 1);
95669d5fd8fSJohnny Huang 	}
95769d5fd8fSJohnny Huang 	if (fail == 1)
95869d5fd8fSJohnny Huang 		return -1;
95969d5fd8fSJohnny Huang 	else
96069d5fd8fSJohnny Huang 		return 0;
96169d5fd8fSJohnny Huang }
96269d5fd8fSJohnny Huang 
963*2a856b9aSJohnny Huang static int otp_print_strap(int start, int count)
96469d5fd8fSJohnny Huang {
96569d5fd8fSJohnny Huang 	int i, j;
96669d5fd8fSJohnny Huang 	struct otpstrap otpstrap[64];
96769d5fd8fSJohnny Huang 
968*2a856b9aSJohnny Huang 	if (start < 0 || start > 64)
969*2a856b9aSJohnny Huang 		return OTP_USAGE;
970*2a856b9aSJohnny Huang 
971*2a856b9aSJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
972*2a856b9aSJohnny Huang 		return OTP_USAGE;
973*2a856b9aSJohnny Huang 
97469d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
97569d5fd8fSJohnny Huang 
976cd1610b4SJohnny Huang 	for (i = start; i < start + count; i++) {
97769d5fd8fSJohnny Huang 		printf("OTPSTRAP[%d]:\n", i);
97869d5fd8fSJohnny Huang 		printf("  OTP Option value: ");
97969d5fd8fSJohnny Huang 		for (j = 1; j <= 7; j++)
98069d5fd8fSJohnny Huang 			printf("[%d]:%d ", j, otpstrap[i].option_array[j - 1]);
98169d5fd8fSJohnny Huang 		printf("\n");
98269d5fd8fSJohnny Huang 		printf("  OTP Value: %d\n", otpstrap[i].value);
98369d5fd8fSJohnny Huang 		printf("  Status:\n");
98469d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
98569d5fd8fSJohnny Huang 			printf("    OTPSTRAP[%d] is protected and is not writable\n", i);
98669d5fd8fSJohnny Huang 		} else {
98769d5fd8fSJohnny Huang 			printf("    OTPSTRAP[%d] is not protected ", i);
98869d5fd8fSJohnny Huang 			if (otpstrap[i].remain_times == 0) {
98969d5fd8fSJohnny Huang 				printf("and no remaining number of times to write.\n");
99069d5fd8fSJohnny Huang 			} else {
99169d5fd8fSJohnny Huang 				printf("and still can write %d number of times\n", otpstrap[i].remain_times);
99269d5fd8fSJohnny Huang 			}
99369d5fd8fSJohnny Huang 		}
99469d5fd8fSJohnny Huang 	}
995*2a856b9aSJohnny Huang 
996*2a856b9aSJohnny Huang 	return OTP_SUCCESS;
99769d5fd8fSJohnny Huang }
99869d5fd8fSJohnny Huang 
99969d5fd8fSJohnny Huang static int otp_prog_strap(uint32_t *buf)
100069d5fd8fSJohnny Huang {
100169d5fd8fSJohnny Huang 	int i, j;
100269d5fd8fSJohnny Huang 	uint32_t *strap_keep = buf + 2;
100369d5fd8fSJohnny Huang 	uint32_t *strap_protect = buf + 4;
100469d5fd8fSJohnny Huang 	uint32_t prog_bit, prog_address;
100569d5fd8fSJohnny Huang 	int bit, pbit, kbit, offset;
100669d5fd8fSJohnny Huang 	int fail = 0;
100769d5fd8fSJohnny Huang 	int pass, soak;
100869d5fd8fSJohnny Huang 	struct otpstrap otpstrap[64];
100969d5fd8fSJohnny Huang 
101069d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
101169d5fd8fSJohnny Huang 
101269d5fd8fSJohnny Huang 	otp_write(0x3000, 0x4061); // Write MRA
101369d5fd8fSJohnny Huang 	otp_write(0x5000, 0x302f); // Write MRB
101469d5fd8fSJohnny Huang 	otp_write(0x1000, 0x4020); // Write MR
101569d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
10164c1c9b35SJohnny Huang 		printProgress(i + 1, 64, "");
101769d5fd8fSJohnny Huang 		prog_address = 0x800;
101869d5fd8fSJohnny Huang 		if (i < 32) {
101969d5fd8fSJohnny Huang 			offset = i;
102069d5fd8fSJohnny Huang 			bit = (buf[0] >> offset) & 0x1;
102169d5fd8fSJohnny Huang 			kbit = (strap_keep[0] >> offset) & 0x1;
102269d5fd8fSJohnny Huang 			pbit = (strap_protect[0] >> offset) & 0x1;
102369d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
102469d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
102569d5fd8fSJohnny Huang 
102669d5fd8fSJohnny Huang 		} else {
102769d5fd8fSJohnny Huang 			offset = (i - 32);
102869d5fd8fSJohnny Huang 			bit = (buf[1] >> offset) & 0x1;
102969d5fd8fSJohnny Huang 			kbit = (strap_keep[1] >> offset) & 0x1;
103069d5fd8fSJohnny Huang 			pbit = (strap_protect[1] >> offset) & 0x1;
103169d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
103269d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
103369d5fd8fSJohnny Huang 		}
103469d5fd8fSJohnny Huang 		prog_bit = ~(0x1 << offset);
103569d5fd8fSJohnny Huang 
103669d5fd8fSJohnny Huang 		if (kbit == 1) {
103769d5fd8fSJohnny Huang 			continue;
103869d5fd8fSJohnny Huang 		}
103969d5fd8fSJohnny Huang 		if (bit == otpstrap[i].value) {
104069d5fd8fSJohnny Huang 			continue;
104169d5fd8fSJohnny Huang 		}
104269d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
104369d5fd8fSJohnny Huang 			fail = 1;
104469d5fd8fSJohnny Huang 			continue;
104569d5fd8fSJohnny Huang 		}
104669d5fd8fSJohnny Huang 		if (otpstrap[i].remain_times == 0) {
104769d5fd8fSJohnny Huang 			fail = 1;
104869d5fd8fSJohnny Huang 			continue;
104969d5fd8fSJohnny Huang 		}
105069d5fd8fSJohnny Huang 		pass = 0;
105169d5fd8fSJohnny Huang 		soak = 0;
10524b65a65dSJohnny Huang 		otp_write(0x3000, 0x4061); // Write MRA
10534b65a65dSJohnny Huang 		otp_write(0x5000, 0x302f); // Write MRB
10544b65a65dSJohnny Huang 		otp_write(0x1000, 0x4020); // Write MR
10554b65a65dSJohnny Huang 		writel(0x04190760, 0x1e602008); //normal program
105669d5fd8fSJohnny Huang 		for (j = 0; j < RETRY; j++) {
105769d5fd8fSJohnny Huang 			if (!soak) {
105869d5fd8fSJohnny Huang 				otp_prog(prog_address, prog_bit);
1059a6d0d645SJohnny Huang 				if (verify_bit(prog_address, offset, 1) == 0) {
106069d5fd8fSJohnny Huang 					pass = 1;
106169d5fd8fSJohnny Huang 					break;
106269d5fd8fSJohnny Huang 				}
106369d5fd8fSJohnny Huang 				soak = 1;
10644b65a65dSJohnny Huang 				otp_write(0x3000, 0x4021); // Write MRA
10654b65a65dSJohnny Huang 				otp_write(0x5000, 0x1027); // Write MRB
10664b65a65dSJohnny Huang 				otp_write(0x1000, 0x4820); // Write MR
106769d5fd8fSJohnny Huang 				writel(0x041930d4, 0x1e602008); //soak program
10684b65a65dSJohnny Huang 			}
106969d5fd8fSJohnny Huang 			otp_prog(prog_address, prog_bit);
1070a6d0d645SJohnny Huang 			if (verify_bit(prog_address, offset, 1) == 0) {
107169d5fd8fSJohnny Huang 				pass = 1;
107269d5fd8fSJohnny Huang 				break;
107369d5fd8fSJohnny Huang 			}
107469d5fd8fSJohnny Huang 		}
107569d5fd8fSJohnny Huang 		if (!pass)
1076*2a856b9aSJohnny Huang 			return OTP_FAILURE;
107769d5fd8fSJohnny Huang 
107869d5fd8fSJohnny Huang 		if (pbit == 0)
107969d5fd8fSJohnny Huang 			continue;
108069d5fd8fSJohnny Huang 		prog_address = 0x800;
108169d5fd8fSJohnny Huang 		if (i < 32)
108269d5fd8fSJohnny Huang 			prog_address |= 0x60c;
108369d5fd8fSJohnny Huang 		else
108469d5fd8fSJohnny Huang 			prog_address |= 0x60e;
108569d5fd8fSJohnny Huang 
108669d5fd8fSJohnny Huang 		for (j = 0; j < RETRY; j++) {
108769d5fd8fSJohnny Huang 			if (!soak) {
108869d5fd8fSJohnny Huang 				writel(0x04190760, 0x1e602008); //normal program
108969d5fd8fSJohnny Huang 				otp_prog(prog_address, prog_bit);
1090a6d0d645SJohnny Huang 				if (verify_bit(prog_address, offset, 1) == 0) {
109169d5fd8fSJohnny Huang 					pass = 1;
109269d5fd8fSJohnny Huang 					break;
109369d5fd8fSJohnny Huang 				}
109469d5fd8fSJohnny Huang 				soak = 1;
109569d5fd8fSJohnny Huang 			}
109669d5fd8fSJohnny Huang 			writel(0x041930d4, 0x1e602008); //soak program
109769d5fd8fSJohnny Huang 			otp_prog(prog_address, prog_bit);
1098a6d0d645SJohnny Huang 			if (verify_bit(prog_address, offset, 1) == 0) {
109969d5fd8fSJohnny Huang 				pass = 1;
110069d5fd8fSJohnny Huang 				break;
110169d5fd8fSJohnny Huang 			}
110269d5fd8fSJohnny Huang 		}
110369d5fd8fSJohnny Huang 		if (!pass)
1104*2a856b9aSJohnny Huang 			return OTP_FAILURE;
110569d5fd8fSJohnny Huang 
110669d5fd8fSJohnny Huang 	}
110769d5fd8fSJohnny Huang 	if (fail == 1)
1108*2a856b9aSJohnny Huang 		return OTP_FAILURE;
110969d5fd8fSJohnny Huang 	else
1110*2a856b9aSJohnny Huang 		return OTP_SUCCESS;
111169d5fd8fSJohnny Huang 
111269d5fd8fSJohnny Huang }
111369d5fd8fSJohnny Huang 
1114cd1610b4SJohnny Huang static void otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset, int soak)
1115cd1610b4SJohnny Huang {
1116cd1610b4SJohnny Huang 	int prog_bit;
1117cd1610b4SJohnny Huang 
1118cd1610b4SJohnny Huang 	if (soak) {
1119cd1610b4SJohnny Huang 		otp_write(0x3000, 0x4021); // Write MRA
1120cd1610b4SJohnny Huang 		otp_write(0x5000, 0x1027); // Write MRB
1121cd1610b4SJohnny Huang 		otp_write(0x1000, 0x4820); // Write MR
1122cd1610b4SJohnny Huang 		writel(0x041930d4, 0x1e602008); //soak program
1123cd1610b4SJohnny Huang 	} else {
1124cd1610b4SJohnny Huang 		otp_write(0x3000, 0x4061); // Write MRA
1125cd1610b4SJohnny Huang 		otp_write(0x5000, 0x302f); // Write MRB
1126cd1610b4SJohnny Huang 		otp_write(0x1000, 0x4020); // Write MR
1127cd1610b4SJohnny Huang 		writel(0x04190760, 0x1e602008); //normal program
1128cd1610b4SJohnny Huang 	}
1129cd1610b4SJohnny Huang 	if (prog_address % 2 == 0) {
1130cd1610b4SJohnny Huang 		if (value)
1131cd1610b4SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
1132cd1610b4SJohnny Huang 		else
1133cd1610b4SJohnny Huang 			return;
1134cd1610b4SJohnny Huang 	} else {
1135cd1610b4SJohnny Huang 		prog_address |= 1 << 15;
1136cd1610b4SJohnny Huang 		if (!value)
1137cd1610b4SJohnny Huang 			prog_bit = 0x1 << bit_offset;
1138cd1610b4SJohnny Huang 		else
1139cd1610b4SJohnny Huang 			return;
1140cd1610b4SJohnny Huang 	}
1141cd1610b4SJohnny Huang 	otp_prog(prog_address, prog_bit);
1142cd1610b4SJohnny Huang }
1143cd1610b4SJohnny Huang 
1144d90825e2SJohnny Huang static int otp_prog_data(uint32_t *buf)
11454c1c9b35SJohnny Huang {
11464c1c9b35SJohnny Huang 	int i, k;
11474c1c9b35SJohnny Huang 	int pass;
1148d90825e2SJohnny Huang 	int soak = 0;
11494c1c9b35SJohnny Huang 	uint32_t prog_address;
1150d90825e2SJohnny Huang 	uint32_t data[2048];
11514c1c9b35SJohnny Huang 	uint32_t compare[2];
1152d90825e2SJohnny Huang 	uint32_t *buf_keep = &buf[2048];
11534c1c9b35SJohnny Huang 
1154d90825e2SJohnny Huang 	uint32_t data0_masked;
1155d90825e2SJohnny Huang 	uint32_t data1_masked;
1156d90825e2SJohnny Huang 	uint32_t buf0_masked;
1157d90825e2SJohnny Huang 	uint32_t buf1_masked;
11584c1c9b35SJohnny Huang 
11594c1c9b35SJohnny Huang 	printf("Read OTP Data:\n");
11604c1c9b35SJohnny Huang 
1161d90825e2SJohnny Huang 	printProgress(0, 2048, "");
1162d90825e2SJohnny Huang 	for (i = 0; i < 2048 ; i += 2) {
1163d90825e2SJohnny Huang 		printProgress(i + 2, 2048, "");
1164d90825e2SJohnny Huang 		otp_read_data(i, &data[i]);
11654c1c9b35SJohnny Huang 	}
1166d90825e2SJohnny Huang 
11674c1c9b35SJohnny Huang 
11684c1c9b35SJohnny Huang 	printf("Check writable...\n");
1169d90825e2SJohnny Huang 	for (i = 0; i < 2048; i++) {
1170d90825e2SJohnny Huang 		data0_masked = data[i]  & ~buf_keep[i];
1171d90825e2SJohnny Huang 		buf0_masked  = buf[i] & ~buf_keep[i];
1172d90825e2SJohnny Huang 		if (data0_masked == buf0_masked)
11734c1c9b35SJohnny Huang 			continue;
1174d90825e2SJohnny Huang 		if (i % 2 == 0) {
1175d90825e2SJohnny Huang 			if ((data0_masked | buf0_masked) == buf0_masked) {
11764c1c9b35SJohnny Huang 				continue;
11774c1c9b35SJohnny Huang 			} else {
11784c1c9b35SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1179d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
11804c1c9b35SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1181d90825e2SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_keep[i]);
1182*2a856b9aSJohnny Huang 				return OTP_FAILURE;
118369d5fd8fSJohnny Huang 			}
1184d90825e2SJohnny Huang 		} else {
1185d90825e2SJohnny Huang 			if ((data0_masked & buf0_masked) == buf0_masked) {
1186d90825e2SJohnny Huang 				continue;
1187d90825e2SJohnny Huang 			} else {
1188d90825e2SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1189d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1190d90825e2SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1191d90825e2SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_keep[i]);
1192*2a856b9aSJohnny Huang 				return OTP_FAILURE;
1193d90825e2SJohnny Huang 			}
1194d90825e2SJohnny Huang 		}
1195d90825e2SJohnny Huang 	}
119669d5fd8fSJohnny Huang 
1197d90825e2SJohnny Huang 	printf("Start Programing...\n");
1198d90825e2SJohnny Huang 	printProgress(0, 2048, "");
1199d90825e2SJohnny Huang 
1200d90825e2SJohnny Huang 	for (i = 0; i < 2048; i += 2) {
1201d90825e2SJohnny Huang 		prog_address = i;
1202d90825e2SJohnny Huang 		data0_masked = data[i]  & ~buf_keep[i];
1203d90825e2SJohnny Huang 		buf0_masked  = buf[i] & ~buf_keep[i];
1204d90825e2SJohnny Huang 		data1_masked = data[i + 1]  & ~buf_keep[i + 1];
1205d90825e2SJohnny Huang 		buf1_masked  = buf[i + 1] & ~buf_keep[i + 1];
1206d90825e2SJohnny Huang 		if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked)) {
1207d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1208d90825e2SJohnny Huang 			continue;
1209d90825e2SJohnny Huang 		}
1210d90825e2SJohnny Huang 		if (soak) {
1211d90825e2SJohnny Huang 			soak = 0;
1212d90825e2SJohnny Huang 			otp_soak(0);
1213d90825e2SJohnny Huang 		}
1214d90825e2SJohnny Huang 		if (data1_masked == buf1_masked) {
1215d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X    ;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1216d90825e2SJohnny Huang 			otp_prog_dw(buf[i], buf_keep[i], prog_address);
1217d90825e2SJohnny Huang 		} else if (data0_masked == buf0_masked) {
1218d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X    ", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1219d90825e2SJohnny Huang 			otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1);
1220d90825e2SJohnny Huang 		} else {
1221d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X    ;[%03X]=%08X    ", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1222d90825e2SJohnny Huang 			otp_prog_dw(buf[i], buf_keep[i], prog_address);
1223d90825e2SJohnny Huang 			otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1);
1224d90825e2SJohnny Huang 		}
1225d90825e2SJohnny Huang 
1226d90825e2SJohnny Huang 		pass = 0;
1227d90825e2SJohnny Huang 		for (k = 0; k < RETRY; k++) {
1228d90825e2SJohnny Huang 			if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 2) != 0) {
1229d90825e2SJohnny Huang 				if (soak == 0) {
1230d90825e2SJohnny Huang 					soak = 1;
1231d90825e2SJohnny Huang 					otp_soak(1);
1232d90825e2SJohnny Huang 				}
1233d90825e2SJohnny Huang 				if (compare[0] != 0) {
1234d90825e2SJohnny Huang 					otp_prog_dw(compare[0], buf_keep[i], prog_address);
1235d90825e2SJohnny Huang 				}
1236d90825e2SJohnny Huang 				if (compare[1] != ~0) {
1237d90825e2SJohnny Huang 					otp_prog_dw(compare[1], buf_keep[i], prog_address + 1);
1238d90825e2SJohnny Huang 				}
1239d90825e2SJohnny Huang 			} else {
1240d90825e2SJohnny Huang 				pass = 1;
1241d90825e2SJohnny Huang 				break;
1242d90825e2SJohnny Huang 			}
1243d90825e2SJohnny Huang 		}
1244d90825e2SJohnny Huang 
1245d90825e2SJohnny Huang 		if (!pass)
1246*2a856b9aSJohnny Huang 			return OTP_FAILURE;
1247d90825e2SJohnny Huang 	}
1248*2a856b9aSJohnny Huang 	return OTP_SUCCESS;
1249d90825e2SJohnny Huang 
1250d90825e2SJohnny Huang }
1251d90825e2SJohnny Huang 
1252d90825e2SJohnny Huang static int do_otp_prog(int addr, int byte_size, int nconfirm)
125369d5fd8fSJohnny Huang {
125469d5fd8fSJohnny Huang 	int ret;
1255d90825e2SJohnny Huang 	int mode;
125669d5fd8fSJohnny Huang 	uint32_t *buf;
1257d90825e2SJohnny Huang 	uint32_t *data_region = NULL;
1258d90825e2SJohnny Huang 	uint32_t *conf_region = NULL;
1259d90825e2SJohnny Huang 	uint32_t *strap_region = NULL;
126069d5fd8fSJohnny Huang 
1261d90825e2SJohnny Huang 	buf = map_physmem(addr, byte_size, MAP_WRBACK);
126269d5fd8fSJohnny Huang 	if (!buf) {
126369d5fd8fSJohnny Huang 		puts("Failed to map physical memory\n");
1264*2a856b9aSJohnny Huang 		return OTP_FAILURE;
126569d5fd8fSJohnny Huang 	}
1266d90825e2SJohnny Huang 
1267d90825e2SJohnny Huang 	if (((buf[0] >> 29) & 0x7) == 0x7) {
1268d90825e2SJohnny Huang 		mode = OTP_REGION_ALL;
1269d90825e2SJohnny Huang 		conf_region = &buf[1];
1270d90825e2SJohnny Huang 		strap_region = &buf[25];
1271d90825e2SJohnny Huang 		data_region = &buf[31];
1272d90825e2SJohnny Huang 	} else {
1273d90825e2SJohnny Huang 		if (buf[0] & BIT(29)) {
1274d90825e2SJohnny Huang 			mode = OTP_REGION_DATA;
1275d90825e2SJohnny Huang 			data_region = &buf[31];
1276d90825e2SJohnny Huang 		}
1277d90825e2SJohnny Huang 		if (buf[0] & BIT(30)) {
1278d90825e2SJohnny Huang 			mode = OTP_REGION_CONF;
1279d90825e2SJohnny Huang 			strap_region = &buf[25];
1280d90825e2SJohnny Huang 		}
1281d90825e2SJohnny Huang 		if (buf[0] & BIT(31)) {
1282d90825e2SJohnny Huang 			mode = OTP_REGION_STRAP;
1283d90825e2SJohnny Huang 			conf_region = &buf[1];
1284d90825e2SJohnny Huang 		}
1285d90825e2SJohnny Huang 	}
128669d5fd8fSJohnny Huang 	if (!nconfirm) {
1287a6d0d645SJohnny Huang 		if (mode == OTP_REGION_CONF) {
1288d90825e2SJohnny Huang 			if (otp_conf_parse(conf_region) < 0) {
128969d5fd8fSJohnny Huang 				printf("OTP config error, please check.\n");
1290*2a856b9aSJohnny Huang 				return OTP_FAILURE;
129169d5fd8fSJohnny Huang 			}
1292a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_DATA) {
1293d90825e2SJohnny Huang 			if (otp_data_parse(data_region) < 0) {
129469d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
1295*2a856b9aSJohnny Huang 				return OTP_FAILURE;
129669d5fd8fSJohnny Huang 			}
1297a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_STRAP) {
1298d90825e2SJohnny Huang 			if (otp_strap_parse(strap_region) < 0) {
129969d5fd8fSJohnny Huang 				printf("OTP strap error, please check.\n");
1300*2a856b9aSJohnny Huang 				return OTP_FAILURE;
130169d5fd8fSJohnny Huang 			}
1302a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_ALL) {
1303d90825e2SJohnny Huang 			if (otp_conf_parse(conf_region) < 0) {
130469d5fd8fSJohnny Huang 				printf("OTP config error, please check.\n");
1305*2a856b9aSJohnny Huang 				return OTP_FAILURE;
130669d5fd8fSJohnny Huang 			}
1307d90825e2SJohnny Huang 			if (otp_strap_parse(strap_region) < 0) {
130869d5fd8fSJohnny Huang 				printf("OTP strap error, please check.\n");
1309*2a856b9aSJohnny Huang 				return OTP_FAILURE;
131069d5fd8fSJohnny Huang 			}
1311d90825e2SJohnny Huang 			if (otp_data_parse(data_region) < 0) {
131269d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
1313*2a856b9aSJohnny Huang 				return OTP_FAILURE;
131469d5fd8fSJohnny Huang 			}
131569d5fd8fSJohnny Huang 		}
131669d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
131769d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
131869d5fd8fSJohnny Huang 			printf(" Aborting\n");
1319*2a856b9aSJohnny Huang 			return OTP_FAILURE;
132069d5fd8fSJohnny Huang 		}
132169d5fd8fSJohnny Huang 	}
1322a6d0d645SJohnny Huang 	if (mode == OTP_REGION_CONF) {
1323d90825e2SJohnny Huang 		return otp_prog_conf(conf_region);
1324a6d0d645SJohnny Huang 	} else if (mode == OTP_REGION_STRAP) {
1325d90825e2SJohnny Huang 		return otp_prog_strap(strap_region);
1326a6d0d645SJohnny Huang 	} else if (mode == OTP_REGION_DATA) {
1327d90825e2SJohnny Huang 		return otp_prog_data(data_region);
1328a6d0d645SJohnny Huang 	} else if (mode == OTP_REGION_ALL) {
132969d5fd8fSJohnny Huang 		printf("programing data region ... ");
1330d90825e2SJohnny Huang 		ret = otp_prog_data(data_region);
1331*2a856b9aSJohnny Huang 		if (ret != 0) {
133269d5fd8fSJohnny Huang 			printf("Error\n");
133369d5fd8fSJohnny Huang 			return ret;
133469d5fd8fSJohnny Huang 		} else {
133569d5fd8fSJohnny Huang 			printf("Done\n");
133669d5fd8fSJohnny Huang 		}
133769d5fd8fSJohnny Huang 		printf("programing strap region ... ");
1338d90825e2SJohnny Huang 		ret = otp_prog_strap(strap_region);
1339*2a856b9aSJohnny Huang 		if (ret != 0) {
134069d5fd8fSJohnny Huang 			printf("Error\n");
134169d5fd8fSJohnny Huang 			return ret;
134269d5fd8fSJohnny Huang 		} else {
134369d5fd8fSJohnny Huang 			printf("Done\n");
134469d5fd8fSJohnny Huang 		}
134569d5fd8fSJohnny Huang 		printf("programing configuration region ... ");
1346d90825e2SJohnny Huang 		ret = otp_prog_conf(conf_region);
1347*2a856b9aSJohnny Huang 		if (ret != 0) {
134869d5fd8fSJohnny Huang 			printf("Error\n");
134969d5fd8fSJohnny Huang 			return ret;
135069d5fd8fSJohnny Huang 		}
135169d5fd8fSJohnny Huang 		printf("Done\n");
1352*2a856b9aSJohnny Huang 		return OTP_SUCCESS;
135369d5fd8fSJohnny Huang 	}
1354cd1610b4SJohnny Huang 
1355*2a856b9aSJohnny Huang 	return OTP_USAGE;
1356*2a856b9aSJohnny Huang }
1357*2a856b9aSJohnny Huang 
1358*2a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1359cd1610b4SJohnny Huang {
1360cd1610b4SJohnny Huang 	uint32_t ret[2];
1361cd1610b4SJohnny Huang 	uint32_t strap_buf[6];
1362d90825e2SJohnny Huang 	uint32_t prog_address = 0;
1363cd1610b4SJohnny Huang 	struct otpstrap otpstrap[64];
1364cd1610b4SJohnny Huang 	int otp_bit;
1365cd1610b4SJohnny Huang 	int i;
1366cd1610b4SJohnny Huang 	int pass;
1367cd1610b4SJohnny Huang 
1368cd1610b4SJohnny Huang 	switch (mode) {
1369a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1370cd1610b4SJohnny Huang 		otp_read_config(otp_dw_offset, ret);
1371cd1610b4SJohnny Huang 		prog_address = 0x800;
1372cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1373cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1374cd1610b4SJohnny Huang 		otp_bit = (ret[0] >> bit_offset) & 0x1;
1375cd1610b4SJohnny Huang 		if (otp_bit == value) {
1376cd1610b4SJohnny Huang 			printf("OTPCFG%X[%d] = %d\n", otp_dw_offset, bit_offset, value);
1377cd1610b4SJohnny Huang 			printf("No need to program\n");
1378*2a856b9aSJohnny Huang 			return OTP_SUCCESS;
1379cd1610b4SJohnny Huang 		}
1380cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1381cd1610b4SJohnny Huang 			printf("OTPCFG%X[%d] = 1\n", otp_dw_offset, bit_offset);
1382cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
1383*2a856b9aSJohnny Huang 			return OTP_FAILURE;
1384cd1610b4SJohnny Huang 		}
1385cd1610b4SJohnny Huang 		printf("Program OTPCFG%X[%d] to 1\n", otp_dw_offset, bit_offset);
1386cd1610b4SJohnny Huang 		break;
1387a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1388cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1389cd1610b4SJohnny Huang 
1390cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1391cd1610b4SJohnny Huang 			otp_read_data(otp_dw_offset, ret);
1392cd1610b4SJohnny Huang 			otp_bit = (ret[0] >> bit_offset) & 0x1;
1393cd1610b4SJohnny Huang 		} else {
1394cd1610b4SJohnny Huang 			otp_read_data(otp_dw_offset - 1, ret);
1395cd1610b4SJohnny Huang 			otp_bit = (ret[1] >> bit_offset) & 0x1;
1396cd1610b4SJohnny Huang 		}
1397cd1610b4SJohnny Huang 		if (otp_bit == value) {
1398cd1610b4SJohnny Huang 			printf("OTPDATA%X[%d] = %d\n", otp_dw_offset, bit_offset, value);
1399cd1610b4SJohnny Huang 			printf("No need to program\n");
1400*2a856b9aSJohnny Huang 			return OTP_SUCCESS;
1401cd1610b4SJohnny Huang 		}
1402cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1403cd1610b4SJohnny Huang 			printf("OTPDATA%X[%d] = 1\n", otp_dw_offset, bit_offset);
1404cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
1405*2a856b9aSJohnny Huang 			return OTP_FAILURE;
1406cd1610b4SJohnny Huang 		}
1407cd1610b4SJohnny Huang 		printf("Program OTPDATA%X[%d] to 1\n", otp_dw_offset, bit_offset);
1408cd1610b4SJohnny Huang 		break;
1409a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1410cd1610b4SJohnny Huang 		otp_strp_status(otpstrap);
1411cd1610b4SJohnny Huang 		otp_print_strap(bit_offset, 1);
1412cd1610b4SJohnny Huang 		if (bit_offset < 32) {
1413cd1610b4SJohnny Huang 			strap_buf[0] = value << bit_offset;
1414cd1610b4SJohnny Huang 			strap_buf[2] = ~BIT(bit_offset);
1415cd1610b4SJohnny Huang 			strap_buf[3] = ~0;
1416cd1610b4SJohnny Huang 			strap_buf[5] = 0;
1417*2a856b9aSJohnny Huang 			// if (protect)
1418*2a856b9aSJohnny Huang 			// 	strap_buf[4] = BIT(bit_offset);
1419*2a856b9aSJohnny Huang 			// else
1420*2a856b9aSJohnny Huang 			// 	strap_buf[4] = 0;
1421cd1610b4SJohnny Huang 		} else {
1422cd1610b4SJohnny Huang 			strap_buf[1] = value << (bit_offset - 32);
1423cd1610b4SJohnny Huang 			strap_buf[2] = ~0;
1424cd1610b4SJohnny Huang 			strap_buf[3] = ~BIT(bit_offset - 32);
1425cd1610b4SJohnny Huang 			strap_buf[4] = 0;
1426*2a856b9aSJohnny Huang 			// if (protect)
1427*2a856b9aSJohnny Huang 			// 	strap_buf[5] = BIT(bit_offset - 32);
1428*2a856b9aSJohnny Huang 			// else
1429*2a856b9aSJohnny Huang 			// 	strap_buf[5] = 0;
1430cd1610b4SJohnny Huang 		}
1431cd1610b4SJohnny Huang 		if (otp_strap_parse(strap_buf) < 0)
1432*2a856b9aSJohnny Huang 			return OTP_FAILURE;
1433cd1610b4SJohnny Huang 		break;
1434cd1610b4SJohnny Huang 	}
1435cd1610b4SJohnny Huang 
1436cd1610b4SJohnny Huang 	if (!nconfirm) {
1437cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1438cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1439cd1610b4SJohnny Huang 			printf(" Aborting\n");
1440*2a856b9aSJohnny Huang 			return OTP_FAILURE;
1441cd1610b4SJohnny Huang 		}
1442cd1610b4SJohnny Huang 	}
1443cd1610b4SJohnny Huang 
1444cd1610b4SJohnny Huang 	switch (mode) {
1445a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1446cd1610b4SJohnny Huang 		return otp_prog_strap(strap_buf);
1447a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1448a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1449cd1610b4SJohnny Huang 		otp_prog_bit(value, prog_address, bit_offset, 0);
1450cd1610b4SJohnny Huang 		pass = -1;
1451cd1610b4SJohnny Huang 		for (i = 0; i < RETRY; i++) {
1452a6d0d645SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
1453cd1610b4SJohnny Huang 				otp_prog_bit(value, prog_address, bit_offset, 1);
1454cd1610b4SJohnny Huang 			} else {
1455cd1610b4SJohnny Huang 				pass = 0;
1456cd1610b4SJohnny Huang 				break;
1457cd1610b4SJohnny Huang 			}
1458cd1610b4SJohnny Huang 		}
1459*2a856b9aSJohnny Huang 		if (pass == 0)
1460*2a856b9aSJohnny Huang 			return OTP_SUCCESS;
1461cd1610b4SJohnny Huang 	}
1462cd1610b4SJohnny Huang 
1463*2a856b9aSJohnny Huang 	return OTP_USAGE;
1464cd1610b4SJohnny Huang }
1465cd1610b4SJohnny Huang 
1466*2a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
146769d5fd8fSJohnny Huang {
1468*2a856b9aSJohnny Huang 	uint32_t offset, count;
1469*2a856b9aSJohnny Huang 	int ret;
147069d5fd8fSJohnny Huang 
1471*2a856b9aSJohnny Huang 	if (argc == 4) {
1472*2a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
1473*2a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
1474*2a856b9aSJohnny Huang 	} else if (argc == 3) {
1475*2a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
1476*2a856b9aSJohnny Huang 		count = 1;
1477*2a856b9aSJohnny Huang 	} else {
147869d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
147969d5fd8fSJohnny Huang 	}
148069d5fd8fSJohnny Huang 
148169d5fd8fSJohnny Huang 
1482*2a856b9aSJohnny Huang 	if (!strcmp(argv[1], "conf")) {
148369d5fd8fSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
1484*2a856b9aSJohnny Huang 		ret = otp_print_config(offset, count);
1485*2a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "data")) {
1486*2a856b9aSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
1487*2a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
1488*2a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
1489*2a856b9aSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
1490*2a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
1491*2a856b9aSJohnny Huang 	} else {
1492*2a856b9aSJohnny Huang 		return CMD_RET_USAGE;
149369d5fd8fSJohnny Huang 	}
149469d5fd8fSJohnny Huang 
1495*2a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
1496*2a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
1497*2a856b9aSJohnny Huang 	else
1498*2a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1499*2a856b9aSJohnny Huang 
1500*2a856b9aSJohnny Huang }
1501*2a856b9aSJohnny Huang 
1502*2a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
1503*2a856b9aSJohnny Huang {
1504*2a856b9aSJohnny Huang 	phys_addr_t addr;
1505*2a856b9aSJohnny Huang 	uint32_t byte_size;
1506*2a856b9aSJohnny Huang 	int ret;
1507*2a856b9aSJohnny Huang 
1508*2a856b9aSJohnny Huang 	if (argc == 4) {
1509*2a856b9aSJohnny Huang 		if (strcmp(argv[1], "f"))
1510*2a856b9aSJohnny Huang 			return CMD_RET_USAGE;
1511*2a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
1512*2a856b9aSJohnny Huang 		byte_size = simple_strtoul(argv[3], NULL, 16);
151369d5fd8fSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
1514*2a856b9aSJohnny Huang 		ret = do_otp_prog(addr, byte_size, 1);
1515*2a856b9aSJohnny Huang 	} else if (argc == 3) {
1516*2a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
1517*2a856b9aSJohnny Huang 		byte_size = simple_strtoul(argv[2], NULL, 16);
1518*2a856b9aSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
1519*2a856b9aSJohnny Huang 		ret = do_otp_prog(addr, byte_size, 0);
1520*2a856b9aSJohnny Huang 	} else {
1521*2a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1522*2a856b9aSJohnny Huang 	}
1523*2a856b9aSJohnny Huang 
1524*2a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
1525*2a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
1526*2a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
1527*2a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
1528*2a856b9aSJohnny Huang 	else
1529*2a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1530*2a856b9aSJohnny Huang }
1531*2a856b9aSJohnny Huang 
1532*2a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
1533*2a856b9aSJohnny Huang {
1534*2a856b9aSJohnny Huang 	int mode = 0;
1535*2a856b9aSJohnny Huang 	int nconfirm = 0;
1536*2a856b9aSJohnny Huang 	int otp_addr = 0;
1537*2a856b9aSJohnny Huang 	int bit_offset;
1538*2a856b9aSJohnny Huang 	int value;
1539*2a856b9aSJohnny Huang 	int ret;
1540*2a856b9aSJohnny Huang 
1541*2a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
1542*2a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1543*2a856b9aSJohnny Huang 
1544*2a856b9aSJohnny Huang 	/* Drop the pb cmd */
1545*2a856b9aSJohnny Huang 	argc--;
1546*2a856b9aSJohnny Huang 	argv++;
1547*2a856b9aSJohnny Huang 
1548*2a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
1549a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
1550*2a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
1551a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
1552*2a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
1553a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
1554cd1610b4SJohnny Huang 	else
1555*2a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1556*2a856b9aSJohnny Huang 
1557*2a856b9aSJohnny Huang 	/* Drop the region cmd */
1558*2a856b9aSJohnny Huang 	argc--;
1559*2a856b9aSJohnny Huang 	argv++;
1560*2a856b9aSJohnny Huang 
1561*2a856b9aSJohnny Huang 	if (!strcmp(argv[0], "f")) {
1562cd1610b4SJohnny Huang 		nconfirm = 1;
1563*2a856b9aSJohnny Huang 		/* Drop the force option */
1564*2a856b9aSJohnny Huang 		argc--;
1565*2a856b9aSJohnny Huang 		argv++;
1566*2a856b9aSJohnny Huang 	}
1567cd1610b4SJohnny Huang 
1568a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
1569*2a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
1570*2a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
1571cd1610b4SJohnny Huang 		if (bit_offset >= 64)
1572*2a856b9aSJohnny Huang 			return CMD_RET_USAGE;
1573cd1610b4SJohnny Huang 	} else {
1574*2a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
1575*2a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
1576*2a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
1577cd1610b4SJohnny Huang 		if (bit_offset >= 32)
1578*2a856b9aSJohnny Huang 			return CMD_RET_USAGE;
1579cd1610b4SJohnny Huang 	}
1580cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
1581*2a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1582cd1610b4SJohnny Huang 
1583cd1610b4SJohnny Huang 	writel(OTP_PASSWD, 0x1e6f2000); //password
1584*2a856b9aSJohnny Huang 	ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
1585*2a856b9aSJohnny Huang 
1586*2a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
1587*2a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
1588*2a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
1589*2a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
1590*2a856b9aSJohnny Huang 	else
1591*2a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1592*2a856b9aSJohnny Huang }
1593*2a856b9aSJohnny Huang 
1594*2a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
1595*2a856b9aSJohnny Huang {
1596*2a856b9aSJohnny Huang 	phys_addr_t addr;
1597*2a856b9aSJohnny Huang 	int otp_addr = 0;
1598*2a856b9aSJohnny Huang 
1599*2a856b9aSJohnny Huang 	if (argc != 3)
1600*2a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1601*2a856b9aSJohnny Huang 
160269d5fd8fSJohnny Huang 	writel(OTP_PASSWD, 0x1e6f2000); //password
1603*2a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
1604*2a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
1605*2a856b9aSJohnny Huang 	if (otp_compare(otp_addr, addr) == 0) {
160669d5fd8fSJohnny Huang 		printf("Compare pass\n");
1607*2a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
160869d5fd8fSJohnny Huang 	} else {
160969d5fd8fSJohnny Huang 		printf("Compare fail\n");
1610*2a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
161169d5fd8fSJohnny Huang 	}
161269d5fd8fSJohnny Huang }
161369d5fd8fSJohnny Huang 
1614*2a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
1615*2a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
1616*2a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(prog, 4, 0, do_otpprog, "", ""),
1617*2a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
1618*2a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
161969d5fd8fSJohnny Huang 
1620*2a856b9aSJohnny Huang };
1621*2a856b9aSJohnny Huang 
1622*2a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
1623*2a856b9aSJohnny Huang {
1624*2a856b9aSJohnny Huang 	cmd_tbl_t *cp;
1625*2a856b9aSJohnny Huang 
1626*2a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
1627*2a856b9aSJohnny Huang 
1628*2a856b9aSJohnny Huang 	/* Drop the mmc command */
1629*2a856b9aSJohnny Huang 	argc--;
1630*2a856b9aSJohnny Huang 	argv++;
1631*2a856b9aSJohnny Huang 
1632*2a856b9aSJohnny Huang 	if (cp == NULL || argc > cp->maxargs)
1633*2a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1634*2a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
1635*2a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
1636*2a856b9aSJohnny Huang 
1637*2a856b9aSJohnny Huang 	return cp->cmd(cmdtp, flag, argc, argv);
163869d5fd8fSJohnny Huang }
163969d5fd8fSJohnny Huang 
164069d5fd8fSJohnny Huang U_BOOT_CMD(
164169d5fd8fSJohnny Huang 	otp, 7, 0,  do_ast_otp,
164269d5fd8fSJohnny Huang 	"ASPEED One-Time-Programmable sub-system",
1643*2a856b9aSJohnny Huang 	"read conf|data <otp_dw_offset> <dw_count>\n"
1644*2a856b9aSJohnny Huang 	"otp read strap <strap_bit_offset> <bit_count>\n"
1645*2a856b9aSJohnny Huang 	"otp info conf|strap|data <otp_dw_offset> <dw_count>\n"
1646d90825e2SJohnny Huang 	"otp prog [f] <addr> <byte_size>\n"
1647cd1610b4SJohnny Huang 	"otp pb conf|data [f] <otp_dw_offset> <bit_offset> <value>\n"
1648cd1610b4SJohnny Huang 	"otp pb strap [f] <bit_offset> <value> <protect>\n"
1649*2a856b9aSJohnny Huang 	"otp cmp <addr> <otp_dw_offset>\n"
165069d5fd8fSJohnny Huang );
1651