xref: /openbmc/u-boot/cmd/otp.c (revision 7e22f42dbda33495a0c7bc4dab49227c07447baa)
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 
332a856b9aSJohnny Huang #define OTP_USAGE			-1
342a856b9aSJohnny Huang #define OTP_FAILURE			-2
352a856b9aSJohnny Huang #define OTP_SUCCESS			0
362a856b9aSJohnny Huang 
37a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
38a6af4a17SJohnny Huang 
39e1f9e54eSJohnny Huang #define DISABLE_SECREG_PROG		BIT(0)
40e1f9e54eSJohnny Huang #define ENABLE_SEC_BOOT			BIT(1)
41e1f9e54eSJohnny Huang #define INIT_PROG_DONE			BIT(2)
42e1f9e54eSJohnny Huang #define ENABLE_USERREG_ECC		BIT(3)
43e1f9e54eSJohnny Huang #define ENABLE_SECREG_ECC		BIT(4)
44e1f9e54eSJohnny Huang #define DISABLE_LOW_SEC_KEY		BIT(5)
45e1f9e54eSJohnny Huang #define IGNORE_SEC_BOOT_HWSTRAP		BIT(6)
46e1f9e54eSJohnny Huang #define SEC_BOOT_MDOES(x)		(x >> 7)
47e1f9e54eSJohnny Huang #define   SEC_MODE1			0x0
48e1f9e54eSJohnny Huang #define   SEC_MODE2			0x1
49e1f9e54eSJohnny Huang #define OTP_BIT_CELL_MODES(x)		((x >> 8) & 0x3)
50e1f9e54eSJohnny Huang #define   SINGLE_CELL_MODE		0x0
51e1f9e54eSJohnny Huang #define   DIFFERENTIAL_MODE		0x1
52e1f9e54eSJohnny Huang #define   DIFFERENTIAL_REDUDANT_MODE	0x2
53e1f9e54eSJohnny Huang #define CRYPTO_MODES(x)			((x >> 10) & 0x3)
54e1f9e54eSJohnny Huang #define   CRYPTO_RSA1024		0x0
55e1f9e54eSJohnny Huang #define   CRYPTO_RSA2048		0x1
56e1f9e54eSJohnny Huang #define   CRYPTO_RSA3072		0x2
57e1f9e54eSJohnny Huang #define   CRYPTO_RSA4096		0x3
58e1f9e54eSJohnny Huang #define HASH_MODES(x)			((x >> 12) & 0x3)
59e1f9e54eSJohnny Huang #define   HASH_SAH224			0x0
60e1f9e54eSJohnny Huang #define   HASH_SAH256			0x1
61e1f9e54eSJohnny Huang #define   HASH_SAH384			0x2
62e1f9e54eSJohnny Huang #define   HASH_SAH512			0x3
63e1f9e54eSJohnny Huang #define SECREG_SIZE(x)			((x >> 16) & 0x3f)
64e1f9e54eSJohnny Huang #define WRITE_PROTECT_SECREG		BIT(22)
65e1f9e54eSJohnny Huang #define WRITE_PROTECT_USERREG		BIT(23)
66e1f9e54eSJohnny Huang #define WRITE_PROTECT_CONFREG		BIT(24)
67e1f9e54eSJohnny Huang #define WRITE_PROTECT_STRAPREG		BIT(25)
68e1f9e54eSJohnny Huang #define ENABLE_COPY_TO_SRAM		BIT(26)
69e1f9e54eSJohnny Huang #define ENABLE_IMAGE_ENC		BIT(27)
70e1f9e54eSJohnny Huang #define WRITE_PROTECT_KEY_RETIRE	BIT(29)
71e1f9e54eSJohnny Huang #define ENABLE_SIPROM_RED		BIT(30)
72e1f9e54eSJohnny Huang #define ENABLE_SIPROM_MLOCK		BIT(31)
73e1f9e54eSJohnny Huang 
74e1f9e54eSJohnny Huang #define VENDER_ID(x) 			(x & 0xFFFF)
75e1f9e54eSJohnny Huang #define KEY_REVISION(x)			((x >> 16) & 0xFFFF)
76e1f9e54eSJohnny Huang 
77e1f9e54eSJohnny Huang #define SEC_BOOT_HEADER_OFFSET(x)	(x & 0xFFFF)
78e1f9e54eSJohnny Huang 
79e1f9e54eSJohnny Huang #define KEYS_VALID_BITS(x)		(x & 0xff)
80e1f9e54eSJohnny Huang #define KEYS_RETIRE_BITS(x)		((x >> 16) & 0xff)
814c1c9b35SJohnny Huang 
824c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
834c1c9b35SJohnny Huang #define PBWIDTH 60
844c1c9b35SJohnny Huang 
854c1c9b35SJohnny Huang void printProgress(int numerator, int denominator, char *format, ...)
864c1c9b35SJohnny Huang {
874c1c9b35SJohnny Huang 	int val = numerator * 100 / denominator;
884c1c9b35SJohnny Huang 	int lpad = numerator * PBWIDTH / denominator;
894c1c9b35SJohnny Huang 	int rpad = PBWIDTH - lpad;
904c1c9b35SJohnny Huang 	char buffer[256];
914c1c9b35SJohnny Huang 	va_list aptr;
924c1c9b35SJohnny Huang 
934c1c9b35SJohnny Huang 	va_start(aptr, format);
944c1c9b35SJohnny Huang 	vsprintf(buffer, format, aptr);
954c1c9b35SJohnny Huang 	va_end(aptr);
964c1c9b35SJohnny Huang 
974c1c9b35SJohnny Huang 	printf("\r%3d%% [%.*s%*s] %s", val, lpad, PBSTR, rpad, "", buffer);
984c1c9b35SJohnny Huang 	if (numerator == denominator)
994c1c9b35SJohnny Huang 		printf("\n");
1004c1c9b35SJohnny Huang }
1014c1c9b35SJohnny Huang 
10269d5fd8fSJohnny Huang struct otpstrap {
10369d5fd8fSJohnny Huang 	int value;
10469d5fd8fSJohnny Huang 	int option_array[7];
10569d5fd8fSJohnny Huang 	int remain_times;
10669d5fd8fSJohnny Huang 	int writeable_option;
10769d5fd8fSJohnny Huang 	int protected;
10869d5fd8fSJohnny Huang };
10969d5fd8fSJohnny Huang 
1102a856b9aSJohnny Huang static void otp_read_data(uint32_t offset, uint32_t *data)
11169d5fd8fSJohnny Huang {
11269d5fd8fSJohnny Huang 	writel(offset, 0x1e6f2010); //Read address
11369d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
11469d5fd8fSJohnny Huang 	udelay(2);
11569d5fd8fSJohnny Huang 	data[0] = readl(0x1e6f2020);
11669d5fd8fSJohnny Huang 	data[1] = readl(0x1e6f2024);
11769d5fd8fSJohnny Huang }
11869d5fd8fSJohnny Huang 
1192a856b9aSJohnny Huang static void otp_read_config(uint32_t offset, uint32_t *data)
12069d5fd8fSJohnny Huang {
12169d5fd8fSJohnny Huang 	int config_offset;
12269d5fd8fSJohnny Huang 
12369d5fd8fSJohnny Huang 	config_offset = 0x800;
12469d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
12569d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
12669d5fd8fSJohnny Huang 
12769d5fd8fSJohnny Huang 	writel(config_offset, 0x1e6f2010);  //Read address
12869d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
12969d5fd8fSJohnny Huang 	udelay(2);
13069d5fd8fSJohnny Huang 	data[0] = readl(0x1e6f2020);
13169d5fd8fSJohnny Huang }
13269d5fd8fSJohnny Huang 
13369d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count)
13469d5fd8fSJohnny Huang {
13569d5fd8fSJohnny Huang 	int i;
13669d5fd8fSJohnny Huang 	uint32_t ret[1];
13769d5fd8fSJohnny Huang 
13869d5fd8fSJohnny Huang 	if (offset + dw_count > 32)
1392a856b9aSJohnny Huang 		return OTP_USAGE;
14069d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i ++) {
14169d5fd8fSJohnny Huang 		otp_read_config(i, ret);
142a6af4a17SJohnny Huang 		printf("OTPCFG%X: %08X\n", i, ret[0]);
14369d5fd8fSJohnny Huang 	}
14469d5fd8fSJohnny Huang 	printf("\n");
1452a856b9aSJohnny Huang 	return OTP_SUCCESS;
14669d5fd8fSJohnny Huang }
14769d5fd8fSJohnny Huang 
14869d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count)
14969d5fd8fSJohnny Huang {
15069d5fd8fSJohnny Huang 	int i;
15169d5fd8fSJohnny Huang 	uint32_t ret[2];
15269d5fd8fSJohnny Huang 
15369d5fd8fSJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
1542a856b9aSJohnny Huang 		return OTP_USAGE;
15569d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
15669d5fd8fSJohnny Huang 		otp_read_data(i, ret);
15769d5fd8fSJohnny Huang 		if (i % 4 == 0)
15869d5fd8fSJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
15969d5fd8fSJohnny Huang 		else
16069d5fd8fSJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
16169d5fd8fSJohnny Huang 
16269d5fd8fSJohnny Huang 	}
16369d5fd8fSJohnny Huang 	printf("\n");
1642a856b9aSJohnny Huang 	return OTP_SUCCESS;
16569d5fd8fSJohnny Huang }
16669d5fd8fSJohnny Huang 
16769d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr)
16869d5fd8fSJohnny Huang {
16969d5fd8fSJohnny Huang 	uint32_t ret;
17069d5fd8fSJohnny Huang 	uint32_t *buf;
17169d5fd8fSJohnny Huang 
17269d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
17369d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
17469d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
17569d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
17669d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
17769d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //Compare address
17869d5fd8fSJohnny Huang 	writel(buf[0], 0x1e6f2020); //Compare data 1
17969d5fd8fSJohnny Huang 	writel(buf[1], 0x1e6f2024); //Compare data 2
18069d5fd8fSJohnny Huang 	writel(buf[2], 0x1e6f2028); //Compare data 3
18169d5fd8fSJohnny Huang 	writel(buf[3], 0x1e6f202c); //Compare data 4
18269d5fd8fSJohnny Huang 	writel(0x23b1e363, 0x1e6f2004); //Compare command
18369d5fd8fSJohnny Huang 	udelay(10);
18469d5fd8fSJohnny Huang 	ret = readl(0x1e6f2014); //Compare command
18569d5fd8fSJohnny Huang 	if (ret & 0x1)
18669d5fd8fSJohnny Huang 		return 0;
18769d5fd8fSJohnny Huang 	else
18869d5fd8fSJohnny Huang 		return -1;
18969d5fd8fSJohnny Huang }
19069d5fd8fSJohnny Huang 
19169d5fd8fSJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data)
19269d5fd8fSJohnny Huang {
19369d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //write address
19469d5fd8fSJohnny Huang 	writel(data, 0x1e6f2020); //write data
19569d5fd8fSJohnny Huang 	writel(0x23b1e362, 0x1e6f2004); //write command
19669d5fd8fSJohnny Huang 	udelay(100);
19769d5fd8fSJohnny Huang }
19869d5fd8fSJohnny Huang 
19969d5fd8fSJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit)
20069d5fd8fSJohnny Huang {
20169d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //write address
20269d5fd8fSJohnny Huang 	writel(prog_bit, 0x1e6f2020); //write data
20369d5fd8fSJohnny Huang 	writel(0x23b1e364, 0x1e6f2004); //write command
20469d5fd8fSJohnny Huang 	udelay(85);
20569d5fd8fSJohnny Huang }
20669d5fd8fSJohnny Huang 
207a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value)
20869d5fd8fSJohnny Huang {
20969d5fd8fSJohnny Huang 	int ret;
21069d5fd8fSJohnny Huang 
21169d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //Read address
21269d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
21369d5fd8fSJohnny Huang 	udelay(2);
21469d5fd8fSJohnny Huang 	ret = readl(0x1e6f2020);
215a6d0d645SJohnny Huang 	// printf("verify_bit = %x\n", ret);
21669d5fd8fSJohnny Huang 	if (((ret >> bit_offset) & 1) == value)
21769d5fd8fSJohnny Huang 		return 0;
21869d5fd8fSJohnny Huang 	else
21969d5fd8fSJohnny Huang 		return -1;
22069d5fd8fSJohnny Huang }
22169d5fd8fSJohnny Huang 
222d90825e2SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *keep, uint32_t *compare, int size)
2234c1c9b35SJohnny Huang {
2244c1c9b35SJohnny Huang 	uint32_t ret[2];
2254c1c9b35SJohnny Huang 
2264c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
2274c1c9b35SJohnny Huang 
2284c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
2294c1c9b35SJohnny Huang 		writel(otp_addr, 0x1e6f2010); //Read address
2304c1c9b35SJohnny Huang 	else
2314c1c9b35SJohnny Huang 		writel(otp_addr - 1, 0x1e6f2010); //Read address
2324c1c9b35SJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
2334c1c9b35SJohnny Huang 	udelay(2);
2344c1c9b35SJohnny Huang 	ret[0] = readl(0x1e6f2020);
2354c1c9b35SJohnny Huang 	ret[1] = readl(0x1e6f2024);
2364c1c9b35SJohnny Huang 	if (size == 1) {
2374c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
2384c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
239d90825e2SJohnny Huang 			if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0])) {
2404c1c9b35SJohnny Huang 				compare[0] = 0;
2414c1c9b35SJohnny Huang 				return 0;
2424c1c9b35SJohnny Huang 			} else {
2434c1c9b35SJohnny Huang 				compare[0] = value[0] ^ ret[0];
2444c1c9b35SJohnny Huang 				return -1;
2454c1c9b35SJohnny Huang 			}
2464c1c9b35SJohnny Huang 
2474c1c9b35SJohnny Huang 		} else {
2484c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
249d90825e2SJohnny Huang 			if ((value[0] & ~keep[0]) == (ret[1] & ~keep[0])) {
2504c1c9b35SJohnny Huang 				compare[0] = ~0;
2514c1c9b35SJohnny Huang 				return 0;
2524c1c9b35SJohnny Huang 			} else {
253d90825e2SJohnny Huang 				compare[0] = ~(value[0] ^ ret[1]);
2544c1c9b35SJohnny Huang 				return -1;
2554c1c9b35SJohnny Huang 			}
2564c1c9b35SJohnny Huang 		}
2574c1c9b35SJohnny Huang 	} else if (size == 2) {
2584c1c9b35SJohnny Huang 		// otp_addr should be even
259d90825e2SJohnny Huang 		if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0]) && (value[1] & ~keep[1]) == (ret[1] & ~keep[1])) {
2604c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
2614c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
2624c1c9b35SJohnny Huang 			compare[0] = 0;
2634c1c9b35SJohnny Huang 			compare[1] = ~0;
2644c1c9b35SJohnny Huang 			return 0;
2654c1c9b35SJohnny Huang 		} else {
2664c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
2674c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
2684c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
2694c1c9b35SJohnny Huang 			compare[1] = ~(value[1] ^ ret[1]);
2704c1c9b35SJohnny Huang 			return -1;
2714c1c9b35SJohnny Huang 		}
2724c1c9b35SJohnny Huang 	} else {
2734c1c9b35SJohnny Huang 		return -1;
2744c1c9b35SJohnny Huang 	}
2754c1c9b35SJohnny Huang }
2764c1c9b35SJohnny Huang 
277*7e22f42dSJohnny Huang static void otp_soak(int soak)
278d90825e2SJohnny Huang {
279d90825e2SJohnny Huang 	if (soak) {
280d90825e2SJohnny Huang 		otp_write(0x3000, 0x4021); // Write MRA
281d90825e2SJohnny Huang 		otp_write(0x5000, 0x1027); // Write MRB
282d90825e2SJohnny Huang 		otp_write(0x1000, 0x4820); // Write MR
283d90825e2SJohnny Huang 		writel(0x041930d4, 0x1e602008); //soak program
284d90825e2SJohnny Huang 	} else {
285d90825e2SJohnny Huang 		otp_write(0x3000, 0x4061); // Write MRA
286d90825e2SJohnny Huang 		otp_write(0x5000, 0x302f); // Write MRB
287d90825e2SJohnny Huang 		otp_write(0x1000, 0x4020); // Write MR
288d90825e2SJohnny Huang 		writel(0x04190760, 0x1e602008); //normal program
289d90825e2SJohnny Huang 	}
290d90825e2SJohnny Huang }
291d90825e2SJohnny Huang 
292d90825e2SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t keep, uint32_t prog_address)
293d90825e2SJohnny Huang {
294d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
295d90825e2SJohnny Huang 
296d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
297d90825e2SJohnny Huang 		if ((keep >> j) & 0x1)
298d90825e2SJohnny Huang 			continue;
299d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
300d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
301d90825e2SJohnny Huang 			if (bit_value)
302d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
303d90825e2SJohnny Huang 			else
304d90825e2SJohnny Huang 				continue;
305d90825e2SJohnny Huang 		} else {
306d90825e2SJohnny Huang 			prog_address |= 1 << 15;
307d90825e2SJohnny Huang 			if (bit_value)
308d90825e2SJohnny Huang 				continue;
309d90825e2SJohnny Huang 			else
310d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
311d90825e2SJohnny Huang 		}
312d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
313d90825e2SJohnny Huang 	}
314d90825e2SJohnny Huang }
315d90825e2SJohnny Huang 
31669d5fd8fSJohnny Huang static int otp_conf_parse(uint32_t *OTPCFG)
31769d5fd8fSJohnny Huang {
3184c1c9b35SJohnny Huang 	int tmp, i;
3194c1c9b35SJohnny Huang 	int pass = 0;
320442839bbSJohnny Huang 	uint32_t *OTPCFG_KEEP = &OTPCFG[12];
32169d5fd8fSJohnny Huang 
322442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & DISABLE_SECREG_PROG) {
323442839bbSJohnny Huang 		printf("OTPCFG0-D[0]\n");
324442839bbSJohnny Huang 		printf("  Skip\n");
325442839bbSJohnny Huang 	} else {
32669d5fd8fSJohnny Huang 		printf("OTPCFG0-D[0]\n");
327e1f9e54eSJohnny Huang 		if (OTPCFG[0] & DISABLE_SECREG_PROG)
32869d5fd8fSJohnny Huang 			printf("  Disable Secure Region programming\n");
32969d5fd8fSJohnny Huang 		else
33069d5fd8fSJohnny Huang 			printf("  Enable Secure Region programming\n");
331442839bbSJohnny Huang 	}
332442839bbSJohnny Huang 
333442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_SEC_BOOT) {
334442839bbSJohnny Huang 		printf("OTPCFG0-D[1]\n");
335442839bbSJohnny Huang 		printf("  Skip\n");
336442839bbSJohnny Huang 	} else {
337442839bbSJohnny Huang 
33869d5fd8fSJohnny Huang 		printf("OTPCFG0-D[1]\n");
339e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_SEC_BOOT)
34069d5fd8fSJohnny Huang 			printf("  Enable Secure Boot\n");
34169d5fd8fSJohnny Huang 		else
34269d5fd8fSJohnny Huang 			printf("  Disable Secure Boot\n");
343442839bbSJohnny Huang 	}
344442839bbSJohnny Huang 
345442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_USERREG_ECC) {
346442839bbSJohnny Huang 		printf("OTPCFG0-D[3]\n");
347442839bbSJohnny Huang 		printf("  Skip\n");
348442839bbSJohnny Huang 	} else {
34969d5fd8fSJohnny Huang 		printf("OTPCFG0-D[3]\n");
350e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_USERREG_ECC)
35169d5fd8fSJohnny Huang 			printf("  User region ECC enable\n");
35269d5fd8fSJohnny Huang 		else
35369d5fd8fSJohnny Huang 			printf("  User region ECC disable\n");
354442839bbSJohnny Huang 	}
355442839bbSJohnny Huang 
356442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_SECREG_ECC) {
357442839bbSJohnny Huang 		printf("OTPCFG0-D[4]\n");
358442839bbSJohnny Huang 		printf("  Skip\n");
359442839bbSJohnny Huang 	} else {
36069d5fd8fSJohnny Huang 		printf("OTPCFG0-D[4]\n");
361e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_SECREG_ECC)
36269d5fd8fSJohnny Huang 			printf("  Secure Region ECC enable\n");
36369d5fd8fSJohnny Huang 		else
36469d5fd8fSJohnny Huang 			printf("  Secure Region ECC disable\n");
365442839bbSJohnny Huang 	}
366442839bbSJohnny Huang 
367442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & DISABLE_LOW_SEC_KEY) {
368442839bbSJohnny Huang 		printf("OTPCFG0-D[5]\n");
369442839bbSJohnny Huang 		printf("  Skip\n");
370442839bbSJohnny Huang 	} else {
37169d5fd8fSJohnny Huang 		printf("OTPCFG0-D[5]\n");
372e1f9e54eSJohnny Huang 		if (OTPCFG[0] & DISABLE_LOW_SEC_KEY)
37369d5fd8fSJohnny Huang 			printf("  Disable low security key\n");
37469d5fd8fSJohnny Huang 		else
37569d5fd8fSJohnny Huang 			printf("  Enable low security key\n");
376442839bbSJohnny Huang 	}
377442839bbSJohnny Huang 
378442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & IGNORE_SEC_BOOT_HWSTRAP) {
379442839bbSJohnny Huang 		printf("OTPCFG0-D[6]\n");
380442839bbSJohnny Huang 		printf("  Skip\n");
381442839bbSJohnny Huang 	} else {
38269d5fd8fSJohnny Huang 		printf("OTPCFG0-D[6]\n");
383e1f9e54eSJohnny Huang 		if (OTPCFG[0] & IGNORE_SEC_BOOT_HWSTRAP)
38469d5fd8fSJohnny Huang 			printf("  Ignore Secure Boot hardware strap\n");
38569d5fd8fSJohnny Huang 		else
38669d5fd8fSJohnny Huang 			printf("  Do not ignore Secure Boot hardware strap\n");
387442839bbSJohnny Huang 	}
388442839bbSJohnny Huang 
389442839bbSJohnny Huang 	if (SEC_BOOT_MDOES(OTPCFG_KEEP[0]) == 0x1) {
390442839bbSJohnny Huang 		printf("OTPCFG0-D[7]\n");
391442839bbSJohnny Huang 		printf("  Skip\n");
392442839bbSJohnny Huang 	} else {
39369d5fd8fSJohnny Huang 		printf("OTPCFG0-D[7]\n");
394e1f9e54eSJohnny Huang 		if (SEC_BOOT_MDOES(OTPCFG[0]) == SEC_MODE1)
395e1f9e54eSJohnny Huang 			printf("  Secure Boot Mode: 1\n");
396e1f9e54eSJohnny Huang 		else
397e1f9e54eSJohnny Huang 			printf("  Secure Boot Mode: 2\n");
398442839bbSJohnny Huang 	}
399442839bbSJohnny Huang 
400442839bbSJohnny Huang 	if (OTP_BIT_CELL_MODES(OTPCFG_KEEP[0]) == 0x3) {
401442839bbSJohnny Huang 		printf("OTPCFG0-D[9:8]\n");
402442839bbSJohnny Huang 		printf("  Skip\n");
403442839bbSJohnny Huang 	} else {
40469d5fd8fSJohnny Huang 		printf("OTPCFG0-D[9:8]\n");
40569d5fd8fSJohnny Huang 		printf("  OTP bit cell mode : ");
406e1f9e54eSJohnny Huang 		tmp = OTP_BIT_CELL_MODES(OTPCFG[0]);
407e1f9e54eSJohnny Huang 		if (tmp == SINGLE_CELL_MODE) {
40869d5fd8fSJohnny Huang 			printf("Single cell mode (recommended)\n");
409e1f9e54eSJohnny Huang 		} else if (tmp == DIFFERENTIAL_MODE) {
41069d5fd8fSJohnny Huang 			printf("Differnetial mode\n");
411e1f9e54eSJohnny Huang 		} else if (tmp == DIFFERENTIAL_REDUDANT_MODE) {
41269d5fd8fSJohnny Huang 			printf("Differential-redundant mode\n");
41369d5fd8fSJohnny Huang 		} else {
41469d5fd8fSJohnny Huang 			printf("Value error\n");
41569d5fd8fSJohnny Huang 			return -1;
41669d5fd8fSJohnny Huang 		}
417442839bbSJohnny Huang 	}
418442839bbSJohnny Huang 	if (CRYPTO_MODES(OTPCFG_KEEP[0]) == 0x3) {
419442839bbSJohnny Huang 		printf("OTPCFG0-D[11:10]\n");
420442839bbSJohnny Huang 		printf("  Skip\n");
421442839bbSJohnny Huang 	} else {
42269d5fd8fSJohnny Huang 		printf("OTPCFG0-D[11:10]\n");
42369d5fd8fSJohnny Huang 		printf("  RSA mode : ");
424e1f9e54eSJohnny Huang 		tmp = CRYPTO_MODES(OTPCFG[0]);
425e1f9e54eSJohnny Huang 		if (tmp == CRYPTO_RSA1024) {
42669d5fd8fSJohnny Huang 			printf("RSA1024\n");
427e1f9e54eSJohnny Huang 		} else if (tmp == CRYPTO_RSA2048) {
42869d5fd8fSJohnny Huang 			printf("RSA2048\n");
429e1f9e54eSJohnny Huang 		} else if (tmp == CRYPTO_RSA3072) {
43069d5fd8fSJohnny Huang 			printf("RSA3072\n");
43169d5fd8fSJohnny Huang 		} else {
43269d5fd8fSJohnny Huang 			printf("RSA4096\n");
43369d5fd8fSJohnny Huang 		}
434442839bbSJohnny Huang 	}
435442839bbSJohnny Huang 	if (HASH_MODES(OTPCFG_KEEP[0]) == 0x3) {
436442839bbSJohnny Huang 		printf("OTPCFG0-D[13:12]\n");
437442839bbSJohnny Huang 		printf("  Skip\n");
438442839bbSJohnny Huang 	} else {
43969d5fd8fSJohnny Huang 		printf("OTPCFG0-D[13:12]\n");
44069d5fd8fSJohnny Huang 		printf("  SHA mode : ");
441e1f9e54eSJohnny Huang 		tmp = HASH_MODES(OTPCFG[0]);
442e1f9e54eSJohnny Huang 		if (tmp == HASH_SAH224) {
44369d5fd8fSJohnny Huang 			printf("SHA224\n");
444e1f9e54eSJohnny Huang 		} else if (tmp == HASH_SAH256) {
44569d5fd8fSJohnny Huang 			printf("SHA256\n");
446e1f9e54eSJohnny Huang 		} else if (tmp == HASH_SAH384) {
44769d5fd8fSJohnny Huang 			printf("SHA384\n");
44869d5fd8fSJohnny Huang 		} else {
44969d5fd8fSJohnny Huang 			printf("SHA512\n");
45069d5fd8fSJohnny Huang 		}
451442839bbSJohnny Huang 	}
45269d5fd8fSJohnny Huang 
453442839bbSJohnny Huang 	if (SECREG_SIZE(OTPCFG_KEEP[0]) == 0x3f) {
454442839bbSJohnny Huang 		printf("OTPCFG0-D[21:16]\n");
455442839bbSJohnny Huang 		printf("  Skip\n");
456442839bbSJohnny Huang 	} else {
45769d5fd8fSJohnny Huang 		printf("OTPCFG0-D[21:16]\n");
458e1f9e54eSJohnny Huang 		printf("  Secure Region size (DW): %x\n", SECREG_SIZE(OTPCFG[0]));
459442839bbSJohnny Huang 	}
46069d5fd8fSJohnny Huang 
461442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & WRITE_PROTECT_SECREG) {
462442839bbSJohnny Huang 		printf("OTPCFG0-D[22]\n");
463442839bbSJohnny Huang 		printf("  Skip\n");
464442839bbSJohnny Huang 	} else {
46569d5fd8fSJohnny Huang 		printf("OTPCFG0-D[22]\n");
466e1f9e54eSJohnny Huang 		if (OTPCFG[0] & WRITE_PROTECT_SECREG)
46769d5fd8fSJohnny Huang 			printf("  Secure Region : Write Protect\n");
46869d5fd8fSJohnny Huang 		else
46969d5fd8fSJohnny Huang 			printf("  Secure Region : Writable\n");
470442839bbSJohnny Huang 	}
471442839bbSJohnny Huang 
472442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & WRITE_PROTECT_USERREG) {
473442839bbSJohnny Huang 		printf("OTPCFG0-D[23]\n");
474442839bbSJohnny Huang 		printf("  Skip\n");
475442839bbSJohnny Huang 	} else {
47669d5fd8fSJohnny Huang 		printf("OTPCFG0-D[23]\n");
477e1f9e54eSJohnny Huang 		if (OTPCFG[0] & WRITE_PROTECT_USERREG)
47869d5fd8fSJohnny Huang 			printf("  User Region : Write Protect\n");
47969d5fd8fSJohnny Huang 		else
48069d5fd8fSJohnny Huang 			printf("  User Region : Writable\n");
481442839bbSJohnny Huang 	}
482442839bbSJohnny Huang 
483442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & WRITE_PROTECT_CONFREG) {
484442839bbSJohnny Huang 		printf("OTPCFG0-D[24]\n");
485442839bbSJohnny Huang 		printf("  Skip\n");
486442839bbSJohnny Huang 	} else {
48769d5fd8fSJohnny Huang 		printf("OTPCFG0-D[24]\n");
488e1f9e54eSJohnny Huang 		if (OTPCFG[0] & WRITE_PROTECT_CONFREG)
48969d5fd8fSJohnny Huang 			printf("  Configure Region : Write Protect\n");
49069d5fd8fSJohnny Huang 		else
49169d5fd8fSJohnny Huang 			printf("  Configure Region : Writable\n");
492442839bbSJohnny Huang 	}
493442839bbSJohnny Huang 
494442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & WRITE_PROTECT_STRAPREG) {
495442839bbSJohnny Huang 		printf("OTPCFG0-D[25]\n");
496442839bbSJohnny Huang 		printf("  Skip\n");
497442839bbSJohnny Huang 	} else {
49869d5fd8fSJohnny Huang 		printf("OTPCFG0-D[25]\n");
499e1f9e54eSJohnny Huang 		if (OTPCFG[0] & WRITE_PROTECT_STRAPREG)
50069d5fd8fSJohnny Huang 			printf("  OTP strap Region : Write Protect\n");
50169d5fd8fSJohnny Huang 		else
50269d5fd8fSJohnny Huang 			printf("  OTP strap Region : Writable\n");
503442839bbSJohnny Huang 	}
504442839bbSJohnny Huang 
505442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_COPY_TO_SRAM) {
506442839bbSJohnny Huang 		printf("OTPCFG0-D[25]\n");
507442839bbSJohnny Huang 		printf("  Skip\n");
508442839bbSJohnny Huang 	} else {
50969d5fd8fSJohnny Huang 		printf("OTPCFG0-D[26]\n");
510e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_COPY_TO_SRAM)
51169d5fd8fSJohnny Huang 			printf("  Copy Boot Image to Internal SRAM\n");
51269d5fd8fSJohnny Huang 		else
51369d5fd8fSJohnny Huang 			printf("  Disable Copy Boot Image to Internal SRAM\n");
514442839bbSJohnny Huang 	}
515442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_IMAGE_ENC) {
516442839bbSJohnny Huang 		printf("OTPCFG0-D[27]\n");
517442839bbSJohnny Huang 		printf("  Skip\n");
518442839bbSJohnny Huang 	} else {
51969d5fd8fSJohnny Huang 		printf("OTPCFG0-D[27]\n");
520e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_IMAGE_ENC)
52169d5fd8fSJohnny Huang 			printf("  Enable image encryption\n");
52269d5fd8fSJohnny Huang 		else
52369d5fd8fSJohnny Huang 			printf("  Disable image encryption\n");
524442839bbSJohnny Huang 	}
525442839bbSJohnny Huang 
526442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & WRITE_PROTECT_KEY_RETIRE) {
527442839bbSJohnny Huang 		printf("OTPCFG0-D[29]\n");
528442839bbSJohnny Huang 		printf("  Skip\n");
529442839bbSJohnny Huang 	} else {
53069d5fd8fSJohnny Huang 		printf("OTPCFG0-D[29]\n");
531e1f9e54eSJohnny Huang 		if (OTPCFG[0] & WRITE_PROTECT_KEY_RETIRE)
53269d5fd8fSJohnny Huang 			printf("  OTP key retire Region : Write Protect\n");
53369d5fd8fSJohnny Huang 		else
53469d5fd8fSJohnny Huang 			printf("  OTP key retire Region : Writable\n");
535442839bbSJohnny Huang 	}
536442839bbSJohnny Huang 
537442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_SIPROM_RED) {
538442839bbSJohnny Huang 		printf("OTPCFG0-D[30]\n");
539442839bbSJohnny Huang 		printf("  Skip\n");
540442839bbSJohnny Huang 	} else {
54169d5fd8fSJohnny Huang 		printf("OTPCFG0-D[30]\n");
542e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_SIPROM_RED)
54369d5fd8fSJohnny Huang 			printf("  SIPROM RED_EN redundancy repair enable\n");
54469d5fd8fSJohnny Huang 		else
54569d5fd8fSJohnny Huang 			printf("  SIPROM RED_EN redundancy repair disable\n");
546442839bbSJohnny Huang 	}
547442839bbSJohnny Huang 
548442839bbSJohnny Huang 	if (OTPCFG_KEEP[0] & ENABLE_SIPROM_MLOCK) {
549442839bbSJohnny Huang 		printf("OTPCFG0-D[31]\n");
550442839bbSJohnny Huang 		printf("  Skip\n");
551442839bbSJohnny Huang 	} else {
55269d5fd8fSJohnny Huang 		printf("OTPCFG0-D[31]\n");
553e1f9e54eSJohnny Huang 		if (OTPCFG[0] & ENABLE_SIPROM_MLOCK)
55469d5fd8fSJohnny Huang 			printf("  SIPROM Mlock memory lock enable\n");
55569d5fd8fSJohnny Huang 		else
55669d5fd8fSJohnny Huang 			printf("  SIPROM Mlock memory lock disable\n");
557442839bbSJohnny Huang 	}
558442839bbSJohnny Huang 	if (SECREG_SIZE(OTPCFG_KEEP[2]) == 0xFFFF) {
559442839bbSJohnny Huang 		printf("OTPCFG2-D[15:0]\n");
560442839bbSJohnny Huang 		printf("  Skip\n");
561442839bbSJohnny Huang 	} else {
56269d5fd8fSJohnny Huang 		printf("OTPCFG2-D[15:0]\n");
563e1f9e54eSJohnny Huang 		printf("  Vender ID : %x\n", VENDER_ID(OTPCFG[2]));
564442839bbSJohnny Huang 	}
56569d5fd8fSJohnny Huang 
566442839bbSJohnny Huang 	if (SECREG_SIZE(OTPCFG_KEEP[2]) == 0xFFFF) {
567442839bbSJohnny Huang 		printf("OTPCFG2-D[31:16]\n");
568442839bbSJohnny Huang 		printf("  Skip\n");
569442839bbSJohnny Huang 	} else {
57069d5fd8fSJohnny Huang 		printf("OTPCFG2-D[31:16]\n");
571e1f9e54eSJohnny Huang 		printf("  Key Revision : %x\n", KEY_REVISION(OTPCFG[2]));
572442839bbSJohnny Huang 	}
57369d5fd8fSJohnny Huang 
574442839bbSJohnny Huang 	if (SEC_BOOT_HEADER_OFFSET(OTPCFG_KEEP[3]) == 0xFFFF) {
575442839bbSJohnny Huang 		printf("OTPCFG3-D[15:0]\n");
576442839bbSJohnny Huang 		printf("  Skip\n");
577442839bbSJohnny Huang 	} else {
57869d5fd8fSJohnny Huang 		printf("OTPCFG3-D[15:0]\n");
579e1f9e54eSJohnny Huang 		printf("  Secure boot header offset : %x\n",
580e1f9e54eSJohnny Huang 		       SEC_BOOT_HEADER_OFFSET(OTPCFG[3]));
581442839bbSJohnny Huang 	}
58269d5fd8fSJohnny Huang 
583442839bbSJohnny Huang 	if (KEYS_VALID_BITS(OTPCFG_KEEP[4]) == 0xFF) {
584442839bbSJohnny Huang 		printf("OTPCFG4-D[7:0]\n");
585442839bbSJohnny Huang 		printf("  Skip\n");
586442839bbSJohnny Huang 	} else {
58769d5fd8fSJohnny Huang 		printf("OTPCFG4-D[7:0]\n");
588e1f9e54eSJohnny Huang 		tmp = KEYS_VALID_BITS(OTPCFG[4]);
589e1f9e54eSJohnny Huang 		if (tmp != 0) {
59069d5fd8fSJohnny Huang 			for (i = 0; i < 7; i++) {
59169d5fd8fSJohnny Huang 				if (tmp == (1 << i)) {
592e1f9e54eSJohnny Huang 					pass = i + 1;
59369d5fd8fSJohnny Huang 				}
59469d5fd8fSJohnny Huang 			}
595e1f9e54eSJohnny Huang 		} else {
596e1f9e54eSJohnny Huang 			pass = 0;
597e1f9e54eSJohnny Huang 		}
598e1f9e54eSJohnny Huang 		printf("  Keys valid  : %d\n", pass);
599442839bbSJohnny Huang 	}
600442839bbSJohnny Huang 	if (KEYS_RETIRE_BITS(OTPCFG_KEEP[4]) == 0xFF) {
601442839bbSJohnny Huang 		printf("OTPCFG4-D[23:16]\n");
602442839bbSJohnny Huang 		printf("  Skip\n");
603442839bbSJohnny Huang 	} else {
60469d5fd8fSJohnny Huang 		printf("OTPCFG4-D[23:16]\n");
605e1f9e54eSJohnny Huang 		tmp = KEYS_RETIRE_BITS(OTPCFG[4]);
606e1f9e54eSJohnny Huang 		if (tmp != 0) {
60769d5fd8fSJohnny Huang 			for (i = 0; i < 7; i++) {
60869d5fd8fSJohnny Huang 				if (tmp == (1 << i)) {
609e1f9e54eSJohnny Huang 					pass = i + 1;
61069d5fd8fSJohnny Huang 				}
61169d5fd8fSJohnny Huang 			}
612e1f9e54eSJohnny Huang 		} else {
613e1f9e54eSJohnny Huang 			pass = 0;
61469d5fd8fSJohnny Huang 		}
61569d5fd8fSJohnny Huang 		printf("  Keys Retire ID : %d\n", pass);
616442839bbSJohnny Huang 	}
617442839bbSJohnny Huang 	if (OTPCFG_KEEP[5] == 0xFFFFFFFF) {
618442839bbSJohnny Huang 		printf("OTPCFG5-D[31:0]\n");
619442839bbSJohnny Huang 		printf("  Skip\n");
620442839bbSJohnny Huang 	} else {
62169d5fd8fSJohnny Huang 		printf("OTPCFG5-D[31:0]\n");
62269d5fd8fSJohnny Huang 		printf("  User define data, random number low : %x\n", OTPCFG[5]);
623442839bbSJohnny Huang 	}
62469d5fd8fSJohnny Huang 
625442839bbSJohnny Huang 	if (OTPCFG_KEEP[6] == 0xFFFFFFFF) {
626442839bbSJohnny Huang 		printf("OTPCFG6-D[31:0]\n");
627442839bbSJohnny Huang 		printf("  Skip\n");
628442839bbSJohnny Huang 	} else {
62969d5fd8fSJohnny Huang 		printf("OTPCFG6-D[31:0]\n");
63069d5fd8fSJohnny Huang 		printf("  User define data, random number high : %x\n", OTPCFG[6]);
631442839bbSJohnny Huang 	}
63269d5fd8fSJohnny Huang 
633442839bbSJohnny Huang 	if (OTPCFG_KEEP[8] == 0xFFFFFFFF) {
634442839bbSJohnny Huang 		printf("OTPCFG8-D[31:0]\n");
635442839bbSJohnny Huang 		printf("  Skip\n");
636442839bbSJohnny Huang 	} else {
63769d5fd8fSJohnny Huang 		printf("OTPCFG8-D[31:0]\n");
63869d5fd8fSJohnny Huang 		printf("  Redundancy Repair : %x\n", OTPCFG[8]);
639442839bbSJohnny Huang 	}
64069d5fd8fSJohnny Huang 
641442839bbSJohnny Huang 	if (OTPCFG_KEEP[10] == 0xFFFFFFFF) {
642442839bbSJohnny Huang 		printf("OTPCFG10-D[31:0]\n");
643442839bbSJohnny Huang 		printf("  Skip\n");
644442839bbSJohnny Huang 	} else {
64569d5fd8fSJohnny Huang 		printf("OTPCFG10-D[31:0]\n");
64669d5fd8fSJohnny Huang 		printf("  Manifest ID low : %x\n", OTPCFG[10]);
647442839bbSJohnny Huang 	}
64869d5fd8fSJohnny Huang 
649442839bbSJohnny Huang 	if (OTPCFG_KEEP[11] == 0xFFFFFFFF) {
650442839bbSJohnny Huang 		printf("OTPCFG11-D[31:0]\n");
651442839bbSJohnny Huang 		printf("  Skip\n");
652442839bbSJohnny Huang 	} else {
65369d5fd8fSJohnny Huang 		printf("OTPCFG11-D[31:0]\n");
65469d5fd8fSJohnny Huang 		printf("  Manifest ID high : %x\n", OTPCFG[11]);
655442839bbSJohnny Huang 	}
656442839bbSJohnny Huang 
65769d5fd8fSJohnny Huang 	return 0;
65869d5fd8fSJohnny Huang 
65969d5fd8fSJohnny Huang }
66069d5fd8fSJohnny Huang 
66169d5fd8fSJohnny Huang static void buf_print(char *buf, int len)
66269d5fd8fSJohnny Huang {
66369d5fd8fSJohnny Huang 	int i;
66469d5fd8fSJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
66569d5fd8fSJohnny Huang 	for (i = 0; i < len; i++) {
66669d5fd8fSJohnny Huang 		if (i % 16 == 0) {
66769d5fd8fSJohnny Huang 			printf("%04X: ", i);
66869d5fd8fSJohnny Huang 		}
66969d5fd8fSJohnny Huang 		printf("%02X ", buf[i]);
67069d5fd8fSJohnny Huang 		if ((i + 1) % 16 == 0) {
67169d5fd8fSJohnny Huang 			printf("\n");
67269d5fd8fSJohnny Huang 		}
67369d5fd8fSJohnny Huang 	}
67469d5fd8fSJohnny Huang }
67569d5fd8fSJohnny Huang 
676d90825e2SJohnny Huang static int otp_data_parse(uint32_t *buf)
67769d5fd8fSJohnny Huang {
67869d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
67969d5fd8fSJohnny Huang 	char *byte_buf;
68069d5fd8fSJohnny Huang 	int i = 0, len = 0;
68169d5fd8fSJohnny Huang 	byte_buf = (char *)buf;
68269d5fd8fSJohnny Huang 	while (1) {
68369d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
68469d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
68569d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
68669d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
68769d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
68869d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
68969d5fd8fSJohnny Huang 		printf("Key[%d]:\n", i);
69069d5fd8fSJohnny Huang 		printf("Key Type: ");
69169d5fd8fSJohnny Huang 		switch (key_type) {
69269d5fd8fSJohnny Huang 		case 0:
69369d5fd8fSJohnny Huang 			printf("AES-256 as OEM platform key for image encryption/decryption\n");
69469d5fd8fSJohnny Huang 			break;
69569d5fd8fSJohnny Huang 		case 1:
69669d5fd8fSJohnny Huang 			printf("AES-256 as secret vault key\n");
69769d5fd8fSJohnny Huang 			break;
69869d5fd8fSJohnny Huang 		case 4:
69969d5fd8fSJohnny Huang 			printf("HMAC as encrypted OEM HMAC keys in Mode 1\n");
70069d5fd8fSJohnny Huang 			break;
70169d5fd8fSJohnny Huang 		case 8:
70269d5fd8fSJohnny Huang 			printf("RSA-public as OEM DSS public keys in Mode 2\n");
70369d5fd8fSJohnny Huang 			break;
70469d5fd8fSJohnny Huang 		case 9:
70569d5fd8fSJohnny Huang 			printf("RSA-public as SOC public key\n");
70669d5fd8fSJohnny Huang 			break;
70769d5fd8fSJohnny Huang 		case 10:
70869d5fd8fSJohnny Huang 			printf("RSA-public as AES key decryption key\n");
70969d5fd8fSJohnny Huang 			break;
71069d5fd8fSJohnny Huang 		case 13:
71169d5fd8fSJohnny Huang 			printf("RSA-private as SOC private key\n");
71269d5fd8fSJohnny Huang 			break;
71369d5fd8fSJohnny Huang 		case 14:
71469d5fd8fSJohnny Huang 			printf("RSA-private as AES key decryption key\n");
71569d5fd8fSJohnny Huang 			break;
71669d5fd8fSJohnny Huang 		default:
71769d5fd8fSJohnny Huang 			printf("key_type error: %x\n", key_type);
71869d5fd8fSJohnny Huang 			return -1;
71969d5fd8fSJohnny Huang 		}
72069d5fd8fSJohnny Huang 		if (key_type == 4) {
72169d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
72269d5fd8fSJohnny Huang 			switch (key_length) {
72369d5fd8fSJohnny Huang 			case 0:
72469d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
72569d5fd8fSJohnny Huang 				break;
72669d5fd8fSJohnny Huang 			case 1:
72769d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
72869d5fd8fSJohnny Huang 				break;
72969d5fd8fSJohnny Huang 			case 2:
73069d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
73169d5fd8fSJohnny Huang 				break;
73269d5fd8fSJohnny Huang 			case 3:
73369d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
73469d5fd8fSJohnny Huang 				break;
73569d5fd8fSJohnny Huang 			}
736cd1610b4SJohnny Huang 		} else if (key_type != 0 && key_type != 1) {
73769d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
73869d5fd8fSJohnny Huang 			switch (key_length) {
73969d5fd8fSJohnny Huang 			case 0:
74069d5fd8fSJohnny Huang 				printf("RSA1024\n");
74169d5fd8fSJohnny Huang 				len = 0x100;
74269d5fd8fSJohnny Huang 				break;
74369d5fd8fSJohnny Huang 			case 1:
74469d5fd8fSJohnny Huang 				printf("RSA2048\n");
74569d5fd8fSJohnny Huang 				len = 0x200;
74669d5fd8fSJohnny Huang 				break;
74769d5fd8fSJohnny Huang 			case 2:
74869d5fd8fSJohnny Huang 				printf("RSA3072\n");
74969d5fd8fSJohnny Huang 				len = 0x300;
75069d5fd8fSJohnny Huang 				break;
75169d5fd8fSJohnny Huang 			case 3:
75269d5fd8fSJohnny Huang 				printf("RSA4096\n");
75369d5fd8fSJohnny Huang 				len = 0x400;
75469d5fd8fSJohnny Huang 				break;
75569d5fd8fSJohnny Huang 			}
75669d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
75769d5fd8fSJohnny Huang 		}
75869d5fd8fSJohnny Huang 		if (key_type == 4 || key_type == 8)
75969d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
76069d5fd8fSJohnny Huang 		printf("Key Value:\n");
76169d5fd8fSJohnny Huang 		if (key_type == 4) {
76269d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
76369d5fd8fSJohnny Huang 		} else if (key_type == 0 || key_type == 1) {
76469d5fd8fSJohnny Huang 			printf("AES Key:\n");
76569d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
76669d5fd8fSJohnny Huang 			printf("AES IV:\n");
76769d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + 0x20], 0x10);
76869d5fd8fSJohnny Huang 
76969d5fd8fSJohnny Huang 		} else {
77069d5fd8fSJohnny Huang 			printf("RSA mod:\n");
77169d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
77269d5fd8fSJohnny Huang 			printf("RSA exp:\n");
77369d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
77469d5fd8fSJohnny Huang 		}
77569d5fd8fSJohnny Huang 		if (last)
77669d5fd8fSJohnny Huang 			break;
77769d5fd8fSJohnny Huang 		i++;
77869d5fd8fSJohnny Huang 	}
77969d5fd8fSJohnny Huang 	return 0;
78069d5fd8fSJohnny Huang }
78169d5fd8fSJohnny Huang 
782a6d0d645SJohnny Huang static int otp_prog_conf(uint32_t *buf)
78369d5fd8fSJohnny Huang {
784a6d0d645SJohnny Huang 	int i, k;
785d90825e2SJohnny Huang 	int pass = 0;
786d90825e2SJohnny Huang 	int soak = 0;
787a6d0d645SJohnny Huang 	uint32_t prog_address;
788a6d0d645SJohnny Huang 	uint32_t data[12];
789a6d0d645SJohnny Huang 	uint32_t compare[2];
790d90825e2SJohnny Huang 	uint32_t *buf_keep = &buf[12];
791d90825e2SJohnny Huang 	uint32_t data_masked;
792d90825e2SJohnny Huang 	uint32_t buf_masked;
79369d5fd8fSJohnny Huang 
794a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
795a6d0d645SJohnny Huang 
796a6d0d645SJohnny Huang 	printProgress(0, 12, "");
797a6d0d645SJohnny Huang 	for (i = 0; i < 12 ; i ++) {
798a6d0d645SJohnny Huang 		printProgress(i + 1, 12, "");
79969d5fd8fSJohnny Huang 		prog_address = 0x800;
800a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
801a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
802a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
803a6d0d645SJohnny Huang 	}
804a6d0d645SJohnny Huang 
805a6d0d645SJohnny Huang 	printf("Check writable...\n");
806a6d0d645SJohnny Huang 	for (i = 0; i < 12; i++) {
807d90825e2SJohnny Huang 		data_masked = data[i]  & ~buf_keep[i];
808d90825e2SJohnny Huang 		buf_masked  = buf[i] & ~buf_keep[i];
809d90825e2SJohnny Huang 		if (data_masked == buf_masked)
81069d5fd8fSJohnny Huang 			continue;
811d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
812a6d0d645SJohnny Huang 			continue;
813a6d0d645SJohnny Huang 		} else {
814a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
815a6af4a17SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, data[i]);
816a6af4a17SJohnny Huang 			printf("Input [%X] = %x\n", i, buf[i]);
817a6af4a17SJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~buf_keep[i]);
8182a856b9aSJohnny Huang 			return OTP_FAILURE;
819a6d0d645SJohnny Huang 		}
820a6d0d645SJohnny Huang 	}
821a6d0d645SJohnny Huang 
822a6d0d645SJohnny Huang 	printf("Start Programing...\n");
823a6d0d645SJohnny Huang 	printProgress(0, 12, "");
824d90825e2SJohnny Huang 	otp_soak(0);
825a6d0d645SJohnny Huang 	for (i = 0; i < 12; i++) {
826d90825e2SJohnny Huang 		data_masked = data[i]  & ~buf_keep[i];
827d90825e2SJohnny Huang 		buf_masked  = buf[i] & ~buf_keep[i];
828a6d0d645SJohnny Huang 		prog_address = 0x800;
829a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
830a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
831d90825e2SJohnny Huang 		if (data_masked == buf_masked) {
832a6d0d645SJohnny Huang 			printProgress(i + 1, 12, "[%03X]=%08X HIT", prog_address, buf[i]);
833a6d0d645SJohnny Huang 			continue;
834a6d0d645SJohnny Huang 		}
835d90825e2SJohnny Huang 		if (soak) {
836d90825e2SJohnny Huang 			soak = 0;
837d90825e2SJohnny Huang 			otp_soak(0);
838d90825e2SJohnny Huang 		}
839a6d0d645SJohnny Huang 		printProgress(i + 1, 12, "[%03X]=%08X    ", prog_address, buf[i]);
840a6d0d645SJohnny Huang 
841d90825e2SJohnny Huang 		otp_prog_dw(buf[i], buf_keep[i], prog_address);
842a6d0d645SJohnny Huang 
84369d5fd8fSJohnny Huang 		pass = 0;
84469d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
845d90825e2SJohnny Huang 			if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 1) != 0) {
846d90825e2SJohnny Huang 				if (soak == 0) {
847d90825e2SJohnny Huang 					soak = 1;
848d90825e2SJohnny Huang 					otp_soak(1);
849d90825e2SJohnny Huang 				}
850a6d0d645SJohnny Huang 				otp_prog_dw(compare[0], prog_address, 1);
851a6d0d645SJohnny Huang 			} else {
85269d5fd8fSJohnny Huang 				pass = 1;
85369d5fd8fSJohnny Huang 				break;
85469d5fd8fSJohnny Huang 			}
85569d5fd8fSJohnny Huang 		}
856a6d0d645SJohnny Huang 	}
857a6d0d645SJohnny Huang 
85869d5fd8fSJohnny Huang 	if (!pass)
8592a856b9aSJohnny Huang 		return OTP_FAILURE;
860a6d0d645SJohnny Huang 
8612a856b9aSJohnny Huang 	return OTP_SUCCESS;
862d90825e2SJohnny Huang 
86369d5fd8fSJohnny Huang }
86469d5fd8fSJohnny Huang 
86569d5fd8fSJohnny Huang static void otp_strp_status(struct otpstrap *otpstrap)
86669d5fd8fSJohnny Huang {
86769d5fd8fSJohnny Huang 	uint32_t OTPSTRAP_RAW[2];
86869d5fd8fSJohnny Huang 	int i, j;
86969d5fd8fSJohnny Huang 
87069d5fd8fSJohnny Huang 	for (j = 0; j < 64; j++) {
87169d5fd8fSJohnny Huang 		otpstrap[j].value = 0;
87269d5fd8fSJohnny Huang 		otpstrap[j].remain_times = 7;
87369d5fd8fSJohnny Huang 		otpstrap[j].writeable_option = -1;
87469d5fd8fSJohnny Huang 		otpstrap[j].protected = 0;
87569d5fd8fSJohnny Huang 	}
87669d5fd8fSJohnny Huang 
87769d5fd8fSJohnny Huang 	for (i = 16; i < 30; i += 2) {
87869d5fd8fSJohnny Huang 		int option = (i - 16) / 2;
87969d5fd8fSJohnny Huang 		otp_read_config(i, &OTPSTRAP_RAW[0]);
88069d5fd8fSJohnny Huang 		otp_read_config(i + 1, &OTPSTRAP_RAW[1]);
88169d5fd8fSJohnny Huang 		for (j = 0; j < 32; j++) {
88269d5fd8fSJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
88369d5fd8fSJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
88469d5fd8fSJohnny Huang 				otpstrap[j].writeable_option = option;
88569d5fd8fSJohnny Huang 			}
88669d5fd8fSJohnny Huang 			if (bit_value == 1)
88769d5fd8fSJohnny Huang 				otpstrap[j].remain_times --;
88869d5fd8fSJohnny Huang 			otpstrap[j].value ^= bit_value;
88969d5fd8fSJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
89069d5fd8fSJohnny Huang 		}
89169d5fd8fSJohnny Huang 		for (j = 32; j < 64; j++) {
89269d5fd8fSJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
89369d5fd8fSJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
89469d5fd8fSJohnny Huang 				otpstrap[j].writeable_option = option;
89569d5fd8fSJohnny Huang 			}
89669d5fd8fSJohnny Huang 			if (bit_value == 1)
89769d5fd8fSJohnny Huang 				otpstrap[j].remain_times --;
89869d5fd8fSJohnny Huang 			otpstrap[j].value ^= bit_value;
89969d5fd8fSJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
90069d5fd8fSJohnny Huang 		}
90169d5fd8fSJohnny Huang 	}
90269d5fd8fSJohnny Huang 	otp_read_config(30, &OTPSTRAP_RAW[0]);
90369d5fd8fSJohnny Huang 	otp_read_config(31, &OTPSTRAP_RAW[1]);
90469d5fd8fSJohnny Huang 	for (j = 0; j < 32; j++) {
90569d5fd8fSJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
90669d5fd8fSJohnny Huang 			otpstrap[j].protected = 1;
90769d5fd8fSJohnny Huang 	}
90869d5fd8fSJohnny Huang 	for (j = 32; j < 64; j++) {
90969d5fd8fSJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
91069d5fd8fSJohnny Huang 			otpstrap[j].protected = 1;
91169d5fd8fSJohnny Huang 	}
91269d5fd8fSJohnny Huang }
91369d5fd8fSJohnny Huang 
91469d5fd8fSJohnny Huang static int otp_strap_parse(uint32_t *buf)
91569d5fd8fSJohnny Huang {
91669d5fd8fSJohnny Huang 	int i;
91769d5fd8fSJohnny Huang 	uint32_t *strap_keep = buf + 2;
91869d5fd8fSJohnny Huang 	uint32_t *strap_protect = buf + 4;
91969d5fd8fSJohnny Huang 	int bit, pbit, kbit;
92069d5fd8fSJohnny Huang 	int fail = 0;
921a6af4a17SJohnny Huang 	int skip = -1;
92269d5fd8fSJohnny Huang 	struct otpstrap otpstrap[64];
92369d5fd8fSJohnny Huang 
92469d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
92569d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
92669d5fd8fSJohnny Huang 		if (i < 32) {
92769d5fd8fSJohnny Huang 			bit = (buf[0] >> i) & 0x1;
92869d5fd8fSJohnny Huang 			kbit = (strap_keep[0] >> i) & 0x1;
92969d5fd8fSJohnny Huang 			pbit = (strap_protect[0] >> i) & 0x1;
93069d5fd8fSJohnny Huang 		} else {
93169d5fd8fSJohnny Huang 			bit = (buf[1] >> (i - 32)) & 0x1;
93269d5fd8fSJohnny Huang 			kbit = (strap_keep[1] >> (i - 32)) & 0x1;
93369d5fd8fSJohnny Huang 			pbit = (strap_protect[1] >> (i - 32)) & 0x1;
93469d5fd8fSJohnny Huang 		}
93569d5fd8fSJohnny Huang 
93669d5fd8fSJohnny Huang 		if (kbit == 1) {
93769d5fd8fSJohnny Huang 			continue;
93869d5fd8fSJohnny Huang 		} else {
939a6af4a17SJohnny Huang 			printf("OTPSTRAP[%X]:\n", i);
94069d5fd8fSJohnny Huang 		}
94169d5fd8fSJohnny Huang 		if (bit == otpstrap[i].value) {
94269d5fd8fSJohnny Huang 			printf("    The value is same as before, skip it.\n");
943a6af4a17SJohnny Huang 			if (skip == -1)
944a6af4a17SJohnny Huang 				skip = 1;
94569d5fd8fSJohnny Huang 			continue;
946a6af4a17SJohnny Huang 		} else {
947a6af4a17SJohnny Huang 			skip = 0;
94869d5fd8fSJohnny Huang 		}
94969d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
95069d5fd8fSJohnny Huang 			printf("    This bit is protected and is not writable\n");
95169d5fd8fSJohnny Huang 			fail = 1;
95269d5fd8fSJohnny Huang 			continue;
95369d5fd8fSJohnny Huang 		}
95469d5fd8fSJohnny Huang 		if (otpstrap[i].remain_times == 0) {
955a6af4a17SJohnny Huang 			printf("    This bit is no remaining times to write.\n");
95669d5fd8fSJohnny Huang 			fail = 1;
95769d5fd8fSJohnny Huang 			continue;
95869d5fd8fSJohnny Huang 		}
95969d5fd8fSJohnny Huang 		if (pbit == 1) {
96069d5fd8fSJohnny Huang 			printf("    This bit will be protected and become non-writable.\n");
96169d5fd8fSJohnny Huang 		}
962a6af4a17SJohnny Huang 		printf("    Write 1 to OTPSTRAP[%X] OPTION[%X], that value becomes from %d to %d.\n", i, otpstrap[i].writeable_option + 1, otpstrap[i].value, otpstrap[i].value ^ 1);
96369d5fd8fSJohnny Huang 	}
96469d5fd8fSJohnny Huang 	if (fail == 1)
965a6af4a17SJohnny Huang 		return OTP_FAILURE;
966a6af4a17SJohnny Huang 	else if (skip == 1)
967a6af4a17SJohnny Huang 		return OTP_PROG_SKIP;
968*7e22f42dSJohnny Huang 
969*7e22f42dSJohnny Huang 	return 0;
97069d5fd8fSJohnny Huang }
97169d5fd8fSJohnny Huang 
9722a856b9aSJohnny Huang static int otp_print_strap(int start, int count)
97369d5fd8fSJohnny Huang {
97469d5fd8fSJohnny Huang 	int i, j;
97569d5fd8fSJohnny Huang 	struct otpstrap otpstrap[64];
97669d5fd8fSJohnny Huang 
9772a856b9aSJohnny Huang 	if (start < 0 || start > 64)
9782a856b9aSJohnny Huang 		return OTP_USAGE;
9792a856b9aSJohnny Huang 
9802a856b9aSJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
9812a856b9aSJohnny Huang 		return OTP_USAGE;
9822a856b9aSJohnny Huang 
98369d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
98469d5fd8fSJohnny Huang 
985cd1610b4SJohnny Huang 	for (i = start; i < start + count; i++) {
986a6af4a17SJohnny Huang 		printf("OTPSTRAP[%X]:\n", i);
98769d5fd8fSJohnny Huang 		printf("  OTP Option value: ");
98869d5fd8fSJohnny Huang 		for (j = 1; j <= 7; j++)
989a6af4a17SJohnny Huang 			printf("[%X]:%X ", j, otpstrap[i].option_array[j - 1]);
99069d5fd8fSJohnny Huang 		printf("\n");
991a6af4a17SJohnny Huang 		printf("  OTP Value: %X\n", otpstrap[i].value);
99269d5fd8fSJohnny Huang 		printf("  Status:\n");
99369d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
994a6af4a17SJohnny Huang 			printf("    OTPSTRAP[%X] is protected and is not writable\n", i);
99569d5fd8fSJohnny Huang 		} else {
996a6af4a17SJohnny Huang 			printf("    OTPSTRAP[%X] is not protected ", i);
99769d5fd8fSJohnny Huang 			if (otpstrap[i].remain_times == 0) {
998a6af4a17SJohnny Huang 				printf("and no remaining times to write.\n");
99969d5fd8fSJohnny Huang 			} else {
1000a6af4a17SJohnny Huang 				printf("and still can write %d times\n", otpstrap[i].remain_times);
100169d5fd8fSJohnny Huang 			}
100269d5fd8fSJohnny Huang 		}
100369d5fd8fSJohnny Huang 	}
10042a856b9aSJohnny Huang 
10052a856b9aSJohnny Huang 	return OTP_SUCCESS;
100669d5fd8fSJohnny Huang }
100769d5fd8fSJohnny Huang 
100869d5fd8fSJohnny Huang static int otp_prog_strap(uint32_t *buf)
100969d5fd8fSJohnny Huang {
101069d5fd8fSJohnny Huang 	int i, j;
101169d5fd8fSJohnny Huang 	uint32_t *strap_keep = buf + 2;
101269d5fd8fSJohnny Huang 	uint32_t *strap_protect = buf + 4;
101369d5fd8fSJohnny Huang 	uint32_t prog_bit, prog_address;
101469d5fd8fSJohnny Huang 	int bit, pbit, kbit, offset;
101569d5fd8fSJohnny Huang 	int fail = 0;
1016*7e22f42dSJohnny Huang 	int pass = 0;
1017*7e22f42dSJohnny Huang 	int soak = 0;
101869d5fd8fSJohnny Huang 	struct otpstrap otpstrap[64];
101969d5fd8fSJohnny Huang 
102069d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
102169d5fd8fSJohnny Huang 
1022*7e22f42dSJohnny Huang 	otp_soak(0);
1023*7e22f42dSJohnny Huang 
102469d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
10254c1c9b35SJohnny Huang 		printProgress(i + 1, 64, "");
102669d5fd8fSJohnny Huang 		prog_address = 0x800;
102769d5fd8fSJohnny Huang 		if (i < 32) {
102869d5fd8fSJohnny Huang 			offset = i;
102969d5fd8fSJohnny Huang 			bit = (buf[0] >> offset) & 0x1;
103069d5fd8fSJohnny Huang 			kbit = (strap_keep[0] >> offset) & 0x1;
103169d5fd8fSJohnny Huang 			pbit = (strap_protect[0] >> offset) & 0x1;
103269d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
103369d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
103469d5fd8fSJohnny Huang 
103569d5fd8fSJohnny Huang 		} else {
103669d5fd8fSJohnny Huang 			offset = (i - 32);
103769d5fd8fSJohnny Huang 			bit = (buf[1] >> offset) & 0x1;
103869d5fd8fSJohnny Huang 			kbit = (strap_keep[1] >> offset) & 0x1;
103969d5fd8fSJohnny Huang 			pbit = (strap_protect[1] >> offset) & 0x1;
104069d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
104169d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
104269d5fd8fSJohnny Huang 		}
104369d5fd8fSJohnny Huang 		prog_bit = ~(0x1 << offset);
104469d5fd8fSJohnny Huang 
104569d5fd8fSJohnny Huang 		if (kbit == 1) {
104669d5fd8fSJohnny Huang 			continue;
104769d5fd8fSJohnny Huang 		}
104869d5fd8fSJohnny Huang 		if (bit == otpstrap[i].value) {
104969d5fd8fSJohnny Huang 			continue;
105069d5fd8fSJohnny Huang 		}
105169d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
105269d5fd8fSJohnny Huang 			fail = 1;
105369d5fd8fSJohnny Huang 			continue;
105469d5fd8fSJohnny Huang 		}
105569d5fd8fSJohnny Huang 		if (otpstrap[i].remain_times == 0) {
105669d5fd8fSJohnny Huang 			fail = 1;
105769d5fd8fSJohnny Huang 			continue;
105869d5fd8fSJohnny Huang 		}
1059*7e22f42dSJohnny Huang 
1060*7e22f42dSJohnny Huang 		if (soak) {
106169d5fd8fSJohnny Huang 			soak = 0;
1062*7e22f42dSJohnny Huang 			otp_soak(0);
1063*7e22f42dSJohnny Huang 		}
1064*7e22f42dSJohnny Huang 
1065*7e22f42dSJohnny Huang 		otp_prog(prog_address, prog_bit);
1066*7e22f42dSJohnny Huang 
1067*7e22f42dSJohnny Huang 		pass = 0;
1068*7e22f42dSJohnny Huang 
106969d5fd8fSJohnny Huang 		for (j = 0; j < RETRY; j++) {
1070a6d0d645SJohnny Huang 			if (verify_bit(prog_address, offset, 1) == 0) {
107169d5fd8fSJohnny Huang 				pass = 1;
107269d5fd8fSJohnny Huang 				break;
107369d5fd8fSJohnny Huang 			}
1074*7e22f42dSJohnny Huang 			if (soak == 0) {
107569d5fd8fSJohnny Huang 				soak = 1;
1076*7e22f42dSJohnny Huang 				otp_soak(1);
10774b65a65dSJohnny Huang 			}
107869d5fd8fSJohnny Huang 			otp_prog(prog_address, prog_bit);
107969d5fd8fSJohnny Huang 		}
108069d5fd8fSJohnny Huang 		if (!pass)
10812a856b9aSJohnny Huang 			return OTP_FAILURE;
108269d5fd8fSJohnny Huang 
108369d5fd8fSJohnny Huang 		if (pbit == 0)
108469d5fd8fSJohnny Huang 			continue;
108569d5fd8fSJohnny Huang 		prog_address = 0x800;
108669d5fd8fSJohnny Huang 		if (i < 32)
108769d5fd8fSJohnny Huang 			prog_address |= 0x60c;
108869d5fd8fSJohnny Huang 		else
108969d5fd8fSJohnny Huang 			prog_address |= 0x60e;
109069d5fd8fSJohnny Huang 
1091*7e22f42dSJohnny Huang 
1092*7e22f42dSJohnny Huang 		if (soak) {
1093*7e22f42dSJohnny Huang 			soak = 0;
1094*7e22f42dSJohnny Huang 			otp_soak(0);
1095*7e22f42dSJohnny Huang 		}
1096*7e22f42dSJohnny Huang 
1097*7e22f42dSJohnny Huang 		otp_prog(prog_address, prog_bit);
1098*7e22f42dSJohnny Huang 
1099*7e22f42dSJohnny Huang 		pass = 0;
1100*7e22f42dSJohnny Huang 
110169d5fd8fSJohnny Huang 		for (j = 0; j < RETRY; j++) {
1102*7e22f42dSJohnny Huang 
1103a6d0d645SJohnny Huang 			if (verify_bit(prog_address, offset, 1) == 0) {
110469d5fd8fSJohnny Huang 				pass = 1;
110569d5fd8fSJohnny Huang 				break;
110669d5fd8fSJohnny Huang 			}
1107*7e22f42dSJohnny Huang 			if (soak == 0) {
110869d5fd8fSJohnny Huang 				soak = 1;
1109*7e22f42dSJohnny Huang 				otp_soak(1);
111069d5fd8fSJohnny Huang 			}
111169d5fd8fSJohnny Huang 			otp_prog(prog_address, prog_bit);
111269d5fd8fSJohnny Huang 		}
111369d5fd8fSJohnny Huang 		if (!pass)
11142a856b9aSJohnny Huang 			return OTP_FAILURE;
111569d5fd8fSJohnny Huang 
111669d5fd8fSJohnny Huang 	}
111769d5fd8fSJohnny Huang 	if (fail == 1)
11182a856b9aSJohnny Huang 		return OTP_FAILURE;
111969d5fd8fSJohnny Huang 	else
11202a856b9aSJohnny Huang 		return OTP_SUCCESS;
112169d5fd8fSJohnny Huang 
112269d5fd8fSJohnny Huang }
112369d5fd8fSJohnny Huang 
1124cd1610b4SJohnny Huang static void otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset, int soak)
1125cd1610b4SJohnny Huang {
1126cd1610b4SJohnny Huang 	int prog_bit;
1127cd1610b4SJohnny Huang 
1128*7e22f42dSJohnny Huang 	otp_soak(soak);
1129*7e22f42dSJohnny Huang 
1130cd1610b4SJohnny Huang 	if (prog_address % 2 == 0) {
1131cd1610b4SJohnny Huang 		if (value)
1132cd1610b4SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
1133cd1610b4SJohnny Huang 		else
1134cd1610b4SJohnny Huang 			return;
1135cd1610b4SJohnny Huang 	} else {
1136cd1610b4SJohnny Huang 		prog_address |= 1 << 15;
1137cd1610b4SJohnny Huang 		if (!value)
1138cd1610b4SJohnny Huang 			prog_bit = 0x1 << bit_offset;
1139cd1610b4SJohnny Huang 		else
1140cd1610b4SJohnny Huang 			return;
1141cd1610b4SJohnny Huang 	}
1142cd1610b4SJohnny Huang 	otp_prog(prog_address, prog_bit);
1143cd1610b4SJohnny Huang }
1144cd1610b4SJohnny Huang 
1145d90825e2SJohnny Huang static int otp_prog_data(uint32_t *buf)
11464c1c9b35SJohnny Huang {
11474c1c9b35SJohnny Huang 	int i, k;
11484c1c9b35SJohnny Huang 	int pass;
1149d90825e2SJohnny Huang 	int soak = 0;
11504c1c9b35SJohnny Huang 	uint32_t prog_address;
1151d90825e2SJohnny Huang 	uint32_t data[2048];
11524c1c9b35SJohnny Huang 	uint32_t compare[2];
1153d90825e2SJohnny Huang 	uint32_t *buf_keep = &buf[2048];
11544c1c9b35SJohnny Huang 
1155d90825e2SJohnny Huang 	uint32_t data0_masked;
1156d90825e2SJohnny Huang 	uint32_t data1_masked;
1157d90825e2SJohnny Huang 	uint32_t buf0_masked;
1158d90825e2SJohnny Huang 	uint32_t buf1_masked;
11594c1c9b35SJohnny Huang 
11604c1c9b35SJohnny Huang 	printf("Read OTP Data:\n");
11614c1c9b35SJohnny Huang 
1162d90825e2SJohnny Huang 	printProgress(0, 2048, "");
1163d90825e2SJohnny Huang 	for (i = 0; i < 2048 ; i += 2) {
1164d90825e2SJohnny Huang 		printProgress(i + 2, 2048, "");
1165d90825e2SJohnny Huang 		otp_read_data(i, &data[i]);
11664c1c9b35SJohnny Huang 	}
1167d90825e2SJohnny Huang 
11684c1c9b35SJohnny Huang 
11694c1c9b35SJohnny Huang 	printf("Check writable...\n");
1170d90825e2SJohnny Huang 	for (i = 0; i < 2048; i++) {
1171d90825e2SJohnny Huang 		data0_masked = data[i]  & ~buf_keep[i];
1172d90825e2SJohnny Huang 		buf0_masked  = buf[i] & ~buf_keep[i];
1173d90825e2SJohnny Huang 		if (data0_masked == buf0_masked)
11744c1c9b35SJohnny Huang 			continue;
1175d90825e2SJohnny Huang 		if (i % 2 == 0) {
1176d90825e2SJohnny Huang 			if ((data0_masked | buf0_masked) == buf0_masked) {
11774c1c9b35SJohnny Huang 				continue;
11784c1c9b35SJohnny Huang 			} else {
11794c1c9b35SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1180d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
11814c1c9b35SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1182d90825e2SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_keep[i]);
11832a856b9aSJohnny Huang 				return OTP_FAILURE;
118469d5fd8fSJohnny Huang 			}
1185d90825e2SJohnny Huang 		} else {
1186d90825e2SJohnny Huang 			if ((data0_masked & buf0_masked) == buf0_masked) {
1187d90825e2SJohnny Huang 				continue;
1188d90825e2SJohnny Huang 			} else {
1189d90825e2SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1190d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1191d90825e2SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1192d90825e2SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_keep[i]);
11932a856b9aSJohnny Huang 				return OTP_FAILURE;
1194d90825e2SJohnny Huang 			}
1195d90825e2SJohnny Huang 		}
1196d90825e2SJohnny Huang 	}
119769d5fd8fSJohnny Huang 
1198d90825e2SJohnny Huang 	printf("Start Programing...\n");
1199d90825e2SJohnny Huang 	printProgress(0, 2048, "");
1200d90825e2SJohnny Huang 
1201d90825e2SJohnny Huang 	for (i = 0; i < 2048; i += 2) {
1202d90825e2SJohnny Huang 		prog_address = i;
1203d90825e2SJohnny Huang 		data0_masked = data[i]  & ~buf_keep[i];
1204d90825e2SJohnny Huang 		buf0_masked  = buf[i] & ~buf_keep[i];
1205d90825e2SJohnny Huang 		data1_masked = data[i + 1]  & ~buf_keep[i + 1];
1206d90825e2SJohnny Huang 		buf1_masked  = buf[i + 1] & ~buf_keep[i + 1];
1207d90825e2SJohnny Huang 		if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked)) {
1208d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1209d90825e2SJohnny Huang 			continue;
1210d90825e2SJohnny Huang 		}
1211d90825e2SJohnny Huang 		if (soak) {
1212d90825e2SJohnny Huang 			soak = 0;
1213d90825e2SJohnny Huang 			otp_soak(0);
1214d90825e2SJohnny Huang 		}
1215d90825e2SJohnny Huang 		if (data1_masked == buf1_masked) {
1216d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X    ;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1217d90825e2SJohnny Huang 			otp_prog_dw(buf[i], buf_keep[i], prog_address);
1218d90825e2SJohnny Huang 		} else if (data0_masked == buf0_masked) {
1219d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X    ", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1220d90825e2SJohnny Huang 			otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1);
1221d90825e2SJohnny Huang 		} else {
1222d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X    ;[%03X]=%08X    ", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1223d90825e2SJohnny Huang 			otp_prog_dw(buf[i], buf_keep[i], prog_address);
1224d90825e2SJohnny Huang 			otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1);
1225d90825e2SJohnny Huang 		}
1226d90825e2SJohnny Huang 
1227d90825e2SJohnny Huang 		pass = 0;
1228d90825e2SJohnny Huang 		for (k = 0; k < RETRY; k++) {
1229d90825e2SJohnny Huang 			if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 2) != 0) {
1230d90825e2SJohnny Huang 				if (soak == 0) {
1231d90825e2SJohnny Huang 					soak = 1;
1232d90825e2SJohnny Huang 					otp_soak(1);
1233d90825e2SJohnny Huang 				}
1234d90825e2SJohnny Huang 				if (compare[0] != 0) {
1235d90825e2SJohnny Huang 					otp_prog_dw(compare[0], buf_keep[i], prog_address);
1236d90825e2SJohnny Huang 				}
1237d90825e2SJohnny Huang 				if (compare[1] != ~0) {
1238d90825e2SJohnny Huang 					otp_prog_dw(compare[1], buf_keep[i], prog_address + 1);
1239d90825e2SJohnny Huang 				}
1240d90825e2SJohnny Huang 			} else {
1241d90825e2SJohnny Huang 				pass = 1;
1242d90825e2SJohnny Huang 				break;
1243d90825e2SJohnny Huang 			}
1244d90825e2SJohnny Huang 		}
1245d90825e2SJohnny Huang 
1246d90825e2SJohnny Huang 		if (!pass)
12472a856b9aSJohnny Huang 			return OTP_FAILURE;
1248d90825e2SJohnny Huang 	}
12492a856b9aSJohnny Huang 	return OTP_SUCCESS;
1250d90825e2SJohnny Huang 
1251d90825e2SJohnny Huang }
1252d90825e2SJohnny Huang 
1253d90825e2SJohnny Huang static int do_otp_prog(int addr, int byte_size, int nconfirm)
125469d5fd8fSJohnny Huang {
125569d5fd8fSJohnny Huang 	int ret;
1256d90825e2SJohnny Huang 	int mode;
125769d5fd8fSJohnny Huang 	uint32_t *buf;
1258d90825e2SJohnny Huang 	uint32_t *data_region = NULL;
1259d90825e2SJohnny Huang 	uint32_t *conf_region = NULL;
1260d90825e2SJohnny Huang 	uint32_t *strap_region = NULL;
126169d5fd8fSJohnny Huang 
1262d90825e2SJohnny Huang 	buf = map_physmem(addr, byte_size, MAP_WRBACK);
126369d5fd8fSJohnny Huang 	if (!buf) {
126469d5fd8fSJohnny Huang 		puts("Failed to map physical memory\n");
12652a856b9aSJohnny Huang 		return OTP_FAILURE;
126669d5fd8fSJohnny Huang 	}
1267d90825e2SJohnny Huang 
1268d90825e2SJohnny Huang 	if (((buf[0] >> 29) & 0x7) == 0x7) {
1269d90825e2SJohnny Huang 		mode = OTP_REGION_ALL;
1270d90825e2SJohnny Huang 		conf_region = &buf[1];
1271d90825e2SJohnny Huang 		strap_region = &buf[25];
1272d90825e2SJohnny Huang 		data_region = &buf[31];
1273d90825e2SJohnny Huang 	} else {
1274d90825e2SJohnny Huang 		if (buf[0] & BIT(29)) {
1275d90825e2SJohnny Huang 			mode = OTP_REGION_DATA;
1276d90825e2SJohnny Huang 			data_region = &buf[31];
1277d90825e2SJohnny Huang 		}
1278d90825e2SJohnny Huang 		if (buf[0] & BIT(30)) {
1279d90825e2SJohnny Huang 			mode = OTP_REGION_CONF;
1280d90825e2SJohnny Huang 			strap_region = &buf[25];
1281d90825e2SJohnny Huang 		}
1282d90825e2SJohnny Huang 		if (buf[0] & BIT(31)) {
1283d90825e2SJohnny Huang 			mode = OTP_REGION_STRAP;
1284d90825e2SJohnny Huang 			conf_region = &buf[1];
1285d90825e2SJohnny Huang 		}
1286d90825e2SJohnny Huang 	}
128769d5fd8fSJohnny Huang 	if (!nconfirm) {
1288a6d0d645SJohnny Huang 		if (mode == OTP_REGION_CONF) {
1289d90825e2SJohnny Huang 			if (otp_conf_parse(conf_region) < 0) {
129069d5fd8fSJohnny Huang 				printf("OTP config error, please check.\n");
12912a856b9aSJohnny Huang 				return OTP_FAILURE;
129269d5fd8fSJohnny Huang 			}
1293a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_DATA) {
1294d90825e2SJohnny Huang 			if (otp_data_parse(data_region) < 0) {
129569d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
12962a856b9aSJohnny Huang 				return OTP_FAILURE;
129769d5fd8fSJohnny Huang 			}
1298a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_STRAP) {
1299a6af4a17SJohnny Huang 			ret = otp_strap_parse(strap_region);
1300a6af4a17SJohnny Huang 			if (ret == OTP_FAILURE) {
130169d5fd8fSJohnny Huang 				printf("OTP strap error, please check.\n");
13022a856b9aSJohnny Huang 				return OTP_FAILURE;
1303a6af4a17SJohnny Huang 			} else if (ret == OTP_PROG_SKIP) {
1304a6af4a17SJohnny Huang 				printf("OTP strap skip all\n");
1305a6af4a17SJohnny Huang 				return OTP_SUCCESS;
130669d5fd8fSJohnny Huang 			}
1307a6d0d645SJohnny Huang 		} else if (mode == OTP_REGION_ALL) {
1308d90825e2SJohnny Huang 			if (otp_conf_parse(conf_region) < 0) {
130969d5fd8fSJohnny Huang 				printf("OTP config error, please check.\n");
13102a856b9aSJohnny Huang 				return OTP_FAILURE;
131169d5fd8fSJohnny Huang 			}
1312a6af4a17SJohnny Huang 			if (otp_strap_parse(strap_region) == OTP_FAILURE) {
131369d5fd8fSJohnny Huang 				printf("OTP strap error, please check.\n");
13142a856b9aSJohnny Huang 				return OTP_FAILURE;
131569d5fd8fSJohnny Huang 			}
1316d90825e2SJohnny Huang 			if (otp_data_parse(data_region) < 0) {
131769d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
13182a856b9aSJohnny Huang 				return OTP_FAILURE;
131969d5fd8fSJohnny Huang 			}
132069d5fd8fSJohnny Huang 		}
132169d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
132269d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
132369d5fd8fSJohnny Huang 			printf(" Aborting\n");
13242a856b9aSJohnny Huang 			return OTP_FAILURE;
132569d5fd8fSJohnny Huang 		}
132669d5fd8fSJohnny Huang 	}
1327a6d0d645SJohnny Huang 	if (mode == OTP_REGION_CONF) {
1328d90825e2SJohnny Huang 		return otp_prog_conf(conf_region);
1329a6d0d645SJohnny Huang 	} else if (mode == OTP_REGION_STRAP) {
1330d90825e2SJohnny Huang 		return otp_prog_strap(strap_region);
1331a6d0d645SJohnny Huang 	} else if (mode == OTP_REGION_DATA) {
1332d90825e2SJohnny Huang 		return otp_prog_data(data_region);
1333a6d0d645SJohnny Huang 	} else if (mode == OTP_REGION_ALL) {
133469d5fd8fSJohnny Huang 		printf("programing data region ... ");
1335d90825e2SJohnny Huang 		ret = otp_prog_data(data_region);
13362a856b9aSJohnny Huang 		if (ret != 0) {
133769d5fd8fSJohnny Huang 			printf("Error\n");
133869d5fd8fSJohnny Huang 			return ret;
133969d5fd8fSJohnny Huang 		} else {
134069d5fd8fSJohnny Huang 			printf("Done\n");
134169d5fd8fSJohnny Huang 		}
134269d5fd8fSJohnny Huang 		printf("programing strap region ... ");
1343d90825e2SJohnny Huang 		ret = otp_prog_strap(strap_region);
13442a856b9aSJohnny Huang 		if (ret != 0) {
134569d5fd8fSJohnny Huang 			printf("Error\n");
134669d5fd8fSJohnny Huang 			return ret;
134769d5fd8fSJohnny Huang 		} else {
134869d5fd8fSJohnny Huang 			printf("Done\n");
134969d5fd8fSJohnny Huang 		}
135069d5fd8fSJohnny Huang 		printf("programing configuration region ... ");
1351d90825e2SJohnny Huang 		ret = otp_prog_conf(conf_region);
13522a856b9aSJohnny Huang 		if (ret != 0) {
135369d5fd8fSJohnny Huang 			printf("Error\n");
135469d5fd8fSJohnny Huang 			return ret;
135569d5fd8fSJohnny Huang 		}
135669d5fd8fSJohnny Huang 		printf("Done\n");
13572a856b9aSJohnny Huang 		return OTP_SUCCESS;
135869d5fd8fSJohnny Huang 	}
1359cd1610b4SJohnny Huang 
13602a856b9aSJohnny Huang 	return OTP_USAGE;
13612a856b9aSJohnny Huang }
13622a856b9aSJohnny Huang 
13632a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1364cd1610b4SJohnny Huang {
1365a6af4a17SJohnny Huang 	uint32_t read[2];
1366cd1610b4SJohnny Huang 	uint32_t strap_buf[6];
1367d90825e2SJohnny Huang 	uint32_t prog_address = 0;
1368cd1610b4SJohnny Huang 	struct otpstrap otpstrap[64];
1369cd1610b4SJohnny Huang 	int otp_bit;
1370cd1610b4SJohnny Huang 	int i;
1371cd1610b4SJohnny Huang 	int pass;
1372a6af4a17SJohnny Huang 	int ret;
1373cd1610b4SJohnny Huang 
1374cd1610b4SJohnny Huang 	switch (mode) {
1375a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1376a6af4a17SJohnny Huang 		otp_read_config(otp_dw_offset, read);
1377cd1610b4SJohnny Huang 		prog_address = 0x800;
1378cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1379cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1380a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
1381cd1610b4SJohnny Huang 		if (otp_bit == value) {
1382a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1383cd1610b4SJohnny Huang 			printf("No need to program\n");
13842a856b9aSJohnny Huang 			return OTP_SUCCESS;
1385cd1610b4SJohnny Huang 		}
1386cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1387a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
1388cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
13892a856b9aSJohnny Huang 			return OTP_FAILURE;
1390cd1610b4SJohnny Huang 		}
1391a6af4a17SJohnny Huang 		printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
1392cd1610b4SJohnny Huang 		break;
1393a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1394cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1395cd1610b4SJohnny Huang 
1396cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1397a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
1398a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
1399cd1610b4SJohnny Huang 		} else {
1400a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
1401a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
1402cd1610b4SJohnny Huang 		}
1403cd1610b4SJohnny Huang 		if (otp_bit == value) {
1404a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1405cd1610b4SJohnny Huang 			printf("No need to program\n");
14062a856b9aSJohnny Huang 			return OTP_SUCCESS;
1407cd1610b4SJohnny Huang 		}
1408cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1409a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1410cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
14112a856b9aSJohnny Huang 			return OTP_FAILURE;
1412cd1610b4SJohnny Huang 		}
1413a6af4a17SJohnny Huang 		printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
1414cd1610b4SJohnny Huang 		break;
1415a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1416cd1610b4SJohnny Huang 		otp_strp_status(otpstrap);
1417cd1610b4SJohnny Huang 		otp_print_strap(bit_offset, 1);
1418cd1610b4SJohnny Huang 		if (bit_offset < 32) {
1419cd1610b4SJohnny Huang 			strap_buf[0] = value << bit_offset;
1420cd1610b4SJohnny Huang 			strap_buf[2] = ~BIT(bit_offset);
1421cd1610b4SJohnny Huang 			strap_buf[3] = ~0;
1422cd1610b4SJohnny Huang 			strap_buf[5] = 0;
14232a856b9aSJohnny Huang 			// if (protect)
14242a856b9aSJohnny Huang 			// 	strap_buf[4] = BIT(bit_offset);
14252a856b9aSJohnny Huang 			// else
14262a856b9aSJohnny Huang 			// 	strap_buf[4] = 0;
1427cd1610b4SJohnny Huang 		} else {
1428cd1610b4SJohnny Huang 			strap_buf[1] = value << (bit_offset - 32);
1429cd1610b4SJohnny Huang 			strap_buf[2] = ~0;
1430cd1610b4SJohnny Huang 			strap_buf[3] = ~BIT(bit_offset - 32);
1431cd1610b4SJohnny Huang 			strap_buf[4] = 0;
14322a856b9aSJohnny Huang 			// if (protect)
14332a856b9aSJohnny Huang 			// 	strap_buf[5] = BIT(bit_offset - 32);
14342a856b9aSJohnny Huang 			// else
14352a856b9aSJohnny Huang 			// 	strap_buf[5] = 0;
1436cd1610b4SJohnny Huang 		}
1437a6af4a17SJohnny Huang 		ret = otp_strap_parse(strap_buf);
1438a6af4a17SJohnny Huang 		if (ret == OTP_FAILURE)
14392a856b9aSJohnny Huang 			return OTP_FAILURE;
1440a6af4a17SJohnny Huang 		else if (ret == OTP_PROG_SKIP)
1441a6af4a17SJohnny Huang 			return OTP_SUCCESS;
1442a6af4a17SJohnny Huang 
1443cd1610b4SJohnny Huang 		break;
1444cd1610b4SJohnny Huang 	}
1445cd1610b4SJohnny Huang 
1446cd1610b4SJohnny Huang 	if (!nconfirm) {
1447cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1448cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1449cd1610b4SJohnny Huang 			printf(" Aborting\n");
14502a856b9aSJohnny Huang 			return OTP_FAILURE;
1451cd1610b4SJohnny Huang 		}
1452cd1610b4SJohnny Huang 	}
1453cd1610b4SJohnny Huang 
1454cd1610b4SJohnny Huang 	switch (mode) {
1455a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1456cd1610b4SJohnny Huang 		return otp_prog_strap(strap_buf);
1457a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1458a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1459cd1610b4SJohnny Huang 		otp_prog_bit(value, prog_address, bit_offset, 0);
1460cd1610b4SJohnny Huang 		pass = -1;
1461cd1610b4SJohnny Huang 		for (i = 0; i < RETRY; i++) {
1462a6d0d645SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
1463cd1610b4SJohnny Huang 				otp_prog_bit(value, prog_address, bit_offset, 1);
1464cd1610b4SJohnny Huang 			} else {
1465cd1610b4SJohnny Huang 				pass = 0;
1466cd1610b4SJohnny Huang 				break;
1467cd1610b4SJohnny Huang 			}
1468cd1610b4SJohnny Huang 		}
14692a856b9aSJohnny Huang 		if (pass == 0)
14702a856b9aSJohnny Huang 			return OTP_SUCCESS;
1471cd1610b4SJohnny Huang 	}
1472cd1610b4SJohnny Huang 
14732a856b9aSJohnny Huang 	return OTP_USAGE;
1474cd1610b4SJohnny Huang }
1475cd1610b4SJohnny Huang 
14762a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
147769d5fd8fSJohnny Huang {
14782a856b9aSJohnny Huang 	uint32_t offset, count;
14792a856b9aSJohnny Huang 	int ret;
148069d5fd8fSJohnny Huang 
14812a856b9aSJohnny Huang 	if (argc == 4) {
14822a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
14832a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
14842a856b9aSJohnny Huang 	} else if (argc == 3) {
14852a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
14862a856b9aSJohnny Huang 		count = 1;
14872a856b9aSJohnny Huang 	} else {
148869d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
148969d5fd8fSJohnny Huang 	}
149069d5fd8fSJohnny Huang 
149169d5fd8fSJohnny Huang 
14922a856b9aSJohnny Huang 	if (!strcmp(argv[1], "conf")) {
149369d5fd8fSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
14942a856b9aSJohnny Huang 		ret = otp_print_config(offset, count);
14952a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "data")) {
14962a856b9aSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
14972a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
14982a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
14992a856b9aSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
15002a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
15012a856b9aSJohnny Huang 	} else {
15022a856b9aSJohnny Huang 		return CMD_RET_USAGE;
150369d5fd8fSJohnny Huang 	}
150469d5fd8fSJohnny Huang 
15052a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
15062a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
15072a856b9aSJohnny Huang 	else
15082a856b9aSJohnny Huang 		return CMD_RET_USAGE;
15092a856b9aSJohnny Huang 
15102a856b9aSJohnny Huang }
15112a856b9aSJohnny Huang 
15122a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
15132a856b9aSJohnny Huang {
15142a856b9aSJohnny Huang 	phys_addr_t addr;
15152a856b9aSJohnny Huang 	uint32_t byte_size;
15162a856b9aSJohnny Huang 	int ret;
15172a856b9aSJohnny Huang 
15182a856b9aSJohnny Huang 	if (argc == 4) {
15192a856b9aSJohnny Huang 		if (strcmp(argv[1], "f"))
15202a856b9aSJohnny Huang 			return CMD_RET_USAGE;
15212a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
15222a856b9aSJohnny Huang 		byte_size = simple_strtoul(argv[3], NULL, 16);
152369d5fd8fSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
15242a856b9aSJohnny Huang 		ret = do_otp_prog(addr, byte_size, 1);
15252a856b9aSJohnny Huang 	} else if (argc == 3) {
15262a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
15272a856b9aSJohnny Huang 		byte_size = simple_strtoul(argv[2], NULL, 16);
15282a856b9aSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
15292a856b9aSJohnny Huang 		ret = do_otp_prog(addr, byte_size, 0);
15302a856b9aSJohnny Huang 	} else {
15312a856b9aSJohnny Huang 		return CMD_RET_USAGE;
15322a856b9aSJohnny Huang 	}
15332a856b9aSJohnny Huang 
15342a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
15352a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
15362a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
15372a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
15382a856b9aSJohnny Huang 	else
15392a856b9aSJohnny Huang 		return CMD_RET_USAGE;
15402a856b9aSJohnny Huang }
15412a856b9aSJohnny Huang 
15422a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
15432a856b9aSJohnny Huang {
15442a856b9aSJohnny Huang 	int mode = 0;
15452a856b9aSJohnny Huang 	int nconfirm = 0;
15462a856b9aSJohnny Huang 	int otp_addr = 0;
15472a856b9aSJohnny Huang 	int bit_offset;
15482a856b9aSJohnny Huang 	int value;
15492a856b9aSJohnny Huang 	int ret;
15502a856b9aSJohnny Huang 
15512a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
15522a856b9aSJohnny Huang 		return CMD_RET_USAGE;
15532a856b9aSJohnny Huang 
15542a856b9aSJohnny Huang 	/* Drop the pb cmd */
15552a856b9aSJohnny Huang 	argc--;
15562a856b9aSJohnny Huang 	argv++;
15572a856b9aSJohnny Huang 
15582a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
1559a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
15602a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
1561a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
15622a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
1563a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
1564cd1610b4SJohnny Huang 	else
15652a856b9aSJohnny Huang 		return CMD_RET_USAGE;
15662a856b9aSJohnny Huang 
15672a856b9aSJohnny Huang 	/* Drop the region cmd */
15682a856b9aSJohnny Huang 	argc--;
15692a856b9aSJohnny Huang 	argv++;
15702a856b9aSJohnny Huang 
15712a856b9aSJohnny Huang 	if (!strcmp(argv[0], "f")) {
1572cd1610b4SJohnny Huang 		nconfirm = 1;
15732a856b9aSJohnny Huang 		/* Drop the force option */
15742a856b9aSJohnny Huang 		argc--;
15752a856b9aSJohnny Huang 		argv++;
15762a856b9aSJohnny Huang 	}
1577cd1610b4SJohnny Huang 
1578a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
15792a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
15802a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
1581cd1610b4SJohnny Huang 		if (bit_offset >= 64)
15822a856b9aSJohnny Huang 			return CMD_RET_USAGE;
1583cd1610b4SJohnny Huang 	} else {
15842a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
15852a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
15862a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
1587cd1610b4SJohnny Huang 		if (bit_offset >= 32)
15882a856b9aSJohnny Huang 			return CMD_RET_USAGE;
1589cd1610b4SJohnny Huang 	}
1590cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
15912a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1592cd1610b4SJohnny Huang 
1593cd1610b4SJohnny Huang 	writel(OTP_PASSWD, 0x1e6f2000); //password
15942a856b9aSJohnny Huang 	ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
15952a856b9aSJohnny Huang 
15962a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
15972a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
15982a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
15992a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
16002a856b9aSJohnny Huang 	else
16012a856b9aSJohnny Huang 		return CMD_RET_USAGE;
16022a856b9aSJohnny Huang }
16032a856b9aSJohnny Huang 
16042a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
16052a856b9aSJohnny Huang {
16062a856b9aSJohnny Huang 	phys_addr_t addr;
16072a856b9aSJohnny Huang 	int otp_addr = 0;
16082a856b9aSJohnny Huang 
16092a856b9aSJohnny Huang 	if (argc != 3)
16102a856b9aSJohnny Huang 		return CMD_RET_USAGE;
16112a856b9aSJohnny Huang 
161269d5fd8fSJohnny Huang 	writel(OTP_PASSWD, 0x1e6f2000); //password
16132a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
16142a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
16152a856b9aSJohnny Huang 	if (otp_compare(otp_addr, addr) == 0) {
161669d5fd8fSJohnny Huang 		printf("Compare pass\n");
16172a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
161869d5fd8fSJohnny Huang 	} else {
161969d5fd8fSJohnny Huang 		printf("Compare fail\n");
16202a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
162169d5fd8fSJohnny Huang 	}
162269d5fd8fSJohnny Huang }
162369d5fd8fSJohnny Huang 
16242a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
16252a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
16262a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(prog, 4, 0, do_otpprog, "", ""),
16272a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
16282a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
162969d5fd8fSJohnny Huang 
16302a856b9aSJohnny Huang };
16312a856b9aSJohnny Huang 
16322a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
16332a856b9aSJohnny Huang {
16342a856b9aSJohnny Huang 	cmd_tbl_t *cp;
16352a856b9aSJohnny Huang 
16362a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
16372a856b9aSJohnny Huang 
16382a856b9aSJohnny Huang 	/* Drop the mmc command */
16392a856b9aSJohnny Huang 	argc--;
16402a856b9aSJohnny Huang 	argv++;
16412a856b9aSJohnny Huang 
16422a856b9aSJohnny Huang 	if (cp == NULL || argc > cp->maxargs)
16432a856b9aSJohnny Huang 		return CMD_RET_USAGE;
16442a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
16452a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
16462a856b9aSJohnny Huang 
16472a856b9aSJohnny Huang 	return cp->cmd(cmdtp, flag, argc, argv);
164869d5fd8fSJohnny Huang }
164969d5fd8fSJohnny Huang 
165069d5fd8fSJohnny Huang U_BOOT_CMD(
165169d5fd8fSJohnny Huang 	otp, 7, 0,  do_ast_otp,
165269d5fd8fSJohnny Huang 	"ASPEED One-Time-Programmable sub-system",
16532a856b9aSJohnny Huang 	"read conf|data <otp_dw_offset> <dw_count>\n"
16542a856b9aSJohnny Huang 	"otp read strap <strap_bit_offset> <bit_count>\n"
16552a856b9aSJohnny Huang 	"otp info conf|strap|data <otp_dw_offset> <dw_count>\n"
1656d90825e2SJohnny Huang 	"otp prog [f] <addr> <byte_size>\n"
1657cd1610b4SJohnny Huang 	"otp pb conf|data [f] <otp_dw_offset> <bit_offset> <value>\n"
1658cd1610b4SJohnny Huang 	"otp pb strap [f] <bit_offset> <value> <protect>\n"
16592a856b9aSJohnny Huang 	"otp cmp <addr> <otp_dw_offset>\n"
166069d5fd8fSJohnny Huang );
1661