xref: /openbmc/u-boot/cmd/otp.c (revision d90825e2e93939c0ce48ac28a91e4204b7a03c10)
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 
33e1f9e54eSJohnny Huang #define DISABLE_SECREG_PROG		BIT(0)
34e1f9e54eSJohnny Huang #define ENABLE_SEC_BOOT			BIT(1)
35e1f9e54eSJohnny Huang #define INIT_PROG_DONE			BIT(2)
36e1f9e54eSJohnny Huang #define ENABLE_USERREG_ECC		BIT(3)
37e1f9e54eSJohnny Huang #define ENABLE_SECREG_ECC		BIT(4)
38e1f9e54eSJohnny Huang #define DISABLE_LOW_SEC_KEY		BIT(5)
39e1f9e54eSJohnny Huang #define IGNORE_SEC_BOOT_HWSTRAP		BIT(6)
40e1f9e54eSJohnny Huang #define SEC_BOOT_MDOES(x)		(x >> 7)
41e1f9e54eSJohnny Huang #define   SEC_MODE1			0x0
42e1f9e54eSJohnny Huang #define   SEC_MODE2			0x1
43e1f9e54eSJohnny Huang #define OTP_BIT_CELL_MODES(x)		((x >> 8) & 0x3)
44e1f9e54eSJohnny Huang #define   SINGLE_CELL_MODE		0x0
45e1f9e54eSJohnny Huang #define   DIFFERENTIAL_MODE		0x1
46e1f9e54eSJohnny Huang #define   DIFFERENTIAL_REDUDANT_MODE	0x2
47e1f9e54eSJohnny Huang #define CRYPTO_MODES(x)			((x >> 10) & 0x3)
48e1f9e54eSJohnny Huang #define   CRYPTO_RSA1024		0x0
49e1f9e54eSJohnny Huang #define   CRYPTO_RSA2048		0x1
50e1f9e54eSJohnny Huang #define   CRYPTO_RSA3072		0x2
51e1f9e54eSJohnny Huang #define   CRYPTO_RSA4096		0x3
52e1f9e54eSJohnny Huang #define HASH_MODES(x)			((x >> 12) & 0x3)
53e1f9e54eSJohnny Huang #define   HASH_SAH224			0x0
54e1f9e54eSJohnny Huang #define   HASH_SAH256			0x1
55e1f9e54eSJohnny Huang #define   HASH_SAH384			0x2
56e1f9e54eSJohnny Huang #define   HASH_SAH512			0x3
57e1f9e54eSJohnny Huang #define SECREG_SIZE(x)			((x >> 16) & 0x3f)
58e1f9e54eSJohnny Huang #define WRITE_PROTECT_SECREG		BIT(22)
59e1f9e54eSJohnny Huang #define WRITE_PROTECT_USERREG		BIT(23)
60e1f9e54eSJohnny Huang #define WRITE_PROTECT_CONFREG		BIT(24)
61e1f9e54eSJohnny Huang #define WRITE_PROTECT_STRAPREG		BIT(25)
62e1f9e54eSJohnny Huang #define ENABLE_COPY_TO_SRAM		BIT(26)
63e1f9e54eSJohnny Huang #define ENABLE_IMAGE_ENC		BIT(27)
64e1f9e54eSJohnny Huang #define WRITE_PROTECT_KEY_RETIRE	BIT(29)
65e1f9e54eSJohnny Huang #define ENABLE_SIPROM_RED		BIT(30)
66e1f9e54eSJohnny Huang #define ENABLE_SIPROM_MLOCK		BIT(31)
67e1f9e54eSJohnny Huang 
68e1f9e54eSJohnny Huang #define VENDER_ID(x) 			(x & 0xFFFF)
69e1f9e54eSJohnny Huang #define KEY_REVISION(x)			((x >> 16) & 0xFFFF)
70e1f9e54eSJohnny Huang 
71e1f9e54eSJohnny Huang #define SEC_BOOT_HEADER_OFFSET(x)	(x & 0xFFFF)
72e1f9e54eSJohnny Huang 
73e1f9e54eSJohnny Huang #define KEYS_VALID_BITS(x)		(x & 0xff)
74e1f9e54eSJohnny Huang #define KEYS_RETIRE_BITS(x)		((x >> 16) & 0xff)
754c1c9b35SJohnny Huang 
764c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
774c1c9b35SJohnny Huang #define PBWIDTH 60
784c1c9b35SJohnny Huang 
794c1c9b35SJohnny Huang void printProgress(int numerator, int denominator, char *format, ...)
804c1c9b35SJohnny Huang {
814c1c9b35SJohnny Huang 	int val = numerator * 100 / denominator;
824c1c9b35SJohnny Huang 	int lpad = numerator * PBWIDTH / denominator;
834c1c9b35SJohnny Huang 	int rpad = PBWIDTH - lpad;
844c1c9b35SJohnny Huang 	char buffer[256];
854c1c9b35SJohnny Huang 	va_list aptr;
864c1c9b35SJohnny Huang 
874c1c9b35SJohnny Huang 	va_start(aptr, format);
884c1c9b35SJohnny Huang 	vsprintf(buffer, format, aptr);
894c1c9b35SJohnny Huang 	va_end(aptr);
904c1c9b35SJohnny Huang 
914c1c9b35SJohnny Huang 	printf("\r%3d%% [%.*s%*s] %s", val, lpad, PBSTR, rpad, "", buffer);
924c1c9b35SJohnny Huang 	if (numerator == denominator)
934c1c9b35SJohnny Huang 		printf("\n");
944c1c9b35SJohnny Huang }
954c1c9b35SJohnny Huang 
9669d5fd8fSJohnny Huang struct otpstrap {
9769d5fd8fSJohnny Huang 	int value;
9869d5fd8fSJohnny Huang 	int option_array[7];
9969d5fd8fSJohnny Huang 	int remain_times;
10069d5fd8fSJohnny Huang 	int writeable_option;
10169d5fd8fSJohnny Huang 	int protected;
10269d5fd8fSJohnny Huang };
10369d5fd8fSJohnny Huang 
10469d5fd8fSJohnny Huang static int otp_read_data(uint32_t offset, uint32_t *data)
10569d5fd8fSJohnny Huang {
10669d5fd8fSJohnny Huang 	writel(offset, 0x1e6f2010); //Read address
10769d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
10869d5fd8fSJohnny Huang 	udelay(2);
10969d5fd8fSJohnny Huang 	data[0] = readl(0x1e6f2020);
11069d5fd8fSJohnny Huang 	data[1] = readl(0x1e6f2024);
11169d5fd8fSJohnny Huang 	return 1;
11269d5fd8fSJohnny Huang }
11369d5fd8fSJohnny Huang 
11469d5fd8fSJohnny Huang static int otp_read_config(uint32_t offset, uint32_t *data)
11569d5fd8fSJohnny Huang {
11669d5fd8fSJohnny Huang 	int config_offset;
11769d5fd8fSJohnny Huang 
11869d5fd8fSJohnny Huang 	config_offset = 0x800;
11969d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
12069d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
12169d5fd8fSJohnny Huang 
12269d5fd8fSJohnny Huang 	writel(config_offset, 0x1e6f2010);  //Read address
12369d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
12469d5fd8fSJohnny Huang 	udelay(2);
12569d5fd8fSJohnny Huang 	data[0] = readl(0x1e6f2020);
12669d5fd8fSJohnny Huang 
12769d5fd8fSJohnny Huang 	return 1;
12869d5fd8fSJohnny Huang }
12969d5fd8fSJohnny Huang 
13069d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count)
13169d5fd8fSJohnny Huang {
13269d5fd8fSJohnny Huang 	int i;
13369d5fd8fSJohnny Huang 	uint32_t ret[1];
13469d5fd8fSJohnny Huang 
13569d5fd8fSJohnny Huang 	if (offset + dw_count > 32)
13669d5fd8fSJohnny Huang 		return -1;
13769d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i ++) {
13869d5fd8fSJohnny Huang 		otp_read_config(i, ret);
13969d5fd8fSJohnny Huang 		printf("OTPCFG%d: %08X\n", i, ret[0]);
14069d5fd8fSJohnny Huang 	}
14169d5fd8fSJohnny Huang 	printf("\n");
14269d5fd8fSJohnny Huang 	return 1;
14369d5fd8fSJohnny Huang }
14469d5fd8fSJohnny Huang 
14569d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count)
14669d5fd8fSJohnny Huang {
14769d5fd8fSJohnny Huang 	int i;
14869d5fd8fSJohnny Huang 	uint32_t ret[2];
14969d5fd8fSJohnny Huang 
15069d5fd8fSJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
15169d5fd8fSJohnny Huang 		return -1;
15269d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
15369d5fd8fSJohnny Huang 		otp_read_data(i, ret);
15469d5fd8fSJohnny Huang 		if (i % 4 == 0)
15569d5fd8fSJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
15669d5fd8fSJohnny Huang 		else
15769d5fd8fSJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
15869d5fd8fSJohnny Huang 
15969d5fd8fSJohnny Huang 	}
16069d5fd8fSJohnny Huang 	printf("\n");
16169d5fd8fSJohnny Huang 	return 1;
16269d5fd8fSJohnny Huang }
16369d5fd8fSJohnny Huang 
16469d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr)
16569d5fd8fSJohnny Huang {
16669d5fd8fSJohnny Huang 	uint32_t ret;
16769d5fd8fSJohnny Huang 	uint32_t *buf;
16869d5fd8fSJohnny Huang 
16969d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
17069d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
17169d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
17269d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
17369d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
17469d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //Compare address
17569d5fd8fSJohnny Huang 	writel(buf[0], 0x1e6f2020); //Compare data 1
17669d5fd8fSJohnny Huang 	writel(buf[1], 0x1e6f2024); //Compare data 2
17769d5fd8fSJohnny Huang 	writel(buf[2], 0x1e6f2028); //Compare data 3
17869d5fd8fSJohnny Huang 	writel(buf[3], 0x1e6f202c); //Compare data 4
17969d5fd8fSJohnny Huang 	writel(0x23b1e363, 0x1e6f2004); //Compare command
18069d5fd8fSJohnny Huang 	udelay(10);
18169d5fd8fSJohnny Huang 	ret = readl(0x1e6f2014); //Compare command
18269d5fd8fSJohnny Huang 	if (ret & 0x1)
18369d5fd8fSJohnny Huang 		return 0;
18469d5fd8fSJohnny Huang 	else
18569d5fd8fSJohnny Huang 		return -1;
18669d5fd8fSJohnny Huang }
18769d5fd8fSJohnny Huang 
18869d5fd8fSJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data)
18969d5fd8fSJohnny Huang {
19069d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //write address
19169d5fd8fSJohnny Huang 	writel(data, 0x1e6f2020); //write data
19269d5fd8fSJohnny Huang 	writel(0x23b1e362, 0x1e6f2004); //write command
19369d5fd8fSJohnny Huang 	udelay(100);
19469d5fd8fSJohnny Huang }
19569d5fd8fSJohnny Huang 
19669d5fd8fSJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit)
19769d5fd8fSJohnny Huang {
19869d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //write address
19969d5fd8fSJohnny Huang 	writel(prog_bit, 0x1e6f2020); //write data
20069d5fd8fSJohnny Huang 	writel(0x23b1e364, 0x1e6f2004); //write command
20169d5fd8fSJohnny Huang 	udelay(85);
20269d5fd8fSJohnny Huang }
20369d5fd8fSJohnny Huang 
204a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value)
20569d5fd8fSJohnny Huang {
20669d5fd8fSJohnny Huang 	int ret;
20769d5fd8fSJohnny Huang 
20869d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //Read address
20969d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
21069d5fd8fSJohnny Huang 	udelay(2);
21169d5fd8fSJohnny Huang 	ret = readl(0x1e6f2020);
212a6d0d645SJohnny Huang 	// printf("verify_bit = %x\n", ret);
21369d5fd8fSJohnny Huang 	if (((ret >> bit_offset) & 1) == value)
21469d5fd8fSJohnny Huang 		return 0;
21569d5fd8fSJohnny Huang 	else
21669d5fd8fSJohnny Huang 		return -1;
21769d5fd8fSJohnny Huang }
21869d5fd8fSJohnny Huang 
219*d90825e2SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *keep, uint32_t *compare, int size)
2204c1c9b35SJohnny Huang {
2214c1c9b35SJohnny Huang 	uint32_t ret[2];
2224c1c9b35SJohnny Huang 
2234c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
2244c1c9b35SJohnny Huang 
2254c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
2264c1c9b35SJohnny Huang 		writel(otp_addr, 0x1e6f2010); //Read address
2274c1c9b35SJohnny Huang 	else
2284c1c9b35SJohnny Huang 		writel(otp_addr - 1, 0x1e6f2010); //Read address
2294c1c9b35SJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
2304c1c9b35SJohnny Huang 	udelay(2);
2314c1c9b35SJohnny Huang 	ret[0] = readl(0x1e6f2020);
2324c1c9b35SJohnny Huang 	ret[1] = readl(0x1e6f2024);
2334c1c9b35SJohnny Huang 	if (size == 1) {
2344c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
2354c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
236*d90825e2SJohnny Huang 			if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0])) {
2374c1c9b35SJohnny Huang 				compare[0] = 0;
2384c1c9b35SJohnny Huang 				return 0;
2394c1c9b35SJohnny Huang 			} else {
2404c1c9b35SJohnny Huang 				compare[0] = value[0] ^ ret[0];
2414c1c9b35SJohnny Huang 				return -1;
2424c1c9b35SJohnny Huang 			}
2434c1c9b35SJohnny Huang 
2444c1c9b35SJohnny Huang 		} else {
2454c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
246*d90825e2SJohnny Huang 			if ((value[0] & ~keep[0]) == (ret[1] & ~keep[0])) {
2474c1c9b35SJohnny Huang 				compare[0] = ~0;
2484c1c9b35SJohnny Huang 				return 0;
2494c1c9b35SJohnny Huang 			} else {
250*d90825e2SJohnny Huang 				compare[0] = ~(value[0] ^ ret[1]);
2514c1c9b35SJohnny Huang 				return -1;
2524c1c9b35SJohnny Huang 			}
2534c1c9b35SJohnny Huang 		}
2544c1c9b35SJohnny Huang 	} else if (size == 2) {
2554c1c9b35SJohnny Huang 		// otp_addr should be even
256*d90825e2SJohnny Huang 		if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0]) && (value[1] & ~keep[1]) == (ret[1] & ~keep[1])) {
2574c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
2584c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
2594c1c9b35SJohnny Huang 			compare[0] = 0;
2604c1c9b35SJohnny Huang 			compare[1] = ~0;
2614c1c9b35SJohnny Huang 			return 0;
2624c1c9b35SJohnny Huang 		} else {
2634c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
2644c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
2654c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
2664c1c9b35SJohnny Huang 			compare[1] = ~(value[1] ^ ret[1]);
2674c1c9b35SJohnny Huang 			return -1;
2684c1c9b35SJohnny Huang 		}
2694c1c9b35SJohnny Huang 	} else {
2704c1c9b35SJohnny Huang 		return -1;
2714c1c9b35SJohnny Huang 	}
2724c1c9b35SJohnny Huang }
2734c1c9b35SJohnny Huang 
274*d90825e2SJohnny Huang void otp_soak(int soak)
275*d90825e2SJohnny Huang {
276*d90825e2SJohnny Huang 	if (soak) {
277*d90825e2SJohnny Huang 		otp_write(0x3000, 0x4021); // Write MRA
278*d90825e2SJohnny Huang 		otp_write(0x5000, 0x1027); // Write MRB
279*d90825e2SJohnny Huang 		otp_write(0x1000, 0x4820); // Write MR
280*d90825e2SJohnny Huang 		writel(0x041930d4, 0x1e602008); //soak program
281*d90825e2SJohnny Huang 	} else {
282*d90825e2SJohnny Huang 		otp_write(0x3000, 0x4061); // Write MRA
283*d90825e2SJohnny Huang 		otp_write(0x5000, 0x302f); // Write MRB
284*d90825e2SJohnny Huang 		otp_write(0x1000, 0x4020); // Write MR
285*d90825e2SJohnny Huang 		writel(0x04190760, 0x1e602008); //normal program
286*d90825e2SJohnny Huang 	}
287*d90825e2SJohnny Huang }
288*d90825e2SJohnny Huang 
289*d90825e2SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t keep, uint32_t prog_address)
290*d90825e2SJohnny Huang {
291*d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
292*d90825e2SJohnny Huang 
293*d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
294*d90825e2SJohnny Huang 		if ((keep >> j) & 0x1)
295*d90825e2SJohnny Huang 			continue;
296*d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
297*d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
298*d90825e2SJohnny Huang 			if (bit_value)
299*d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
300*d90825e2SJohnny Huang 			else
301*d90825e2SJohnny Huang 				continue;
302*d90825e2SJohnny Huang 		} else {
303*d90825e2SJohnny Huang 			prog_address |= 1 << 15;
304*d90825e2SJohnny Huang 			if (bit_value)
305*d90825e2SJohnny Huang 				continue;
306*d90825e2SJohnny Huang 			else
307*d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
308*d90825e2SJohnny Huang 		}
309*d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
310*d90825e2SJohnny Huang 	}
311*d90825e2SJohnny Huang }
312*d90825e2SJohnny Huang 
31369d5fd8fSJohnny Huang static int otp_conf_parse(uint32_t *OTPCFG)
31469d5fd8fSJohnny Huang {
3154c1c9b35SJohnny Huang 	int tmp, i;
3164c1c9b35SJohnny Huang 	int pass = 0;
31769d5fd8fSJohnny Huang 
31869d5fd8fSJohnny Huang 	printf("OTPCFG0-D[0]\n");
319e1f9e54eSJohnny Huang 	if (OTPCFG[0] & DISABLE_SECREG_PROG)
32069d5fd8fSJohnny Huang 		printf("  Disable Secure Region programming\n");
32169d5fd8fSJohnny Huang 	else
32269d5fd8fSJohnny Huang 		printf("  Enable Secure Region programming\n");
32369d5fd8fSJohnny Huang 	printf("OTPCFG0-D[1]\n");
324e1f9e54eSJohnny Huang 	if (OTPCFG[0] & ENABLE_SEC_BOOT)
32569d5fd8fSJohnny Huang 		printf("  Enable Secure Boot\n");
32669d5fd8fSJohnny Huang 	else
32769d5fd8fSJohnny Huang 		printf("  Disable Secure Boot\n");
32869d5fd8fSJohnny Huang 	printf("OTPCFG0-D[3]\n");
329e1f9e54eSJohnny Huang 	if (OTPCFG[0] & ENABLE_USERREG_ECC)
33069d5fd8fSJohnny Huang 		printf("  User region ECC enable\n");
33169d5fd8fSJohnny Huang 	else
33269d5fd8fSJohnny Huang 		printf("  User region ECC disable\n");
33369d5fd8fSJohnny Huang 	printf("OTPCFG0-D[4]\n");
334e1f9e54eSJohnny Huang 	if (OTPCFG[0] & ENABLE_SECREG_ECC)
33569d5fd8fSJohnny Huang 		printf("  Secure Region ECC enable\n");
33669d5fd8fSJohnny Huang 	else
33769d5fd8fSJohnny Huang 		printf("  Secure Region ECC disable\n");
33869d5fd8fSJohnny Huang 	printf("OTPCFG0-D[5]\n");
339e1f9e54eSJohnny Huang 	if (OTPCFG[0] & DISABLE_LOW_SEC_KEY)
34069d5fd8fSJohnny Huang 		printf("  Disable low security key\n");
34169d5fd8fSJohnny Huang 	else
34269d5fd8fSJohnny Huang 		printf("  Enable low security key\n");
34369d5fd8fSJohnny Huang 	printf("OTPCFG0-D[6]\n");
344e1f9e54eSJohnny Huang 	if (OTPCFG[0] & IGNORE_SEC_BOOT_HWSTRAP)
34569d5fd8fSJohnny Huang 		printf("  Ignore Secure Boot hardware strap\n");
34669d5fd8fSJohnny Huang 	else
34769d5fd8fSJohnny Huang 		printf("  Do not ignore Secure Boot hardware strap\n");
34869d5fd8fSJohnny Huang 	printf("OTPCFG0-D[7]\n");
349e1f9e54eSJohnny Huang 	if (SEC_BOOT_MDOES(OTPCFG[0]) == SEC_MODE1)
350e1f9e54eSJohnny Huang 		printf("  Secure Boot Mode: 1\n");
351e1f9e54eSJohnny Huang 	else
352e1f9e54eSJohnny Huang 		printf("  Secure Boot Mode: 2\n");
35369d5fd8fSJohnny Huang 	printf("OTPCFG0-D[9:8]\n");
35469d5fd8fSJohnny Huang 	printf("  OTP bit cell mode : ");
355e1f9e54eSJohnny Huang 	tmp = OTP_BIT_CELL_MODES(OTPCFG[0]);
356e1f9e54eSJohnny Huang 	if (tmp == SINGLE_CELL_MODE) {
35769d5fd8fSJohnny Huang 		printf("Single cell mode (recommended)\n");
358e1f9e54eSJohnny Huang 	} else if (tmp == DIFFERENTIAL_MODE) {
35969d5fd8fSJohnny Huang 		printf("Differnetial mode\n");
360e1f9e54eSJohnny Huang 	} else if (tmp == DIFFERENTIAL_REDUDANT_MODE) {
36169d5fd8fSJohnny Huang 		printf("Differential-redundant mode\n");
36269d5fd8fSJohnny Huang 	} else {
36369d5fd8fSJohnny Huang 		printf("Value error\n");
36469d5fd8fSJohnny Huang 		return -1;
36569d5fd8fSJohnny Huang 	}
36669d5fd8fSJohnny Huang 	printf("OTPCFG0-D[11:10]\n");
36769d5fd8fSJohnny Huang 	printf("  RSA mode : ");
368e1f9e54eSJohnny Huang 	tmp = CRYPTO_MODES(OTPCFG[0]);
369e1f9e54eSJohnny Huang 	if (tmp == CRYPTO_RSA1024) {
37069d5fd8fSJohnny Huang 		printf("RSA1024\n");
371e1f9e54eSJohnny Huang 	} else if (tmp == CRYPTO_RSA2048) {
37269d5fd8fSJohnny Huang 		printf("RSA2048\n");
373e1f9e54eSJohnny Huang 	} else if (tmp == CRYPTO_RSA3072) {
37469d5fd8fSJohnny Huang 		printf("RSA3072\n");
37569d5fd8fSJohnny Huang 	} else {
37669d5fd8fSJohnny Huang 		printf("RSA4096\n");
37769d5fd8fSJohnny Huang 	}
37869d5fd8fSJohnny Huang 	printf("OTPCFG0-D[13:12]\n");
37969d5fd8fSJohnny Huang 	printf("  SHA mode : ");
380e1f9e54eSJohnny Huang 	tmp = HASH_MODES(OTPCFG[0]);
381e1f9e54eSJohnny Huang 	if (tmp == HASH_SAH224) {
38269d5fd8fSJohnny Huang 		printf("SHA224\n");
383e1f9e54eSJohnny Huang 	} else if (tmp == HASH_SAH256) {
38469d5fd8fSJohnny Huang 		printf("SHA256\n");
385e1f9e54eSJohnny Huang 	} else if (tmp == HASH_SAH384) {
38669d5fd8fSJohnny Huang 		printf("SHA384\n");
38769d5fd8fSJohnny Huang 	} else {
38869d5fd8fSJohnny Huang 		printf("SHA512\n");
38969d5fd8fSJohnny Huang 	}
39069d5fd8fSJohnny Huang 
39169d5fd8fSJohnny Huang 	printf("OTPCFG0-D[21:16]\n");
392e1f9e54eSJohnny Huang 	printf("  Secure Region size (DW): %x\n", SECREG_SIZE(OTPCFG[0]));
39369d5fd8fSJohnny Huang 
39469d5fd8fSJohnny Huang 	printf("OTPCFG0-D[22]\n");
395e1f9e54eSJohnny Huang 	if (OTPCFG[0] & WRITE_PROTECT_SECREG)
39669d5fd8fSJohnny Huang 		printf("  Secure Region : Write Protect\n");
39769d5fd8fSJohnny Huang 	else
39869d5fd8fSJohnny Huang 		printf("  Secure Region : Writable\n");
39969d5fd8fSJohnny Huang 	printf("OTPCFG0-D[23]\n");
400e1f9e54eSJohnny Huang 	if (OTPCFG[0] & WRITE_PROTECT_USERREG)
40169d5fd8fSJohnny Huang 		printf("  User Region : Write Protect\n");
40269d5fd8fSJohnny Huang 	else
40369d5fd8fSJohnny Huang 		printf("  User Region : Writable\n");
40469d5fd8fSJohnny Huang 	printf("OTPCFG0-D[24]\n");
405e1f9e54eSJohnny Huang 	if (OTPCFG[0] & WRITE_PROTECT_CONFREG)
40669d5fd8fSJohnny Huang 		printf("  Configure Region : Write Protect\n");
40769d5fd8fSJohnny Huang 	else
40869d5fd8fSJohnny Huang 		printf("  Configure Region : Writable\n");
40969d5fd8fSJohnny Huang 	printf("OTPCFG0-D[25]\n");
410e1f9e54eSJohnny Huang 	if (OTPCFG[0] & WRITE_PROTECT_STRAPREG)
41169d5fd8fSJohnny Huang 		printf("  OTP strap Region : Write Protect\n");
41269d5fd8fSJohnny Huang 	else
41369d5fd8fSJohnny Huang 		printf("  OTP strap Region : Writable\n");
41469d5fd8fSJohnny Huang 	printf("OTPCFG0-D[26]\n");
415e1f9e54eSJohnny Huang 	if (OTPCFG[0] & ENABLE_COPY_TO_SRAM)
41669d5fd8fSJohnny Huang 		printf("  Copy Boot Image to Internal SRAM\n");
41769d5fd8fSJohnny Huang 	else
41869d5fd8fSJohnny Huang 		printf("  Disable Copy Boot Image to Internal SRAM\n");
41969d5fd8fSJohnny Huang 	printf("OTPCFG0-D[27]\n");
420e1f9e54eSJohnny Huang 	if (OTPCFG[0] & ENABLE_IMAGE_ENC)
42169d5fd8fSJohnny Huang 		printf("  Enable image encryption\n");
42269d5fd8fSJohnny Huang 	else
42369d5fd8fSJohnny Huang 		printf("  Disable image encryption\n");
42469d5fd8fSJohnny Huang 	printf("OTPCFG0-D[29]\n");
425e1f9e54eSJohnny Huang 	if (OTPCFG[0] & WRITE_PROTECT_KEY_RETIRE)
42669d5fd8fSJohnny Huang 		printf("  OTP key retire Region : Write Protect\n");
42769d5fd8fSJohnny Huang 	else
42869d5fd8fSJohnny Huang 		printf("  OTP key retire Region : Writable\n");
42969d5fd8fSJohnny Huang 	printf("OTPCFG0-D[30]\n");
430e1f9e54eSJohnny Huang 	if (OTPCFG[0] & ENABLE_SIPROM_RED)
43169d5fd8fSJohnny Huang 		printf("  SIPROM RED_EN redundancy repair enable\n");
43269d5fd8fSJohnny Huang 	else
43369d5fd8fSJohnny Huang 		printf("  SIPROM RED_EN redundancy repair disable\n");
43469d5fd8fSJohnny Huang 	printf("OTPCFG0-D[31]\n");
435e1f9e54eSJohnny Huang 	if (OTPCFG[0] & ENABLE_SIPROM_MLOCK)
43669d5fd8fSJohnny Huang 		printf("  SIPROM Mlock memory lock enable\n");
43769d5fd8fSJohnny Huang 	else
43869d5fd8fSJohnny Huang 		printf("  SIPROM Mlock memory lock disable\n");
43969d5fd8fSJohnny Huang 
44069d5fd8fSJohnny Huang 	printf("OTPCFG2-D[15:0]\n");
441e1f9e54eSJohnny Huang 	printf("  Vender ID : %x\n", VENDER_ID(OTPCFG[2]));
44269d5fd8fSJohnny Huang 
44369d5fd8fSJohnny Huang 	printf("OTPCFG2-D[31:16]\n");
444e1f9e54eSJohnny Huang 	printf("  Key Revision : %x\n", KEY_REVISION(OTPCFG[2]));
44569d5fd8fSJohnny Huang 
44669d5fd8fSJohnny Huang 	printf("OTPCFG3-D[15:0]\n");
447e1f9e54eSJohnny Huang 	printf("  Secure boot header offset : %x\n",
448e1f9e54eSJohnny Huang 	       SEC_BOOT_HEADER_OFFSET(OTPCFG[3]));
44969d5fd8fSJohnny Huang 
45069d5fd8fSJohnny Huang 	printf("OTPCFG4-D[7:0]\n");
451e1f9e54eSJohnny Huang 	tmp = KEYS_VALID_BITS(OTPCFG[4]);
452e1f9e54eSJohnny Huang 	if (tmp != 0) {
45369d5fd8fSJohnny Huang 		for (i = 0; i < 7; i++) {
45469d5fd8fSJohnny Huang 			if (tmp == (1 << i)) {
455e1f9e54eSJohnny Huang 				pass = i + 1;
45669d5fd8fSJohnny Huang 			}
45769d5fd8fSJohnny Huang 		}
458e1f9e54eSJohnny Huang 	} else {
459e1f9e54eSJohnny Huang 		pass = 0;
460e1f9e54eSJohnny Huang 	}
461e1f9e54eSJohnny Huang 	printf("  Keys valid  : %d\n", pass);
46269d5fd8fSJohnny Huang 
46369d5fd8fSJohnny Huang 	printf("OTPCFG4-D[23:16]\n");
464e1f9e54eSJohnny Huang 	tmp = KEYS_RETIRE_BITS(OTPCFG[4]);
465e1f9e54eSJohnny Huang 	if (tmp != 0) {
46669d5fd8fSJohnny Huang 		for (i = 0; i < 7; i++) {
46769d5fd8fSJohnny Huang 			if (tmp == (1 << i)) {
468e1f9e54eSJohnny Huang 				pass = i + 1;
46969d5fd8fSJohnny Huang 			}
47069d5fd8fSJohnny Huang 		}
471e1f9e54eSJohnny Huang 	} else {
472e1f9e54eSJohnny Huang 		pass = 0;
47369d5fd8fSJohnny Huang 	}
47469d5fd8fSJohnny Huang 	printf("  Keys Retire ID : %d\n", pass);
47569d5fd8fSJohnny Huang 
47669d5fd8fSJohnny Huang 	printf("OTPCFG5-D[31:0]\n");
47769d5fd8fSJohnny Huang 	printf("  User define data, random number low : %x\n", OTPCFG[5]);
47869d5fd8fSJohnny Huang 
47969d5fd8fSJohnny Huang 	printf("OTPCFG6-D[31:0]\n");
48069d5fd8fSJohnny Huang 	printf("  User define data, random number high : %x\n", OTPCFG[6]);
48169d5fd8fSJohnny Huang 
48269d5fd8fSJohnny Huang 	printf("OTPCFG8-D[31:0]\n");
48369d5fd8fSJohnny Huang 	printf("  Redundancy Repair : %x\n", OTPCFG[8]);
48469d5fd8fSJohnny Huang 
48569d5fd8fSJohnny Huang 	printf("OTPCFG10-D[31:0]\n");
48669d5fd8fSJohnny Huang 	printf("  Manifest ID low : %x\n", OTPCFG[10]);
48769d5fd8fSJohnny Huang 
48869d5fd8fSJohnny Huang 	printf("OTPCFG11-D[31:0]\n");
48969d5fd8fSJohnny Huang 	printf("  Manifest ID high : %x\n", OTPCFG[11]);
49069d5fd8fSJohnny Huang 	return 0;
49169d5fd8fSJohnny Huang 
49269d5fd8fSJohnny Huang }
49369d5fd8fSJohnny Huang 
49469d5fd8fSJohnny Huang static void buf_print(char *buf, int len)
49569d5fd8fSJohnny Huang {
49669d5fd8fSJohnny Huang 	int i;
49769d5fd8fSJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
49869d5fd8fSJohnny Huang 	for (i = 0; i < len; i++) {
49969d5fd8fSJohnny Huang 		if (i % 16 == 0) {
50069d5fd8fSJohnny Huang 			printf("%04X: ", i);
50169d5fd8fSJohnny Huang 		}
50269d5fd8fSJohnny Huang 		printf("%02X ", buf[i]);
50369d5fd8fSJohnny Huang 		if ((i + 1) % 16 == 0) {
50469d5fd8fSJohnny Huang 			printf("\n");
50569d5fd8fSJohnny Huang 		}
50669d5fd8fSJohnny Huang 	}
50769d5fd8fSJohnny Huang }
50869d5fd8fSJohnny Huang 
509*d90825e2SJohnny Huang static int otp_data_parse(uint32_t *buf)
51069d5fd8fSJohnny Huang {
51169d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
51269d5fd8fSJohnny Huang 	char *byte_buf;
51369d5fd8fSJohnny Huang 	int i = 0, len = 0;
51469d5fd8fSJohnny Huang 	byte_buf = (char *)buf;
51569d5fd8fSJohnny Huang 	while (1) {
51669d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
51769d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
51869d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
51969d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
52069d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
52169d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
52269d5fd8fSJohnny Huang 		printf("Key[%d]:\n", i);
52369d5fd8fSJohnny Huang 		printf("Key Type: ");
52469d5fd8fSJohnny Huang 		switch (key_type) {
52569d5fd8fSJohnny Huang 		case 0:
52669d5fd8fSJohnny Huang 			printf("AES-256 as OEM platform key for image encryption/decryption\n");
52769d5fd8fSJohnny Huang 			break;
52869d5fd8fSJohnny Huang 		case 1:
52969d5fd8fSJohnny Huang 			printf("AES-256 as secret vault key\n");
53069d5fd8fSJohnny Huang 			break;
53169d5fd8fSJohnny Huang 		case 4:
53269d5fd8fSJohnny Huang 			printf("HMAC as encrypted OEM HMAC keys in Mode 1\n");
53369d5fd8fSJohnny Huang 			break;
53469d5fd8fSJohnny Huang 		case 8:
53569d5fd8fSJohnny Huang 			printf("RSA-public as OEM DSS public keys in Mode 2\n");
53669d5fd8fSJohnny Huang 			break;
53769d5fd8fSJohnny Huang 		case 9:
53869d5fd8fSJohnny Huang 			printf("RSA-public as SOC public key\n");
53969d5fd8fSJohnny Huang 			break;
54069d5fd8fSJohnny Huang 		case 10:
54169d5fd8fSJohnny Huang 			printf("RSA-public as AES key decryption key\n");
54269d5fd8fSJohnny Huang 			break;
54369d5fd8fSJohnny Huang 		case 13:
54469d5fd8fSJohnny Huang 			printf("RSA-private as SOC private key\n");
54569d5fd8fSJohnny Huang 			break;
54669d5fd8fSJohnny Huang 		case 14:
54769d5fd8fSJohnny Huang 			printf("RSA-private as AES key decryption key\n");
54869d5fd8fSJohnny Huang 			break;
54969d5fd8fSJohnny Huang 		default:
55069d5fd8fSJohnny Huang 			printf("key_type error: %x\n", key_type);
55169d5fd8fSJohnny Huang 			return -1;
55269d5fd8fSJohnny Huang 		}
55369d5fd8fSJohnny Huang 		if (key_type == 4) {
55469d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
55569d5fd8fSJohnny Huang 			switch (key_length) {
55669d5fd8fSJohnny Huang 			case 0:
55769d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
55869d5fd8fSJohnny Huang 				break;
55969d5fd8fSJohnny Huang 			case 1:
56069d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
56169d5fd8fSJohnny Huang 				break;
56269d5fd8fSJohnny Huang 			case 2:
56369d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
56469d5fd8fSJohnny Huang 				break;
56569d5fd8fSJohnny Huang 			case 3:
56669d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
56769d5fd8fSJohnny Huang 				break;
56869d5fd8fSJohnny Huang 			}
569cd1610b4SJohnny Huang 		} else if (key_type != 0 && key_type != 1) {
57069d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
57169d5fd8fSJohnny Huang 			switch (key_length) {
57269d5fd8fSJohnny Huang 			case 0:
57369d5fd8fSJohnny Huang 				printf("RSA1024\n");
57469d5fd8fSJohnny Huang 				len = 0x100;
57569d5fd8fSJohnny Huang 				break;
57669d5fd8fSJohnny Huang 			case 1:
57769d5fd8fSJohnny Huang 				printf("RSA2048\n");
57869d5fd8fSJohnny Huang 				len = 0x200;
57969d5fd8fSJohnny Huang 				break;
58069d5fd8fSJohnny Huang 			case 2:
58169d5fd8fSJohnny Huang 				printf("RSA3072\n");
58269d5fd8fSJohnny Huang 				len = 0x300;
58369d5fd8fSJohnny Huang 				break;
58469d5fd8fSJohnny Huang 			case 3:
58569d5fd8fSJohnny Huang 				printf("RSA4096\n");
58669d5fd8fSJohnny Huang 				len = 0x400;
58769d5fd8fSJohnny Huang 				break;
58869d5fd8fSJohnny Huang 			}
58969d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
59069d5fd8fSJohnny Huang 		}
59169d5fd8fSJohnny Huang 		if (key_type == 4 || key_type == 8)
59269d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
59369d5fd8fSJohnny Huang 		printf("Key Value:\n");
59469d5fd8fSJohnny Huang 		if (key_type == 4) {
59569d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
59669d5fd8fSJohnny Huang 		} else if (key_type == 0 || key_type == 1) {
59769d5fd8fSJohnny Huang 			printf("AES Key:\n");
59869d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
59969d5fd8fSJohnny Huang 			printf("AES IV:\n");
60069d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + 0x20], 0x10);
60169d5fd8fSJohnny Huang 
60269d5fd8fSJohnny Huang 		} else {
60369d5fd8fSJohnny Huang 			printf("RSA mod:\n");
60469d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
60569d5fd8fSJohnny Huang 			printf("RSA exp:\n");
60669d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
60769d5fd8fSJohnny Huang 		}
60869d5fd8fSJohnny Huang 		if (last)
60969d5fd8fSJohnny Huang 			break;
61069d5fd8fSJohnny Huang 		i++;
61169d5fd8fSJohnny Huang 	}
61269d5fd8fSJohnny Huang 	return 0;
61369d5fd8fSJohnny Huang }
61469d5fd8fSJohnny Huang 
615a6d0d645SJohnny Huang static int otp_prog_conf(uint32_t *buf)
61669d5fd8fSJohnny Huang {
617a6d0d645SJohnny Huang 	int i, k;
618*d90825e2SJohnny Huang 	int pass = 0;
619*d90825e2SJohnny Huang 	int soak = 0;
620a6d0d645SJohnny Huang 	uint32_t prog_address;
621a6d0d645SJohnny Huang 	uint32_t data[12];
622a6d0d645SJohnny Huang 	uint32_t compare[2];
623*d90825e2SJohnny Huang 	uint32_t *buf_keep = &buf[12];
624*d90825e2SJohnny Huang 	uint32_t data_masked;
625*d90825e2SJohnny Huang 	uint32_t buf_masked;
62669d5fd8fSJohnny Huang 
627a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
628a6d0d645SJohnny Huang 
629a6d0d645SJohnny Huang 	printProgress(0, 12, "");
630a6d0d645SJohnny Huang 	for (i = 0; i < 12 ; i ++) {
631a6d0d645SJohnny Huang 		printProgress(i + 1, 12, "");
63269d5fd8fSJohnny Huang 		prog_address = 0x800;
633a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
634a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
635a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
636a6d0d645SJohnny Huang 	}
637a6d0d645SJohnny Huang 
638a6d0d645SJohnny Huang 	printf("Check writable...\n");
639a6d0d645SJohnny Huang 	for (i = 0; i < 12; i++) {
640*d90825e2SJohnny Huang 		data_masked = data[i]  & ~buf_keep[i];
641*d90825e2SJohnny Huang 		buf_masked  = buf[i] & ~buf_keep[i];
642*d90825e2SJohnny Huang 		if (data_masked == buf_masked)
64369d5fd8fSJohnny Huang 			continue;
644*d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
645a6d0d645SJohnny Huang 			continue;
646a6d0d645SJohnny Huang 		} else {
647a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
648a6d0d645SJohnny Huang 			printf("OTPCFG[%d] = %x\n", i, data[i]);
649a6d0d645SJohnny Huang 			printf("Input [%d] = %x\n", i, buf[i]);
650*d90825e2SJohnny Huang 			printf("Mask  [%x] = %x\n", i, ~buf_keep[i]);
651*d90825e2SJohnny Huang 			return -1;
652a6d0d645SJohnny Huang 		}
653a6d0d645SJohnny Huang 	}
654a6d0d645SJohnny Huang 
655a6d0d645SJohnny Huang 	printf("Start Programing...\n");
656a6d0d645SJohnny Huang 	printProgress(0, 12, "");
657*d90825e2SJohnny Huang 	otp_soak(0);
658a6d0d645SJohnny Huang 	for (i = 0; i < 12; i++) {
659*d90825e2SJohnny Huang 		data_masked = data[i]  & ~buf_keep[i];
660*d90825e2SJohnny Huang 		buf_masked  = buf[i] & ~buf_keep[i];
661a6d0d645SJohnny Huang 		prog_address = 0x800;
662a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
663a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
664*d90825e2SJohnny Huang 		if (data_masked == buf_masked) {
665a6d0d645SJohnny Huang 			printProgress(i + 1, 12, "[%03X]=%08X HIT", prog_address, buf[i]);
666a6d0d645SJohnny Huang 			continue;
667a6d0d645SJohnny Huang 		}
668*d90825e2SJohnny Huang 		if (soak) {
669*d90825e2SJohnny Huang 			soak = 0;
670*d90825e2SJohnny Huang 			otp_soak(0);
671*d90825e2SJohnny Huang 		}
672a6d0d645SJohnny Huang 		printProgress(i + 1, 12, "[%03X]=%08X    ", prog_address, buf[i]);
673a6d0d645SJohnny Huang 
674*d90825e2SJohnny Huang 		otp_prog_dw(buf[i], buf_keep[i], prog_address);
675a6d0d645SJohnny Huang 
67669d5fd8fSJohnny Huang 		pass = 0;
67769d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
678*d90825e2SJohnny Huang 			if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 1) != 0) {
679*d90825e2SJohnny Huang 				if (soak == 0) {
680*d90825e2SJohnny Huang 					soak = 1;
681*d90825e2SJohnny Huang 					otp_soak(1);
682*d90825e2SJohnny Huang 				}
683a6d0d645SJohnny Huang 				otp_prog_dw(compare[0], prog_address, 1);
684a6d0d645SJohnny Huang 			} else {
68569d5fd8fSJohnny Huang 				pass = 1;
68669d5fd8fSJohnny Huang 				break;
68769d5fd8fSJohnny Huang 			}
68869d5fd8fSJohnny Huang 		}
689a6d0d645SJohnny Huang 	}
690a6d0d645SJohnny Huang 
69169d5fd8fSJohnny Huang 	if (!pass)
692a6d0d645SJohnny Huang 		return -1;
693a6d0d645SJohnny Huang 
694*d90825e2SJohnny Huang 	return 0;
695*d90825e2SJohnny Huang 
69669d5fd8fSJohnny Huang }
69769d5fd8fSJohnny Huang 
69869d5fd8fSJohnny Huang static void otp_strp_status(struct otpstrap *otpstrap)
69969d5fd8fSJohnny Huang {
70069d5fd8fSJohnny Huang 	uint32_t OTPSTRAP_RAW[2];
70169d5fd8fSJohnny Huang 	int i, j;
70269d5fd8fSJohnny Huang 
70369d5fd8fSJohnny Huang 	for (j = 0; j < 64; j++) {
70469d5fd8fSJohnny Huang 		otpstrap[j].value = 0;
70569d5fd8fSJohnny Huang 		otpstrap[j].remain_times = 7;
70669d5fd8fSJohnny Huang 		otpstrap[j].writeable_option = -1;
70769d5fd8fSJohnny Huang 		otpstrap[j].protected = 0;
70869d5fd8fSJohnny Huang 	}
70969d5fd8fSJohnny Huang 
71069d5fd8fSJohnny Huang 	for (i = 16; i < 30; i += 2) {
71169d5fd8fSJohnny Huang 		int option = (i - 16) / 2;
71269d5fd8fSJohnny Huang 		otp_read_config(i, &OTPSTRAP_RAW[0]);
71369d5fd8fSJohnny Huang 		otp_read_config(i + 1, &OTPSTRAP_RAW[1]);
71469d5fd8fSJohnny Huang 		for (j = 0; j < 32; j++) {
71569d5fd8fSJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
71669d5fd8fSJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
71769d5fd8fSJohnny Huang 				otpstrap[j].writeable_option = option;
71869d5fd8fSJohnny Huang 			}
71969d5fd8fSJohnny Huang 			if (bit_value == 1)
72069d5fd8fSJohnny Huang 				otpstrap[j].remain_times --;
72169d5fd8fSJohnny Huang 			otpstrap[j].value ^= bit_value;
72269d5fd8fSJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
72369d5fd8fSJohnny Huang 		}
72469d5fd8fSJohnny Huang 		for (j = 32; j < 64; j++) {
72569d5fd8fSJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
72669d5fd8fSJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
72769d5fd8fSJohnny Huang 				otpstrap[j].writeable_option = option;
72869d5fd8fSJohnny Huang 			}
72969d5fd8fSJohnny Huang 			if (bit_value == 1)
73069d5fd8fSJohnny Huang 				otpstrap[j].remain_times --;
73169d5fd8fSJohnny Huang 			otpstrap[j].value ^= bit_value;
73269d5fd8fSJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
73369d5fd8fSJohnny Huang 		}
73469d5fd8fSJohnny Huang 	}
73569d5fd8fSJohnny Huang 	otp_read_config(30, &OTPSTRAP_RAW[0]);
73669d5fd8fSJohnny Huang 	otp_read_config(31, &OTPSTRAP_RAW[1]);
73769d5fd8fSJohnny Huang 	for (j = 0; j < 32; j++) {
73869d5fd8fSJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
73969d5fd8fSJohnny Huang 			otpstrap[j].protected = 1;
74069d5fd8fSJohnny Huang 	}
74169d5fd8fSJohnny Huang 	for (j = 32; j < 64; j++) {
74269d5fd8fSJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
74369d5fd8fSJohnny Huang 			otpstrap[j].protected = 1;
74469d5fd8fSJohnny Huang 	}
74569d5fd8fSJohnny Huang }
74669d5fd8fSJohnny Huang 
74769d5fd8fSJohnny Huang static int otp_strap_parse(uint32_t *buf)
74869d5fd8fSJohnny Huang {
74969d5fd8fSJohnny Huang 	int i;
75069d5fd8fSJohnny Huang 	uint32_t *strap_keep = buf + 2;
75169d5fd8fSJohnny Huang 	uint32_t *strap_protect = buf + 4;
75269d5fd8fSJohnny Huang 	int bit, pbit, kbit;
75369d5fd8fSJohnny Huang 	int fail = 0;
75469d5fd8fSJohnny Huang 	struct otpstrap otpstrap[64];
75569d5fd8fSJohnny Huang 
75669d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
75769d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
75869d5fd8fSJohnny Huang 		if (i < 32) {
75969d5fd8fSJohnny Huang 			bit = (buf[0] >> i) & 0x1;
76069d5fd8fSJohnny Huang 			kbit = (strap_keep[0] >> i) & 0x1;
76169d5fd8fSJohnny Huang 			pbit = (strap_protect[0] >> i) & 0x1;
76269d5fd8fSJohnny Huang 		} else {
76369d5fd8fSJohnny Huang 			bit = (buf[1] >> (i - 32)) & 0x1;
76469d5fd8fSJohnny Huang 			kbit = (strap_keep[1] >> (i - 32)) & 0x1;
76569d5fd8fSJohnny Huang 			pbit = (strap_protect[1] >> (i - 32)) & 0x1;
76669d5fd8fSJohnny Huang 		}
76769d5fd8fSJohnny Huang 
76869d5fd8fSJohnny Huang 		if (kbit == 1) {
76969d5fd8fSJohnny Huang 			continue;
77069d5fd8fSJohnny Huang 		} else {
77169d5fd8fSJohnny Huang 			printf("OTPSTRAP[%d]:\n", i);
77269d5fd8fSJohnny Huang 		}
77369d5fd8fSJohnny Huang 		if (bit == otpstrap[i].value) {
77469d5fd8fSJohnny Huang 			printf("    The value is same as before, skip it.\n");
77569d5fd8fSJohnny Huang 			continue;
77669d5fd8fSJohnny Huang 		}
77769d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
77869d5fd8fSJohnny Huang 			printf("    This bit is protected and is not writable\n");
77969d5fd8fSJohnny Huang 			fail = 1;
78069d5fd8fSJohnny Huang 			continue;
78169d5fd8fSJohnny Huang 		}
78269d5fd8fSJohnny Huang 		if (otpstrap[i].remain_times == 0) {
78369d5fd8fSJohnny Huang 			printf("    This bit is no remaining number of times to write.\n");
78469d5fd8fSJohnny Huang 			fail = 1;
78569d5fd8fSJohnny Huang 			continue;
78669d5fd8fSJohnny Huang 		}
78769d5fd8fSJohnny Huang 		if (pbit == 1) {
78869d5fd8fSJohnny Huang 			printf("    This bit will be protected and become non-writable.\n");
78969d5fd8fSJohnny Huang 		}
790cd1610b4SJohnny 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);
79169d5fd8fSJohnny Huang 	}
79269d5fd8fSJohnny Huang 	if (fail == 1)
79369d5fd8fSJohnny Huang 		return -1;
79469d5fd8fSJohnny Huang 	else
79569d5fd8fSJohnny Huang 		return 0;
79669d5fd8fSJohnny Huang }
79769d5fd8fSJohnny Huang 
798cd1610b4SJohnny Huang static void otp_print_strap(int start, int count)
79969d5fd8fSJohnny Huang {
80069d5fd8fSJohnny Huang 	int i, j;
80169d5fd8fSJohnny Huang 	struct otpstrap otpstrap[64];
80269d5fd8fSJohnny Huang 
80369d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
80469d5fd8fSJohnny Huang 
805cd1610b4SJohnny Huang 	for (i = start; i < start + count; i++) {
80669d5fd8fSJohnny Huang 		printf("OTPSTRAP[%d]:\n", i);
80769d5fd8fSJohnny Huang 		printf("  OTP Option value: ");
80869d5fd8fSJohnny Huang 		for (j = 1; j <= 7; j++)
80969d5fd8fSJohnny Huang 			printf("[%d]:%d ", j, otpstrap[i].option_array[j - 1]);
81069d5fd8fSJohnny Huang 		printf("\n");
81169d5fd8fSJohnny Huang 		printf("  OTP Value: %d\n", otpstrap[i].value);
81269d5fd8fSJohnny Huang 		printf("  Status:\n");
81369d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
81469d5fd8fSJohnny Huang 			printf("    OTPSTRAP[%d] is protected and is not writable\n", i);
81569d5fd8fSJohnny Huang 		} else {
81669d5fd8fSJohnny Huang 			printf("    OTPSTRAP[%d] is not protected ", i);
81769d5fd8fSJohnny Huang 			if (otpstrap[i].remain_times == 0) {
81869d5fd8fSJohnny Huang 				printf("and no remaining number of times to write.\n");
81969d5fd8fSJohnny Huang 			} else {
82069d5fd8fSJohnny Huang 				printf("and still can write %d number of times\n", otpstrap[i].remain_times);
82169d5fd8fSJohnny Huang 			}
82269d5fd8fSJohnny Huang 		}
82369d5fd8fSJohnny Huang 	}
82469d5fd8fSJohnny Huang }
82569d5fd8fSJohnny Huang 
82669d5fd8fSJohnny Huang static int otp_prog_strap(uint32_t *buf)
82769d5fd8fSJohnny Huang {
82869d5fd8fSJohnny Huang 	int i, j;
82969d5fd8fSJohnny Huang 	uint32_t *strap_keep = buf + 2;
83069d5fd8fSJohnny Huang 	uint32_t *strap_protect = buf + 4;
83169d5fd8fSJohnny Huang 	uint32_t prog_bit, prog_address;
83269d5fd8fSJohnny Huang 	int bit, pbit, kbit, offset;
83369d5fd8fSJohnny Huang 	int fail = 0;
83469d5fd8fSJohnny Huang 	int pass, soak;
83569d5fd8fSJohnny Huang 	struct otpstrap otpstrap[64];
83669d5fd8fSJohnny Huang 
83769d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
83869d5fd8fSJohnny Huang 
83969d5fd8fSJohnny Huang 	otp_write(0x3000, 0x4061); // Write MRA
84069d5fd8fSJohnny Huang 	otp_write(0x5000, 0x302f); // Write MRB
84169d5fd8fSJohnny Huang 	otp_write(0x1000, 0x4020); // Write MR
84269d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
8434c1c9b35SJohnny Huang 		printProgress(i + 1, 64, "");
84469d5fd8fSJohnny Huang 		prog_address = 0x800;
84569d5fd8fSJohnny Huang 		if (i < 32) {
84669d5fd8fSJohnny Huang 			offset = i;
84769d5fd8fSJohnny Huang 			bit = (buf[0] >> offset) & 0x1;
84869d5fd8fSJohnny Huang 			kbit = (strap_keep[0] >> offset) & 0x1;
84969d5fd8fSJohnny Huang 			pbit = (strap_protect[0] >> offset) & 0x1;
85069d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
85169d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
85269d5fd8fSJohnny Huang 
85369d5fd8fSJohnny Huang 		} else {
85469d5fd8fSJohnny Huang 			offset = (i - 32);
85569d5fd8fSJohnny Huang 			bit = (buf[1] >> offset) & 0x1;
85669d5fd8fSJohnny Huang 			kbit = (strap_keep[1] >> offset) & 0x1;
85769d5fd8fSJohnny Huang 			pbit = (strap_protect[1] >> offset) & 0x1;
85869d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
85969d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
86069d5fd8fSJohnny Huang 		}
86169d5fd8fSJohnny Huang 		prog_bit = ~(0x1 << offset);
86269d5fd8fSJohnny Huang 
86369d5fd8fSJohnny Huang 		if (kbit == 1) {
86469d5fd8fSJohnny Huang 			continue;
86569d5fd8fSJohnny Huang 		}
86669d5fd8fSJohnny Huang 		if (bit == otpstrap[i].value) {
86769d5fd8fSJohnny Huang 			continue;
86869d5fd8fSJohnny Huang 		}
86969d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
87069d5fd8fSJohnny Huang 			fail = 1;
87169d5fd8fSJohnny Huang 			continue;
87269d5fd8fSJohnny Huang 		}
87369d5fd8fSJohnny Huang 		if (otpstrap[i].remain_times == 0) {
87469d5fd8fSJohnny Huang 			fail = 1;
87569d5fd8fSJohnny Huang 			continue;
87669d5fd8fSJohnny Huang 		}
87769d5fd8fSJohnny Huang 		pass = 0;
87869d5fd8fSJohnny Huang 		soak = 0;
8794b65a65dSJohnny Huang 		otp_write(0x3000, 0x4061); // Write MRA
8804b65a65dSJohnny Huang 		otp_write(0x5000, 0x302f); // Write MRB
8814b65a65dSJohnny Huang 		otp_write(0x1000, 0x4020); // Write MR
8824b65a65dSJohnny Huang 		writel(0x04190760, 0x1e602008); //normal program
88369d5fd8fSJohnny Huang 		for (j = 0; j < RETRY; j++) {
88469d5fd8fSJohnny Huang 			if (!soak) {
88569d5fd8fSJohnny Huang 				otp_prog(prog_address, prog_bit);
886a6d0d645SJohnny Huang 				if (verify_bit(prog_address, offset, 1) == 0) {
88769d5fd8fSJohnny Huang 					pass = 1;
88869d5fd8fSJohnny Huang 					break;
88969d5fd8fSJohnny Huang 				}
89069d5fd8fSJohnny Huang 				soak = 1;
8914b65a65dSJohnny Huang 				otp_write(0x3000, 0x4021); // Write MRA
8924b65a65dSJohnny Huang 				otp_write(0x5000, 0x1027); // Write MRB
8934b65a65dSJohnny Huang 				otp_write(0x1000, 0x4820); // Write MR
89469d5fd8fSJohnny Huang 				writel(0x041930d4, 0x1e602008); //soak program
8954b65a65dSJohnny Huang 			}
89669d5fd8fSJohnny Huang 			otp_prog(prog_address, prog_bit);
897a6d0d645SJohnny Huang 			if (verify_bit(prog_address, offset, 1) == 0) {
89869d5fd8fSJohnny Huang 				pass = 1;
89969d5fd8fSJohnny Huang 				break;
90069d5fd8fSJohnny Huang 			}
90169d5fd8fSJohnny Huang 		}
90269d5fd8fSJohnny Huang 		if (!pass)
90369d5fd8fSJohnny Huang 			return -1;
90469d5fd8fSJohnny Huang 
90569d5fd8fSJohnny Huang 		if (pbit == 0)
90669d5fd8fSJohnny Huang 			continue;
90769d5fd8fSJohnny Huang 		prog_address = 0x800;
90869d5fd8fSJohnny Huang 		if (i < 32)
90969d5fd8fSJohnny Huang 			prog_address |= 0x60c;
91069d5fd8fSJohnny Huang 		else
91169d5fd8fSJohnny Huang 			prog_address |= 0x60e;
91269d5fd8fSJohnny Huang 
91369d5fd8fSJohnny Huang 		for (j = 0; j < RETRY; j++) {
91469d5fd8fSJohnny Huang 			if (!soak) {
91569d5fd8fSJohnny Huang 				writel(0x04190760, 0x1e602008); //normal program
91669d5fd8fSJohnny Huang 				otp_prog(prog_address, prog_bit);
917a6d0d645SJohnny Huang 				if (verify_bit(prog_address, offset, 1) == 0) {
91869d5fd8fSJohnny Huang 					pass = 1;
91969d5fd8fSJohnny Huang 					break;
92069d5fd8fSJohnny Huang 				}
92169d5fd8fSJohnny Huang 				soak = 1;
92269d5fd8fSJohnny Huang 			}
92369d5fd8fSJohnny Huang 			writel(0x041930d4, 0x1e602008); //soak program
92469d5fd8fSJohnny Huang 			otp_prog(prog_address, prog_bit);
925a6d0d645SJohnny Huang 			if (verify_bit(prog_address, offset, 1) == 0) {
92669d5fd8fSJohnny Huang 				pass = 1;
92769d5fd8fSJohnny Huang 				break;
92869d5fd8fSJohnny Huang 			}
92969d5fd8fSJohnny Huang 		}
93069d5fd8fSJohnny Huang 		if (!pass)
93169d5fd8fSJohnny Huang 			return -1;
93269d5fd8fSJohnny Huang 
93369d5fd8fSJohnny Huang 	}
93469d5fd8fSJohnny Huang 	if (fail == 1)
93569d5fd8fSJohnny Huang 		return -1;
93669d5fd8fSJohnny Huang 	else
93769d5fd8fSJohnny Huang 		return 0;
93869d5fd8fSJohnny Huang 
93969d5fd8fSJohnny Huang }
94069d5fd8fSJohnny Huang 
941cd1610b4SJohnny Huang static void otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset, int soak)
942cd1610b4SJohnny Huang {
943cd1610b4SJohnny Huang 	int prog_bit;
944cd1610b4SJohnny Huang 
945cd1610b4SJohnny Huang 	if (soak) {
946cd1610b4SJohnny Huang 		otp_write(0x3000, 0x4021); // Write MRA
947cd1610b4SJohnny Huang 		otp_write(0x5000, 0x1027); // Write MRB
948cd1610b4SJohnny Huang 		otp_write(0x1000, 0x4820); // Write MR
949cd1610b4SJohnny Huang 		writel(0x041930d4, 0x1e602008); //soak program
950cd1610b4SJohnny Huang 	} else {
951cd1610b4SJohnny Huang 		otp_write(0x3000, 0x4061); // Write MRA
952cd1610b4SJohnny Huang 		otp_write(0x5000, 0x302f); // Write MRB
953cd1610b4SJohnny Huang 		otp_write(0x1000, 0x4020); // Write MR
954cd1610b4SJohnny Huang 		writel(0x04190760, 0x1e602008); //normal program
955cd1610b4SJohnny Huang 	}
956cd1610b4SJohnny Huang 	if (prog_address % 2 == 0) {
957cd1610b4SJohnny Huang 		if (value)
958cd1610b4SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
959cd1610b4SJohnny Huang 		else
960cd1610b4SJohnny Huang 			return;
961cd1610b4SJohnny Huang 	} else {
962cd1610b4SJohnny Huang 		prog_address |= 1 << 15;
963cd1610b4SJohnny Huang 		if (!value)
964cd1610b4SJohnny Huang 			prog_bit = 0x1 << bit_offset;
965cd1610b4SJohnny Huang 		else
966cd1610b4SJohnny Huang 			return;
967cd1610b4SJohnny Huang 	}
968cd1610b4SJohnny Huang 	otp_prog(prog_address, prog_bit);
969cd1610b4SJohnny Huang }
970cd1610b4SJohnny Huang 
971*d90825e2SJohnny Huang static int otp_prog_data(uint32_t *buf)
9724c1c9b35SJohnny Huang {
9734c1c9b35SJohnny Huang 	int i, k;
9744c1c9b35SJohnny Huang 	int pass;
975*d90825e2SJohnny Huang 	int soak = 0;
9764c1c9b35SJohnny Huang 	uint32_t prog_address;
977*d90825e2SJohnny Huang 	uint32_t data[2048];
9784c1c9b35SJohnny Huang 	uint32_t compare[2];
979*d90825e2SJohnny Huang 	uint32_t *buf_keep = &buf[2048];
9804c1c9b35SJohnny Huang 
981*d90825e2SJohnny Huang 	uint32_t data0_masked;
982*d90825e2SJohnny Huang 	uint32_t data1_masked;
983*d90825e2SJohnny Huang 	uint32_t buf0_masked;
984*d90825e2SJohnny Huang 	uint32_t buf1_masked;
9854c1c9b35SJohnny Huang 
9864c1c9b35SJohnny Huang 	printf("Read OTP Data:\n");
9874c1c9b35SJohnny Huang 
988*d90825e2SJohnny Huang 	printProgress(0, 2048, "");
989*d90825e2SJohnny Huang 	for (i = 0; i < 2048 ; i += 2) {
990*d90825e2SJohnny Huang 		printProgress(i + 2, 2048, "");
991*d90825e2SJohnny Huang 		otp_read_data(i, &data[i]);
9924c1c9b35SJohnny Huang 	}
993*d90825e2SJohnny Huang 
9944c1c9b35SJohnny Huang 
9954c1c9b35SJohnny Huang 	printf("Check writable...\n");
996*d90825e2SJohnny Huang 	for (i = 0; i < 2048; i++) {
997*d90825e2SJohnny Huang 		data0_masked = data[i]  & ~buf_keep[i];
998*d90825e2SJohnny Huang 		buf0_masked  = buf[i] & ~buf_keep[i];
999*d90825e2SJohnny Huang 		if (data0_masked == buf0_masked)
10004c1c9b35SJohnny Huang 			continue;
1001*d90825e2SJohnny Huang 		if (i % 2 == 0) {
1002*d90825e2SJohnny Huang 			if ((data0_masked | buf0_masked) == buf0_masked) {
10034c1c9b35SJohnny Huang 				continue;
10044c1c9b35SJohnny Huang 			} else {
10054c1c9b35SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1006*d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
10074c1c9b35SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1008*d90825e2SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_keep[i]);
10094c1c9b35SJohnny Huang 				return -1;
101069d5fd8fSJohnny Huang 			}
1011*d90825e2SJohnny Huang 		} else {
1012*d90825e2SJohnny Huang 			if ((data0_masked & buf0_masked) == buf0_masked) {
1013*d90825e2SJohnny Huang 				continue;
1014*d90825e2SJohnny Huang 			} else {
1015*d90825e2SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1016*d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1017*d90825e2SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1018*d90825e2SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_keep[i]);
1019*d90825e2SJohnny Huang 				return -1;
1020*d90825e2SJohnny Huang 			}
1021*d90825e2SJohnny Huang 		}
1022*d90825e2SJohnny Huang 	}
102369d5fd8fSJohnny Huang 
1024*d90825e2SJohnny Huang 	printf("Start Programing...\n");
1025*d90825e2SJohnny Huang 	printProgress(0, 2048, "");
1026*d90825e2SJohnny Huang 
1027*d90825e2SJohnny Huang 	for (i = 0; i < 2048; i += 2) {
1028*d90825e2SJohnny Huang 		prog_address = i;
1029*d90825e2SJohnny Huang 		data0_masked = data[i]  & ~buf_keep[i];
1030*d90825e2SJohnny Huang 		buf0_masked  = buf[i] & ~buf_keep[i];
1031*d90825e2SJohnny Huang 		data1_masked = data[i + 1]  & ~buf_keep[i + 1];
1032*d90825e2SJohnny Huang 		buf1_masked  = buf[i + 1] & ~buf_keep[i + 1];
1033*d90825e2SJohnny Huang 		if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked)) {
1034*d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1035*d90825e2SJohnny Huang 			continue;
1036*d90825e2SJohnny Huang 		}
1037*d90825e2SJohnny Huang 		if (soak) {
1038*d90825e2SJohnny Huang 			soak = 0;
1039*d90825e2SJohnny Huang 			otp_soak(0);
1040*d90825e2SJohnny Huang 		}
1041*d90825e2SJohnny Huang 		if (data1_masked == buf1_masked) {
1042*d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X    ;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1043*d90825e2SJohnny Huang 			otp_prog_dw(buf[i], buf_keep[i], prog_address);
1044*d90825e2SJohnny Huang 		} else if (data0_masked == buf0_masked) {
1045*d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X    ", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1046*d90825e2SJohnny Huang 			otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1);
1047*d90825e2SJohnny Huang 		} else {
1048*d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X    ;[%03X]=%08X    ", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1049*d90825e2SJohnny Huang 			otp_prog_dw(buf[i], buf_keep[i], prog_address);
1050*d90825e2SJohnny Huang 			otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1);
1051*d90825e2SJohnny Huang 		}
1052*d90825e2SJohnny Huang 
1053*d90825e2SJohnny Huang 		pass = 0;
1054*d90825e2SJohnny Huang 		for (k = 0; k < RETRY; k++) {
1055*d90825e2SJohnny Huang 			if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 2) != 0) {
1056*d90825e2SJohnny Huang 				if (soak == 0) {
1057*d90825e2SJohnny Huang 					soak = 1;
1058*d90825e2SJohnny Huang 					otp_soak(1);
1059*d90825e2SJohnny Huang 				}
1060*d90825e2SJohnny Huang 				if (compare[0] != 0) {
1061*d90825e2SJohnny Huang 					otp_prog_dw(compare[0], buf_keep[i], prog_address);
1062*d90825e2SJohnny Huang 				}
1063*d90825e2SJohnny Huang 				if (compare[1] != ~0) {
1064*d90825e2SJohnny Huang 					otp_prog_dw(compare[1], buf_keep[i], prog_address + 1);
1065*d90825e2SJohnny Huang 				}
1066*d90825e2SJohnny Huang 			} else {
1067*d90825e2SJohnny Huang 				pass = 1;
1068*d90825e2SJohnny Huang 				break;
1069*d90825e2SJohnny Huang 			}
1070*d90825e2SJohnny Huang 		}
1071*d90825e2SJohnny Huang 
1072*d90825e2SJohnny Huang 		if (!pass)
1073*d90825e2SJohnny Huang 			return -1;
1074*d90825e2SJohnny Huang 	}
1075*d90825e2SJohnny Huang 	return 0;
1076*d90825e2SJohnny Huang 
1077*d90825e2SJohnny Huang }
1078*d90825e2SJohnny Huang 
1079*d90825e2SJohnny Huang static int do_otp_prog(int addr, int byte_size, int nconfirm)
108069d5fd8fSJohnny Huang {
108169d5fd8fSJohnny Huang 	int ret;
1082*d90825e2SJohnny Huang 	int mode;
108369d5fd8fSJohnny Huang 	uint32_t *buf;
1084*d90825e2SJohnny Huang 	uint32_t *data_region = NULL;
1085*d90825e2SJohnny Huang 	uint32_t *conf_region = NULL;
1086*d90825e2SJohnny Huang 	uint32_t *strap_region = NULL;
108769d5fd8fSJohnny Huang 
1088*d90825e2SJohnny Huang 	buf = map_physmem(addr, byte_size, MAP_WRBACK);
108969d5fd8fSJohnny Huang 	if (!buf) {
109069d5fd8fSJohnny Huang 		puts("Failed to map physical memory\n");
109169d5fd8fSJohnny Huang 		return 1;
109269d5fd8fSJohnny Huang 	}
1093*d90825e2SJohnny Huang 
1094*d90825e2SJohnny Huang 	if (((buf[0] >> 29) & 0x7) == 0x7) {
1095*d90825e2SJohnny Huang 		mode = OTP_REGION_ALL;
1096*d90825e2SJohnny Huang 		conf_region = &buf[1];
1097*d90825e2SJohnny Huang 		strap_region = &buf[25];
1098*d90825e2SJohnny Huang 		data_region = &buf[31];
1099*d90825e2SJohnny Huang 	} else {
1100*d90825e2SJohnny Huang 		if (buf[0] & BIT(29)) {
1101*d90825e2SJohnny Huang 			mode = OTP_REGION_DATA;
1102*d90825e2SJohnny Huang 			data_region = &buf[31];
1103*d90825e2SJohnny Huang 		}
1104*d90825e2SJohnny Huang 		if (buf[0] & BIT(30)) {
1105*d90825e2SJohnny Huang 			mode = OTP_REGION_CONF;
1106*d90825e2SJohnny Huang 			strap_region = &buf[25];
1107*d90825e2SJohnny Huang 		}
1108*d90825e2SJohnny Huang 		if (buf[0] & BIT(31)) {
1109*d90825e2SJohnny Huang 			mode = OTP_REGION_STRAP;
1110*d90825e2SJohnny Huang 			conf_region = &buf[1];
1111*d90825e2SJohnny Huang 		}
1112*d90825e2SJohnny Huang 	}
1113*d90825e2SJohnny Huang 
111469d5fd8fSJohnny Huang 	if (!nconfirm) {
1115a6d0d645SJohnny Huang 		if (mode == OTP_REGION_CONF) {
1116*d90825e2SJohnny Huang 			if (otp_conf_parse(conf_region) < 0) {
111769d5fd8fSJohnny Huang 				printf("OTP config error, please check.\n");
111869d5fd8fSJohnny Huang 				return -1;
111969d5fd8fSJohnny Huang 			}
1120a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_DATA) {
1121*d90825e2SJohnny Huang 			if (otp_data_parse(data_region) < 0) {
112269d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
112369d5fd8fSJohnny Huang 				return -1;
112469d5fd8fSJohnny Huang 			}
1125a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_STRAP) {
1126*d90825e2SJohnny Huang 			if (otp_strap_parse(strap_region) < 0) {
112769d5fd8fSJohnny Huang 				printf("OTP strap error, please check.\n");
112869d5fd8fSJohnny Huang 				return -1;
112969d5fd8fSJohnny Huang 			}
1130a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_ALL) {
1131*d90825e2SJohnny Huang 			if (otp_conf_parse(conf_region) < 0) {
113269d5fd8fSJohnny Huang 				printf("OTP config error, please check.\n");
113369d5fd8fSJohnny Huang 				return -1;
113469d5fd8fSJohnny Huang 			}
1135*d90825e2SJohnny Huang 			if (otp_strap_parse(strap_region) < 0) {
113669d5fd8fSJohnny Huang 				printf("OTP strap error, please check.\n");
113769d5fd8fSJohnny Huang 				return -1;
113869d5fd8fSJohnny Huang 			}
1139*d90825e2SJohnny Huang 			if (otp_data_parse(data_region) < 0) {
114069d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
114169d5fd8fSJohnny Huang 				return -1;
114269d5fd8fSJohnny Huang 			}
114369d5fd8fSJohnny Huang 		}
114469d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
114569d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
114669d5fd8fSJohnny Huang 			printf(" Aborting\n");
114769d5fd8fSJohnny Huang 			return 1;
114869d5fd8fSJohnny Huang 		}
114969d5fd8fSJohnny Huang 	}
1150a6d0d645SJohnny Huang 	if (mode == OTP_REGION_CONF) {
1151*d90825e2SJohnny Huang 		return otp_prog_conf(conf_region);
1152a6d0d645SJohnny Huang 	} else if (mode == OTP_REGION_STRAP) {
1153*d90825e2SJohnny Huang 		return otp_prog_strap(strap_region);
1154a6d0d645SJohnny Huang 	} else if (mode == OTP_REGION_DATA) {
1155*d90825e2SJohnny Huang 		return otp_prog_data(data_region);
1156a6d0d645SJohnny Huang 	} else if (mode == OTP_REGION_ALL) {
115769d5fd8fSJohnny Huang 		printf("programing data region ... ");
1158*d90825e2SJohnny Huang 		ret = otp_prog_data(data_region);
115969d5fd8fSJohnny Huang 		if (ret < 0) {
116069d5fd8fSJohnny Huang 			printf("Error\n");
116169d5fd8fSJohnny Huang 			return ret;
116269d5fd8fSJohnny Huang 		} else {
116369d5fd8fSJohnny Huang 			printf("Done\n");
116469d5fd8fSJohnny Huang 		}
116569d5fd8fSJohnny Huang 		printf("programing strap region ... ");
1166*d90825e2SJohnny Huang 		ret = otp_prog_strap(strap_region);
116769d5fd8fSJohnny Huang 		if (ret < 0) {
116869d5fd8fSJohnny Huang 			printf("Error\n");
116969d5fd8fSJohnny Huang 			return ret;
117069d5fd8fSJohnny Huang 		} else {
117169d5fd8fSJohnny Huang 			printf("Done\n");
117269d5fd8fSJohnny Huang 		}
117369d5fd8fSJohnny Huang 		printf("programing configuration region ... ");
1174*d90825e2SJohnny Huang 		ret = otp_prog_conf(conf_region);
117569d5fd8fSJohnny Huang 		if (ret < 0) {
117669d5fd8fSJohnny Huang 			printf("Error\n");
117769d5fd8fSJohnny Huang 			return ret;
117869d5fd8fSJohnny Huang 		}
117969d5fd8fSJohnny Huang 		printf("Done\n");
118069d5fd8fSJohnny Huang 		return ret;
118169d5fd8fSJohnny Huang 	}
118269d5fd8fSJohnny Huang 	return 0;
118369d5fd8fSJohnny Huang }
1184cd1610b4SJohnny Huang 
1185cd1610b4SJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int protect, int nconfirm)
1186cd1610b4SJohnny Huang {
1187cd1610b4SJohnny Huang 	uint32_t ret[2];
1188cd1610b4SJohnny Huang 	uint32_t strap_buf[6];
1189*d90825e2SJohnny Huang 	uint32_t prog_address = 0;
1190cd1610b4SJohnny Huang 	struct otpstrap otpstrap[64];
1191cd1610b4SJohnny Huang 	int otp_bit;
1192cd1610b4SJohnny Huang 	int i;
1193cd1610b4SJohnny Huang 	int pass;
1194cd1610b4SJohnny Huang 
1195cd1610b4SJohnny Huang 	switch (mode) {
1196a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1197cd1610b4SJohnny Huang 		otp_read_config(otp_dw_offset, ret);
1198cd1610b4SJohnny Huang 		prog_address = 0x800;
1199cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1200cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1201cd1610b4SJohnny Huang 		otp_bit = (ret[0] >> bit_offset) & 0x1;
1202cd1610b4SJohnny Huang 		if (otp_bit == value) {
1203cd1610b4SJohnny Huang 			printf("OTPCFG%X[%d] = %d\n", otp_dw_offset, bit_offset, value);
1204cd1610b4SJohnny Huang 			printf("No need to program\n");
1205cd1610b4SJohnny Huang 			return 0;
1206cd1610b4SJohnny Huang 		}
1207cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1208cd1610b4SJohnny Huang 			printf("OTPCFG%X[%d] = 1\n", otp_dw_offset, bit_offset);
1209cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
1210cd1610b4SJohnny Huang 			return -1;
1211cd1610b4SJohnny Huang 		}
1212cd1610b4SJohnny Huang 		printf("Program OTPCFG%X[%d] to 1\n", otp_dw_offset, bit_offset);
1213cd1610b4SJohnny Huang 		break;
1214a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1215cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1216cd1610b4SJohnny Huang 
1217cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1218cd1610b4SJohnny Huang 			otp_read_data(otp_dw_offset, ret);
1219cd1610b4SJohnny Huang 			otp_bit = (ret[0] >> bit_offset) & 0x1;
1220cd1610b4SJohnny Huang 		} else {
1221cd1610b4SJohnny Huang 			otp_read_data(otp_dw_offset - 1, ret);
1222cd1610b4SJohnny Huang 			otp_bit = (ret[1] >> bit_offset) & 0x1;
1223cd1610b4SJohnny Huang 		}
1224cd1610b4SJohnny Huang 		if (otp_bit == value) {
1225cd1610b4SJohnny Huang 			printf("OTPDATA%X[%d] = %d\n", otp_dw_offset, bit_offset, value);
1226cd1610b4SJohnny Huang 			printf("No need to program\n");
1227cd1610b4SJohnny Huang 			return 0;
1228cd1610b4SJohnny Huang 		}
1229cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1230cd1610b4SJohnny Huang 			printf("OTPDATA%X[%d] = 1\n", otp_dw_offset, bit_offset);
1231cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
1232cd1610b4SJohnny Huang 			return -1;
1233cd1610b4SJohnny Huang 		}
1234cd1610b4SJohnny Huang 		printf("Program OTPDATA%X[%d] to 1\n", otp_dw_offset, bit_offset);
1235cd1610b4SJohnny Huang 		break;
1236a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1237cd1610b4SJohnny Huang 		otp_strp_status(otpstrap);
1238cd1610b4SJohnny Huang 		otp_print_strap(bit_offset, 1);
1239cd1610b4SJohnny Huang 		if (bit_offset < 32) {
1240cd1610b4SJohnny Huang 			strap_buf[0] = value << bit_offset;
1241cd1610b4SJohnny Huang 			strap_buf[2] = ~BIT(bit_offset);
1242cd1610b4SJohnny Huang 			strap_buf[3] = ~0;
1243cd1610b4SJohnny Huang 			strap_buf[5] = 0;
1244cd1610b4SJohnny Huang 			if (protect)
1245cd1610b4SJohnny Huang 				strap_buf[4] = BIT(bit_offset);
1246cd1610b4SJohnny Huang 			else
1247cd1610b4SJohnny Huang 				strap_buf[4] = 0;
1248cd1610b4SJohnny Huang 		} else {
1249cd1610b4SJohnny Huang 			strap_buf[1] = value << (bit_offset - 32);
1250cd1610b4SJohnny Huang 			strap_buf[2] = ~0;
1251cd1610b4SJohnny Huang 			strap_buf[3] = ~BIT(bit_offset - 32);
1252cd1610b4SJohnny Huang 			strap_buf[4] = 0;
1253cd1610b4SJohnny Huang 			if (protect)
1254cd1610b4SJohnny Huang 				strap_buf[5] = BIT(bit_offset - 32);
1255cd1610b4SJohnny Huang 			else
1256cd1610b4SJohnny Huang 				strap_buf[5] = 0;
1257cd1610b4SJohnny Huang 		}
1258cd1610b4SJohnny Huang 		if (otp_strap_parse(strap_buf) < 0)
1259cd1610b4SJohnny Huang 			return -1;
1260cd1610b4SJohnny Huang 		break;
1261cd1610b4SJohnny Huang 	}
1262cd1610b4SJohnny Huang 
1263cd1610b4SJohnny Huang 	if (!nconfirm) {
1264cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1265cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1266cd1610b4SJohnny Huang 			printf(" Aborting\n");
1267cd1610b4SJohnny Huang 			return 1;
1268cd1610b4SJohnny Huang 		}
1269cd1610b4SJohnny Huang 	}
1270cd1610b4SJohnny Huang 
1271cd1610b4SJohnny Huang 	switch (mode) {
1272a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1273cd1610b4SJohnny Huang 		return otp_prog_strap(strap_buf);
1274a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1275a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1276cd1610b4SJohnny Huang 		otp_prog_bit(value, prog_address, bit_offset, 0);
1277cd1610b4SJohnny Huang 		pass = -1;
1278cd1610b4SJohnny Huang 		for (i = 0; i < RETRY; i++) {
1279a6d0d645SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
1280cd1610b4SJohnny Huang 				otp_prog_bit(value, prog_address, bit_offset, 1);
1281cd1610b4SJohnny Huang 			} else {
1282cd1610b4SJohnny Huang 				pass = 0;
1283cd1610b4SJohnny Huang 				break;
1284cd1610b4SJohnny Huang 			}
1285cd1610b4SJohnny Huang 		}
1286cd1610b4SJohnny Huang 		return pass;
1287cd1610b4SJohnny Huang 	}
1288cd1610b4SJohnny Huang 
1289cd1610b4SJohnny Huang 	return -1;
1290cd1610b4SJohnny Huang }
1291cd1610b4SJohnny Huang 
129269d5fd8fSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc,
129369d5fd8fSJohnny Huang 		      char *const argv[])
129469d5fd8fSJohnny Huang {
129569d5fd8fSJohnny Huang 	char *cmd;
129669d5fd8fSJohnny Huang 	int mode = 0;
129769d5fd8fSJohnny Huang 	int nconfirm = 0;
1298cd1610b4SJohnny Huang 	uint32_t addr = 0;
1299cd1610b4SJohnny Huang 	uint32_t otp_addr = 0;
1300cd1610b4SJohnny Huang 	int dw_count = 0;
1301*d90825e2SJohnny Huang 	int byte_size = 0;
1302cd1610b4SJohnny Huang 	int bit_offset = 0;
1303cd1610b4SJohnny Huang 	int value = 0;
1304cd1610b4SJohnny Huang 	int protect = 0;
130569d5fd8fSJohnny Huang 
130669d5fd8fSJohnny Huang 
130769d5fd8fSJohnny Huang 
130869d5fd8fSJohnny Huang 	if (argc < 2) {
130969d5fd8fSJohnny Huang usage:
131069d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
131169d5fd8fSJohnny Huang 	}
131269d5fd8fSJohnny Huang 
131369d5fd8fSJohnny Huang 	cmd = argv[1];
131469d5fd8fSJohnny Huang 	if (!strcmp(cmd, "read")) {
131569d5fd8fSJohnny Huang 		if (!strcmp(argv[2], "conf"))
1316a6d0d645SJohnny Huang 			mode = OTP_REGION_CONF;
131769d5fd8fSJohnny Huang 		else if (!strcmp(argv[2], "data"))
1318a6d0d645SJohnny Huang 			mode = OTP_REGION_DATA;
131969d5fd8fSJohnny Huang 		else if (!strcmp(argv[2], "strap"))
1320a6d0d645SJohnny Huang 			mode = OTP_REGION_STRAP;
132169d5fd8fSJohnny Huang 		else
132269d5fd8fSJohnny Huang 			goto usage;
132369d5fd8fSJohnny Huang 
132469d5fd8fSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
132569d5fd8fSJohnny Huang 		otp_addr = simple_strtoul(argv[3], NULL, 16);
132669d5fd8fSJohnny Huang 		dw_count = simple_strtoul(argv[4], NULL, 16);
1327a6d0d645SJohnny Huang 		if (mode == OTP_REGION_CONF) {
132869d5fd8fSJohnny Huang 			otp_print_config(otp_addr, dw_count);
1329a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_DATA) {
133069d5fd8fSJohnny Huang 			otp_print_data(otp_addr, dw_count);
1331a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_STRAP) {
1332cd1610b4SJohnny Huang 			otp_print_strap(0, 64);
133369d5fd8fSJohnny Huang 		}
133469d5fd8fSJohnny Huang 	} else if (!strcmp(cmd, "prog")) {
1335*d90825e2SJohnny Huang 		// if (!strcmp(argv[2], "conf"))
1336*d90825e2SJohnny Huang 		// 	mode = OTP_REGION_CONF;
1337*d90825e2SJohnny Huang 		// else if (!strcmp(argv[2], "strap"))
1338*d90825e2SJohnny Huang 		// 	mode = OTP_REGION_STRAP;
1339*d90825e2SJohnny Huang 		// else if (!strcmp(argv[2], "data"))
1340*d90825e2SJohnny Huang 		// 	mode = OTP_REGION_DATA;
1341*d90825e2SJohnny Huang 		// else if (!strcmp(argv[2], "all"))
1342*d90825e2SJohnny Huang 		// 	mode = OTP_REGION_ALL;
1343*d90825e2SJohnny Huang 		// else
1344*d90825e2SJohnny Huang 		// 	goto usage;
134569d5fd8fSJohnny Huang 
1346*d90825e2SJohnny Huang 		if (!strcmp(argv[2], "f"))
134769d5fd8fSJohnny Huang 			nconfirm = 1;
134869d5fd8fSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
1349*d90825e2SJohnny Huang 		addr = simple_strtoul(argv[2 + nconfirm], NULL, 16);
1350*d90825e2SJohnny Huang 		byte_size = simple_strtoul(argv[3 + nconfirm], NULL, 16);
1351*d90825e2SJohnny Huang 		return do_otp_prog(addr, byte_size, nconfirm);
1352cd1610b4SJohnny Huang 	} else if (!strcmp(cmd, "pb")) {
1353cd1610b4SJohnny Huang 		if (!strcmp(argv[2], "conf"))
1354a6d0d645SJohnny Huang 			mode = OTP_REGION_CONF;
1355cd1610b4SJohnny Huang 		else if (!strcmp(argv[2], "strap"))
1356a6d0d645SJohnny Huang 			mode = OTP_REGION_STRAP;
1357cd1610b4SJohnny Huang 		else if (!strcmp(argv[2], "data"))
1358a6d0d645SJohnny Huang 			mode = OTP_REGION_DATA;
1359cd1610b4SJohnny Huang 		else
1360cd1610b4SJohnny Huang 			goto usage;
1361cd1610b4SJohnny Huang 		if (!strcmp(argv[3], "f"))
1362cd1610b4SJohnny Huang 			nconfirm = 1;
1363cd1610b4SJohnny Huang 
1364a6d0d645SJohnny Huang 		if (mode == OTP_REGION_STRAP) {
1365cd1610b4SJohnny Huang 			bit_offset = simple_strtoul(argv[3 + nconfirm], NULL, 16);
1366cd1610b4SJohnny Huang 			value = simple_strtoul(argv[4 + nconfirm], NULL, 16);
1367cd1610b4SJohnny Huang 			protect = simple_strtoul(argv[5 + nconfirm], NULL, 16);
1368cd1610b4SJohnny Huang 			if (bit_offset >= 64)
1369cd1610b4SJohnny Huang 				return -1;
1370cd1610b4SJohnny Huang 		} else {
1371cd1610b4SJohnny Huang 			otp_addr = simple_strtoul(argv[3 + nconfirm], NULL, 16);
1372cd1610b4SJohnny Huang 			bit_offset = simple_strtoul(argv[4 + nconfirm], NULL, 16);
1373cd1610b4SJohnny Huang 			value = simple_strtoul(argv[5 + nconfirm], NULL, 16);
1374cd1610b4SJohnny Huang 			if (bit_offset >= 32)
1375cd1610b4SJohnny Huang 				return -1;
1376cd1610b4SJohnny Huang 		}
1377cd1610b4SJohnny Huang 		if (value != 0 && value != 1)
1378cd1610b4SJohnny Huang 			return -1;
1379cd1610b4SJohnny Huang 
1380cd1610b4SJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
1381cd1610b4SJohnny Huang 		return do_otp_prog_bit(mode, otp_addr, bit_offset, value, protect, nconfirm);
138269d5fd8fSJohnny Huang 	} else if (!strcmp(cmd, "comp")) {
138369d5fd8fSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
138469d5fd8fSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
138569d5fd8fSJohnny Huang 		otp_addr = simple_strtoul(argv[3], NULL, 16);
138669d5fd8fSJohnny Huang 		if (otp_compare(otp_addr, addr) >= 0) {
138769d5fd8fSJohnny Huang 			printf("Compare pass\n");
138869d5fd8fSJohnny Huang 		} else {
138969d5fd8fSJohnny Huang 			printf("Compare fail\n");
139069d5fd8fSJohnny Huang 		}
139169d5fd8fSJohnny Huang 	} else {
139269d5fd8fSJohnny Huang 		goto usage;
139369d5fd8fSJohnny Huang 	}
139469d5fd8fSJohnny Huang 
139569d5fd8fSJohnny Huang 
139669d5fd8fSJohnny Huang 	return 0;
139769d5fd8fSJohnny Huang }
139869d5fd8fSJohnny Huang 
139969d5fd8fSJohnny Huang 
140069d5fd8fSJohnny Huang U_BOOT_CMD(
140169d5fd8fSJohnny Huang 	otp, 7, 0,  do_ast_otp,
140269d5fd8fSJohnny Huang 	"ASPEED One-Time-Programmable sub-system",
1403cd1610b4SJohnny Huang 	"read conf|strap|data <otp_dw_offset> <dw_count>\n"
1404*d90825e2SJohnny Huang 	"otp prog [f] <addr> <byte_size>\n"
1405cd1610b4SJohnny Huang 	"otp pb conf|data [f] <otp_dw_offset> <bit_offset> <value>\n"
1406cd1610b4SJohnny Huang 	"otp pb strap [f] <bit_offset> <value> <protect>\n"
1407cd1610b4SJohnny Huang 	"otp comp <addr> <otp_dw_offset>\n"
140869d5fd8fSJohnny Huang );
1409