xref: /openbmc/u-boot/cmd/otp.c (revision 9a4fe6901f6110929040b5d40cfee6cc7f22a1e1)
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
287332532cSJohnny Huang #define OTP_REGION_STRAP		BIT(0)
297332532cSJohnny Huang #define OTP_REGION_CONF			BIT(1)
307332532cSJohnny Huang #define OTP_REGION_DATA			BIT(2)
3169d5fd8fSJohnny Huang 
322a856b9aSJohnny Huang #define OTP_USAGE			-1
332a856b9aSJohnny Huang #define OTP_FAILURE			-2
342a856b9aSJohnny Huang #define OTP_SUCCESS			0
352a856b9aSJohnny Huang 
36a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
37a6af4a17SJohnny Huang 
38*9a4fe690SJohnny Huang #define OTP_KEY_TYPE_RSA		1
39*9a4fe690SJohnny Huang #define OTP_KEY_TYPE_AES		2
40*9a4fe690SJohnny Huang #define OTP_KEY_TYPE_VAULT		3
41*9a4fe690SJohnny Huang #define OTP_KEY_TYPE_HMAC		4
42*9a4fe690SJohnny Huang 
43*9a4fe690SJohnny Huang 
44a8bd6d8cSJohnny Huang #define OTP_REG_RESERVED		-1
45b458cd62SJohnny Huang #define OTP_REG_VALUE			-2
46b458cd62SJohnny Huang #define OTP_REG_VALID_BIT		-3
4776d13988SJohnny Huang 
484c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
494c1c9b35SJohnny Huang #define PBWIDTH 60
504c1c9b35SJohnny Huang 
5166f2f8e5SJohnny Huang struct otpstrap_status {
5269d5fd8fSJohnny Huang 	int value;
5369d5fd8fSJohnny Huang 	int option_array[7];
5469d5fd8fSJohnny Huang 	int remain_times;
5569d5fd8fSJohnny Huang 	int writeable_option;
5669d5fd8fSJohnny Huang 	int protected;
5769d5fd8fSJohnny Huang };
5869d5fd8fSJohnny Huang 
5966f2f8e5SJohnny Huang struct otpconf_parse {
6066f2f8e5SJohnny Huang 	int dw_offset;
6166f2f8e5SJohnny Huang 	int bit;
6266f2f8e5SJohnny Huang 	int length;
6366f2f8e5SJohnny Huang 	int value;
6466f2f8e5SJohnny Huang 	int keep;
6566f2f8e5SJohnny Huang 	char status[80];
6666f2f8e5SJohnny Huang };
6766f2f8e5SJohnny Huang 
68a8bd6d8cSJohnny Huang struct otpstrap_info {
69a8bd6d8cSJohnny Huang 	uint32_t bit_offset;
70a8bd6d8cSJohnny Huang 	uint32_t length;
7176d13988SJohnny Huang 	int value;
72a8bd6d8cSJohnny Huang 	char information[80];
73a8bd6d8cSJohnny Huang };
74a8bd6d8cSJohnny Huang 
75a8bd6d8cSJohnny Huang struct otpconf_info {
76a8bd6d8cSJohnny Huang 	uint32_t dw_offset;
77a8bd6d8cSJohnny Huang 	uint32_t bit_offset;
78a8bd6d8cSJohnny Huang 	uint32_t length;
79a8bd6d8cSJohnny Huang 	int value;
80a8bd6d8cSJohnny Huang 	char information[80];
81a8bd6d8cSJohnny Huang };
82a8bd6d8cSJohnny Huang 
83*9a4fe690SJohnny Huang struct otpkey_type {
84*9a4fe690SJohnny Huang 	int value;
85*9a4fe690SJohnny Huang 	int key_type;
86*9a4fe690SJohnny Huang 	int need_id;
87*9a4fe690SJohnny Huang 	char information[110];
88*9a4fe690SJohnny Huang };
89*9a4fe690SJohnny Huang 
90*9a4fe690SJohnny Huang struct otp_info_cb {
91*9a4fe690SJohnny Huang 	int version;
92*9a4fe690SJohnny Huang 	struct otpstrap_info *strap_info;
93*9a4fe690SJohnny Huang 	int strap_info_len;
94*9a4fe690SJohnny Huang 	struct otpconf_info *conf_info;
95*9a4fe690SJohnny Huang 	int conf_info_len;
96*9a4fe690SJohnny Huang 	struct otpkey_type *key_info;
97*9a4fe690SJohnny Huang 	int key_info_len;
98*9a4fe690SJohnny Huang };
99*9a4fe690SJohnny Huang 
100a8bd6d8cSJohnny Huang void printProgress(int numerator, int denominator, char *format, ...)
101a8bd6d8cSJohnny Huang {
102a8bd6d8cSJohnny Huang 	int val = numerator * 100 / denominator;
103a8bd6d8cSJohnny Huang 	int lpad = numerator * PBWIDTH / denominator;
104a8bd6d8cSJohnny Huang 	int rpad = PBWIDTH - lpad;
105a8bd6d8cSJohnny Huang 	char buffer[256];
106a8bd6d8cSJohnny Huang 	va_list aptr;
107a8bd6d8cSJohnny Huang 
108a8bd6d8cSJohnny Huang 	va_start(aptr, format);
109a8bd6d8cSJohnny Huang 	vsprintf(buffer, format, aptr);
110a8bd6d8cSJohnny Huang 	va_end(aptr);
111a8bd6d8cSJohnny Huang 
112a8bd6d8cSJohnny Huang 	printf("\r%3d%% [%.*s%*s] %s", val, lpad, PBSTR, rpad, "", buffer);
113a8bd6d8cSJohnny Huang 	if (numerator == denominator)
114a8bd6d8cSJohnny Huang 		printf("\n");
115a8bd6d8cSJohnny Huang }
116a8bd6d8cSJohnny Huang 
117*9a4fe690SJohnny Huang static struct otp_info_cb info_cb;
118*9a4fe690SJohnny Huang 
119a8bd6d8cSJohnny Huang struct otpstrap_info a0_strap_info[] = {
12091448c03SJohnny Huang 	{ 0, 1, 0, "Disable secure boot" },
12191448c03SJohnny Huang 	{ 0, 1, 1, "Enable secure boot"	},
12291448c03SJohnny Huang 	{ 1, 1, 0, "Disable boot from eMMC" },
12391448c03SJohnny Huang 	{ 1, 1, 1, "Enable boot from eMMC" },
12491448c03SJohnny Huang 	{ 2, 1, 0, "Disable Boot from debug SPI" },
12591448c03SJohnny Huang 	{ 2, 1, 1, "Enable Boot from debug SPI" },
12691448c03SJohnny Huang 	{ 3, 1, 0, "Enable ARM CM3" },
12791448c03SJohnny Huang 	{ 3, 1, 1, "Disable ARM CM3" },
12891448c03SJohnny Huang 	{ 4, 1, 0, "No VGA BISO ROM, VGA BIOS is merged in the system BIOS" },
12991448c03SJohnny Huang 	{ 4, 1, 1, "Enable dedicated VGA BIOS ROM" },
13091448c03SJohnny Huang 	{ 5, 1, 0, "MAC 1 : RMII/NCSI" },
13191448c03SJohnny Huang 	{ 5, 1, 1, "MAC 1 : RGMII" },
13291448c03SJohnny Huang 	{ 6, 1, 0, "MAC 2 : RMII/NCSI" },
13391448c03SJohnny Huang 	{ 6, 1, 1, "MAC 2 : RGMII" },
13491448c03SJohnny Huang 	{ 7, 3, 0, "CPU Frequency : 1GHz" },
13591448c03SJohnny Huang 	{ 7, 3, 1, "CPU Frequency : 800MHz" },
13691448c03SJohnny Huang 	{ 7, 3, 2, "CPU Frequency : 1.2GHz" },
13791448c03SJohnny Huang 	{ 7, 3, 3, "CPU Frequency : 1.4GHz" },
13891448c03SJohnny Huang 	{ 10, 2, 0, "HCLK ratio AXI:AHB = 2:1" },
13991448c03SJohnny Huang 	{ 10, 2, 1, "HCLK ratio AXI:AHB = 2:1" },
14091448c03SJohnny Huang 	{ 10, 2, 2, "HCLK ratio AXI:AHB = 3:1" },
14191448c03SJohnny Huang 	{ 10, 2, 3, "HCLK ratio AXI:AHB = 4:1" },
14291448c03SJohnny Huang 	{ 12, 2, 0, "VGA memory size : 8MB" },
14391448c03SJohnny Huang 	{ 12, 2, 1, "VGA memory size : 16MB" },
14491448c03SJohnny Huang 	{ 12, 2, 2, "VGA memory size : 32MB" },
14591448c03SJohnny Huang 	{ 12, 2, 3, "VGA memory size : 64MB" },
14691448c03SJohnny Huang 	{ 14, 3, OTP_REG_RESERVED, "" },
14791448c03SJohnny Huang 	{ 17, 1, 0, "VGA class code : Class Code for video device" },
14891448c03SJohnny Huang 	{ 17, 1, 1, "VGA class code : Class Code for VGA device" },
14991448c03SJohnny Huang 	{ 18, 1, 0, "Enable debug interfaces 0" },
15091448c03SJohnny Huang 	{ 18, 1, 1, "Disable debug interfaces 0" },
15191448c03SJohnny Huang 	{ 19, 1, 0, "Boot from emmc mode : High eMMC speed" },
15291448c03SJohnny Huang 	{ 19, 1, 1, "Boot from emmc mode : Normal eMMC speed" },
15391448c03SJohnny Huang 	{ 20, 1, 0, "Enable Pcie EHCI device" },
15491448c03SJohnny Huang 	{ 20, 1, 1, "Disable Pcie EHCI device" },
15591448c03SJohnny Huang 	{ 21, 1, 0, "Enable VGA XDMA function" },
15691448c03SJohnny Huang 	{ 21, 1, 1, "Disable VGA XDMA function" },
15791448c03SJohnny Huang 	{ 22, 1, 0, "Normal BMC mode" },
15891448c03SJohnny Huang 	{ 22, 1, 1, "Disable dedicated BMC functions for non-BMC application" },
15991448c03SJohnny Huang 	{ 23, 1, 0, "SSPRST# pin is for secondary processor dedicated reset pin" },
16091448c03SJohnny Huang 	{ 23, 1, 1, "SSPRST# pin is for PCIE root complex dedicated reset pin" },
16191448c03SJohnny Huang 	{ 24, 1, 0, "DRAM types : DDR4" },
16291448c03SJohnny Huang 	{ 24, 1, 1, "DRAM types : DDR3" },
16391448c03SJohnny Huang 	{ 25, 5, OTP_REG_RESERVED, "" },
16491448c03SJohnny Huang 	{ 30, 2, OTP_REG_RESERVED, "" },
16591448c03SJohnny Huang 	{ 32, 1, 0, "MAC 3 : RMII/NCSI" },
16691448c03SJohnny Huang 	{ 32, 1, 1, "MAC 3 : RGMII" },
16791448c03SJohnny Huang 	{ 33, 1, 0, "MAC 4 : RMII/NCSI" },
16891448c03SJohnny Huang 	{ 33, 1, 1, "MAC 4 : RGMII" },
16991448c03SJohnny Huang 	{ 34, 1, 0, "SuperIO configuration address : 0x2E" },
17091448c03SJohnny Huang 	{ 34, 1, 1, "SuperIO configuration address : 0x4E" },
17191448c03SJohnny Huang 	{ 35, 1, 0, "Enable LPC to decode SuperIO" },
17291448c03SJohnny Huang 	{ 35, 1, 1, "Disable LPC to decode SuperIO" },
17391448c03SJohnny Huang 	{ 36, 1, 0, "Enable debug interfaces 1" },
17491448c03SJohnny Huang 	{ 36, 1, 1, "Disable debug interfaces 1" },
17591448c03SJohnny Huang 	{ 37, 1, 0, "Disable ACPI function" },
17691448c03SJohnny Huang 	{ 37, 1, 1, "Enable ACPI function" },
17791448c03SJohnny Huang 	{ 38, 1, 0, "Enable eSPI mode" },
17891448c03SJohnny Huang 	{ 38, 1, 1, "Enable LPC mode" },
17991448c03SJohnny Huang 	{ 39, 1, 0, "Enable SAFS mode" },
18091448c03SJohnny Huang 	{ 39, 1, 1, "Enable SAFS mode" },
18191448c03SJohnny Huang 	{ 40, 2, OTP_REG_RESERVED, "" },
18291448c03SJohnny Huang 	{ 42, 1, 0, "Disable boot SPI 3B/4B address mode auto detection" },
18391448c03SJohnny Huang 	{ 42, 1, 1, "Enable boot SPI 3B/4B address mode auto detection" },
18491448c03SJohnny Huang 	{ 43, 1, 0, "Disable boot SPI ABR" },
18591448c03SJohnny Huang 	{ 43, 1, 1, "Enable boot SPI ABR" },
18691448c03SJohnny Huang 	{ 44, 1, 0, "Boot SPI ABR mode : dual SPI flash" },
18791448c03SJohnny Huang 	{ 44, 1, 1, "Boot SPI ABR mode : single SPI flash" },
18891448c03SJohnny Huang 	{ 45, 3, 0, "Boot SPI flash size : no define size" },
18991448c03SJohnny Huang 	{ 45, 3, 1, "Boot SPI flash size : 2MB" },
19091448c03SJohnny Huang 	{ 45, 3, 2, "Boot SPI flash size : 4MB" },
19191448c03SJohnny Huang 	{ 45, 3, 3, "Boot SPI flash size : 8MB" },
19291448c03SJohnny Huang 	{ 45, 3, 4, "Boot SPI flash size : 16MB" },
19391448c03SJohnny Huang 	{ 45, 3, 5, "Boot SPI flash size : 32MB" },
19491448c03SJohnny Huang 	{ 45, 3, 6, "Boot SPI flash size : 64MB" },
19591448c03SJohnny Huang 	{ 45, 3, 7, "Boot SPI flash size : 128MB" },
19691448c03SJohnny Huang 	{ 48, 1, 0, "Disable host SPI ABR" },
19791448c03SJohnny Huang 	{ 48, 1, 1, "Enable host SPI ABR" },
19891448c03SJohnny Huang 	{ 49, 1, 0, "Disable host SPI ABR mode select pin" },
19991448c03SJohnny Huang 	{ 49, 1, 1, "Enable host SPI ABR mode select pin" },
20091448c03SJohnny Huang 	{ 50, 1, 0, "Host SPI ABR mode : dual SPI flash" },
20191448c03SJohnny Huang 	{ 50, 1, 1, "Host SPI ABR mode : single SPI flash" },
20291448c03SJohnny Huang 	{ 51, 3, 0, "Host SPI flash size : no define size" },
20391448c03SJohnny Huang 	{ 51, 3, 1, "Host SPI flash size : 2MB" },
20491448c03SJohnny Huang 	{ 51, 3, 2, "Host SPI flash size : 4MB" },
20591448c03SJohnny Huang 	{ 51, 3, 3, "Host SPI flash size : 8MB" },
20691448c03SJohnny Huang 	{ 51, 3, 4, "Host SPI flash size : 16MB" },
20791448c03SJohnny Huang 	{ 51, 3, 5, "Host SPI flash size : 32MB" },
20891448c03SJohnny Huang 	{ 51, 3, 6, "Host SPI flash size : 64MB" },
20991448c03SJohnny Huang 	{ 51, 3, 7, "Host SPI flash size : 128MB" },
21091448c03SJohnny Huang 	{ 54, 1, 0, "Disable boot SPI auxiliary control pins" },
21191448c03SJohnny Huang 	{ 54, 1, 1, "Enable boot SPI auxiliary control pins" },
21291448c03SJohnny Huang 	{ 55, 2, 0, "Boot SPI CRTM size : disable CRTM" },
21391448c03SJohnny Huang 	{ 55, 2, 1, "Boot SPI CRTM size : 256KB" },
21491448c03SJohnny Huang 	{ 55, 2, 2, "Boot SPI CRTM size : 512KB" },
21591448c03SJohnny Huang 	{ 55, 2, 3, "Boot SPI CRTM size : 1MB" },
21691448c03SJohnny Huang 	{ 57, 2, 0, "Host SPI CRTM size : disable CRTM" },
21791448c03SJohnny Huang 	{ 57, 2, 1, "Host SPI CRTM size : 256KB" },
21891448c03SJohnny Huang 	{ 57, 2, 2, "Host SPI CRTM size : 512KB" },
21991448c03SJohnny Huang 	{ 57, 2, 3, "Host SPI CRTM size : 1MB" },
22091448c03SJohnny Huang 	{ 59, 1, 0, "Disable host SPI auxiliary control pins" },
22191448c03SJohnny Huang 	{ 59, 1, 1, "Enable host SPI auxiliary control pins" },
22291448c03SJohnny Huang 	{ 60, 1, 0, "Disable GPIO pass through" },
22391448c03SJohnny Huang 	{ 60, 1, 1, "Enable GPIO pass through" },
22491448c03SJohnny Huang 	{ 61, 1, 0, "Enable low security secure boot key" },
22591448c03SJohnny Huang 	{ 61, 1, 1, "Disable low security secure boot key" },
22691448c03SJohnny Huang 	{ 62, 1, 0, "Disable dedicate GPIO strap pins" },
22791448c03SJohnny Huang 	{ 62, 1, 1, "Enable dedicate GPIO strap pins" },
22891448c03SJohnny Huang 	{ 63, 1, OTP_REG_RESERVED, "" }
22976d13988SJohnny Huang };
230*9a4fe690SJohnny Huang 
231b458cd62SJohnny Huang struct otpconf_info a0_conf_info[] = {
23291448c03SJohnny Huang 	{ 0, 0,  1,  0, "Enable Secure Region programming" },
23391448c03SJohnny Huang 	{ 0, 0,  1,  1, "Disable Secure Region programming" },
23491448c03SJohnny Huang 	{ 0, 1,  1,  0, "Disable Secure Boot" },
23591448c03SJohnny Huang 	{ 0, 1,  1,  1, "Enable Secure Boot" },
23691448c03SJohnny Huang 	{ 0, 2,  1,  0, "Initialization programming not done" },
23791448c03SJohnny Huang 	{ 0, 2,  1,  1, "Initialization programming done" },
23891448c03SJohnny Huang 	{ 0, 3,  1,  0, "User region ECC disable" },
23991448c03SJohnny Huang 	{ 0, 3,  1,  1, "User region ECC enable" },
24091448c03SJohnny Huang 	{ 0, 4,  1,  0, "Secure Region ECC disable" },
24191448c03SJohnny Huang 	{ 0, 4,  1,  1, "Secure Region ECC enable" },
24291448c03SJohnny Huang 	{ 0, 5,  1,  0, "Enable low security key" },
24391448c03SJohnny Huang 	{ 0, 5,  1,  1, "Disable low security key" },
24491448c03SJohnny Huang 	{ 0, 6,  1,  0, "Do not ignore Secure Boot hardware strap" },
24591448c03SJohnny Huang 	{ 0, 6,  1,  1, "Ignore Secure Boot hardware strap" },
24691448c03SJohnny Huang 	{ 0, 7,  1,  0, "Secure Boot Mode: 1" },
24791448c03SJohnny Huang 	{ 0, 7,  1,  1, "Secure Boot Mode: 2" },
24891448c03SJohnny Huang 	{ 0, 8,  2,  0, "Single cell mode (recommended)" },
24991448c03SJohnny Huang 	{ 0, 8,  2,  1, "Differnetial mode" },
25091448c03SJohnny Huang 	{ 0, 8,  2,  2, "Differential-redundant mode" },
25191448c03SJohnny Huang 	{ 0, 10, 2,  0, "RSA mode : RSA1024" },
25291448c03SJohnny Huang 	{ 0, 10, 2,  1, "RSA mode : RSA2048" },
25391448c03SJohnny Huang 	{ 0, 10, 2,  2, "RSA mode : RSA3072" },
25491448c03SJohnny Huang 	{ 0, 10, 2,  3, "RSA mode : RSA4096" },
25591448c03SJohnny Huang 	{ 0, 12, 2,  0, "SHA mode : SHA224" },
25691448c03SJohnny Huang 	{ 0, 12, 2,  1, "SHA mode : SHA256" },
25791448c03SJohnny Huang 	{ 0, 12, 2,  2, "SHA mode : SHA384" },
25891448c03SJohnny Huang 	{ 0, 12, 2,  3, "SHA mode : SHA512" },
25991448c03SJohnny Huang 	{ 0, 14, 2,  OTP_REG_RESERVED, "" },
26091448c03SJohnny Huang 	{ 0, 16, 6,  OTP_REG_VALUE, "Secure Region size (DW): 0x%x" },
26191448c03SJohnny Huang 	{ 0, 22, 1,  0, "Secure Region : Writable" },
26291448c03SJohnny Huang 	{ 0, 22, 1,  1, "Secure Region : Write Protect" },
26391448c03SJohnny Huang 	{ 0, 23, 1,  0, "User Region : Writable" },
26491448c03SJohnny Huang 	{ 0, 23, 1,  1, "User Region : Write Protect" },
26591448c03SJohnny Huang 	{ 0, 24, 1,  0, "Configure Region : Writable" },
26691448c03SJohnny Huang 	{ 0, 24, 1,  1, "Configure Region : Write Protect" },
26791448c03SJohnny Huang 	{ 0, 25, 1,  0, "OTP strap Region : Writable" },
26891448c03SJohnny Huang 	{ 0, 25, 1,  1, "OTP strap Region : Write Protect" },
26991448c03SJohnny Huang 	{ 0, 26, 1,  0, "Disable Copy Boot Image to Internal SRAM" },
27091448c03SJohnny Huang 	{ 0, 26, 1,  1, "Copy Boot Image to Internal SRAM" },
27191448c03SJohnny Huang 	{ 0, 27, 1,  0, "Disable image encryption" },
27291448c03SJohnny Huang 	{ 0, 27, 1,  1, "Enable image encryption" },
27391448c03SJohnny Huang 	{ 0, 28, 1,  OTP_REG_RESERVED, "" },
27491448c03SJohnny Huang 	{ 0, 29, 1,  0, "OTP key retire Region : Writable" },
27591448c03SJohnny Huang 	{ 0, 29, 1,  1, "OTP key retire Region : Write Protect" },
27691448c03SJohnny Huang 	{ 0, 30, 1,  0, "SIPROM RED_EN redundancy repair disable" },
27791448c03SJohnny Huang 	{ 0, 30, 1,  1, "SIPROM RED_EN redundancy repair enable" },
27891448c03SJohnny Huang 	{ 0, 31, 1,  0, "SIPROM Mlock memory lock disable" },
27991448c03SJohnny Huang 	{ 0, 31, 1,  1, "SIPROM Mlock memory lock enable" },
28091448c03SJohnny Huang 	{ 2, 0,  16, OTP_REG_VALUE, "Vender ID : 0x%x" },
28191448c03SJohnny Huang 	{ 2, 16, 16, OTP_REG_VALUE, "Key Revision : 0x%x" },
28291448c03SJohnny Huang 	{ 3, 0,  16, OTP_REG_VALUE, "Secure boot header offset : 0x%x" },
28373f11549SJohnny Huang 	{ 4, 0,  8,  OTP_REG_VALID_BIT, "Keys valid  : %s" },
28473f11549SJohnny Huang 	{ 4, 16, 8,  OTP_REG_VALID_BIT, "Keys retire  : %s" },
28591448c03SJohnny Huang 	{ 5, 0,  32, OTP_REG_VALUE, "User define data, random number low : 0x%x" },
28691448c03SJohnny Huang 	{ 6, 0,  32, OTP_REG_VALUE, "User define data, random number high : 0x%x" },
28791448c03SJohnny Huang 	{ 7, 0,  1,  0, "Force enable PCI bus to AHB bus bridge" },
28891448c03SJohnny Huang 	{ 7, 0,  1,  1, "Force disable PCI bus to AHB bus bridge" },
28991448c03SJohnny Huang 	{ 7, 1,  1,  0, "Force enable UART5 debug port function" },
29091448c03SJohnny Huang 	{ 7, 1,  1,  1, "Force disable UART5 debug port function" },
29191448c03SJohnny Huang 	{ 7, 2,  1,  0, "Force enable XDMA function" },
29291448c03SJohnny Huang 	{ 7, 2,  1,  1, "Force disable XDMA function" },
29391448c03SJohnny Huang 	{ 7, 3,  1,  0, "Force enable APB to PCIE device bridge" },
29491448c03SJohnny Huang 	{ 7, 3,  1,  1, "Force disable APB to PCIE device bridge" },
29591448c03SJohnny Huang 	{ 7, 4,  1,  0, "Force enable APB to PCIE bridge config access" },
29691448c03SJohnny Huang 	{ 7, 4,  1,  1, "Force disable APB to PCIE bridge config access" },
29791448c03SJohnny Huang 	{ 7, 5,  1,  0, "Force enable PCIE bus trace buffer" },
29891448c03SJohnny Huang 	{ 7, 5,  1,  1, "Force disable PCIE bus trace buffer" },
29991448c03SJohnny Huang 	{ 7, 6,  1,  0, "Force enable the capability for PCIE device port as a Root Complex" },
30091448c03SJohnny Huang 	{ 7, 6,  1,  1, "Force disable the capability for PCIE device port as a Root Complex" },
30191448c03SJohnny Huang 	{ 7, 16, 1,  0, "Force enable ESPI bus to AHB bus bridge" },
30291448c03SJohnny Huang 	{ 7, 16, 1,  1, "Force disable ESPI bus to AHB bus bridge" },
30391448c03SJohnny Huang 	{ 7, 17, 1,  0, "Force enable LPC bus to AHB bus bridge1" },
30491448c03SJohnny Huang 	{ 7, 17, 1,  1, "Force disable LPC bus to AHB bus bridge1" },
30591448c03SJohnny Huang 	{ 7, 18, 1,  0, "Force enable LPC bus to AHB bus bridge2" },
30691448c03SJohnny Huang 	{ 7, 18, 1,  1, "Force disable LPC bus to AHB bus bridge2" },
30791448c03SJohnny Huang 	{ 7, 19, 1,  0, "Force enable UART1 debug port function" },
30891448c03SJohnny Huang 	{ 7, 19, 1,  1, "Force disable UART1 debug port function" },
30991448c03SJohnny Huang 	{ 7, 31, 1,  0, "Disable chip security setting" },
31091448c03SJohnny Huang 	{ 7, 31, 1,  1, "Enable chip security setting" },
31191448c03SJohnny Huang 	{ 8, 0,  32, OTP_REG_VALUE, "Redundancy Repair : 0x%x" },
31291448c03SJohnny Huang 	{ 10, 0, 32, OTP_REG_VALUE, "Manifest ID low : 0x%x" },
31391448c03SJohnny Huang 	{ 11, 0, 32, OTP_REG_VALUE, "Manifest ID high : 0x%x" }
314b458cd62SJohnny Huang };
315*9a4fe690SJohnny Huang 
316*9a4fe690SJohnny Huang struct otpkey_type a0_key_type[] = {
317*9a4fe690SJohnny Huang 	{0, OTP_KEY_TYPE_AES,   0, "AES-256 as OEM platform key for image encryption/decryption"},
318*9a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
319*9a4fe690SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,  1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
320*9a4fe690SJohnny Huang 	{8, OTP_KEY_TYPE_RSA,   1, "RSA-public as OEM DSS public keys in Mode 2"},
321*9a4fe690SJohnny Huang 	{9, OTP_KEY_TYPE_RSA,   0, "RSA-public as SOC public key"},
322*9a4fe690SJohnny Huang 	{10, OTP_KEY_TYPE_RSA,  0, "RSA-public as AES key decryption key"},
323*9a4fe690SJohnny Huang 	{13, OTP_KEY_TYPE_RSA,  0, "RSA-private as SOC private key"},
324*9a4fe690SJohnny Huang 	{14, OTP_KEY_TYPE_RSA,  0, "RSA-private as AES key decryption key"},
325*9a4fe690SJohnny Huang };
326*9a4fe690SJohnny Huang 
327*9a4fe690SJohnny Huang struct otpkey_type a1_key_type[] = {
328*9a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
329*9a4fe690SJohnny Huang 	{2, OTP_KEY_TYPE_AES,   1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
330*9a4fe690SJohnny Huang 	{8, OTP_KEY_TYPE_RSA,   1, "RSA-public as OEM DSS public keys in Mode 2"},
331*9a4fe690SJohnny Huang 	{10, OTP_KEY_TYPE_RSA,  0, "RSA-public as AES key decryption key"},
332*9a4fe690SJohnny Huang 	{14, OTP_KEY_TYPE_RSA,  0, "RSA-private as AES key decryption key"},
333*9a4fe690SJohnny Huang };
334*9a4fe690SJohnny Huang 
335*9a4fe690SJohnny Huang static uint32_t chip_version(void)
336*9a4fe690SJohnny Huang {
337*9a4fe690SJohnny Huang 	uint32_t rev_id;
338*9a4fe690SJohnny Huang 
339*9a4fe690SJohnny Huang 	rev_id = (readl(0x1e6e2004) >> 16) & 0xff ;
340*9a4fe690SJohnny Huang 
341*9a4fe690SJohnny Huang 	return rev_id;
342*9a4fe690SJohnny Huang }
343*9a4fe690SJohnny Huang 
3442a856b9aSJohnny Huang static void otp_read_data(uint32_t offset, uint32_t *data)
34569d5fd8fSJohnny Huang {
34669d5fd8fSJohnny Huang 	writel(offset, 0x1e6f2010); //Read address
34769d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
34869d5fd8fSJohnny Huang 	udelay(2);
34969d5fd8fSJohnny Huang 	data[0] = readl(0x1e6f2020);
35069d5fd8fSJohnny Huang 	data[1] = readl(0x1e6f2024);
35169d5fd8fSJohnny Huang }
35269d5fd8fSJohnny Huang 
3532a856b9aSJohnny Huang static void otp_read_config(uint32_t offset, uint32_t *data)
35469d5fd8fSJohnny Huang {
35569d5fd8fSJohnny Huang 	int config_offset;
35669d5fd8fSJohnny Huang 
35769d5fd8fSJohnny Huang 	config_offset = 0x800;
35869d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
35969d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
36069d5fd8fSJohnny Huang 
36169d5fd8fSJohnny Huang 	writel(config_offset, 0x1e6f2010);  //Read address
36269d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
36369d5fd8fSJohnny Huang 	udelay(2);
36469d5fd8fSJohnny Huang 	data[0] = readl(0x1e6f2020);
36569d5fd8fSJohnny Huang }
36669d5fd8fSJohnny Huang 
36769d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count)
36869d5fd8fSJohnny Huang {
36969d5fd8fSJohnny Huang 	int i;
37069d5fd8fSJohnny Huang 	uint32_t ret[1];
37169d5fd8fSJohnny Huang 
37269d5fd8fSJohnny Huang 	if (offset + dw_count > 32)
3732a856b9aSJohnny Huang 		return OTP_USAGE;
37469d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i ++) {
37569d5fd8fSJohnny Huang 		otp_read_config(i, ret);
376a6af4a17SJohnny Huang 		printf("OTPCFG%X: %08X\n", i, ret[0]);
37769d5fd8fSJohnny Huang 	}
37869d5fd8fSJohnny Huang 	printf("\n");
3792a856b9aSJohnny Huang 	return OTP_SUCCESS;
38069d5fd8fSJohnny Huang }
38169d5fd8fSJohnny Huang 
38269d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count)
38369d5fd8fSJohnny Huang {
38469d5fd8fSJohnny Huang 	int i;
38569d5fd8fSJohnny Huang 	uint32_t ret[2];
38669d5fd8fSJohnny Huang 
38769d5fd8fSJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
3882a856b9aSJohnny Huang 		return OTP_USAGE;
38969d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
39069d5fd8fSJohnny Huang 		otp_read_data(i, ret);
39169d5fd8fSJohnny Huang 		if (i % 4 == 0)
39269d5fd8fSJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
39369d5fd8fSJohnny Huang 		else
39469d5fd8fSJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
39569d5fd8fSJohnny Huang 
39669d5fd8fSJohnny Huang 	}
39769d5fd8fSJohnny Huang 	printf("\n");
3982a856b9aSJohnny Huang 	return OTP_SUCCESS;
39969d5fd8fSJohnny Huang }
40069d5fd8fSJohnny Huang 
40169d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr)
40269d5fd8fSJohnny Huang {
40369d5fd8fSJohnny Huang 	uint32_t ret;
40469d5fd8fSJohnny Huang 	uint32_t *buf;
40569d5fd8fSJohnny Huang 
40669d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
40769d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
40869d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
40969d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
41069d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
41169d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //Compare address
41269d5fd8fSJohnny Huang 	writel(buf[0], 0x1e6f2020); //Compare data 1
41369d5fd8fSJohnny Huang 	writel(buf[1], 0x1e6f2024); //Compare data 2
41469d5fd8fSJohnny Huang 	writel(buf[2], 0x1e6f2028); //Compare data 3
41569d5fd8fSJohnny Huang 	writel(buf[3], 0x1e6f202c); //Compare data 4
41669d5fd8fSJohnny Huang 	writel(0x23b1e363, 0x1e6f2004); //Compare command
41769d5fd8fSJohnny Huang 	udelay(10);
41869d5fd8fSJohnny Huang 	ret = readl(0x1e6f2014); //Compare command
41969d5fd8fSJohnny Huang 	if (ret & 0x1)
42069d5fd8fSJohnny Huang 		return 0;
42169d5fd8fSJohnny Huang 	else
42269d5fd8fSJohnny Huang 		return -1;
42369d5fd8fSJohnny Huang }
42469d5fd8fSJohnny Huang 
42569d5fd8fSJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data)
42669d5fd8fSJohnny Huang {
42769d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //write address
42869d5fd8fSJohnny Huang 	writel(data, 0x1e6f2020); //write data
42969d5fd8fSJohnny Huang 	writel(0x23b1e362, 0x1e6f2004); //write command
43069d5fd8fSJohnny Huang 	udelay(100);
43169d5fd8fSJohnny Huang }
43269d5fd8fSJohnny Huang 
43369d5fd8fSJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit)
43469d5fd8fSJohnny Huang {
43569d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //write address
43669d5fd8fSJohnny Huang 	writel(prog_bit, 0x1e6f2020); //write data
43769d5fd8fSJohnny Huang 	writel(0x23b1e364, 0x1e6f2004); //write command
43869d5fd8fSJohnny Huang 	udelay(85);
43969d5fd8fSJohnny Huang }
44069d5fd8fSJohnny Huang 
441a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value)
44269d5fd8fSJohnny Huang {
44369d5fd8fSJohnny Huang 	int ret;
44469d5fd8fSJohnny Huang 
44569d5fd8fSJohnny Huang 	writel(otp_addr, 0x1e6f2010); //Read address
44669d5fd8fSJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
44769d5fd8fSJohnny Huang 	udelay(2);
44869d5fd8fSJohnny Huang 	ret = readl(0x1e6f2020);
449a6d0d645SJohnny Huang 	// printf("verify_bit = %x\n", ret);
45069d5fd8fSJohnny Huang 	if (((ret >> bit_offset) & 1) == value)
45169d5fd8fSJohnny Huang 		return 0;
45269d5fd8fSJohnny Huang 	else
45369d5fd8fSJohnny Huang 		return -1;
45469d5fd8fSJohnny Huang }
45569d5fd8fSJohnny Huang 
456d90825e2SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *keep, uint32_t *compare, int size)
4574c1c9b35SJohnny Huang {
4584c1c9b35SJohnny Huang 	uint32_t ret[2];
4594c1c9b35SJohnny Huang 
4604c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
4614c1c9b35SJohnny Huang 
4624c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
4634c1c9b35SJohnny Huang 		writel(otp_addr, 0x1e6f2010); //Read address
4644c1c9b35SJohnny Huang 	else
4654c1c9b35SJohnny Huang 		writel(otp_addr - 1, 0x1e6f2010); //Read address
4664c1c9b35SJohnny Huang 	writel(0x23b1e361, 0x1e6f2004); //trigger read
4674c1c9b35SJohnny Huang 	udelay(2);
4684c1c9b35SJohnny Huang 	ret[0] = readl(0x1e6f2020);
4694c1c9b35SJohnny Huang 	ret[1] = readl(0x1e6f2024);
4704c1c9b35SJohnny Huang 	if (size == 1) {
4714c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
4724c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
473d90825e2SJohnny Huang 			if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0])) {
4744c1c9b35SJohnny Huang 				compare[0] = 0;
4754c1c9b35SJohnny Huang 				return 0;
4764c1c9b35SJohnny Huang 			} else {
4774c1c9b35SJohnny Huang 				compare[0] = value[0] ^ ret[0];
4784c1c9b35SJohnny Huang 				return -1;
4794c1c9b35SJohnny Huang 			}
4804c1c9b35SJohnny Huang 
4814c1c9b35SJohnny Huang 		} else {
4824c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
483d90825e2SJohnny Huang 			if ((value[0] & ~keep[0]) == (ret[1] & ~keep[0])) {
4844c1c9b35SJohnny Huang 				compare[0] = ~0;
4854c1c9b35SJohnny Huang 				return 0;
4864c1c9b35SJohnny Huang 			} else {
487d90825e2SJohnny Huang 				compare[0] = ~(value[0] ^ ret[1]);
4884c1c9b35SJohnny Huang 				return -1;
4894c1c9b35SJohnny Huang 			}
4904c1c9b35SJohnny Huang 		}
4914c1c9b35SJohnny Huang 	} else if (size == 2) {
4924c1c9b35SJohnny Huang 		// otp_addr should be even
493d90825e2SJohnny Huang 		if ((value[0] & ~keep[0]) == (ret[0] & ~keep[0]) && (value[1] & ~keep[1]) == (ret[1] & ~keep[1])) {
4944c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4954c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4964c1c9b35SJohnny Huang 			compare[0] = 0;
4974c1c9b35SJohnny Huang 			compare[1] = ~0;
4984c1c9b35SJohnny Huang 			return 0;
4994c1c9b35SJohnny Huang 		} else {
5004c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
5014c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
5024c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
5034c1c9b35SJohnny Huang 			compare[1] = ~(value[1] ^ ret[1]);
5044c1c9b35SJohnny Huang 			return -1;
5054c1c9b35SJohnny Huang 		}
5064c1c9b35SJohnny Huang 	} else {
5074c1c9b35SJohnny Huang 		return -1;
5084c1c9b35SJohnny Huang 	}
5094c1c9b35SJohnny Huang }
5104c1c9b35SJohnny Huang 
5117e22f42dSJohnny Huang static void otp_soak(int soak)
512d90825e2SJohnny Huang {
513d90825e2SJohnny Huang 	if (soak) {
514d90825e2SJohnny Huang 		otp_write(0x3000, 0x4021); // Write MRA
515d90825e2SJohnny Huang 		otp_write(0x5000, 0x1027); // Write MRB
516d90825e2SJohnny Huang 		otp_write(0x1000, 0x4820); // Write MR
517d90825e2SJohnny Huang 		writel(0x041930d4, 0x1e602008); //soak program
518d90825e2SJohnny Huang 	} else {
519d90825e2SJohnny Huang 		otp_write(0x3000, 0x4061); // Write MRA
520d90825e2SJohnny Huang 		otp_write(0x5000, 0x302f); // Write MRB
521d90825e2SJohnny Huang 		otp_write(0x1000, 0x4020); // Write MR
522d90825e2SJohnny Huang 		writel(0x04190760, 0x1e602008); //normal program
523d90825e2SJohnny Huang 	}
524d90825e2SJohnny Huang }
525d90825e2SJohnny Huang 
526d90825e2SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t keep, uint32_t prog_address)
527d90825e2SJohnny Huang {
528d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
529d90825e2SJohnny Huang 
530d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
531d90825e2SJohnny Huang 		if ((keep >> j) & 0x1)
532d90825e2SJohnny Huang 			continue;
533d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
534d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
535d90825e2SJohnny Huang 			if (bit_value)
536d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
537d90825e2SJohnny Huang 			else
538d90825e2SJohnny Huang 				continue;
539d90825e2SJohnny Huang 		} else {
540d90825e2SJohnny Huang 			prog_address |= 1 << 15;
541d90825e2SJohnny Huang 			if (bit_value)
542d90825e2SJohnny Huang 				continue;
543d90825e2SJohnny Huang 			else
544d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
545d90825e2SJohnny Huang 		}
546d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
547d90825e2SJohnny Huang 	}
548d90825e2SJohnny Huang }
549d90825e2SJohnny Huang 
55076d13988SJohnny Huang 
55176d13988SJohnny Huang static void otp_strp_status(struct otpstrap_status *otpstrap)
55276d13988SJohnny Huang {
55376d13988SJohnny Huang 	uint32_t OTPSTRAP_RAW[2];
55476d13988SJohnny Huang 	int i, j;
55576d13988SJohnny Huang 
55676d13988SJohnny Huang 	for (j = 0; j < 64; j++) {
55776d13988SJohnny Huang 		otpstrap[j].value = 0;
55876d13988SJohnny Huang 		otpstrap[j].remain_times = 7;
55976d13988SJohnny Huang 		otpstrap[j].writeable_option = -1;
56076d13988SJohnny Huang 		otpstrap[j].protected = 0;
56176d13988SJohnny Huang 	}
56276d13988SJohnny Huang 
56376d13988SJohnny Huang 	for (i = 16; i < 30; i += 2) {
56476d13988SJohnny Huang 		int option = (i - 16) / 2;
56576d13988SJohnny Huang 		otp_read_config(i, &OTPSTRAP_RAW[0]);
56676d13988SJohnny Huang 		otp_read_config(i + 1, &OTPSTRAP_RAW[1]);
56776d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
56876d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
56976d13988SJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
57076d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
57176d13988SJohnny Huang 			}
57276d13988SJohnny Huang 			if (bit_value == 1)
57376d13988SJohnny Huang 				otpstrap[j].remain_times --;
57476d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
57576d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
57676d13988SJohnny Huang 		}
57776d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
57876d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
57976d13988SJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
58076d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
58176d13988SJohnny Huang 			}
58276d13988SJohnny Huang 			if (bit_value == 1)
58376d13988SJohnny Huang 				otpstrap[j].remain_times --;
58476d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
58576d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
58676d13988SJohnny Huang 		}
58776d13988SJohnny Huang 	}
58876d13988SJohnny Huang 	otp_read_config(30, &OTPSTRAP_RAW[0]);
58976d13988SJohnny Huang 	otp_read_config(31, &OTPSTRAP_RAW[1]);
59076d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
59176d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
59276d13988SJohnny Huang 			otpstrap[j].protected = 1;
59376d13988SJohnny Huang 	}
59476d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
59576d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
59676d13988SJohnny Huang 			otpstrap[j].protected = 1;
59776d13988SJohnny Huang 	}
59876d13988SJohnny Huang }
59976d13988SJohnny Huang 
600b458cd62SJohnny Huang static int otp_print_conf_image(uint32_t *OTPCFG)
60169d5fd8fSJohnny Huang {
602442839bbSJohnny Huang 	uint32_t *OTPCFG_KEEP = &OTPCFG[12];
603b458cd62SJohnny Huang 	uint32_t mask;
604b458cd62SJohnny Huang 	uint32_t dw_offset;
605b458cd62SJohnny Huang 	uint32_t bit_offset;
606b458cd62SJohnny Huang 	uint32_t otp_value;
607b458cd62SJohnny Huang 	uint32_t otp_keep;
608b458cd62SJohnny Huang 	int fail = 0;
60973f11549SJohnny Huang 	char valid_bit[20];
61066f2f8e5SJohnny Huang 	int i;
61173f11549SJohnny Huang 	int j;
61266f2f8e5SJohnny Huang 
613737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
61466f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
615b458cd62SJohnny Huang 	for (i = 0; i < ARRAY_SIZE(a0_conf_info); i++) {
616b458cd62SJohnny Huang 		dw_offset = a0_conf_info[i].dw_offset;
617b458cd62SJohnny Huang 		bit_offset = a0_conf_info[i].bit_offset;
618b458cd62SJohnny Huang 		mask = BIT(a0_conf_info[i].length) - 1;
619b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
620b458cd62SJohnny Huang 		otp_keep = (OTPCFG_KEEP[dw_offset] >> bit_offset) & mask;
621b458cd62SJohnny Huang 
622b458cd62SJohnny Huang 		if (otp_keep == mask) {
623b458cd62SJohnny Huang 			continue;
624b458cd62SJohnny Huang 		} else if (otp_keep != 0) {
625b458cd62SJohnny Huang 			fail = 1;
626b458cd62SJohnny Huang 		}
627b458cd62SJohnny Huang 
628b458cd62SJohnny Huang 		if ((otp_value != a0_conf_info[i].value) &&
629b458cd62SJohnny Huang 		    a0_conf_info[i].value != OTP_REG_RESERVED &&
630b458cd62SJohnny Huang 		    a0_conf_info[i].value != OTP_REG_VALUE &&
631b458cd62SJohnny Huang 		    a0_conf_info[i].value != OTP_REG_VALID_BIT)
632b458cd62SJohnny Huang 			continue;
633b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
634b458cd62SJohnny Huang 
635b458cd62SJohnny Huang 		if (a0_conf_info[i].length == 1) {
636b458cd62SJohnny Huang 			printf("0x%-9X", a0_conf_info[i].bit_offset);
63766f2f8e5SJohnny Huang 		} else {
638b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
639b458cd62SJohnny Huang 			       a0_conf_info[i].bit_offset + a0_conf_info[i].length - 1,
640b458cd62SJohnny Huang 			       a0_conf_info[i].bit_offset);
64166f2f8e5SJohnny Huang 		}
642b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
643b458cd62SJohnny Huang 
644b458cd62SJohnny Huang 		if (fail) {
645b458cd62SJohnny Huang 			printf("Keep mask error\n");
646b458cd62SJohnny Huang 		} else {
647b458cd62SJohnny Huang 			if (a0_conf_info[i].value == OTP_REG_RESERVED) {
648b458cd62SJohnny Huang 				printf("Reserved\n");
649b458cd62SJohnny Huang 			} else if (a0_conf_info[i].value == OTP_REG_VALUE) {
650b458cd62SJohnny Huang 				printf(a0_conf_info[i].information, otp_value);
651b458cd62SJohnny Huang 				printf("\n");
652b458cd62SJohnny Huang 			} else if (a0_conf_info[i].value == OTP_REG_VALID_BIT) {
653b458cd62SJohnny Huang 				if (otp_value != 0) {
65473f11549SJohnny Huang 					for (j = 0; j < 7; j++) {
65573f11549SJohnny Huang 						if (otp_value == (1 << j)) {
65673f11549SJohnny Huang 							valid_bit[j * 2] = '1';
657b458cd62SJohnny Huang 						} else {
65873f11549SJohnny Huang 							valid_bit[j * 2] = '0';
65973f11549SJohnny Huang 						}
66073f11549SJohnny Huang 						valid_bit[j * 2 + 1] = ' ';
66173f11549SJohnny Huang 					}
66273f11549SJohnny Huang 					valid_bit[15] = 0;
66373f11549SJohnny Huang 				} else {
66473f11549SJohnny Huang 					strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
665b458cd62SJohnny Huang 				}
666b458cd62SJohnny Huang 				printf(a0_conf_info[i].information, valid_bit);
667b458cd62SJohnny Huang 				printf("\n");
668b458cd62SJohnny Huang 			} else {
669b458cd62SJohnny Huang 				printf("%s\n", a0_conf_info[i].information);
670b458cd62SJohnny Huang 			}
671b458cd62SJohnny Huang 		}
672b458cd62SJohnny Huang 	}
673b458cd62SJohnny Huang 
674b458cd62SJohnny Huang 	if (fail)
675b458cd62SJohnny Huang 		return OTP_FAILURE;
676b458cd62SJohnny Huang 
67766f2f8e5SJohnny Huang 	return OTP_SUCCESS;
67866f2f8e5SJohnny Huang }
67966f2f8e5SJohnny Huang 
6802d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
68166f2f8e5SJohnny Huang {
682b458cd62SJohnny Huang 	uint32_t OTPCFG[12];
683b458cd62SJohnny Huang 	uint32_t mask;
684b458cd62SJohnny Huang 	uint32_t dw_offset;
685b458cd62SJohnny Huang 	uint32_t bit_offset;
686b458cd62SJohnny Huang 	uint32_t otp_value;
68773f11549SJohnny Huang 	char valid_bit[20];
68866f2f8e5SJohnny Huang 	int i;
68973f11549SJohnny Huang 	int j;
69066f2f8e5SJohnny Huang 
69166f2f8e5SJohnny Huang 	for (i = 0; i < 12; i++)
69266f2f8e5SJohnny Huang 		otp_read_config(i, &OTPCFG[i]);
69366f2f8e5SJohnny Huang 
69466f2f8e5SJohnny Huang 
695b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
696b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
697b458cd62SJohnny Huang 	for (i = 0; i < ARRAY_SIZE(a0_conf_info); i++) {
6982d4b0742SJohnny Huang 		if (input_offset != -1 && input_offset != a0_conf_info[i].dw_offset)
6992d4b0742SJohnny Huang 			continue;
700b458cd62SJohnny Huang 		dw_offset = a0_conf_info[i].dw_offset;
701b458cd62SJohnny Huang 		bit_offset = a0_conf_info[i].bit_offset;
702b458cd62SJohnny Huang 		mask = BIT(a0_conf_info[i].length) - 1;
703b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
704b458cd62SJohnny Huang 
705b458cd62SJohnny Huang 		if ((otp_value != a0_conf_info[i].value) &&
706b458cd62SJohnny Huang 		    a0_conf_info[i].value != OTP_REG_RESERVED &&
707b458cd62SJohnny Huang 		    a0_conf_info[i].value != OTP_REG_VALUE &&
708b458cd62SJohnny Huang 		    a0_conf_info[i].value != OTP_REG_VALID_BIT)
709b458cd62SJohnny Huang 			continue;
710b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
711b458cd62SJohnny Huang 
712b458cd62SJohnny Huang 		if (a0_conf_info[i].length == 1) {
713b458cd62SJohnny Huang 			printf("0x%-9X", a0_conf_info[i].bit_offset);
714b458cd62SJohnny Huang 		} else {
715b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
716b458cd62SJohnny Huang 			       a0_conf_info[i].bit_offset + a0_conf_info[i].length - 1,
717b458cd62SJohnny Huang 			       a0_conf_info[i].bit_offset);
718b458cd62SJohnny Huang 		}
719b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
720b458cd62SJohnny Huang 
721b458cd62SJohnny Huang 		if (a0_conf_info[i].value == OTP_REG_RESERVED) {
722b458cd62SJohnny Huang 			printf("Reserved\n");
723b458cd62SJohnny Huang 		} else if (a0_conf_info[i].value == OTP_REG_VALUE) {
724b458cd62SJohnny Huang 			printf(a0_conf_info[i].information, otp_value);
725b458cd62SJohnny Huang 			printf("\n");
726b458cd62SJohnny Huang 		} else if (a0_conf_info[i].value == OTP_REG_VALID_BIT) {
727b458cd62SJohnny Huang 			if (otp_value != 0) {
72873f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
72973f11549SJohnny Huang 					if (otp_value == (1 << j)) {
73073f11549SJohnny Huang 						valid_bit[j * 2] = '1';
731b458cd62SJohnny Huang 					} else {
73273f11549SJohnny Huang 						valid_bit[j * 2] = '0';
73373f11549SJohnny Huang 					}
73473f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
73573f11549SJohnny Huang 				}
73673f11549SJohnny Huang 				valid_bit[15] = 0;
73773f11549SJohnny Huang 			} else {
73873f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
739b458cd62SJohnny Huang 			}
740b458cd62SJohnny Huang 			printf(a0_conf_info[i].information, valid_bit);
741b458cd62SJohnny Huang 			printf("\n");
742b458cd62SJohnny Huang 		} else {
743b458cd62SJohnny Huang 			printf("%s\n", a0_conf_info[i].information);
744b458cd62SJohnny Huang 		}
745b458cd62SJohnny Huang 	}
746b458cd62SJohnny Huang 	return OTP_SUCCESS;
74766f2f8e5SJohnny Huang }
74866f2f8e5SJohnny Huang 
749b458cd62SJohnny Huang static int otp_print_strap_image(uint32_t *OTPSTRAP)
75076d13988SJohnny Huang {
751a8bd6d8cSJohnny Huang 	uint32_t *OTPSTRAP_PRO = &OTPSTRAP[4];
752a8bd6d8cSJohnny Huang 	uint32_t *OTPSTRAP_KEEP = &OTPSTRAP[2];
75376d13988SJohnny Huang 	int i;
754a8bd6d8cSJohnny Huang 	int fail = 0;
755a8bd6d8cSJohnny Huang 	uint32_t bit_offset;
756a8bd6d8cSJohnny Huang 	uint32_t dw_offset;
757a8bd6d8cSJohnny Huang 	uint32_t mask;
758a8bd6d8cSJohnny Huang 	uint32_t otp_value;
759a8bd6d8cSJohnny Huang 	uint32_t otp_protect;
760a8bd6d8cSJohnny Huang 	uint32_t otp_keep;
76176d13988SJohnny Huang 
762a8bd6d8cSJohnny Huang 	printf("BIT(hex)   Value       Protect     Description\n");
763a8bd6d8cSJohnny Huang 	printf("__________________________________________________________________________________________\n");
764b458cd62SJohnny Huang 
765a8bd6d8cSJohnny Huang 	for (i = 0; i < ARRAY_SIZE(a0_strap_info); i++) {
766a8bd6d8cSJohnny Huang 		if (a0_strap_info[i].bit_offset > 32) {
767a8bd6d8cSJohnny Huang 			dw_offset = 1;
768a8bd6d8cSJohnny Huang 			bit_offset = a0_strap_info[i].bit_offset - 32;
769a8bd6d8cSJohnny Huang 		} else {
770a8bd6d8cSJohnny Huang 			dw_offset = 0;
771a8bd6d8cSJohnny Huang 			bit_offset = a0_strap_info[i].bit_offset;
772a8bd6d8cSJohnny Huang 		}
77376d13988SJohnny Huang 
774a8bd6d8cSJohnny Huang 		mask = BIT(a0_strap_info[i].length) - 1;
775a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
776a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
777a8bd6d8cSJohnny Huang 		otp_keep = (OTPSTRAP_KEEP[dw_offset] >> bit_offset) & mask;
778a8bd6d8cSJohnny Huang 
779a8bd6d8cSJohnny Huang 		if (otp_keep == mask) {
780a8bd6d8cSJohnny Huang 			continue;
781a8bd6d8cSJohnny Huang 		} else if (otp_keep != 0) {
782a8bd6d8cSJohnny Huang 			fail = 1;
783a8bd6d8cSJohnny Huang 		}
784a8bd6d8cSJohnny Huang 
785a8bd6d8cSJohnny Huang 		if ((otp_value != a0_strap_info[i].value) &&
786a8bd6d8cSJohnny Huang 		    a0_strap_info[i].value != OTP_REG_RESERVED)
787a8bd6d8cSJohnny Huang 			continue;
788a8bd6d8cSJohnny Huang 
789a8bd6d8cSJohnny Huang 		if (a0_strap_info[i].length == 1) {
790b458cd62SJohnny Huang 			printf("0x%-9X", a0_strap_info[i].bit_offset);
791a8bd6d8cSJohnny Huang 		} else {
792b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
793a8bd6d8cSJohnny Huang 			       a0_strap_info[i].bit_offset + a0_strap_info[i].length - 1,
794a8bd6d8cSJohnny Huang 			       a0_strap_info[i].bit_offset);
795a8bd6d8cSJohnny Huang 		}
796a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
797a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
798a8bd6d8cSJohnny Huang 
799a8bd6d8cSJohnny Huang 		if (fail) {
800a8bd6d8cSJohnny Huang 			printf("Keep mask error\n");
801a8bd6d8cSJohnny Huang 		} else {
802a8bd6d8cSJohnny Huang 			if (a0_strap_info[i].value != OTP_REG_RESERVED)
803a8bd6d8cSJohnny Huang 				printf("%s\n", a0_strap_info[i].information);
804a8bd6d8cSJohnny Huang 			else
805a8bd6d8cSJohnny Huang 				printf("Reserved\n");
806a8bd6d8cSJohnny Huang 		}
807a8bd6d8cSJohnny Huang 	}
808a8bd6d8cSJohnny Huang 
809a8bd6d8cSJohnny Huang 	if (fail)
81076d13988SJohnny Huang 		return OTP_FAILURE;
81176d13988SJohnny Huang 
81276d13988SJohnny Huang 	return OTP_SUCCESS;
81376d13988SJohnny Huang }
81476d13988SJohnny Huang 
815b458cd62SJohnny Huang static int otp_print_strap_info(int view)
81676d13988SJohnny Huang {
81776d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
81807baa4e8SJohnny Huang 	int i, j;
819b458cd62SJohnny Huang 	int fail = 0;
820b458cd62SJohnny Huang 	uint32_t bit_offset;
821b458cd62SJohnny Huang 	uint32_t length;
822b458cd62SJohnny Huang 	uint32_t otp_value;
823b458cd62SJohnny Huang 	uint32_t otp_protect;
82476d13988SJohnny Huang 
82576d13988SJohnny Huang 	otp_strp_status(strap_status);
82676d13988SJohnny Huang 
827b458cd62SJohnny Huang 	if (view) {
82807baa4e8SJohnny Huang 		// printf("BIT(hex) Value  Option         Protect   Description\n");
82907baa4e8SJohnny Huang 		// printf("                0 1 2 3 4 5 6\n");
83007baa4e8SJohnny Huang 		printf("BIT(hex) Value  Remains  Protect   Description\n");
83107baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
832b458cd62SJohnny Huang 	} else {
833b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
834b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
83576d13988SJohnny Huang 	}
836b458cd62SJohnny Huang 	for (i = 0; i < ARRAY_SIZE(a0_strap_info); i++) {
837b458cd62SJohnny Huang 		otp_value = 0;
838b458cd62SJohnny Huang 		bit_offset = a0_strap_info[i].bit_offset;
839b458cd62SJohnny Huang 		length = a0_strap_info[i].length;
840b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
841c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
842c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
843b458cd62SJohnny Huang 		}
844b458cd62SJohnny Huang 		if ((otp_value != a0_strap_info[i].value) &&
845b458cd62SJohnny Huang 		    a0_strap_info[i].value != OTP_REG_RESERVED)
846b458cd62SJohnny Huang 			continue;
847b458cd62SJohnny Huang 		if (view) {
848b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
849b458cd62SJohnny Huang 				printf("0x%-7X", a0_strap_info[i].bit_offset + j);
850b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
85107baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
852b458cd62SJohnny Huang 				printf("0x%-7X", strap_status[bit_offset].protected);
853b458cd62SJohnny Huang 				if (a0_strap_info[i].value == OTP_REG_RESERVED) {
854b458cd62SJohnny Huang 					printf(" Reserved\n");
855b458cd62SJohnny Huang 					continue;
856b458cd62SJohnny Huang 				}
857b458cd62SJohnny Huang 				if (length == 1) {
858b458cd62SJohnny Huang 					printf(" %s\n", a0_strap_info[i].information);
859b458cd62SJohnny Huang 					continue;
86076d13988SJohnny Huang 				}
86176d13988SJohnny Huang 
862b458cd62SJohnny Huang 				if (j == 0)
863b458cd62SJohnny Huang 					printf("/%s\n", a0_strap_info[i].information);
864b458cd62SJohnny Huang 				else if (j == length - 1)
865b458cd62SJohnny Huang 					printf("\\ \"\n");
866b458cd62SJohnny Huang 				else
867b458cd62SJohnny Huang 					printf("| \"\n");
86876d13988SJohnny Huang 			}
869b458cd62SJohnny Huang 		} else {
870c947ef08SJohnny Huang 			if (length == 1) {
871b458cd62SJohnny Huang 				printf("0x%-9X", a0_strap_info[i].bit_offset);
872b458cd62SJohnny Huang 			} else {
873b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
874b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
875b458cd62SJohnny Huang 			}
876b458cd62SJohnny Huang 
877b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
878b458cd62SJohnny Huang 
879b458cd62SJohnny Huang 			if (a0_strap_info[i].value != OTP_REG_RESERVED)
880b458cd62SJohnny Huang 				printf("%s\n", a0_strap_info[i].information);
881b458cd62SJohnny Huang 			else
882b458cd62SJohnny Huang 				printf("Reserved\n");
883b458cd62SJohnny Huang 		}
884b458cd62SJohnny Huang 	}
885b458cd62SJohnny Huang 
886b458cd62SJohnny Huang 	if (fail)
887b458cd62SJohnny Huang 		return OTP_FAILURE;
888b458cd62SJohnny Huang 
889b458cd62SJohnny Huang 	return OTP_SUCCESS;
890b458cd62SJohnny Huang }
891b458cd62SJohnny Huang 
89269d5fd8fSJohnny Huang static void buf_print(char *buf, int len)
89369d5fd8fSJohnny Huang {
89469d5fd8fSJohnny Huang 	int i;
89569d5fd8fSJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
89669d5fd8fSJohnny Huang 	for (i = 0; i < len; i++) {
89769d5fd8fSJohnny Huang 		if (i % 16 == 0) {
89869d5fd8fSJohnny Huang 			printf("%04X: ", i);
89969d5fd8fSJohnny Huang 		}
90069d5fd8fSJohnny Huang 		printf("%02X ", buf[i]);
90169d5fd8fSJohnny Huang 		if ((i + 1) % 16 == 0) {
90269d5fd8fSJohnny Huang 			printf("\n");
90369d5fd8fSJohnny Huang 		}
90469d5fd8fSJohnny Huang 	}
90569d5fd8fSJohnny Huang }
90669d5fd8fSJohnny Huang 
9077f795e57SJohnny Huang static int otp_print_data_info(uint32_t *buf)
90869d5fd8fSJohnny Huang {
90969d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
910*9a4fe690SJohnny Huang 	struct otpkey_type *key_info_array = info_cb.key_info;
911*9a4fe690SJohnny Huang 	struct otpkey_type key_info;
91269d5fd8fSJohnny Huang 	char *byte_buf;
91369d5fd8fSJohnny Huang 	int i = 0, len = 0;
914*9a4fe690SJohnny Huang 	int j;
91569d5fd8fSJohnny Huang 	byte_buf = (char *)buf;
91669d5fd8fSJohnny Huang 	while (1) {
91769d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
91869d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
91969d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
92069d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
92169d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
92269d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
923*9a4fe690SJohnny Huang 
924*9a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
925*9a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
926*9a4fe690SJohnny Huang 				key_info = key_info_array[j];
927*9a4fe690SJohnny Huang 				break;
928*9a4fe690SJohnny Huang 			}
929*9a4fe690SJohnny Huang 		}
930*9a4fe690SJohnny Huang 
9317f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
93269d5fd8fSJohnny Huang 		printf("Key Type: ");
933*9a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
934*9a4fe690SJohnny Huang 
935*9a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
93669d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
93769d5fd8fSJohnny Huang 			switch (key_length) {
93869d5fd8fSJohnny Huang 			case 0:
93969d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
94069d5fd8fSJohnny Huang 				break;
94169d5fd8fSJohnny Huang 			case 1:
94269d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
94369d5fd8fSJohnny Huang 				break;
94469d5fd8fSJohnny Huang 			case 2:
94569d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
94669d5fd8fSJohnny Huang 				break;
94769d5fd8fSJohnny Huang 			case 3:
94869d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
94969d5fd8fSJohnny Huang 				break;
95069d5fd8fSJohnny Huang 			}
951*9a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA) {
95269d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
95369d5fd8fSJohnny Huang 			switch (key_length) {
95469d5fd8fSJohnny Huang 			case 0:
95569d5fd8fSJohnny Huang 				printf("RSA1024\n");
95669d5fd8fSJohnny Huang 				len = 0x100;
95769d5fd8fSJohnny Huang 				break;
95869d5fd8fSJohnny Huang 			case 1:
95969d5fd8fSJohnny Huang 				printf("RSA2048\n");
96069d5fd8fSJohnny Huang 				len = 0x200;
96169d5fd8fSJohnny Huang 				break;
96269d5fd8fSJohnny Huang 			case 2:
96369d5fd8fSJohnny Huang 				printf("RSA3072\n");
96469d5fd8fSJohnny Huang 				len = 0x300;
96569d5fd8fSJohnny Huang 				break;
96669d5fd8fSJohnny Huang 			case 3:
96769d5fd8fSJohnny Huang 				printf("RSA4096\n");
96869d5fd8fSJohnny Huang 				len = 0x400;
96969d5fd8fSJohnny Huang 				break;
97069d5fd8fSJohnny Huang 			}
97169d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
97269d5fd8fSJohnny Huang 		}
973*9a4fe690SJohnny Huang 		if (key_info.need_id)
97469d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
97569d5fd8fSJohnny Huang 		printf("Key Value:\n");
976*9a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
97769d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
978*9a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
979*9a4fe690SJohnny Huang 			printf("AES Key:\n");
980*9a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
981*9a4fe690SJohnny Huang 			if (info_cb.version == 0) {
982*9a4fe690SJohnny Huang 				printf("AES IV:\n");
983*9a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
984*9a4fe690SJohnny Huang 			}
985*9a4fe690SJohnny Huang 
986*9a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
987*9a4fe690SJohnny Huang 			if (info_cb.version == 0) {
98869d5fd8fSJohnny Huang 				printf("AES Key:\n");
98969d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
99069d5fd8fSJohnny Huang 				printf("AES IV:\n");
99169d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
992*9a4fe690SJohnny Huang 			} else if (info_cb.version == 1) {
993*9a4fe690SJohnny Huang 				printf("AES Key 1:\n");
994*9a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
995*9a4fe690SJohnny Huang 				printf("AES Key 2:\n");
996*9a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
997*9a4fe690SJohnny Huang 			}
99869d5fd8fSJohnny Huang 
999*9a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA) {
100069d5fd8fSJohnny Huang 			printf("RSA mod:\n");
100169d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
100269d5fd8fSJohnny Huang 			printf("RSA exp:\n");
100369d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
100469d5fd8fSJohnny Huang 		}
100569d5fd8fSJohnny Huang 		if (last)
100669d5fd8fSJohnny Huang 			break;
100769d5fd8fSJohnny Huang 		i++;
100869d5fd8fSJohnny Huang 	}
100969d5fd8fSJohnny Huang 	return 0;
101069d5fd8fSJohnny Huang }
101169d5fd8fSJohnny Huang 
1012a6d0d645SJohnny Huang static int otp_prog_conf(uint32_t *buf)
101369d5fd8fSJohnny Huang {
1014a6d0d645SJohnny Huang 	int i, k;
1015d90825e2SJohnny Huang 	int pass = 0;
1016d90825e2SJohnny Huang 	int soak = 0;
1017a6d0d645SJohnny Huang 	uint32_t prog_address;
1018a6d0d645SJohnny Huang 	uint32_t data[12];
1019a6d0d645SJohnny Huang 	uint32_t compare[2];
1020d90825e2SJohnny Huang 	uint32_t *buf_keep = &buf[12];
1021d90825e2SJohnny Huang 	uint32_t data_masked;
1022d90825e2SJohnny Huang 	uint32_t buf_masked;
102369d5fd8fSJohnny Huang 
1024a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
1025a6d0d645SJohnny Huang 
1026a6d0d645SJohnny Huang 	printProgress(0, 12, "");
1027a6d0d645SJohnny Huang 	for (i = 0; i < 12 ; i ++) {
1028a6d0d645SJohnny Huang 		printProgress(i + 1, 12, "");
102969d5fd8fSJohnny Huang 		prog_address = 0x800;
1030a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1031a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1032a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
1033a6d0d645SJohnny Huang 	}
1034a6d0d645SJohnny Huang 
1035a6d0d645SJohnny Huang 	printf("Check writable...\n");
1036a6d0d645SJohnny Huang 	for (i = 0; i < 12; i++) {
1037d90825e2SJohnny Huang 		data_masked = data[i]  & ~buf_keep[i];
1038d90825e2SJohnny Huang 		buf_masked  = buf[i] & ~buf_keep[i];
1039d90825e2SJohnny Huang 		if (data_masked == buf_masked)
104069d5fd8fSJohnny Huang 			continue;
1041d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1042a6d0d645SJohnny Huang 			continue;
1043a6d0d645SJohnny Huang 		} else {
1044a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1045a6af4a17SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, data[i]);
1046a6af4a17SJohnny Huang 			printf("Input [%X] = %x\n", i, buf[i]);
1047a6af4a17SJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~buf_keep[i]);
10482a856b9aSJohnny Huang 			return OTP_FAILURE;
1049a6d0d645SJohnny Huang 		}
1050a6d0d645SJohnny Huang 	}
1051a6d0d645SJohnny Huang 
1052a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1053a6d0d645SJohnny Huang 	printProgress(0, 12, "");
1054d90825e2SJohnny Huang 	otp_soak(0);
1055a6d0d645SJohnny Huang 	for (i = 0; i < 12; i++) {
1056d90825e2SJohnny Huang 		data_masked = data[i]  & ~buf_keep[i];
1057d90825e2SJohnny Huang 		buf_masked  = buf[i] & ~buf_keep[i];
1058a6d0d645SJohnny Huang 		prog_address = 0x800;
1059a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1060a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1061d90825e2SJohnny Huang 		if (data_masked == buf_masked) {
1062a6d0d645SJohnny Huang 			printProgress(i + 1, 12, "[%03X]=%08X HIT", prog_address, buf[i]);
1063a6d0d645SJohnny Huang 			continue;
1064a6d0d645SJohnny Huang 		}
1065d90825e2SJohnny Huang 		if (soak) {
1066d90825e2SJohnny Huang 			soak = 0;
1067d90825e2SJohnny Huang 			otp_soak(0);
1068d90825e2SJohnny Huang 		}
1069a6d0d645SJohnny Huang 		printProgress(i + 1, 12, "[%03X]=%08X    ", prog_address, buf[i]);
1070a6d0d645SJohnny Huang 
1071d90825e2SJohnny Huang 		otp_prog_dw(buf[i], buf_keep[i], prog_address);
1072a6d0d645SJohnny Huang 
107369d5fd8fSJohnny Huang 		pass = 0;
107469d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
1075d90825e2SJohnny Huang 			if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 1) != 0) {
1076d90825e2SJohnny Huang 				if (soak == 0) {
1077d90825e2SJohnny Huang 					soak = 1;
1078d90825e2SJohnny Huang 					otp_soak(1);
1079d90825e2SJohnny Huang 				}
1080a6d0d645SJohnny Huang 				otp_prog_dw(compare[0], prog_address, 1);
1081a6d0d645SJohnny Huang 			} else {
108269d5fd8fSJohnny Huang 				pass = 1;
108369d5fd8fSJohnny Huang 				break;
108469d5fd8fSJohnny Huang 			}
108569d5fd8fSJohnny Huang 		}
1086a6d0d645SJohnny Huang 	}
1087a6d0d645SJohnny Huang 
108869d5fd8fSJohnny Huang 	if (!pass)
10892a856b9aSJohnny Huang 		return OTP_FAILURE;
1090a6d0d645SJohnny Huang 
10912a856b9aSJohnny Huang 	return OTP_SUCCESS;
1092d90825e2SJohnny Huang 
109369d5fd8fSJohnny Huang }
109469d5fd8fSJohnny Huang 
109569d5fd8fSJohnny Huang 
109676d13988SJohnny Huang static int otp_strap_image_confirm(uint32_t *buf)
109769d5fd8fSJohnny Huang {
109869d5fd8fSJohnny Huang 	int i;
109969d5fd8fSJohnny Huang 	uint32_t *strap_keep = buf + 2;
110069d5fd8fSJohnny Huang 	uint32_t *strap_protect = buf + 4;
110169d5fd8fSJohnny Huang 	int bit, pbit, kbit;
110269d5fd8fSJohnny Huang 	int fail = 0;
1103a6af4a17SJohnny Huang 	int skip = -1;
110466f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
110569d5fd8fSJohnny Huang 
110669d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
110769d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
110869d5fd8fSJohnny Huang 		if (i < 32) {
110969d5fd8fSJohnny Huang 			bit = (buf[0] >> i) & 0x1;
111069d5fd8fSJohnny Huang 			kbit = (strap_keep[0] >> i) & 0x1;
111169d5fd8fSJohnny Huang 			pbit = (strap_protect[0] >> i) & 0x1;
111269d5fd8fSJohnny Huang 		} else {
111369d5fd8fSJohnny Huang 			bit = (buf[1] >> (i - 32)) & 0x1;
111469d5fd8fSJohnny Huang 			kbit = (strap_keep[1] >> (i - 32)) & 0x1;
111569d5fd8fSJohnny Huang 			pbit = (strap_protect[1] >> (i - 32)) & 0x1;
111669d5fd8fSJohnny Huang 		}
111769d5fd8fSJohnny Huang 
111869d5fd8fSJohnny Huang 		if (kbit == 1) {
111969d5fd8fSJohnny Huang 			continue;
112069d5fd8fSJohnny Huang 		} else {
1121a6af4a17SJohnny Huang 			printf("OTPSTRAP[%X]:\n", i);
112269d5fd8fSJohnny Huang 		}
112369d5fd8fSJohnny Huang 		if (bit == otpstrap[i].value) {
112469d5fd8fSJohnny Huang 			printf("    The value is same as before, skip it.\n");
1125a6af4a17SJohnny Huang 			if (skip == -1)
1126a6af4a17SJohnny Huang 				skip = 1;
112769d5fd8fSJohnny Huang 			continue;
1128a6af4a17SJohnny Huang 		} else {
1129a6af4a17SJohnny Huang 			skip = 0;
113069d5fd8fSJohnny Huang 		}
113169d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
113269d5fd8fSJohnny Huang 			printf("    This bit is protected and is not writable\n");
113369d5fd8fSJohnny Huang 			fail = 1;
113469d5fd8fSJohnny Huang 			continue;
113569d5fd8fSJohnny Huang 		}
113669d5fd8fSJohnny Huang 		if (otpstrap[i].remain_times == 0) {
1137a6af4a17SJohnny Huang 			printf("    This bit is no remaining times to write.\n");
113869d5fd8fSJohnny Huang 			fail = 1;
113969d5fd8fSJohnny Huang 			continue;
114069d5fd8fSJohnny Huang 		}
114169d5fd8fSJohnny Huang 		if (pbit == 1) {
114269d5fd8fSJohnny Huang 			printf("    This bit will be protected and become non-writable.\n");
114369d5fd8fSJohnny Huang 		}
1144a6af4a17SJohnny 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);
114569d5fd8fSJohnny Huang 	}
114669d5fd8fSJohnny Huang 	if (fail == 1)
1147a6af4a17SJohnny Huang 		return OTP_FAILURE;
1148a6af4a17SJohnny Huang 	else if (skip == 1)
1149a6af4a17SJohnny Huang 		return OTP_PROG_SKIP;
11507e22f42dSJohnny Huang 
11517e22f42dSJohnny Huang 	return 0;
115269d5fd8fSJohnny Huang }
115369d5fd8fSJohnny Huang 
11542a856b9aSJohnny Huang static int otp_print_strap(int start, int count)
115569d5fd8fSJohnny Huang {
115669d5fd8fSJohnny Huang 	int i, j;
115766f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
115869d5fd8fSJohnny Huang 
11592a856b9aSJohnny Huang 	if (start < 0 || start > 64)
11602a856b9aSJohnny Huang 		return OTP_USAGE;
11612a856b9aSJohnny Huang 
11622a856b9aSJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
11632a856b9aSJohnny Huang 		return OTP_USAGE;
11642a856b9aSJohnny Huang 
116569d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
116669d5fd8fSJohnny Huang 
116707baa4e8SJohnny Huang 	printf("BIT(hex)  Value  Option           Status\n");
1168a8bd6d8cSJohnny Huang 	printf("___________________________________________________________________________\n");
1169737ed20bSJohnny Huang 
1170cd1610b4SJohnny Huang 	for (i = start; i < start + count; i++) {
117107baa4e8SJohnny Huang 		printf("0x%-8X", i);
1172737ed20bSJohnny Huang 		printf("%-7d", otpstrap[i].value);
1173737ed20bSJohnny Huang 		for (j = 0; j < 7; j++)
1174737ed20bSJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
1175737ed20bSJohnny Huang 		printf("   ");
117669d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
1177737ed20bSJohnny Huang 			printf("protected and not writable");
117869d5fd8fSJohnny Huang 		} else {
1179737ed20bSJohnny Huang 			printf("not protected ");
118069d5fd8fSJohnny Huang 			if (otpstrap[i].remain_times == 0) {
1181737ed20bSJohnny Huang 				printf("and no remaining times to write.");
118269d5fd8fSJohnny Huang 			} else {
1183737ed20bSJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
118469d5fd8fSJohnny Huang 			}
118569d5fd8fSJohnny Huang 		}
1186737ed20bSJohnny Huang 		printf("\n");
118769d5fd8fSJohnny Huang 	}
11882a856b9aSJohnny Huang 
11892a856b9aSJohnny Huang 	return OTP_SUCCESS;
119069d5fd8fSJohnny Huang }
119169d5fd8fSJohnny Huang 
119269d5fd8fSJohnny Huang static int otp_prog_strap(uint32_t *buf)
119369d5fd8fSJohnny Huang {
119469d5fd8fSJohnny Huang 	int i, j;
119569d5fd8fSJohnny Huang 	uint32_t *strap_keep = buf + 2;
119669d5fd8fSJohnny Huang 	uint32_t *strap_protect = buf + 4;
119769d5fd8fSJohnny Huang 	uint32_t prog_bit, prog_address;
119869d5fd8fSJohnny Huang 	int bit, pbit, kbit, offset;
119969d5fd8fSJohnny Huang 	int fail = 0;
12007e22f42dSJohnny Huang 	int pass = 0;
12017e22f42dSJohnny Huang 	int soak = 0;
120266f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
120369d5fd8fSJohnny Huang 
12047f795e57SJohnny Huang 	printf("Read OTP Strap Region:\n");
120569d5fd8fSJohnny Huang 	otp_strp_status(otpstrap);
120669d5fd8fSJohnny Huang 
12077f795e57SJohnny Huang 	printf("Check writable...\n");
12087f795e57SJohnny Huang 	if (otp_strap_image_confirm(buf) == OTP_FAILURE) {
12097f795e57SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
12107f795e57SJohnny Huang 		return OTP_FAILURE;
12117f795e57SJohnny Huang 	}
12127e22f42dSJohnny Huang 
12137f795e57SJohnny Huang 	otp_soak(0);
121469d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
12154c1c9b35SJohnny Huang 		printProgress(i + 1, 64, "");
121669d5fd8fSJohnny Huang 		prog_address = 0x800;
121769d5fd8fSJohnny Huang 		if (i < 32) {
121869d5fd8fSJohnny Huang 			offset = i;
121969d5fd8fSJohnny Huang 			bit = (buf[0] >> offset) & 0x1;
122069d5fd8fSJohnny Huang 			kbit = (strap_keep[0] >> offset) & 0x1;
122169d5fd8fSJohnny Huang 			pbit = (strap_protect[0] >> offset) & 0x1;
122269d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
122369d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
122469d5fd8fSJohnny Huang 
122569d5fd8fSJohnny Huang 		} else {
122669d5fd8fSJohnny Huang 			offset = (i - 32);
122769d5fd8fSJohnny Huang 			bit = (buf[1] >> offset) & 0x1;
122869d5fd8fSJohnny Huang 			kbit = (strap_keep[1] >> offset) & 0x1;
122969d5fd8fSJohnny Huang 			pbit = (strap_protect[1] >> offset) & 0x1;
123069d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
123169d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
123269d5fd8fSJohnny Huang 		}
123369d5fd8fSJohnny Huang 		prog_bit = ~(0x1 << offset);
123469d5fd8fSJohnny Huang 
123569d5fd8fSJohnny Huang 		if (kbit == 1) {
123669d5fd8fSJohnny Huang 			continue;
123769d5fd8fSJohnny Huang 		}
123869d5fd8fSJohnny Huang 		if (bit == otpstrap[i].value) {
123969d5fd8fSJohnny Huang 			continue;
124069d5fd8fSJohnny Huang 		}
124169d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
124269d5fd8fSJohnny Huang 			fail = 1;
124369d5fd8fSJohnny Huang 			continue;
124469d5fd8fSJohnny Huang 		}
124569d5fd8fSJohnny Huang 		if (otpstrap[i].remain_times == 0) {
124669d5fd8fSJohnny Huang 			fail = 1;
124769d5fd8fSJohnny Huang 			continue;
124869d5fd8fSJohnny Huang 		}
12497e22f42dSJohnny Huang 
12507e22f42dSJohnny Huang 		if (soak) {
125169d5fd8fSJohnny Huang 			soak = 0;
12527e22f42dSJohnny Huang 			otp_soak(0);
12537e22f42dSJohnny Huang 		}
12547e22f42dSJohnny Huang 
12557e22f42dSJohnny Huang 		otp_prog(prog_address, prog_bit);
12567e22f42dSJohnny Huang 
12577e22f42dSJohnny Huang 		pass = 0;
12587e22f42dSJohnny Huang 
125969d5fd8fSJohnny Huang 		for (j = 0; j < RETRY; j++) {
1260a6d0d645SJohnny Huang 			if (verify_bit(prog_address, offset, 1) == 0) {
126169d5fd8fSJohnny Huang 				pass = 1;
126269d5fd8fSJohnny Huang 				break;
126369d5fd8fSJohnny Huang 			}
12647e22f42dSJohnny Huang 			if (soak == 0) {
126569d5fd8fSJohnny Huang 				soak = 1;
12667e22f42dSJohnny Huang 				otp_soak(1);
12674b65a65dSJohnny Huang 			}
126869d5fd8fSJohnny Huang 			otp_prog(prog_address, prog_bit);
126969d5fd8fSJohnny Huang 		}
127069d5fd8fSJohnny Huang 		if (!pass)
12712a856b9aSJohnny Huang 			return OTP_FAILURE;
127269d5fd8fSJohnny Huang 
127369d5fd8fSJohnny Huang 		if (pbit == 0)
127469d5fd8fSJohnny Huang 			continue;
127569d5fd8fSJohnny Huang 		prog_address = 0x800;
127669d5fd8fSJohnny Huang 		if (i < 32)
127769d5fd8fSJohnny Huang 			prog_address |= 0x60c;
127869d5fd8fSJohnny Huang 		else
127969d5fd8fSJohnny Huang 			prog_address |= 0x60e;
128069d5fd8fSJohnny Huang 
12817e22f42dSJohnny Huang 
12827e22f42dSJohnny Huang 		if (soak) {
12837e22f42dSJohnny Huang 			soak = 0;
12847e22f42dSJohnny Huang 			otp_soak(0);
12857e22f42dSJohnny Huang 		}
12867e22f42dSJohnny Huang 
12877e22f42dSJohnny Huang 		otp_prog(prog_address, prog_bit);
12887e22f42dSJohnny Huang 
12897e22f42dSJohnny Huang 		pass = 0;
12907e22f42dSJohnny Huang 
129169d5fd8fSJohnny Huang 		for (j = 0; j < RETRY; j++) {
12927e22f42dSJohnny Huang 
1293a6d0d645SJohnny Huang 			if (verify_bit(prog_address, offset, 1) == 0) {
129469d5fd8fSJohnny Huang 				pass = 1;
129569d5fd8fSJohnny Huang 				break;
129669d5fd8fSJohnny Huang 			}
12977e22f42dSJohnny Huang 			if (soak == 0) {
129869d5fd8fSJohnny Huang 				soak = 1;
12997e22f42dSJohnny Huang 				otp_soak(1);
130069d5fd8fSJohnny Huang 			}
130169d5fd8fSJohnny Huang 			otp_prog(prog_address, prog_bit);
130269d5fd8fSJohnny Huang 		}
130369d5fd8fSJohnny Huang 		if (!pass)
13042a856b9aSJohnny Huang 			return OTP_FAILURE;
130569d5fd8fSJohnny Huang 
130669d5fd8fSJohnny Huang 	}
130769d5fd8fSJohnny Huang 	if (fail == 1)
13082a856b9aSJohnny Huang 		return OTP_FAILURE;
130969d5fd8fSJohnny Huang 	else
13102a856b9aSJohnny Huang 		return OTP_SUCCESS;
131169d5fd8fSJohnny Huang 
131269d5fd8fSJohnny Huang }
131369d5fd8fSJohnny Huang 
1314cd1610b4SJohnny Huang static void otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset, int soak)
1315cd1610b4SJohnny Huang {
1316cd1610b4SJohnny Huang 	int prog_bit;
1317cd1610b4SJohnny Huang 
13187e22f42dSJohnny Huang 	otp_soak(soak);
13197e22f42dSJohnny Huang 
1320cd1610b4SJohnny Huang 	if (prog_address % 2 == 0) {
1321cd1610b4SJohnny Huang 		if (value)
1322cd1610b4SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
1323cd1610b4SJohnny Huang 		else
1324cd1610b4SJohnny Huang 			return;
1325cd1610b4SJohnny Huang 	} else {
1326cd1610b4SJohnny Huang 		prog_address |= 1 << 15;
1327cd1610b4SJohnny Huang 		if (!value)
1328cd1610b4SJohnny Huang 			prog_bit = 0x1 << bit_offset;
1329cd1610b4SJohnny Huang 		else
1330cd1610b4SJohnny Huang 			return;
1331cd1610b4SJohnny Huang 	}
1332cd1610b4SJohnny Huang 	otp_prog(prog_address, prog_bit);
1333cd1610b4SJohnny Huang }
1334cd1610b4SJohnny Huang 
1335d90825e2SJohnny Huang static int otp_prog_data(uint32_t *buf)
13364c1c9b35SJohnny Huang {
13374c1c9b35SJohnny Huang 	int i, k;
13384c1c9b35SJohnny Huang 	int pass;
1339d90825e2SJohnny Huang 	int soak = 0;
13404c1c9b35SJohnny Huang 	uint32_t prog_address;
1341d90825e2SJohnny Huang 	uint32_t data[2048];
13424c1c9b35SJohnny Huang 	uint32_t compare[2];
1343d90825e2SJohnny Huang 	uint32_t *buf_keep = &buf[2048];
13444c1c9b35SJohnny Huang 
1345d90825e2SJohnny Huang 	uint32_t data0_masked;
1346d90825e2SJohnny Huang 	uint32_t data1_masked;
1347d90825e2SJohnny Huang 	uint32_t buf0_masked;
1348d90825e2SJohnny Huang 	uint32_t buf1_masked;
13494c1c9b35SJohnny Huang 
13504c1c9b35SJohnny Huang 	printf("Read OTP Data:\n");
13514c1c9b35SJohnny Huang 
1352d90825e2SJohnny Huang 	printProgress(0, 2048, "");
1353d90825e2SJohnny Huang 	for (i = 0; i < 2048 ; i += 2) {
1354d90825e2SJohnny Huang 		printProgress(i + 2, 2048, "");
1355d90825e2SJohnny Huang 		otp_read_data(i, &data[i]);
13564c1c9b35SJohnny Huang 	}
1357d90825e2SJohnny Huang 
13584c1c9b35SJohnny Huang 
13594c1c9b35SJohnny Huang 	printf("Check writable...\n");
1360d90825e2SJohnny Huang 	for (i = 0; i < 2048; i++) {
1361d90825e2SJohnny Huang 		data0_masked = data[i]  & ~buf_keep[i];
1362d90825e2SJohnny Huang 		buf0_masked  = buf[i] & ~buf_keep[i];
1363d90825e2SJohnny Huang 		if (data0_masked == buf0_masked)
13644c1c9b35SJohnny Huang 			continue;
1365d90825e2SJohnny Huang 		if (i % 2 == 0) {
1366d90825e2SJohnny Huang 			if ((data0_masked | buf0_masked) == buf0_masked) {
13674c1c9b35SJohnny Huang 				continue;
13684c1c9b35SJohnny Huang 			} else {
13694c1c9b35SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1370d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
13714c1c9b35SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1372d90825e2SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_keep[i]);
13732a856b9aSJohnny Huang 				return OTP_FAILURE;
137469d5fd8fSJohnny Huang 			}
1375d90825e2SJohnny Huang 		} else {
1376d90825e2SJohnny Huang 			if ((data0_masked & buf0_masked) == buf0_masked) {
1377d90825e2SJohnny Huang 				continue;
1378d90825e2SJohnny Huang 			} else {
1379d90825e2SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1380d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1381d90825e2SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1382d90825e2SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_keep[i]);
13832a856b9aSJohnny Huang 				return OTP_FAILURE;
1384d90825e2SJohnny Huang 			}
1385d90825e2SJohnny Huang 		}
1386d90825e2SJohnny Huang 	}
138769d5fd8fSJohnny Huang 
1388d90825e2SJohnny Huang 	printf("Start Programing...\n");
1389d90825e2SJohnny Huang 	printProgress(0, 2048, "");
1390d90825e2SJohnny Huang 
1391d90825e2SJohnny Huang 	for (i = 0; i < 2048; i += 2) {
1392d90825e2SJohnny Huang 		prog_address = i;
1393d90825e2SJohnny Huang 		data0_masked = data[i]  & ~buf_keep[i];
1394d90825e2SJohnny Huang 		buf0_masked  = buf[i] & ~buf_keep[i];
1395d90825e2SJohnny Huang 		data1_masked = data[i + 1]  & ~buf_keep[i + 1];
1396d90825e2SJohnny Huang 		buf1_masked  = buf[i + 1] & ~buf_keep[i + 1];
1397d90825e2SJohnny Huang 		if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked)) {
1398d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1399d90825e2SJohnny Huang 			continue;
1400d90825e2SJohnny Huang 		}
1401d90825e2SJohnny Huang 		if (soak) {
1402d90825e2SJohnny Huang 			soak = 0;
1403d90825e2SJohnny Huang 			otp_soak(0);
1404d90825e2SJohnny Huang 		}
1405d90825e2SJohnny Huang 		if (data1_masked == buf1_masked) {
1406d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X    ;[%03X]=%08X HIT", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1407d90825e2SJohnny Huang 			otp_prog_dw(buf[i], buf_keep[i], prog_address);
1408d90825e2SJohnny Huang 		} else if (data0_masked == buf0_masked) {
1409d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X HIT;[%03X]=%08X    ", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1410d90825e2SJohnny Huang 			otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1);
1411d90825e2SJohnny Huang 		} else {
1412d90825e2SJohnny Huang 			printProgress(i + 2, 2048, "[%03X]=%08X    ;[%03X]=%08X    ", prog_address, buf[i], prog_address + 1, buf[i + 1]);
1413d90825e2SJohnny Huang 			otp_prog_dw(buf[i], buf_keep[i], prog_address);
1414d90825e2SJohnny Huang 			otp_prog_dw(buf[i + 1], buf_keep[i + 1], prog_address + 1);
1415d90825e2SJohnny Huang 		}
1416d90825e2SJohnny Huang 
1417d90825e2SJohnny Huang 		pass = 0;
1418d90825e2SJohnny Huang 		for (k = 0; k < RETRY; k++) {
1419d90825e2SJohnny Huang 			if (verify_dw(prog_address, &buf[i], &buf_keep[i], compare, 2) != 0) {
1420d90825e2SJohnny Huang 				if (soak == 0) {
1421d90825e2SJohnny Huang 					soak = 1;
1422d90825e2SJohnny Huang 					otp_soak(1);
1423d90825e2SJohnny Huang 				}
1424d90825e2SJohnny Huang 				if (compare[0] != 0) {
1425d90825e2SJohnny Huang 					otp_prog_dw(compare[0], buf_keep[i], prog_address);
1426d90825e2SJohnny Huang 				}
1427d90825e2SJohnny Huang 				if (compare[1] != ~0) {
1428d90825e2SJohnny Huang 					otp_prog_dw(compare[1], buf_keep[i], prog_address + 1);
1429d90825e2SJohnny Huang 				}
1430d90825e2SJohnny Huang 			} else {
1431d90825e2SJohnny Huang 				pass = 1;
1432d90825e2SJohnny Huang 				break;
1433d90825e2SJohnny Huang 			}
1434d90825e2SJohnny Huang 		}
1435d90825e2SJohnny Huang 
1436d90825e2SJohnny Huang 		if (!pass)
14372a856b9aSJohnny Huang 			return OTP_FAILURE;
1438d90825e2SJohnny Huang 	}
14392a856b9aSJohnny Huang 	return OTP_SUCCESS;
1440d90825e2SJohnny Huang 
1441d90825e2SJohnny Huang }
1442d90825e2SJohnny Huang 
1443d90825e2SJohnny Huang static int do_otp_prog(int addr, int byte_size, int nconfirm)
144469d5fd8fSJohnny Huang {
144569d5fd8fSJohnny Huang 	int ret;
14467332532cSJohnny Huang 	int mode = 0;
1447*9a4fe690SJohnny Huang 	int image_version = 0;
144869d5fd8fSJohnny Huang 	uint32_t *buf;
1449d90825e2SJohnny Huang 	uint32_t *data_region = NULL;
1450d90825e2SJohnny Huang 	uint32_t *conf_region = NULL;
1451d90825e2SJohnny Huang 	uint32_t *strap_region = NULL;
145269d5fd8fSJohnny Huang 
1453d90825e2SJohnny Huang 	buf = map_physmem(addr, byte_size, MAP_WRBACK);
145469d5fd8fSJohnny Huang 	if (!buf) {
145569d5fd8fSJohnny Huang 		puts("Failed to map physical memory\n");
14562a856b9aSJohnny Huang 		return OTP_FAILURE;
145769d5fd8fSJohnny Huang 	}
1458d90825e2SJohnny Huang 
1459*9a4fe690SJohnny Huang 	image_version = buf[0] & 0x3;
1460*9a4fe690SJohnny Huang 	if (image_version != info_cb.version) {
1461*9a4fe690SJohnny Huang 		puts("Version is not match\n");
1462*9a4fe690SJohnny Huang 		return OTP_FAILURE;
1463*9a4fe690SJohnny Huang 	}
1464*9a4fe690SJohnny Huang 
1465d90825e2SJohnny Huang 	if (buf[0] & BIT(29)) {
14667332532cSJohnny Huang 		mode |= OTP_REGION_DATA;
14677332532cSJohnny Huang 		data_region = &buf[36];
1468d90825e2SJohnny Huang 	}
1469d90825e2SJohnny Huang 	if (buf[0] & BIT(30)) {
14707332532cSJohnny Huang 		mode |= OTP_REGION_CONF;
14717332532cSJohnny Huang 		conf_region = &buf[12];
1472d90825e2SJohnny Huang 	}
1473d90825e2SJohnny Huang 	if (buf[0] & BIT(31)) {
14747332532cSJohnny Huang 		mode |= OTP_REGION_STRAP;
14757332532cSJohnny Huang 		strap_region = &buf[4];
1476d90825e2SJohnny Huang 	}
14777332532cSJohnny Huang 
147869d5fd8fSJohnny Huang 	if (!nconfirm) {
14797332532cSJohnny Huang 		if (mode & OTP_REGION_DATA) {
14807f795e57SJohnny Huang 			printf("\nOTP data region :\n");
14817f795e57SJohnny Huang 			if (otp_print_data_info(data_region) < 0) {
148269d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
14832a856b9aSJohnny Huang 				return OTP_FAILURE;
148469d5fd8fSJohnny Huang 			}
148569d5fd8fSJohnny Huang 		}
14867332532cSJohnny Huang 		if (mode & OTP_REGION_STRAP) {
14877332532cSJohnny Huang 			printf("\nOTP strap region :\n");
14887332532cSJohnny Huang 			if (otp_print_strap_image(strap_region) < 0) {
14897332532cSJohnny Huang 				printf("OTP strap error, please check.\n");
14907332532cSJohnny Huang 				return OTP_FAILURE;
14917332532cSJohnny Huang 			}
14927332532cSJohnny Huang 		}
14937332532cSJohnny Huang 		if (mode & OTP_REGION_CONF) {
14947332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
14957332532cSJohnny Huang 			if (otp_print_conf_image(conf_region) < 0) {
14967332532cSJohnny Huang 				printf("OTP config error, please check.\n");
14977332532cSJohnny Huang 				return OTP_FAILURE;
14987332532cSJohnny Huang 			}
14997332532cSJohnny Huang 		}
15007332532cSJohnny Huang 
150169d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
150269d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
150369d5fd8fSJohnny Huang 			printf(" Aborting\n");
15042a856b9aSJohnny Huang 			return OTP_FAILURE;
150569d5fd8fSJohnny Huang 		}
150669d5fd8fSJohnny Huang 	}
15077332532cSJohnny Huang 
15087332532cSJohnny Huang 	if (mode & OTP_REGION_DATA) {
15097332532cSJohnny Huang 		printf("programing data region ...\n");
1510d90825e2SJohnny Huang 		ret = otp_prog_data(data_region);
15112a856b9aSJohnny Huang 		if (ret != 0) {
151269d5fd8fSJohnny Huang 			printf("Error\n");
151369d5fd8fSJohnny Huang 			return ret;
151469d5fd8fSJohnny Huang 		} else {
151569d5fd8fSJohnny Huang 			printf("Done\n");
151669d5fd8fSJohnny Huang 		}
15177332532cSJohnny Huang 	}
15187332532cSJohnny Huang 	if (mode & OTP_REGION_STRAP) {
15197332532cSJohnny Huang 		printf("programing strap region ...\n");
1520d90825e2SJohnny Huang 		ret = otp_prog_strap(strap_region);
15212a856b9aSJohnny Huang 		if (ret != 0) {
152269d5fd8fSJohnny Huang 			printf("Error\n");
152369d5fd8fSJohnny Huang 			return ret;
152469d5fd8fSJohnny Huang 		} else {
152569d5fd8fSJohnny Huang 			printf("Done\n");
152669d5fd8fSJohnny Huang 		}
15277332532cSJohnny Huang 	}
15287332532cSJohnny Huang 	if (mode & OTP_REGION_CONF) {
15297332532cSJohnny Huang 		printf("programing configuration region ...\n");
1530d90825e2SJohnny Huang 		ret = otp_prog_conf(conf_region);
15312a856b9aSJohnny Huang 		if (ret != 0) {
153269d5fd8fSJohnny Huang 			printf("Error\n");
153369d5fd8fSJohnny Huang 			return ret;
153469d5fd8fSJohnny Huang 		}
153569d5fd8fSJohnny Huang 		printf("Done\n");
153669d5fd8fSJohnny Huang 	}
1537cd1610b4SJohnny Huang 
15387332532cSJohnny Huang 	return OTP_SUCCESS;
15392a856b9aSJohnny Huang }
15402a856b9aSJohnny Huang 
15412a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1542cd1610b4SJohnny Huang {
1543a6af4a17SJohnny Huang 	uint32_t read[2];
1544cd1610b4SJohnny Huang 	uint32_t strap_buf[6];
1545d90825e2SJohnny Huang 	uint32_t prog_address = 0;
154666f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
1547cd1610b4SJohnny Huang 	int otp_bit;
1548cd1610b4SJohnny Huang 	int i;
1549cd1610b4SJohnny Huang 	int pass;
1550a6af4a17SJohnny Huang 	int ret;
1551cd1610b4SJohnny Huang 
1552cd1610b4SJohnny Huang 	switch (mode) {
1553a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1554a6af4a17SJohnny Huang 		otp_read_config(otp_dw_offset, read);
1555cd1610b4SJohnny Huang 		prog_address = 0x800;
1556cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1557cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1558a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
1559cd1610b4SJohnny Huang 		if (otp_bit == value) {
1560a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1561cd1610b4SJohnny Huang 			printf("No need to program\n");
15622a856b9aSJohnny Huang 			return OTP_SUCCESS;
1563cd1610b4SJohnny Huang 		}
1564cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1565a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
1566cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
15672a856b9aSJohnny Huang 			return OTP_FAILURE;
1568cd1610b4SJohnny Huang 		}
1569a6af4a17SJohnny Huang 		printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
1570cd1610b4SJohnny Huang 		break;
1571a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1572cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1573cd1610b4SJohnny Huang 
1574cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1575a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
1576a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
1577cd1610b4SJohnny Huang 		} else {
1578a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
1579a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
1580cd1610b4SJohnny Huang 		}
1581cd1610b4SJohnny Huang 		if (otp_bit == value) {
1582a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1583cd1610b4SJohnny Huang 			printf("No need to program\n");
15842a856b9aSJohnny Huang 			return OTP_SUCCESS;
1585cd1610b4SJohnny Huang 		}
1586cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1587a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1588cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
15892a856b9aSJohnny Huang 			return OTP_FAILURE;
1590cd1610b4SJohnny Huang 		}
1591a6af4a17SJohnny Huang 		printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
1592cd1610b4SJohnny Huang 		break;
1593a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1594cd1610b4SJohnny Huang 		otp_strp_status(otpstrap);
1595cd1610b4SJohnny Huang 		otp_print_strap(bit_offset, 1);
1596cd1610b4SJohnny Huang 		if (bit_offset < 32) {
1597cd1610b4SJohnny Huang 			strap_buf[0] = value << bit_offset;
1598cd1610b4SJohnny Huang 			strap_buf[2] = ~BIT(bit_offset);
1599cd1610b4SJohnny Huang 			strap_buf[3] = ~0;
1600cd1610b4SJohnny Huang 			strap_buf[5] = 0;
16012a856b9aSJohnny Huang 			// if (protect)
16022a856b9aSJohnny Huang 			// 	strap_buf[4] = BIT(bit_offset);
16032a856b9aSJohnny Huang 			// else
16042a856b9aSJohnny Huang 			// 	strap_buf[4] = 0;
1605cd1610b4SJohnny Huang 		} else {
1606cd1610b4SJohnny Huang 			strap_buf[1] = value << (bit_offset - 32);
1607cd1610b4SJohnny Huang 			strap_buf[2] = ~0;
1608cd1610b4SJohnny Huang 			strap_buf[3] = ~BIT(bit_offset - 32);
1609cd1610b4SJohnny Huang 			strap_buf[4] = 0;
16102a856b9aSJohnny Huang 			// if (protect)
16112a856b9aSJohnny Huang 			// 	strap_buf[5] = BIT(bit_offset - 32);
16122a856b9aSJohnny Huang 			// else
16132a856b9aSJohnny Huang 			// 	strap_buf[5] = 0;
1614cd1610b4SJohnny Huang 		}
161576d13988SJohnny Huang 		ret = otp_strap_image_confirm(strap_buf);
1616a6af4a17SJohnny Huang 		if (ret == OTP_FAILURE)
16172a856b9aSJohnny Huang 			return OTP_FAILURE;
1618a6af4a17SJohnny Huang 		else if (ret == OTP_PROG_SKIP)
1619a6af4a17SJohnny Huang 			return OTP_SUCCESS;
1620a6af4a17SJohnny Huang 
1621cd1610b4SJohnny Huang 		break;
1622cd1610b4SJohnny Huang 	}
1623cd1610b4SJohnny Huang 
1624cd1610b4SJohnny Huang 	if (!nconfirm) {
1625cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1626cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1627cd1610b4SJohnny Huang 			printf(" Aborting\n");
16282a856b9aSJohnny Huang 			return OTP_FAILURE;
1629cd1610b4SJohnny Huang 		}
1630cd1610b4SJohnny Huang 	}
1631cd1610b4SJohnny Huang 
1632cd1610b4SJohnny Huang 	switch (mode) {
1633a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1634cd1610b4SJohnny Huang 		return otp_prog_strap(strap_buf);
1635a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1636a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1637cd1610b4SJohnny Huang 		otp_prog_bit(value, prog_address, bit_offset, 0);
1638cd1610b4SJohnny Huang 		pass = -1;
1639cd1610b4SJohnny Huang 		for (i = 0; i < RETRY; i++) {
1640a6d0d645SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
1641cd1610b4SJohnny Huang 				otp_prog_bit(value, prog_address, bit_offset, 1);
1642cd1610b4SJohnny Huang 			} else {
1643cd1610b4SJohnny Huang 				pass = 0;
1644cd1610b4SJohnny Huang 				break;
1645cd1610b4SJohnny Huang 			}
1646cd1610b4SJohnny Huang 		}
16472a856b9aSJohnny Huang 		if (pass == 0)
16482a856b9aSJohnny Huang 			return OTP_SUCCESS;
1649cd1610b4SJohnny Huang 	}
1650cd1610b4SJohnny Huang 
16512a856b9aSJohnny Huang 	return OTP_USAGE;
1652cd1610b4SJohnny Huang }
1653cd1610b4SJohnny Huang 
16542a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
165569d5fd8fSJohnny Huang {
16562a856b9aSJohnny Huang 	uint32_t offset, count;
16572a856b9aSJohnny Huang 	int ret;
165869d5fd8fSJohnny Huang 
16592a856b9aSJohnny Huang 	if (argc == 4) {
16602a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
16612a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
16622a856b9aSJohnny Huang 	} else if (argc == 3) {
16632a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
16642a856b9aSJohnny Huang 		count = 1;
16652a856b9aSJohnny Huang 	} else {
166669d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
166769d5fd8fSJohnny Huang 	}
166869d5fd8fSJohnny Huang 
166969d5fd8fSJohnny Huang 
16702a856b9aSJohnny Huang 	if (!strcmp(argv[1], "conf")) {
167169d5fd8fSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
16722a856b9aSJohnny Huang 		ret = otp_print_config(offset, count);
16732a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "data")) {
16742a856b9aSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
16752a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
16762a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
16772a856b9aSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
16782a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
16792a856b9aSJohnny Huang 	} else {
16802a856b9aSJohnny Huang 		return CMD_RET_USAGE;
168169d5fd8fSJohnny Huang 	}
168269d5fd8fSJohnny Huang 
16832a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
16842a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
16852a856b9aSJohnny Huang 	else
16862a856b9aSJohnny Huang 		return CMD_RET_USAGE;
16872a856b9aSJohnny Huang 
16882a856b9aSJohnny Huang }
16892a856b9aSJohnny Huang 
16902a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
16912a856b9aSJohnny Huang {
16922a856b9aSJohnny Huang 	phys_addr_t addr;
16932a856b9aSJohnny Huang 	uint32_t byte_size;
16942a856b9aSJohnny Huang 	int ret;
16952a856b9aSJohnny Huang 
16962a856b9aSJohnny Huang 	if (argc == 4) {
16972a856b9aSJohnny Huang 		if (strcmp(argv[1], "f"))
16982a856b9aSJohnny Huang 			return CMD_RET_USAGE;
16992a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
17002a856b9aSJohnny Huang 		byte_size = simple_strtoul(argv[3], NULL, 16);
170169d5fd8fSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
17022a856b9aSJohnny Huang 		ret = do_otp_prog(addr, byte_size, 1);
17032a856b9aSJohnny Huang 	} else if (argc == 3) {
17042a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
17052a856b9aSJohnny Huang 		byte_size = simple_strtoul(argv[2], NULL, 16);
17062a856b9aSJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
17072a856b9aSJohnny Huang 		ret = do_otp_prog(addr, byte_size, 0);
17082a856b9aSJohnny Huang 	} else {
17092a856b9aSJohnny Huang 		return CMD_RET_USAGE;
17102a856b9aSJohnny Huang 	}
17112a856b9aSJohnny Huang 
17122a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
17132a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
17142a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
17152a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
17162a856b9aSJohnny Huang 	else
17172a856b9aSJohnny Huang 		return CMD_RET_USAGE;
17182a856b9aSJohnny Huang }
17192a856b9aSJohnny Huang 
17202a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
17212a856b9aSJohnny Huang {
17222a856b9aSJohnny Huang 	int mode = 0;
17232a856b9aSJohnny Huang 	int nconfirm = 0;
17242a856b9aSJohnny Huang 	int otp_addr = 0;
17252a856b9aSJohnny Huang 	int bit_offset;
17262a856b9aSJohnny Huang 	int value;
17272a856b9aSJohnny Huang 	int ret;
17282a856b9aSJohnny Huang 
17292a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
17302a856b9aSJohnny Huang 		return CMD_RET_USAGE;
17312a856b9aSJohnny Huang 
17322a856b9aSJohnny Huang 	/* Drop the pb cmd */
17332a856b9aSJohnny Huang 	argc--;
17342a856b9aSJohnny Huang 	argv++;
17352a856b9aSJohnny Huang 
17362a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
1737a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
17382a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
1739a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
17402a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
1741a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
1742cd1610b4SJohnny Huang 	else
17432a856b9aSJohnny Huang 		return CMD_RET_USAGE;
17442a856b9aSJohnny Huang 
17452a856b9aSJohnny Huang 	/* Drop the region cmd */
17462a856b9aSJohnny Huang 	argc--;
17472a856b9aSJohnny Huang 	argv++;
17482a856b9aSJohnny Huang 
17492a856b9aSJohnny Huang 	if (!strcmp(argv[0], "f")) {
1750cd1610b4SJohnny Huang 		nconfirm = 1;
17512a856b9aSJohnny Huang 		/* Drop the force option */
17522a856b9aSJohnny Huang 		argc--;
17532a856b9aSJohnny Huang 		argv++;
17542a856b9aSJohnny Huang 	}
1755cd1610b4SJohnny Huang 
1756a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
17572a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
17582a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
1759cd1610b4SJohnny Huang 		if (bit_offset >= 64)
17602a856b9aSJohnny Huang 			return CMD_RET_USAGE;
1761cd1610b4SJohnny Huang 	} else {
17622a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
17632a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
17642a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
1765cd1610b4SJohnny Huang 		if (bit_offset >= 32)
17662a856b9aSJohnny Huang 			return CMD_RET_USAGE;
1767cd1610b4SJohnny Huang 	}
1768cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
17692a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1770cd1610b4SJohnny Huang 
1771cd1610b4SJohnny Huang 	writel(OTP_PASSWD, 0x1e6f2000); //password
17722a856b9aSJohnny Huang 	ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
17732a856b9aSJohnny Huang 
17742a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
17752a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
17762a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
17772a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
17782a856b9aSJohnny Huang 	else
17792a856b9aSJohnny Huang 		return CMD_RET_USAGE;
17802a856b9aSJohnny Huang }
17812a856b9aSJohnny Huang 
17822a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
17832a856b9aSJohnny Huang {
17842a856b9aSJohnny Huang 	phys_addr_t addr;
17852a856b9aSJohnny Huang 	int otp_addr = 0;
17862a856b9aSJohnny Huang 
17872a856b9aSJohnny Huang 	if (argc != 3)
17882a856b9aSJohnny Huang 		return CMD_RET_USAGE;
17892a856b9aSJohnny Huang 
179069d5fd8fSJohnny Huang 	writel(OTP_PASSWD, 0x1e6f2000); //password
17912a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
17922a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
17932a856b9aSJohnny Huang 	if (otp_compare(otp_addr, addr) == 0) {
179469d5fd8fSJohnny Huang 		printf("Compare pass\n");
17952a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
179669d5fd8fSJohnny Huang 	} else {
179769d5fd8fSJohnny Huang 		printf("Compare fail\n");
17982a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
179969d5fd8fSJohnny Huang 	}
180069d5fd8fSJohnny Huang }
180169d5fd8fSJohnny Huang 
180266f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
180366f2f8e5SJohnny Huang {
1804a8bd6d8cSJohnny Huang 	int view = 0;
18052d4b0742SJohnny Huang 	int input;
1806a8bd6d8cSJohnny Huang 
1807a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
180866f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
180966f2f8e5SJohnny Huang 
18102d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
181166f2f8e5SJohnny Huang 
18122d4b0742SJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
18132d4b0742SJohnny Huang 		if (argc == 3) {
18142d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
18152d4b0742SJohnny Huang 			otp_print_conf_info(input);
18162d4b0742SJohnny Huang 		} else {
18172d4b0742SJohnny Huang 			otp_print_conf_info(-1);
18182d4b0742SJohnny Huang 		}
18192d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
18202d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
1821a8bd6d8cSJohnny Huang 			view = 1;
1822a8bd6d8cSJohnny Huang 			/* Drop the view option */
1823a8bd6d8cSJohnny Huang 			argc--;
1824a8bd6d8cSJohnny Huang 			argv++;
1825a8bd6d8cSJohnny Huang 		}
182666f2f8e5SJohnny Huang 		writel(OTP_PASSWD, 0x1e6f2000); //password
1827b458cd62SJohnny Huang 		otp_print_strap_info(view);
182866f2f8e5SJohnny Huang 	} else {
182966f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
183066f2f8e5SJohnny Huang 	}
18312d4b0742SJohnny Huang 
183266f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
183366f2f8e5SJohnny Huang }
183466f2f8e5SJohnny Huang 
1835737ed20bSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
1836737ed20bSJohnny Huang {
1837737ed20bSJohnny Huang 	int input;
1838737ed20bSJohnny Huang 	int bit_offset;
1839737ed20bSJohnny Huang 	int prog_address;
1840737ed20bSJohnny Huang 	int pass;
1841737ed20bSJohnny Huang 	int i;
1842737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
1843737ed20bSJohnny Huang 		return CMD_RET_USAGE;
1844737ed20bSJohnny Huang 
1845737ed20bSJohnny Huang 	if (!strcmp(argv[0], "f")) {
1846737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
1847737ed20bSJohnny Huang 	} else {
1848737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
1849737ed20bSJohnny Huang 		printf("OTPSTRAP[%d] will be protected\n", input);
1850737ed20bSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1851737ed20bSJohnny Huang 		if (!confirm_yesno()) {
1852737ed20bSJohnny Huang 			printf(" Aborting\n");
1853737ed20bSJohnny Huang 			return CMD_RET_FAILURE;
1854737ed20bSJohnny Huang 		}
1855737ed20bSJohnny Huang 	}
1856737ed20bSJohnny Huang 
1857737ed20bSJohnny Huang 	prog_address = 0x800;
1858737ed20bSJohnny Huang 	if (input < 32) {
1859737ed20bSJohnny Huang 		bit_offset = input;
1860737ed20bSJohnny Huang 		prog_address |= 0x60c;
1861737ed20bSJohnny Huang 	} else if (input < 64) {
1862737ed20bSJohnny Huang 		bit_offset = input - 32;
1863737ed20bSJohnny Huang 		prog_address |= 0x60e;
1864737ed20bSJohnny Huang 	} else {
1865737ed20bSJohnny Huang 		return CMD_RET_USAGE;
1866737ed20bSJohnny Huang 	}
1867737ed20bSJohnny Huang 
1868737ed20bSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
1869737ed20bSJohnny Huang 		printf("OTPSTRAP[%d] already protected\n", input);
1870737ed20bSJohnny Huang 	}
1871737ed20bSJohnny Huang 	otp_prog_bit(1, prog_address, bit_offset, 0);
1872737ed20bSJohnny Huang 	pass = -1;
1873737ed20bSJohnny Huang 	for (i = 0; i < RETRY; i++) {
1874737ed20bSJohnny Huang 		if (verify_bit(prog_address, bit_offset, 1) != 0) {
1875737ed20bSJohnny Huang 			otp_prog_bit(1, prog_address, bit_offset, 1);
1876737ed20bSJohnny Huang 		} else {
1877737ed20bSJohnny Huang 			pass = 0;
1878737ed20bSJohnny Huang 			break;
1879737ed20bSJohnny Huang 		}
1880737ed20bSJohnny Huang 	}
1881737ed20bSJohnny Huang 	if (pass == 0) {
1882737ed20bSJohnny Huang 		printf("OTPSTRAP[%d] is protected\n", input);
1883737ed20bSJohnny Huang 		return CMD_RET_SUCCESS;
1884737ed20bSJohnny Huang 	}
1885737ed20bSJohnny Huang 
1886737ed20bSJohnny Huang 	printf("Protect OTPSTRAP[%d] fail\n", input);
1887737ed20bSJohnny Huang 	return CMD_RET_FAILURE;
1888737ed20bSJohnny Huang 
1889737ed20bSJohnny Huang }
1890*9a4fe690SJohnny Huang 
18912a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
18922a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
1893a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
18942a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(prog, 4, 0, do_otpprog, "", ""),
18952a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
1896737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
18972a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
18982a856b9aSJohnny Huang };
18992a856b9aSJohnny Huang 
19002a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
19012a856b9aSJohnny Huang {
19022a856b9aSJohnny Huang 	cmd_tbl_t *cp;
19032a856b9aSJohnny Huang 
19042a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
19052a856b9aSJohnny Huang 
1906737ed20bSJohnny Huang 	/* Drop the otp command */
19072a856b9aSJohnny Huang 	argc--;
19082a856b9aSJohnny Huang 	argv++;
19092a856b9aSJohnny Huang 
19102a856b9aSJohnny Huang 	if (cp == NULL || argc > cp->maxargs)
19112a856b9aSJohnny Huang 		return CMD_RET_USAGE;
19122a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
19132a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
19142a856b9aSJohnny Huang 
1915*9a4fe690SJohnny Huang 	if (chip_version() == 0) {
1916*9a4fe690SJohnny Huang 		info_cb.version = 0;
1917*9a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
1918*9a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
1919*9a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
1920*9a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
1921*9a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
1922*9a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
1923*9a4fe690SJohnny Huang 	} else if (chip_version() == 1) {
1924*9a4fe690SJohnny Huang 		info_cb.version = 1;
1925*9a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
1926*9a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
1927*9a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
1928*9a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
1929*9a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
1930*9a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
1931*9a4fe690SJohnny Huang 	}
1932*9a4fe690SJohnny Huang 
19332a856b9aSJohnny Huang 	return cp->cmd(cmdtp, flag, argc, argv);
193469d5fd8fSJohnny Huang }
193569d5fd8fSJohnny Huang 
193669d5fd8fSJohnny Huang U_BOOT_CMD(
193769d5fd8fSJohnny Huang 	otp, 7, 0,  do_ast_otp,
193869d5fd8fSJohnny Huang 	"ASPEED One-Time-Programmable sub-system",
19392a856b9aSJohnny Huang 	"read conf|data <otp_dw_offset> <dw_count>\n"
19402a856b9aSJohnny Huang 	"otp read strap <strap_bit_offset> <bit_count>\n"
19412d4b0742SJohnny Huang 	"otp info strap [v]\n"
19422d4b0742SJohnny Huang 	"otp info conf [otp_dw_offset]\n"
1943d90825e2SJohnny Huang 	"otp prog [f] <addr> <byte_size>\n"
1944cd1610b4SJohnny Huang 	"otp pb conf|data [f] <otp_dw_offset> <bit_offset> <value>\n"
1945737ed20bSJohnny Huang 	"otp pb strap [f] <bit_offset> <value>\n"
1946737ed20bSJohnny Huang 	"otp protect [f] <bit_offset>\n"
19472a856b9aSJohnny Huang 	"otp cmp <addr> <otp_dw_offset>\n"
194869d5fd8fSJohnny Huang );
1949