1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+
269d5fd8fSJohnny Huang /*
3a219f6deSJohnny Huang * Copyright 2021 Aspeed Technology Inc.
469d5fd8fSJohnny Huang */
5e417205bSJohnny Huang
64c1c9b35SJohnny Huang #include <stdlib.h>
769d5fd8fSJohnny Huang #include <common.h>
869d5fd8fSJohnny Huang #include <console.h>
969d5fd8fSJohnny Huang #include <bootretry.h>
1069d5fd8fSJohnny Huang #include <cli.h>
1169d5fd8fSJohnny Huang #include <command.h>
1269d5fd8fSJohnny Huang #include <console.h>
134c1c9b35SJohnny Huang #include <malloc.h>
1469d5fd8fSJohnny Huang #include <inttypes.h>
1569d5fd8fSJohnny Huang #include <mapmem.h>
1669d5fd8fSJohnny Huang #include <asm/io.h>
1769d5fd8fSJohnny Huang #include <linux/compiler.h>
182031a123SJohnny Huang #include <linux/iopoll.h>
19e7e21c44SJohnny Huang #include <u-boot/sha256.h>
20a3dcef30SJohnny Huang #include <u-boot/sha512.h>
21e7e21c44SJohnny Huang #include <u-boot/rsa.h>
22e7e21c44SJohnny Huang #include <u-boot/rsa-mod-exp.h>
23e7e21c44SJohnny Huang #include <dm.h>
240cee9a95SJohnny Huang #include "otp_info.h"
2569d5fd8fSJohnny Huang
2669d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR;
2769d5fd8fSJohnny Huang
28a3dcef30SJohnny Huang #define OTP_VER "2.0.0"
29f67375f7SJohnny Huang
3069d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a
31dacbba92SJohnny Huang #define RETRY 20
327332532cSJohnny Huang #define OTP_REGION_STRAP BIT(0)
337332532cSJohnny Huang #define OTP_REGION_CONF BIT(1)
347332532cSJohnny Huang #define OTP_REGION_DATA BIT(2)
3569d5fd8fSJohnny Huang
362a856b9aSJohnny Huang #define OTP_USAGE -1
372a856b9aSJohnny Huang #define OTP_FAILURE -2
382a856b9aSJohnny Huang #define OTP_SUCCESS 0
392a856b9aSJohnny Huang
40a6af4a17SJohnny Huang #define OTP_PROG_SKIP 1
41a6af4a17SJohnny Huang
42181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB 1
43181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV 2
44181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES 3
45181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT 4
46181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC 5
479a4fe690SJohnny Huang
48e7e21c44SJohnny Huang #define OTP_LIT_END 0
49e7e21c44SJohnny Huang #define OTP_BIG_END 1
50e7e21c44SJohnny Huang
513d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000
523d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE
533d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4
543d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8
553d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10
563d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14
573d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20
583d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24
593d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28
603d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c
61a8789b47SJohnny Huang #define SW_REV_ID0 OTP_BASE + 0x68
62a8789b47SJohnny Huang #define SW_REV_ID1 OTP_BASE + 0x6c
63030cb4a7SJohnny Huang #define SEC_KEY_NUM OTP_BASE + 0x78
643d3688adSJohnny Huang
65696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP"
66e7e21c44SJohnny Huang #define CHECKSUM_LEN 64
67a219f6deSJohnny Huang #define OTP_INC_DATA BIT(31)
68a219f6deSJohnny Huang #define OTP_INC_CONFIG BIT(30)
69a219f6deSJohnny Huang #define OTP_INC_STRAP BIT(29)
70a219f6deSJohnny Huang #define OTP_ECC_EN BIT(28)
71b25f02d2SJohnny Huang #define OTP_INC_SCU_PRO BIT(25)
72696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff)
73696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff)
74696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff)
75696656c6SJohnny Huang
76e417205bSJohnny Huang #define OTP_A0 0
77e417205bSJohnny Huang #define OTP_A1 1
78e417205bSJohnny Huang #define OTP_A2 2
79e417205bSJohnny Huang #define OTP_A3 3
80e417205bSJohnny Huang
81e417205bSJohnny Huang #define ID0_AST2600A0 0x05000303
82e417205bSJohnny Huang #define ID1_AST2600A0 0x05000303
83e417205bSJohnny Huang #define ID0_AST2600A1 0x05010303
8421a8cfceSJohnny Huang #define ID1_AST2600A1 0x05010303
85e417205bSJohnny Huang #define ID0_AST2600A2 0x05010303
86e417205bSJohnny Huang #define ID1_AST2600A2 0x05020303
87e417205bSJohnny Huang #define ID0_AST2600A3 0x05030303
88e417205bSJohnny Huang #define ID1_AST2600A3 0x05030303
89e417205bSJohnny Huang #define ID0_AST2620A1 0x05010203
90e417205bSJohnny Huang #define ID1_AST2620A1 0x05010203
91e417205bSJohnny Huang #define ID0_AST2620A2 0x05010203
92e417205bSJohnny Huang #define ID1_AST2620A2 0x05020203
93e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203
94e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203
95e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203
96e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203
97e417205bSJohnny Huang #define ID0_AST2605A2 0x05010103
98e417205bSJohnny Huang #define ID1_AST2605A2 0x05020103
99e417205bSJohnny Huang #define ID0_AST2605A3 0x05030103
100e417205bSJohnny Huang #define ID1_AST2605A3 0x05030103
101e417205bSJohnny Huang #define ID0_AST2625A3 0x05030403
102e417205bSJohnny Huang #define ID1_AST2625A3 0x05030403
103696656c6SJohnny Huang
10461a6cda7SJohnny Huang #define SOC_AST2600A0 0
10561a6cda7SJohnny Huang #define SOC_AST2600A1 1
10661a6cda7SJohnny Huang #define SOC_AST2600A2 2
10761a6cda7SJohnny Huang #define SOC_AST2600A3 3
10861a6cda7SJohnny Huang
10961a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c))
1105e096f11SJohnny Huang #define OTPTOOL_VERSION_MAJOR(x) (((x) >> 24) & 0xff)
1115e096f11SJohnny Huang #define OTPTOOL_VERSION_PATCHLEVEL(x) (((x) >> 12) & 0xfff)
1125e096f11SJohnny Huang #define OTPTOOL_VERSION_SUBLEVEL(x) ((x) & 0xfff)
113a3dcef30SJohnny Huang #define OTPTOOL_COMPT_VERSION 2
11461a6cda7SJohnny Huang
115696656c6SJohnny Huang struct otp_header {
116696656c6SJohnny Huang u8 otp_magic[8];
11761a6cda7SJohnny Huang u32 soc_ver;
11861a6cda7SJohnny Huang u32 otptool_ver;
119696656c6SJohnny Huang u32 image_info;
120696656c6SJohnny Huang u32 data_info;
121696656c6SJohnny Huang u32 config_info;
122696656c6SJohnny Huang u32 strap_info;
1237e523e3bSJohnny Huang u32 scu_protect_info;
124696656c6SJohnny Huang u32 checksum_offset;
125a219f6deSJohnny Huang } __packed;
126696656c6SJohnny Huang
12766f2f8e5SJohnny Huang struct otpstrap_status {
12869d5fd8fSJohnny Huang int value;
12969d5fd8fSJohnny Huang int option_array[7];
13069d5fd8fSJohnny Huang int remain_times;
13169d5fd8fSJohnny Huang int writeable_option;
13269d5fd8fSJohnny Huang int protected;
13369d5fd8fSJohnny Huang };
13469d5fd8fSJohnny Huang
1359a4fe690SJohnny Huang struct otpkey_type {
136*1cf1c480SJoel Stanley unsigned int value;
137*1cf1c480SJoel Stanley unsigned int key_type;
138*1cf1c480SJoel Stanley unsigned int order;
139*1cf1c480SJoel Stanley unsigned int need_id;
14022fda007SJoel Stanley char *information;
1419a4fe690SJohnny Huang };
1429a4fe690SJohnny Huang
143030cb4a7SJohnny Huang struct otp_pro_sts {
144030cb4a7SJohnny Huang char mem_lock;
145030cb4a7SJohnny Huang char pro_key_ret;
146030cb4a7SJohnny Huang char pro_strap;
147030cb4a7SJohnny Huang char pro_conf;
148030cb4a7SJohnny Huang char pro_data;
149030cb4a7SJohnny Huang char pro_sec;
150030cb4a7SJohnny Huang u32 sec_size;
151030cb4a7SJohnny Huang };
152030cb4a7SJohnny Huang
1539a4fe690SJohnny Huang struct otp_info_cb {
1549a4fe690SJohnny Huang int version;
155e417205bSJohnny Huang char ver_name[3];
15679e42a59SJoel Stanley const struct otpstrap_info *strap_info;
1579a4fe690SJohnny Huang int strap_info_len;
15879e42a59SJoel Stanley const struct otpconf_info *conf_info;
1599a4fe690SJohnny Huang int conf_info_len;
16079e42a59SJoel Stanley const struct otpkey_type *key_info;
1619a4fe690SJohnny Huang int key_info_len;
1620dc9a440SJohnny Huang const struct scu_info *scu_info;
1630dc9a440SJohnny Huang int scu_info_len;
164030cb4a7SJohnny Huang struct otp_pro_sts pro_sts;
1659a4fe690SJohnny Huang };
1669a4fe690SJohnny Huang
167696656c6SJohnny Huang struct otp_image_layout {
1685010032bSJohnny Huang int data_length;
1695010032bSJohnny Huang int conf_length;
1705010032bSJohnny Huang int strap_length;
171b25f02d2SJohnny Huang int scu_pro_length;
172a219f6deSJohnny Huang u8 *data;
173a219f6deSJohnny Huang u8 *data_ignore;
174a219f6deSJohnny Huang u8 *conf;
175a219f6deSJohnny Huang u8 *conf_ignore;
176a219f6deSJohnny Huang u8 *strap;
177a219f6deSJohnny Huang u8 *strap_pro;
178a219f6deSJohnny Huang u8 *strap_ignore;
179b25f02d2SJohnny Huang u8 *scu_pro;
180b25f02d2SJohnny Huang u8 *scu_pro_ignore;
181696656c6SJohnny Huang };
182696656c6SJohnny Huang
183e7e21c44SJohnny Huang struct sb_info {
184e7e21c44SJohnny Huang int header_offset;
185e7e21c44SJohnny Huang int secure_region;
186e7e21c44SJohnny Huang int rsa_algo;
187e7e21c44SJohnny Huang int sha_algo;
188e7e21c44SJohnny Huang int digest_len;
189e7e21c44SJohnny Huang int retire_list[8];
190e7e21c44SJohnny Huang int enc_flag;
191e7e21c44SJohnny Huang };
192e7e21c44SJohnny Huang
193e7e21c44SJohnny Huang struct key_list {
194e7e21c44SJohnny Huang const struct otpkey_type *key_info;
195e7e21c44SJohnny Huang int offset;
196e7e21c44SJohnny Huang int id;
197e7e21c44SJohnny Huang int retire;
198e7e21c44SJohnny Huang };
199e7e21c44SJohnny Huang
200e7e21c44SJohnny Huang struct sb_header {
201e7e21c44SJohnny Huang u32 aes_data_offset;
202e7e21c44SJohnny Huang u32 enc_offset;
203e7e21c44SJohnny Huang u32 sign_image_size;
204e7e21c44SJohnny Huang u32 signature_offset;
205e7e21c44SJohnny Huang u32 revision_low;
206e7e21c44SJohnny Huang u32 revision_high;
207e7e21c44SJohnny Huang u32 reserved;
208e7e21c44SJohnny Huang u32 bl1_header_checksum;
209e7e21c44SJohnny Huang };
210e7e21c44SJohnny Huang
2119a4fe690SJohnny Huang static struct otp_info_cb info_cb;
2129a4fe690SJohnny Huang
21379e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
214e7e21c44SJohnny Huang {0, OTP_KEY_TYPE_AES, OTP_LIT_END, 0, "AES-256 as OEM platform key for image encryption/decryption"},
215e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"},
216e7e21c44SJohnny Huang {4, OTP_KEY_TYPE_HMAC, OTP_LIT_END, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
217e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"},
218e7e21c44SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as SOC public key"},
219e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"},
220e7e21c44SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as SOC private key"},
221e7e21c44SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"},
2229a4fe690SJohnny Huang };
2239a4fe690SJohnny Huang
22479e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
225e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"},
226e7e21c44SJohnny Huang {2, OTP_KEY_TYPE_AES, OTP_LIT_END, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
227e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"},
228e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"},
229e7e21c44SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"},
2309a4fe690SJohnny Huang };
2319a4fe690SJohnny Huang
2325fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
233e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"},
234e7e21c44SJohnny Huang {2, OTP_KEY_TYPE_AES, OTP_LIT_END, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
235e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"},
236e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"},
237e7e21c44SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"},
238181f72d8SJohnny Huang };
239181f72d8SJohnny Huang
240181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = {
241e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"},
242e7e21c44SJohnny Huang {2, OTP_KEY_TYPE_AES, OTP_LIT_END, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
243e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"},
244e7e21c44SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, OTP_BIG_END, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
245e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"},
246e7e21c44SJohnny Huang {11, OTP_KEY_TYPE_RSA_PUB, OTP_BIG_END, 0, "RSA-public as AES key decryption key(big endian)"},
247e7e21c44SJohnny Huang {12, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"},
248e7e21c44SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, OTP_BIG_END, 0, "RSA-private as AES key decryption key(big endian)"},
2495fdde29fSJohnny Huang };
2505fdde29fSJohnny Huang
buf_print(u8 * buf,int len)251f347c284SJohnny Huang static void buf_print(u8 *buf, int len)
252f347c284SJohnny Huang {
253f347c284SJohnny Huang int i;
254f347c284SJohnny Huang
255f347c284SJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
256f347c284SJohnny Huang for (i = 0; i < len; i++) {
257f347c284SJohnny Huang if (i % 16 == 0)
258f347c284SJohnny Huang printf("%04X: ", i);
259f347c284SJohnny Huang printf("%02X ", buf[i]);
260f347c284SJohnny Huang if ((i + 1) % 16 == 0)
261f347c284SJohnny Huang printf("\n");
262f347c284SJohnny Huang }
26388bd7d58SJohnny Huang printf("\n");
264f347c284SJohnny Huang }
265f347c284SJohnny Huang
get_dw_bit(u32 * rid,int offset)266794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset)
267794e27ecSJohnny Huang {
268794e27ecSJohnny Huang int bit_offset;
269794e27ecSJohnny Huang int i;
270794e27ecSJohnny Huang
271794e27ecSJohnny Huang if (offset < 32) {
272794e27ecSJohnny Huang i = 0;
273794e27ecSJohnny Huang bit_offset = offset;
274794e27ecSJohnny Huang } else {
275794e27ecSJohnny Huang i = 1;
276794e27ecSJohnny Huang bit_offset = offset - 32;
277794e27ecSJohnny Huang }
278794e27ecSJohnny Huang if ((rid[i] >> bit_offset) & 0x1)
279794e27ecSJohnny Huang return 1;
280794e27ecSJohnny Huang else
281794e27ecSJohnny Huang return 0;
282794e27ecSJohnny Huang }
283794e27ecSJohnny Huang
get_rid_num(u32 * rid)284794e27ecSJohnny Huang static int get_rid_num(u32 *rid)
285794e27ecSJohnny Huang {
286794e27ecSJohnny Huang int i;
287794e27ecSJohnny Huang int fz = 0;
288794e27ecSJohnny Huang int rid_num = 0;
289794e27ecSJohnny Huang int ret = 0;
290794e27ecSJohnny Huang
291794e27ecSJohnny Huang for (i = 0; i < 64; i++) {
292794e27ecSJohnny Huang if (get_dw_bit(rid, i) == 0) {
293794e27ecSJohnny Huang if (!fz)
294794e27ecSJohnny Huang fz = 1;
295794e27ecSJohnny Huang
296794e27ecSJohnny Huang } else {
297794e27ecSJohnny Huang rid_num++;
298794e27ecSJohnny Huang if (fz)
299794e27ecSJohnny Huang ret = OTP_FAILURE;
300794e27ecSJohnny Huang }
301794e27ecSJohnny Huang }
302794e27ecSJohnny Huang if (ret)
303794e27ecSJohnny Huang return ret;
304794e27ecSJohnny Huang
305794e27ecSJohnny Huang return rid_num;
306794e27ecSJohnny Huang }
307794e27ecSJohnny Huang
chip_version(void)308a219f6deSJohnny Huang static u32 chip_version(void)
3099a4fe690SJohnny Huang {
310e417205bSJohnny Huang u32 revid0, revid1;
3119a4fe690SJohnny Huang
312e417205bSJohnny Huang revid0 = readl(ASPEED_REVISION_ID0);
313e417205bSJohnny Huang revid1 = readl(ASPEED_REVISION_ID1);
3149a4fe690SJohnny Huang
315e417205bSJohnny Huang if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) {
316badd21c2SJohnny Huang /* AST2600-A0 */
317e417205bSJohnny Huang return OTP_A0;
318e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) {
319badd21c2SJohnny Huang /* AST2600-A1 */
320e417205bSJohnny Huang return OTP_A1;
321e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) {
322badd21c2SJohnny Huang /* AST2600-A2 */
323e417205bSJohnny Huang return OTP_A2;
324e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) {
32564b66712SJohnny Huang /* AST2600-A3 */
326e417205bSJohnny Huang return OTP_A3;
327e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) {
328e417205bSJohnny Huang /* AST2620-A1 */
329e417205bSJohnny Huang return OTP_A1;
330e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) {
331e417205bSJohnny Huang /* AST2620-A2 */
332e417205bSJohnny Huang return OTP_A2;
333e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) {
33464b66712SJohnny Huang /* AST2620-A3 */
335e417205bSJohnny Huang return OTP_A3;
336e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) {
337e417205bSJohnny Huang /* AST2605-A2 */
338e417205bSJohnny Huang return OTP_A2;
339e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) {
340e417205bSJohnny Huang /* AST2605-A3 */
341e417205bSJohnny Huang return OTP_A3;
342e417205bSJohnny Huang } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) {
343e417205bSJohnny Huang /* AST2605-A3 */
344e417205bSJohnny Huang return OTP_A3;
3450dae9d52SJohnny Huang }
346f347c284SJohnny Huang return OTP_FAILURE;
3479a4fe690SJohnny Huang }
3489a4fe690SJohnny Huang
wait_complete(void)3492031a123SJohnny Huang static int wait_complete(void)
3503d3688adSJohnny Huang {
3512031a123SJohnny Huang u32 val;
3522031a123SJohnny Huang int ret;
3533d3688adSJohnny Huang
3542031a123SJohnny Huang udelay(1);
3552031a123SJohnny Huang ret = readl_poll_timeout(OTP_STATUS, val, (val & 0x6) == 0x6, 100000);
3562031a123SJohnny Huang if (ret)
3572031a123SJohnny Huang printf("%s: timeout, SEC14 = 0x%x\n", __func__, val);
3582031a123SJohnny Huang
3592031a123SJohnny Huang return ret;
3603d3688adSJohnny Huang }
3613d3688adSJohnny Huang
otp_write(u32 otp_addr,u32 data)362a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data)
363dacbba92SJohnny Huang {
364dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address
365dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data
366dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command
367dacbba92SJohnny Huang wait_complete();
368dacbba92SJohnny Huang }
369dacbba92SJohnny Huang
otp_soak(int soak)370dacbba92SJohnny Huang static void otp_soak(int soak)
371dacbba92SJohnny Huang {
372e417205bSJohnny Huang if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) {
373dacbba92SJohnny Huang switch (soak) {
374dacbba92SJohnny Huang case 0: //default
375377f8cd7SJohnny Huang otp_write(0x3000, 0x0); // Write MRA
376377f8cd7SJohnny Huang otp_write(0x5000, 0x0); // Write MRB
377dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR
378dacbba92SJohnny Huang break;
379dacbba92SJohnny Huang case 1: //normal program
380377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA
381377f8cd7SJohnny Huang otp_write(0x5000, 0x1008); // Write MRB
382377f8cd7SJohnny Huang otp_write(0x1000, 0x0024); // Write MR
383feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us
384dacbba92SJohnny Huang break;
385dacbba92SJohnny Huang case 2: //soak program
386377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA
387377f8cd7SJohnny Huang otp_write(0x5000, 0x0007); // Write MRB
388377f8cd7SJohnny Huang otp_write(0x1000, 0x0100); // Write MR
389feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us
390dacbba92SJohnny Huang break;
391dacbba92SJohnny Huang }
392dacbba92SJohnny Huang } else {
393dacbba92SJohnny Huang switch (soak) {
394dacbba92SJohnny Huang case 0: //default
395dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA
396dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB
397dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR
398dacbba92SJohnny Huang break;
399dacbba92SJohnny Huang case 1: //normal program
400dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA
401dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB
402dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR
403feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us
404dacbba92SJohnny Huang break;
405dacbba92SJohnny Huang case 2: //soak program
406dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA
407dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB
408dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR
409feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us
410dacbba92SJohnny Huang break;
411dacbba92SJohnny Huang }
412dacbba92SJohnny Huang }
413dacbba92SJohnny Huang
414dacbba92SJohnny Huang wait_complete();
415dacbba92SJohnny Huang }
416dacbba92SJohnny Huang
otp_read_data(u32 offset,u32 * data)417a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data)
41869d5fd8fSJohnny Huang {
4193d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address
4203d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read
4213d3688adSJohnny Huang wait_complete();
4223d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1);
4233d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2);
42469d5fd8fSJohnny Huang }
42569d5fd8fSJohnny Huang
otp_read_conf(u32 offset,u32 * data)426f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data)
42769d5fd8fSJohnny Huang {
42869d5fd8fSJohnny Huang int config_offset;
42969d5fd8fSJohnny Huang
43069d5fd8fSJohnny Huang config_offset = 0x800;
43169d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200;
43269d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2;
43369d5fd8fSJohnny Huang
4343d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address
4353d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read
4363d3688adSJohnny Huang wait_complete();
4373d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1);
43869d5fd8fSJohnny Huang }
43969d5fd8fSJohnny Huang
otp_compare(u32 otp_addr,u32 addr)440a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr)
44169d5fd8fSJohnny Huang {
442a219f6deSJohnny Huang u32 ret;
443a219f6deSJohnny Huang u32 *buf;
44469d5fd8fSJohnny Huang
44569d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK);
44669d5fd8fSJohnny Huang printf("%08X\n", buf[0]);
44769d5fd8fSJohnny Huang printf("%08X\n", buf[1]);
44869d5fd8fSJohnny Huang printf("%08X\n", buf[2]);
44969d5fd8fSJohnny Huang printf("%08X\n", buf[3]);
4503d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address
451fd3e7122SNeal Liu writel(~buf[0], OTP_COMPARE_1); //Compare data 1
452fd3e7122SNeal Liu writel(~buf[1], OTP_COMPARE_2); //Compare data 2
453fd3e7122SNeal Liu writel(~buf[2], OTP_COMPARE_3); //Compare data 3
454fd3e7122SNeal Liu writel(~buf[3], OTP_COMPARE_4); //Compare data 4
4553d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command
4563d3688adSJohnny Huang wait_complete();
4573d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command
45869d5fd8fSJohnny Huang if (ret & 0x1)
459f347c284SJohnny Huang return OTP_SUCCESS;
46069d5fd8fSJohnny Huang else
461f347c284SJohnny Huang return OTP_FAILURE;
46269d5fd8fSJohnny Huang }
46369d5fd8fSJohnny Huang
verify_bit(u32 otp_addr,int bit_offset,int value)464a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value)
46569d5fd8fSJohnny Huang {
466a219f6deSJohnny Huang u32 ret[2];
46769d5fd8fSJohnny Huang
46830a8c590SJohnny Huang if (otp_addr % 2 == 0)
4693d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address
47030a8c590SJohnny Huang else
4713d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address
47230a8c590SJohnny Huang
4733d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read
4743d3688adSJohnny Huang wait_complete();
4753d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1);
4763d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2);
47783655e91SJohnny Huang
47830a8c590SJohnny Huang if (otp_addr % 2 == 0) {
47930a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value)
480f347c284SJohnny Huang return OTP_SUCCESS;
48169d5fd8fSJohnny Huang else
482f347c284SJohnny Huang return OTP_FAILURE;
48330a8c590SJohnny Huang } else {
48430a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value)
485f347c284SJohnny Huang return OTP_SUCCESS;
48630a8c590SJohnny Huang else
487f347c284SJohnny Huang return OTP_FAILURE;
48830a8c590SJohnny Huang }
48969d5fd8fSJohnny Huang }
49069d5fd8fSJohnny Huang
verify_dw(u32 otp_addr,u32 * value,u32 * ignore,u32 * compare,int size)491a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size)
4924c1c9b35SJohnny Huang {
493a219f6deSJohnny Huang u32 ret[2];
4944c1c9b35SJohnny Huang
4954c1c9b35SJohnny Huang otp_addr &= ~(1 << 15);
4964c1c9b35SJohnny Huang
4974c1c9b35SJohnny Huang if (otp_addr % 2 == 0)
4983d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address
4994c1c9b35SJohnny Huang else
5003d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address
5013d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read
5023d3688adSJohnny Huang wait_complete();
5033d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1);
5043d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2);
5054c1c9b35SJohnny Huang if (size == 1) {
5064c1c9b35SJohnny Huang if (otp_addr % 2 == 0) {
5074c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
508696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
5094c1c9b35SJohnny Huang compare[0] = 0;
510f347c284SJohnny Huang return OTP_SUCCESS;
511a219f6deSJohnny Huang }
5124c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0];
513f347c284SJohnny Huang return OTP_FAILURE;
5144c1c9b35SJohnny Huang
5154c1c9b35SJohnny Huang } else {
5164c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
517696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
5184c1c9b35SJohnny Huang compare[0] = ~0;
519f347c284SJohnny Huang return OTP_SUCCESS;
520a219f6deSJohnny Huang }
521d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]);
522f347c284SJohnny Huang return OTP_FAILURE;
5234c1c9b35SJohnny Huang }
5244c1c9b35SJohnny Huang } else if (size == 2) {
5254c1c9b35SJohnny Huang // otp_addr should be even
526696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
5274c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
5284c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
5294c1c9b35SJohnny Huang compare[0] = 0;
5304c1c9b35SJohnny Huang compare[1] = ~0;
531f347c284SJohnny Huang return OTP_SUCCESS;
532a219f6deSJohnny Huang }
5334c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
5344c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
5354c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0];
5364c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]);
537f347c284SJohnny Huang return OTP_FAILURE;
5384c1c9b35SJohnny Huang } else {
539f347c284SJohnny Huang return OTP_FAILURE;
5404c1c9b35SJohnny Huang }
5414c1c9b35SJohnny Huang }
5424c1c9b35SJohnny Huang
otp_prog(u32 otp_addr,u32 prog_bit)5432031a123SJohnny Huang static int otp_prog(u32 otp_addr, u32 prog_bit)
54483655e91SJohnny Huang {
54590965bb3SJohnny Huang otp_write(0x0, prog_bit);
54683655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address
54783655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data
54883655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command
5492031a123SJohnny Huang
5502031a123SJohnny Huang return wait_complete();
55183655e91SJohnny Huang }
55283655e91SJohnny Huang
_otp_prog_bit(u32 value,u32 prog_address,u32 bit_offset)5532031a123SJohnny Huang static int _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
55483655e91SJohnny Huang {
55583655e91SJohnny Huang int prog_bit;
55683655e91SJohnny Huang
55783655e91SJohnny Huang if (prog_address % 2 == 0) {
55883655e91SJohnny Huang if (value)
55983655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset);
56083655e91SJohnny Huang else
5612031a123SJohnny Huang return 0;
56283655e91SJohnny Huang } else {
563e417205bSJohnny Huang if (info_cb.version != OTP_A3)
56483655e91SJohnny Huang prog_address |= 1 << 15;
56583655e91SJohnny Huang if (!value)
56683655e91SJohnny Huang prog_bit = 0x1 << bit_offset;
56783655e91SJohnny Huang else
5682031a123SJohnny Huang return 0;
56983655e91SJohnny Huang }
5702031a123SJohnny Huang return otp_prog(prog_address, prog_bit);
57183655e91SJohnny Huang }
57283655e91SJohnny Huang
otp_prog_dc_b(u32 value,u32 prog_address,u32 bit_offset)573f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset)
57483655e91SJohnny Huang {
57583655e91SJohnny Huang int pass;
57683655e91SJohnny Huang int i;
5772031a123SJohnny Huang int ret;
57883655e91SJohnny Huang
57983655e91SJohnny Huang otp_soak(1);
5802031a123SJohnny Huang ret = _otp_prog_bit(value, prog_address, bit_offset);
5812031a123SJohnny Huang if (ret)
5822031a123SJohnny Huang return OTP_FAILURE;
58383655e91SJohnny Huang pass = 0;
58483655e91SJohnny Huang
58583655e91SJohnny Huang for (i = 0; i < RETRY; i++) {
58683655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) {
58783655e91SJohnny Huang otp_soak(2);
5882031a123SJohnny Huang ret = _otp_prog_bit(value, prog_address, bit_offset);
5892031a123SJohnny Huang if (ret)
5902031a123SJohnny Huang return OTP_FAILURE;
59183655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) {
59283655e91SJohnny Huang otp_soak(1);
59383655e91SJohnny Huang } else {
59483655e91SJohnny Huang pass = 1;
59583655e91SJohnny Huang break;
59683655e91SJohnny Huang }
59783655e91SJohnny Huang } else {
59883655e91SJohnny Huang pass = 1;
59983655e91SJohnny Huang break;
60083655e91SJohnny Huang }
60183655e91SJohnny Huang }
602794e27ecSJohnny Huang if (pass)
603794e27ecSJohnny Huang return OTP_SUCCESS;
60483655e91SJohnny Huang
605794e27ecSJohnny Huang return OTP_FAILURE;
60683655e91SJohnny Huang }
60783655e91SJohnny Huang
otp_prog_dw(u32 value,u32 ignore,u32 prog_address)6082031a123SJohnny Huang static int otp_prog_dw(u32 value, u32 ignore, u32 prog_address)
609d90825e2SJohnny Huang {
610d90825e2SJohnny Huang int j, bit_value, prog_bit;
6112031a123SJohnny Huang int ret;
612d90825e2SJohnny Huang
613d90825e2SJohnny Huang for (j = 0; j < 32; j++) {
614696656c6SJohnny Huang if ((ignore >> j) & 0x1)
615d90825e2SJohnny Huang continue;
616d90825e2SJohnny Huang bit_value = (value >> j) & 0x1;
617d90825e2SJohnny Huang if (prog_address % 2 == 0) {
618d90825e2SJohnny Huang if (bit_value)
619d90825e2SJohnny Huang prog_bit = ~(0x1 << j);
620d90825e2SJohnny Huang else
621d90825e2SJohnny Huang continue;
622d90825e2SJohnny Huang } else {
623e417205bSJohnny Huang if (info_cb.version != OTP_A3)
624d90825e2SJohnny Huang prog_address |= 1 << 15;
625d90825e2SJohnny Huang if (bit_value)
626d90825e2SJohnny Huang continue;
627d90825e2SJohnny Huang else
628d90825e2SJohnny Huang prog_bit = 0x1 << j;
629d90825e2SJohnny Huang }
6302031a123SJohnny Huang ret = otp_prog(prog_address, prog_bit);
6312031a123SJohnny Huang if (ret)
6322031a123SJohnny Huang return ret;
633d90825e2SJohnny Huang }
6342031a123SJohnny Huang return 0;
635d90825e2SJohnny Huang }
636d90825e2SJohnny Huang
otp_prog_verify_2dw(u32 * data,u32 * buf,u32 * ignore_mask,u32 prog_address)637a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address)
63854552c69SJohnny Huang {
63954552c69SJohnny Huang int pass;
64054552c69SJohnny Huang int i;
641a219f6deSJohnny Huang u32 data0_masked;
642a219f6deSJohnny Huang u32 data1_masked;
643a219f6deSJohnny Huang u32 buf0_masked;
644a219f6deSJohnny Huang u32 buf1_masked;
645a219f6deSJohnny Huang u32 compare[2];
6462031a123SJohnny Huang int ret;
64754552c69SJohnny Huang
64854552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0];
64954552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0];
65054552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1];
65154552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1];
652a219f6deSJohnny Huang if (data0_masked == buf0_masked && data1_masked == buf1_masked)
653f347c284SJohnny Huang return OTP_SUCCESS;
65454552c69SJohnny Huang
655b64ca396SJohnny Huang for (i = 0; i < 32; i++) {
656b64ca396SJohnny Huang if (((data0_masked >> i) & 0x1) == 1 && ((buf0_masked >> i) & 0x1) == 0)
657b64ca396SJohnny Huang return OTP_FAILURE;
658b64ca396SJohnny Huang if (((data1_masked >> i) & 0x1) == 0 && ((buf1_masked >> i) & 0x1) == 1)
659b64ca396SJohnny Huang return OTP_FAILURE;
660b64ca396SJohnny Huang }
661b64ca396SJohnny Huang
66254552c69SJohnny Huang otp_soak(1);
6632031a123SJohnny Huang if (data0_masked != buf0_masked) {
6642031a123SJohnny Huang ret = otp_prog_dw(buf[0], ignore_mask[0], prog_address);
6652031a123SJohnny Huang if (ret)
6662031a123SJohnny Huang return OTP_FAILURE;
6672031a123SJohnny Huang }
6682031a123SJohnny Huang
6692031a123SJohnny Huang if (data1_masked != buf1_masked) {
6702031a123SJohnny Huang ret = otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
6712031a123SJohnny Huang if (ret)
6722031a123SJohnny Huang return OTP_FAILURE;
6732031a123SJohnny Huang }
67454552c69SJohnny Huang
67554552c69SJohnny Huang pass = 0;
67654552c69SJohnny Huang for (i = 0; i < RETRY; i++) {
67754552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
67854552c69SJohnny Huang otp_soak(2);
6792031a123SJohnny Huang if (compare[0] != 0) {
6802031a123SJohnny Huang ret = otp_prog_dw(compare[0], ignore_mask[0], prog_address);
6812031a123SJohnny Huang if (ret)
6822031a123SJohnny Huang return OTP_FAILURE;
6832031a123SJohnny Huang }
6842031a123SJohnny Huang if (compare[1] != ~0) {
6852031a123SJohnny Huang ret = otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
6862031a123SJohnny Huang if (ret)
6872031a123SJohnny Huang return OTP_FAILURE;
6882031a123SJohnny Huang }
68954552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
69054552c69SJohnny Huang otp_soak(1);
69154552c69SJohnny Huang } else {
69254552c69SJohnny Huang pass = 1;
69354552c69SJohnny Huang break;
69454552c69SJohnny Huang }
69554552c69SJohnny Huang } else {
69654552c69SJohnny Huang pass = 1;
69754552c69SJohnny Huang break;
69854552c69SJohnny Huang }
69954552c69SJohnny Huang }
70054552c69SJohnny Huang
70154552c69SJohnny Huang if (!pass) {
70254552c69SJohnny Huang otp_soak(0);
70354552c69SJohnny Huang return OTP_FAILURE;
70454552c69SJohnny Huang }
70554552c69SJohnny Huang return OTP_SUCCESS;
70654552c69SJohnny Huang }
70754552c69SJohnny Huang
otp_strap_status(struct otpstrap_status * otpstrap)708541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
70976d13988SJohnny Huang {
710a219f6deSJohnny Huang u32 OTPSTRAP_RAW[2];
7115010032bSJohnny Huang int strap_end;
71276d13988SJohnny Huang int i, j;
71376d13988SJohnny Huang
714e417205bSJohnny Huang if (info_cb.version == OTP_A0) {
71576d13988SJohnny Huang for (j = 0; j < 64; j++) {
71676d13988SJohnny Huang otpstrap[j].value = 0;
71776d13988SJohnny Huang otpstrap[j].remain_times = 7;
71876d13988SJohnny Huang otpstrap[j].writeable_option = -1;
71976d13988SJohnny Huang otpstrap[j].protected = 0;
72076d13988SJohnny Huang }
7215010032bSJohnny Huang strap_end = 30;
7225010032bSJohnny Huang } else {
7235010032bSJohnny Huang for (j = 0; j < 64; j++) {
7245010032bSJohnny Huang otpstrap[j].value = 0;
7255010032bSJohnny Huang otpstrap[j].remain_times = 6;
7265010032bSJohnny Huang otpstrap[j].writeable_option = -1;
7275010032bSJohnny Huang otpstrap[j].protected = 0;
7285010032bSJohnny Huang }
7295010032bSJohnny Huang strap_end = 28;
7305010032bSJohnny Huang }
73176d13988SJohnny Huang
732dacbba92SJohnny Huang otp_soak(0);
7335010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) {
73476d13988SJohnny Huang int option = (i - 16) / 2;
735a219f6deSJohnny Huang
736f347c284SJohnny Huang otp_read_conf(i, &OTPSTRAP_RAW[0]);
737f347c284SJohnny Huang otp_read_conf(i + 1, &OTPSTRAP_RAW[1]);
73876d13988SJohnny Huang for (j = 0; j < 32; j++) {
73976d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
740a219f6deSJohnny Huang
741a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1)
74276d13988SJohnny Huang otpstrap[j].writeable_option = option;
74376d13988SJohnny Huang if (bit_value == 1)
74476d13988SJohnny Huang otpstrap[j].remain_times--;
74576d13988SJohnny Huang otpstrap[j].value ^= bit_value;
74676d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value;
74776d13988SJohnny Huang }
74876d13988SJohnny Huang for (j = 32; j < 64; j++) {
74976d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
750a219f6deSJohnny Huang
751a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1)
75276d13988SJohnny Huang otpstrap[j].writeable_option = option;
75376d13988SJohnny Huang if (bit_value == 1)
75476d13988SJohnny Huang otpstrap[j].remain_times--;
75576d13988SJohnny Huang otpstrap[j].value ^= bit_value;
75676d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value;
75776d13988SJohnny Huang }
75876d13988SJohnny Huang }
7595010032bSJohnny Huang
760f347c284SJohnny Huang otp_read_conf(30, &OTPSTRAP_RAW[0]);
761f347c284SJohnny Huang otp_read_conf(31, &OTPSTRAP_RAW[1]);
76276d13988SJohnny Huang for (j = 0; j < 32; j++) {
76376d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
76476d13988SJohnny Huang otpstrap[j].protected = 1;
76576d13988SJohnny Huang }
76676d13988SJohnny Huang for (j = 32; j < 64; j++) {
76776d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
76876d13988SJohnny Huang otpstrap[j].protected = 1;
76976d13988SJohnny Huang }
77076d13988SJohnny Huang }
77176d13988SJohnny Huang
otp_strap_bit_confirm(struct otpstrap_status * otpstrap,int offset,int ibit,int bit,int pbit)7727e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit)
773f347c284SJohnny Huang {
774f347c284SJohnny Huang int prog_flag = 0;
775f347c284SJohnny Huang
776f347c284SJohnny Huang // ignore this bit
777f347c284SJohnny Huang if (ibit == 1)
778f347c284SJohnny Huang return OTP_SUCCESS;
779b489486eSJohnny Huang printf("OTPSTRAP[0x%X]:\n", offset);
780f347c284SJohnny Huang
781f347c284SJohnny Huang if (bit == otpstrap->value) {
7827e523e3bSJohnny Huang if (!pbit) {
783f347c284SJohnny Huang printf(" The value is same as before, skip it.\n");
784f347c284SJohnny Huang return OTP_PROG_SKIP;
785f347c284SJohnny Huang }
786f347c284SJohnny Huang printf(" The value is same as before.\n");
787f347c284SJohnny Huang } else {
788f347c284SJohnny Huang prog_flag = 1;
789f347c284SJohnny Huang }
790f347c284SJohnny Huang if (otpstrap->protected == 1 && prog_flag) {
791f347c284SJohnny Huang printf(" This bit is protected and is not writable\n");
792f347c284SJohnny Huang return OTP_FAILURE;
793f347c284SJohnny Huang }
794f347c284SJohnny Huang if (otpstrap->remain_times == 0 && prog_flag) {
795b489486eSJohnny Huang printf(" This bit has no remaining chance to write.\n");
796f347c284SJohnny Huang return OTP_FAILURE;
797f347c284SJohnny Huang }
798f347c284SJohnny Huang if (pbit == 1)
799f347c284SJohnny Huang printf(" This bit will be protected and become non-writable.\n");
800f347c284SJohnny Huang if (prog_flag)
801b489486eSJohnny Huang printf(" Write 1 to OTPSTRAP[0x%X] OPTION[0x%X], that value becomes from 0x%X to 0x%X.\n", offset, otpstrap->writeable_option + 1, otpstrap->value, otpstrap->value ^ 1);
802f347c284SJohnny Huang
803f347c284SJohnny Huang return OTP_SUCCESS;
804f347c284SJohnny Huang }
805f347c284SJohnny Huang
otp_prog_strap_b(int bit_offset,int value)806f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value)
807f347c284SJohnny Huang {
808f347c284SJohnny Huang struct otpstrap_status otpstrap[64];
809f347c284SJohnny Huang u32 prog_address;
810f347c284SJohnny Huang int offset;
811f347c284SJohnny Huang int ret;
812f347c284SJohnny Huang
813f347c284SJohnny Huang otp_strap_status(otpstrap);
814f347c284SJohnny Huang
8157e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
816f347c284SJohnny Huang
817f347c284SJohnny Huang if (ret != OTP_SUCCESS)
818f347c284SJohnny Huang return ret;
819f347c284SJohnny Huang
820f347c284SJohnny Huang prog_address = 0x800;
821f347c284SJohnny Huang if (bit_offset < 32) {
822f347c284SJohnny Huang offset = bit_offset;
823f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
824f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
825f347c284SJohnny Huang
826f347c284SJohnny Huang } else {
827f347c284SJohnny Huang offset = (bit_offset - 32);
828f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
829f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
830f347c284SJohnny Huang }
831f347c284SJohnny Huang
832f347c284SJohnny Huang return otp_prog_dc_b(1, prog_address, offset);
833f347c284SJohnny Huang }
834f347c284SJohnny Huang
otp_print_conf(u32 offset,int dw_count)835f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count)
836f347c284SJohnny Huang {
837f347c284SJohnny Huang int i;
838f347c284SJohnny Huang u32 ret[1];
839f347c284SJohnny Huang
840f347c284SJohnny Huang if (offset + dw_count > 32)
841f347c284SJohnny Huang return OTP_USAGE;
842f347c284SJohnny Huang otp_soak(0);
843f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i++) {
844f347c284SJohnny Huang otp_read_conf(i, ret);
845b489486eSJohnny Huang printf("OTPCFG0x%X: 0x%08X\n", i, ret[0]);
846f347c284SJohnny Huang }
847f347c284SJohnny Huang printf("\n");
848f347c284SJohnny Huang return OTP_SUCCESS;
849f347c284SJohnny Huang }
850f347c284SJohnny Huang
otp_print_data(u32 offset,int dw_count)851f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count)
852f347c284SJohnny Huang {
853f347c284SJohnny Huang int i;
854f347c284SJohnny Huang u32 ret[2];
855f347c284SJohnny Huang
856f347c284SJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0)
857f347c284SJohnny Huang return OTP_USAGE;
858f347c284SJohnny Huang otp_soak(0);
859f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i += 2) {
860f347c284SJohnny Huang otp_read_data(i, ret);
861f347c284SJohnny Huang if (i % 4 == 0)
862f347c284SJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
863f347c284SJohnny Huang else
864f347c284SJohnny Huang printf("%08X %08X\n", ret[0], ret[1]);
865f347c284SJohnny Huang }
866f347c284SJohnny Huang printf("\n");
867f347c284SJohnny Huang return OTP_SUCCESS;
868f347c284SJohnny Huang }
869f347c284SJohnny Huang
otp_print_strap(int start,int count)870f347c284SJohnny Huang static int otp_print_strap(int start, int count)
871f347c284SJohnny Huang {
872f347c284SJohnny Huang int i, j;
873f347c284SJohnny Huang int remains;
874f347c284SJohnny Huang struct otpstrap_status otpstrap[64];
875f347c284SJohnny Huang
876f347c284SJohnny Huang if (start < 0 || start > 64)
877f347c284SJohnny Huang return OTP_USAGE;
878f347c284SJohnny Huang
879f347c284SJohnny Huang if ((start + count) < 0 || (start + count) > 64)
880f347c284SJohnny Huang return OTP_USAGE;
881f347c284SJohnny Huang
882f347c284SJohnny Huang otp_strap_status(otpstrap);
883f347c284SJohnny Huang
8847e523e3bSJohnny Huang if (info_cb.version == OTP_A0)
885f347c284SJohnny Huang remains = 7;
8867e523e3bSJohnny Huang else
887f347c284SJohnny Huang remains = 6;
8887e523e3bSJohnny Huang printf("BIT(hex) Value Option Status\n");
889f347c284SJohnny Huang printf("______________________________________________________________________________\n");
890f347c284SJohnny Huang
891f347c284SJohnny Huang for (i = start; i < start + count; i++) {
892f347c284SJohnny Huang printf("0x%-8X", i);
893f347c284SJohnny Huang printf("%-7d", otpstrap[i].value);
894f347c284SJohnny Huang for (j = 0; j < remains; j++)
895f347c284SJohnny Huang printf("%d ", otpstrap[i].option_array[j]);
896f347c284SJohnny Huang printf(" ");
897f347c284SJohnny Huang if (otpstrap[i].protected == 1) {
898f347c284SJohnny Huang printf("protected and not writable");
899f347c284SJohnny Huang } else {
900f347c284SJohnny Huang printf("not protected ");
901f347c284SJohnny Huang if (otpstrap[i].remain_times == 0)
902f347c284SJohnny Huang printf("and no remaining times to write.");
903f347c284SJohnny Huang else
904f347c284SJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times);
905f347c284SJohnny Huang }
906f347c284SJohnny Huang printf("\n");
907f347c284SJohnny Huang }
908f347c284SJohnny Huang
909f347c284SJohnny Huang return OTP_SUCCESS;
910f347c284SJohnny Huang }
911f347c284SJohnny Huang
otp_print_revid(u32 * rid)912794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
913794e27ecSJohnny Huang {
914794e27ecSJohnny Huang int bit_offset;
915794e27ecSJohnny Huang int i, j;
916794e27ecSJohnny Huang
917794e27ecSJohnny Huang printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
918794e27ecSJohnny Huang printf("___________________________________________________\n");
919794e27ecSJohnny Huang for (i = 0; i < 64; i++) {
920794e27ecSJohnny Huang if (i < 32) {
921794e27ecSJohnny Huang j = 0;
922794e27ecSJohnny Huang bit_offset = i;
923794e27ecSJohnny Huang } else {
924794e27ecSJohnny Huang j = 1;
925794e27ecSJohnny Huang bit_offset = i - 32;
926794e27ecSJohnny Huang }
927794e27ecSJohnny Huang if (i % 16 == 0)
928794e27ecSJohnny Huang printf("%2x | ", i);
929794e27ecSJohnny Huang printf("%d ", (rid[j] >> bit_offset) & 0x1);
930794e27ecSJohnny Huang if ((i + 1) % 16 == 0)
931794e27ecSJohnny Huang printf("\n");
932794e27ecSJohnny Huang }
933794e27ecSJohnny Huang }
934794e27ecSJohnny Huang
otp_print_scu_image(struct otp_image_layout * image_layout)935b25f02d2SJohnny Huang static int otp_print_scu_image(struct otp_image_layout *image_layout)
936b25f02d2SJohnny Huang {
937b25f02d2SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info;
938b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro;
939b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
940b25f02d2SJohnny Huang int i;
941b25f02d2SJohnny Huang u32 scu_offset;
942b25f02d2SJohnny Huang u32 dw_offset;
943b25f02d2SJohnny Huang u32 bit_offset;
944b25f02d2SJohnny Huang u32 mask;
945b25f02d2SJohnny Huang u32 otp_value;
946b25f02d2SJohnny Huang u32 otp_ignore;
947b25f02d2SJohnny Huang
948b25f02d2SJohnny Huang printf("SCU BIT reg_protect Description\n");
949b25f02d2SJohnny Huang printf("____________________________________________________________________\n");
950b25f02d2SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) {
951b25f02d2SJohnny Huang mask = BIT(scu_info[i].length) - 1;
952b25f02d2SJohnny Huang
953b25f02d2SJohnny Huang if (scu_info[i].bit_offset > 31) {
954b25f02d2SJohnny Huang scu_offset = 0x510;
955b25f02d2SJohnny Huang dw_offset = 1;
956b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset - 32;
957b25f02d2SJohnny Huang } else {
958b25f02d2SJohnny Huang scu_offset = 0x500;
959b25f02d2SJohnny Huang dw_offset = 0;
960b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset;
961b25f02d2SJohnny Huang }
962b25f02d2SJohnny Huang
963b25f02d2SJohnny Huang otp_value = (OTPSCU[dw_offset] >> bit_offset) & mask;
964b25f02d2SJohnny Huang otp_ignore = (OTPSCU_IGNORE[dw_offset] >> bit_offset) & mask;
965b25f02d2SJohnny Huang
966b25f02d2SJohnny Huang if (otp_ignore == mask)
967b25f02d2SJohnny Huang continue;
968b25f02d2SJohnny Huang else if (otp_ignore != 0)
969b25f02d2SJohnny Huang return OTP_FAILURE;
970b25f02d2SJohnny Huang
971b25f02d2SJohnny Huang if (otp_value != 0 && otp_value != mask)
972b25f02d2SJohnny Huang return OTP_FAILURE;
973b25f02d2SJohnny Huang
974b25f02d2SJohnny Huang printf("0x%-6X", scu_offset);
975b25f02d2SJohnny Huang if (scu_info[i].length == 1)
976b25f02d2SJohnny Huang printf("0x%-11X", bit_offset);
977b25f02d2SJohnny Huang else
9782131c250SJohnny Huang printf("0x%-2X:0x%-6x", bit_offset, bit_offset + scu_info[i].length - 1);
979b25f02d2SJohnny Huang printf("0x%-14X", otp_value);
980b25f02d2SJohnny Huang printf("%s\n", scu_info[i].information);
981b25f02d2SJohnny Huang }
982b25f02d2SJohnny Huang return OTP_SUCCESS;
983b25f02d2SJohnny Huang }
984b25f02d2SJohnny Huang
otp_print_scu_info(void)9850dc9a440SJohnny Huang static void otp_print_scu_info(void)
9860dc9a440SJohnny Huang {
9870dc9a440SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info;
9880dc9a440SJohnny Huang u32 OTPCFG[2];
9890dc9a440SJohnny Huang u32 scu_offset;
9900dc9a440SJohnny Huang u32 bit_offset;
9910dc9a440SJohnny Huang u32 reg_p;
9920dc9a440SJohnny Huang u32 length;
9930dc9a440SJohnny Huang int i, j;
9940dc9a440SJohnny Huang
9950dc9a440SJohnny Huang otp_soak(0);
9960dc9a440SJohnny Huang otp_read_conf(28, &OTPCFG[0]);
9970dc9a440SJohnny Huang otp_read_conf(29, &OTPCFG[1]);
9980dc9a440SJohnny Huang printf("SCU BIT reg_protect Description\n");
9990dc9a440SJohnny Huang printf("____________________________________________________________________\n");
10000dc9a440SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) {
10010dc9a440SJohnny Huang length = scu_info[i].length;
10020dc9a440SJohnny Huang for (j = 0; j < length; j++) {
10030dc9a440SJohnny Huang if (scu_info[i].bit_offset + j < 32) {
10040dc9a440SJohnny Huang scu_offset = 0x500;
10050dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j;
10060dc9a440SJohnny Huang reg_p = (OTPCFG[0] >> bit_offset) & 0x1;
10070dc9a440SJohnny Huang } else {
10080dc9a440SJohnny Huang scu_offset = 0x510;
10090dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j - 32;
10100dc9a440SJohnny Huang reg_p = (OTPCFG[1] >> bit_offset) & 0x1;
10110dc9a440SJohnny Huang }
10120dc9a440SJohnny Huang printf("0x%-6X", scu_offset);
10130dc9a440SJohnny Huang printf("0x%-4X", bit_offset);
10140dc9a440SJohnny Huang printf("0x%-13X", reg_p);
10150dc9a440SJohnny Huang if (length == 1) {
10160dc9a440SJohnny Huang printf(" %s\n", scu_info[i].information);
10170dc9a440SJohnny Huang continue;
10180dc9a440SJohnny Huang }
10190dc9a440SJohnny Huang
10200dc9a440SJohnny Huang if (j == 0)
10210dc9a440SJohnny Huang printf("/%s\n", scu_info[i].information);
10220dc9a440SJohnny Huang else if (j == length - 1)
10230dc9a440SJohnny Huang printf("\\ \"\n");
10240dc9a440SJohnny Huang else
10250dc9a440SJohnny Huang printf("| \"\n");
10260dc9a440SJohnny Huang }
10270dc9a440SJohnny Huang }
10280dc9a440SJohnny Huang }
10290dc9a440SJohnny Huang
otp_print_conf_image(struct otp_image_layout * image_layout)1030696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
103169d5fd8fSJohnny Huang {
103279e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info;
1033a219f6deSJohnny Huang u32 *OTPCFG = (u32 *)image_layout->conf;
1034a219f6deSJohnny Huang u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
1035a219f6deSJohnny Huang u32 mask;
1036a219f6deSJohnny Huang u32 dw_offset;
1037a219f6deSJohnny Huang u32 bit_offset;
1038a219f6deSJohnny Huang u32 otp_value;
1039a219f6deSJohnny Huang u32 otp_ignore;
1040b458cd62SJohnny Huang int fail = 0;
10417adec5f6SJohnny Huang int mask_err;
1042794e27ecSJohnny Huang int rid_num = 0;
104373f11549SJohnny Huang char valid_bit[20];
1044794e27ecSJohnny Huang int fz;
104566f2f8e5SJohnny Huang int i;
104673f11549SJohnny Huang int j;
104766f2f8e5SJohnny Huang
1048737ed20bSJohnny Huang printf("DW BIT Value Description\n");
104966f2f8e5SJohnny Huang printf("__________________________________________________________________________\n");
10503cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) {
10517adec5f6SJohnny Huang mask_err = 0;
10523cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset;
10533cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset;
10543cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1;
1055b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
1056696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
1057b458cd62SJohnny Huang
10587adec5f6SJohnny Huang if (conf_info[i].value == OTP_REG_VALID_BIT) {
10597adec5f6SJohnny Huang if (((otp_value + otp_ignore) & mask) != mask) {
1060b458cd62SJohnny Huang fail = 1;
10617adec5f6SJohnny Huang mask_err = 1;
10627adec5f6SJohnny Huang }
10637adec5f6SJohnny Huang } else {
10647adec5f6SJohnny Huang if (otp_ignore == mask) {
10657adec5f6SJohnny Huang continue;
10667adec5f6SJohnny Huang } else if (otp_ignore != 0) {
10677adec5f6SJohnny Huang fail = 1;
10687adec5f6SJohnny Huang mask_err = 1;
10697adec5f6SJohnny Huang }
10707adec5f6SJohnny Huang }
1071b458cd62SJohnny Huang
1072a219f6deSJohnny Huang if (otp_value != conf_info[i].value &&
10733cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED &&
10743cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE &&
10753cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT)
1076b458cd62SJohnny Huang continue;
1077b458cd62SJohnny Huang printf("0x%-4X", dw_offset);
1078b458cd62SJohnny Huang
10793cb28812SJohnny Huang if (conf_info[i].length == 1) {
10803cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset);
108166f2f8e5SJohnny Huang } else {
1082b458cd62SJohnny Huang printf("0x%-2X:0x%-4X",
10833cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1,
10843cb28812SJohnny Huang conf_info[i].bit_offset);
108566f2f8e5SJohnny Huang }
1086b458cd62SJohnny Huang printf("0x%-10x", otp_value);
1087b458cd62SJohnny Huang
10887adec5f6SJohnny Huang if (mask_err) {
10897adec5f6SJohnny Huang printf("Ignore, mask error\n");
1090a219f6deSJohnny Huang continue;
1091a219f6deSJohnny Huang }
10923cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) {
1093b458cd62SJohnny Huang printf("Reserved\n");
10943cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) {
10953cb28812SJohnny Huang printf(conf_info[i].information, otp_value);
1096b458cd62SJohnny Huang printf("\n");
10973cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1098b458cd62SJohnny Huang if (otp_value != 0) {
109973f11549SJohnny Huang for (j = 0; j < 7; j++) {
1100e2b82258SJohnny Huang if (otp_value & (1 << j))
110173f11549SJohnny Huang valid_bit[j * 2] = '1';
1102a219f6deSJohnny Huang else
110373f11549SJohnny Huang valid_bit[j * 2] = '0';
110473f11549SJohnny Huang valid_bit[j * 2 + 1] = ' ';
110573f11549SJohnny Huang }
110673f11549SJohnny Huang valid_bit[15] = 0;
110773f11549SJohnny Huang } else {
110873f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1109b458cd62SJohnny Huang }
11103cb28812SJohnny Huang printf(conf_info[i].information, valid_bit);
1111b458cd62SJohnny Huang printf("\n");
1112b458cd62SJohnny Huang } else {
11133cb28812SJohnny Huang printf("%s\n", conf_info[i].information);
1114b458cd62SJohnny Huang }
1115b458cd62SJohnny Huang }
1116b458cd62SJohnny Huang
1117794e27ecSJohnny Huang if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
1118794e27ecSJohnny Huang if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
1119794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n");
1120794e27ecSJohnny Huang fail = 1;
1121794e27ecSJohnny Huang } else {
1122794e27ecSJohnny Huang fz = 0;
1123794e27ecSJohnny Huang for (i = 0; i < 64; i++) {
1124794e27ecSJohnny Huang if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
1125794e27ecSJohnny Huang if (!fz)
1126794e27ecSJohnny Huang fz = 1;
1127794e27ecSJohnny Huang } else {
1128794e27ecSJohnny Huang rid_num++;
1129794e27ecSJohnny Huang if (fz) {
1130794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n");
1131794e27ecSJohnny Huang fail = 1;
1132794e27ecSJohnny Huang break;
1133794e27ecSJohnny Huang }
1134794e27ecSJohnny Huang }
1135794e27ecSJohnny Huang }
1136794e27ecSJohnny Huang }
1137794e27ecSJohnny Huang if (fail)
1138794e27ecSJohnny Huang printf("OTP revision ID\n");
1139794e27ecSJohnny Huang else
1140794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num);
1141794e27ecSJohnny Huang otp_print_revid(&OTPCFG[0xa]);
1142794e27ecSJohnny Huang }
1143794e27ecSJohnny Huang
1144b458cd62SJohnny Huang if (fail)
1145b458cd62SJohnny Huang return OTP_FAILURE;
1146b458cd62SJohnny Huang
114766f2f8e5SJohnny Huang return OTP_SUCCESS;
114866f2f8e5SJohnny Huang }
114966f2f8e5SJohnny Huang
otp_print_conf_info(int input_offset)11502d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
115166f2f8e5SJohnny Huang {
115279e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info;
1153a219f6deSJohnny Huang u32 OTPCFG[16];
1154a219f6deSJohnny Huang u32 mask;
1155a219f6deSJohnny Huang u32 dw_offset;
1156a219f6deSJohnny Huang u32 bit_offset;
1157a219f6deSJohnny Huang u32 otp_value;
115873f11549SJohnny Huang char valid_bit[20];
115966f2f8e5SJohnny Huang int i;
116073f11549SJohnny Huang int j;
116166f2f8e5SJohnny Huang
1162dacbba92SJohnny Huang otp_soak(0);
1163bb34a7bfSJohnny Huang for (i = 0; i < 16; i++)
1164f347c284SJohnny Huang otp_read_conf(i, &OTPCFG[i]);
116566f2f8e5SJohnny Huang
1166b458cd62SJohnny Huang printf("DW BIT Value Description\n");
1167b458cd62SJohnny Huang printf("__________________________________________________________________________\n");
11683cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) {
11693cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
11702d4b0742SJohnny Huang continue;
11713cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset;
11723cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset;
11733cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1;
1174b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
1175b458cd62SJohnny Huang
1176a219f6deSJohnny Huang if (otp_value != conf_info[i].value &&
11773cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED &&
11783cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE &&
11793cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT)
1180b458cd62SJohnny Huang continue;
1181b458cd62SJohnny Huang printf("0x%-4X", dw_offset);
1182b458cd62SJohnny Huang
11833cb28812SJohnny Huang if (conf_info[i].length == 1) {
11843cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset);
1185b458cd62SJohnny Huang } else {
1186b458cd62SJohnny Huang printf("0x%-2X:0x%-4X",
11873cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1,
11883cb28812SJohnny Huang conf_info[i].bit_offset);
1189b458cd62SJohnny Huang }
1190b458cd62SJohnny Huang printf("0x%-10x", otp_value);
1191b458cd62SJohnny Huang
11923cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) {
1193b458cd62SJohnny Huang printf("Reserved\n");
11943cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) {
11953cb28812SJohnny Huang printf(conf_info[i].information, otp_value);
1196b458cd62SJohnny Huang printf("\n");
11973cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1198b458cd62SJohnny Huang if (otp_value != 0) {
119973f11549SJohnny Huang for (j = 0; j < 7; j++) {
1200030cb4a7SJohnny Huang if (otp_value & (1 << j))
120173f11549SJohnny Huang valid_bit[j * 2] = '1';
1202a219f6deSJohnny Huang else
120373f11549SJohnny Huang valid_bit[j * 2] = '0';
120473f11549SJohnny Huang valid_bit[j * 2 + 1] = ' ';
120573f11549SJohnny Huang }
120673f11549SJohnny Huang valid_bit[15] = 0;
120773f11549SJohnny Huang } else {
120873f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1209b458cd62SJohnny Huang }
12103cb28812SJohnny Huang printf(conf_info[i].information, valid_bit);
1211b458cd62SJohnny Huang printf("\n");
1212b458cd62SJohnny Huang } else {
12133cb28812SJohnny Huang printf("%s\n", conf_info[i].information);
1214b458cd62SJohnny Huang }
1215b458cd62SJohnny Huang }
1216b458cd62SJohnny Huang return OTP_SUCCESS;
121766f2f8e5SJohnny Huang }
121866f2f8e5SJohnny Huang
otp_print_strap_image(struct otp_image_layout * image_layout)12195010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
122076d13988SJohnny Huang {
122179e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info;
1222a219f6deSJohnny Huang u32 *OTPSTRAP;
1223a219f6deSJohnny Huang u32 *OTPSTRAP_PRO;
1224a219f6deSJohnny Huang u32 *OTPSTRAP_IGNORE;
122576d13988SJohnny Huang int i;
1226a8bd6d8cSJohnny Huang int fail = 0;
1227a219f6deSJohnny Huang u32 bit_offset;
1228a219f6deSJohnny Huang u32 dw_offset;
1229a219f6deSJohnny Huang u32 mask;
1230a219f6deSJohnny Huang u32 otp_value;
1231a219f6deSJohnny Huang u32 otp_protect;
1232a219f6deSJohnny Huang u32 otp_ignore;
123376d13988SJohnny Huang
1234a219f6deSJohnny Huang OTPSTRAP = (u32 *)image_layout->strap;
1235a219f6deSJohnny Huang OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
1236a219f6deSJohnny Huang OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
12377e523e3bSJohnny Huang
1238a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n");
1239de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n");
1240b458cd62SJohnny Huang
12413cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) {
12427adec5f6SJohnny Huang fail = 0;
1243696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) {
1244a8bd6d8cSJohnny Huang dw_offset = 1;
12453cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32;
1246a8bd6d8cSJohnny Huang } else {
1247a8bd6d8cSJohnny Huang dw_offset = 0;
12483cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset;
1249a8bd6d8cSJohnny Huang }
125076d13988SJohnny Huang
12513cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1;
1252a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
1253a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
1254696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
1255a8bd6d8cSJohnny Huang
1256a219f6deSJohnny Huang if (otp_ignore == mask)
1257a8bd6d8cSJohnny Huang continue;
1258a219f6deSJohnny Huang else if (otp_ignore != 0)
1259a8bd6d8cSJohnny Huang fail = 1;
1260a8bd6d8cSJohnny Huang
1261a219f6deSJohnny Huang if (otp_value != strap_info[i].value &&
12623cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED)
1263a8bd6d8cSJohnny Huang continue;
1264a8bd6d8cSJohnny Huang
12653cb28812SJohnny Huang if (strap_info[i].length == 1) {
12663cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset);
1267a8bd6d8cSJohnny Huang } else {
1268b458cd62SJohnny Huang printf("0x%-2X:0x%-4X",
12693cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1,
12703cb28812SJohnny Huang strap_info[i].bit_offset);
1271a8bd6d8cSJohnny Huang }
1272a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value);
1273a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect);
1274a8bd6d8cSJohnny Huang
1275a8bd6d8cSJohnny Huang if (fail) {
1276696656c6SJohnny Huang printf("Ignore mask error\n");
1277a8bd6d8cSJohnny Huang } else {
12783cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED)
12793cb28812SJohnny Huang printf("%s\n", strap_info[i].information);
1280a8bd6d8cSJohnny Huang else
1281a8bd6d8cSJohnny Huang printf("Reserved\n");
1282a8bd6d8cSJohnny Huang }
1283a8bd6d8cSJohnny Huang }
1284a8bd6d8cSJohnny Huang
1285a8bd6d8cSJohnny Huang if (fail)
128676d13988SJohnny Huang return OTP_FAILURE;
128776d13988SJohnny Huang
128876d13988SJohnny Huang return OTP_SUCCESS;
128976d13988SJohnny Huang }
129076d13988SJohnny Huang
otp_print_strap_info(int view)1291b458cd62SJohnny Huang static int otp_print_strap_info(int view)
129276d13988SJohnny Huang {
129379e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info;
129476d13988SJohnny Huang struct otpstrap_status strap_status[64];
129507baa4e8SJohnny Huang int i, j;
1296b458cd62SJohnny Huang int fail = 0;
1297a219f6deSJohnny Huang u32 bit_offset;
1298a219f6deSJohnny Huang u32 length;
1299a219f6deSJohnny Huang u32 otp_value;
1300a219f6deSJohnny Huang u32 otp_protect;
130176d13988SJohnny Huang
1302541eb887SJohnny Huang otp_strap_status(strap_status);
130376d13988SJohnny Huang
1304b458cd62SJohnny Huang if (view) {
130507baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n");
130607baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n");
1307b458cd62SJohnny Huang } else {
1308b458cd62SJohnny Huang printf("BIT(hex) Value Description\n");
1309b458cd62SJohnny Huang printf("________________________________________________________________________________\n");
131076d13988SJohnny Huang }
13113cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) {
1312b458cd62SJohnny Huang otp_value = 0;
13133cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset;
13143cb28812SJohnny Huang length = strap_info[i].length;
1315b458cd62SJohnny Huang for (j = 0; j < length; j++) {
1316c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j;
1317c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j;
1318b458cd62SJohnny Huang }
1319a219f6deSJohnny Huang if (otp_value != strap_info[i].value &&
13203cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED)
1321b458cd62SJohnny Huang continue;
1322b458cd62SJohnny Huang if (view) {
1323b458cd62SJohnny Huang for (j = 0; j < length; j++) {
13243cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j);
1325b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value);
132607baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times);
1327e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected);
13283cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) {
1329b458cd62SJohnny Huang printf(" Reserved\n");
1330b458cd62SJohnny Huang continue;
1331b458cd62SJohnny Huang }
1332b458cd62SJohnny Huang if (length == 1) {
13333cb28812SJohnny Huang printf(" %s\n", strap_info[i].information);
1334b458cd62SJohnny Huang continue;
133576d13988SJohnny Huang }
133676d13988SJohnny Huang
1337b458cd62SJohnny Huang if (j == 0)
13383cb28812SJohnny Huang printf("/%s\n", strap_info[i].information);
1339b458cd62SJohnny Huang else if (j == length - 1)
1340b458cd62SJohnny Huang printf("\\ \"\n");
1341b458cd62SJohnny Huang else
1342b458cd62SJohnny Huang printf("| \"\n");
134376d13988SJohnny Huang }
1344b458cd62SJohnny Huang } else {
1345c947ef08SJohnny Huang if (length == 1) {
13463cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset);
1347b458cd62SJohnny Huang } else {
1348b458cd62SJohnny Huang printf("0x%-2X:0x%-4X",
1349b458cd62SJohnny Huang bit_offset + length - 1, bit_offset);
1350b458cd62SJohnny Huang }
1351b458cd62SJohnny Huang
1352b458cd62SJohnny Huang printf("0x%-10X", otp_value);
1353b458cd62SJohnny Huang
13543cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED)
13553cb28812SJohnny Huang printf("%s\n", strap_info[i].information);
1356b458cd62SJohnny Huang else
1357b458cd62SJohnny Huang printf("Reserved\n");
1358b458cd62SJohnny Huang }
1359b458cd62SJohnny Huang }
1360b458cd62SJohnny Huang
1361b458cd62SJohnny Huang if (fail)
1362b458cd62SJohnny Huang return OTP_FAILURE;
1363b458cd62SJohnny Huang
1364b458cd62SJohnny Huang return OTP_SUCCESS;
1365b458cd62SJohnny Huang }
1366b458cd62SJohnny Huang
_otp_print_key(u32 header,u32 offset,u8 * data)1367418822f0SJohnny Huang static void _otp_print_key(u32 header, u32 offset, u8 *data)
136869d5fd8fSJohnny Huang {
136988bd7d58SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info;
1370bf54cdd1SJammy Huang struct otpkey_type key_info = { .value = -1 };
1371418822f0SJohnny Huang int key_id, key_offset, key_type, key_length, exp_length;
137288bd7d58SJohnny Huang int len = 0;
1373418822f0SJohnny Huang int i;
137454552c69SJohnny Huang
1375418822f0SJohnny Huang key_id = header & 0x7;
1376418822f0SJohnny Huang key_offset = header & 0x1ff8;
1377418822f0SJohnny Huang key_type = (header >> 14) & 0xf;
1378418822f0SJohnny Huang key_length = (header >> 18) & 0x3;
1379418822f0SJohnny Huang exp_length = (header >> 20) & 0xfff;
13809d998018SJohnny Huang
1381418822f0SJohnny Huang printf("\nKey[%d]:\n", offset);
1382418822f0SJohnny Huang printf("Header: %x\n", header);
13839a4fe690SJohnny Huang
1384418822f0SJohnny Huang for (i = 0; i < info_cb.key_info_len; i++) {
1385418822f0SJohnny Huang if (key_type == key_info_array[i].value) {
1386418822f0SJohnny Huang key_info = key_info_array[i];
13879a4fe690SJohnny Huang break;
13889a4fe690SJohnny Huang }
13899a4fe690SJohnny Huang }
139088bd7d58SJohnny Huang if (key_info.value == -1)
1391418822f0SJohnny Huang return;
13929a4fe690SJohnny Huang
139369d5fd8fSJohnny Huang printf("Key Type: ");
13949a4fe690SJohnny Huang printf("%s\n", key_info.information);
13959a4fe690SJohnny Huang
13969a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
139769d5fd8fSJohnny Huang printf("HMAC SHA Type: ");
139869d5fd8fSJohnny Huang switch (key_length) {
139969d5fd8fSJohnny Huang case 0:
140069d5fd8fSJohnny Huang printf("HMAC(SHA224)\n");
140169d5fd8fSJohnny Huang break;
140269d5fd8fSJohnny Huang case 1:
140369d5fd8fSJohnny Huang printf("HMAC(SHA256)\n");
140469d5fd8fSJohnny Huang break;
140569d5fd8fSJohnny Huang case 2:
140669d5fd8fSJohnny Huang printf("HMAC(SHA384)\n");
140769d5fd8fSJohnny Huang break;
140869d5fd8fSJohnny Huang case 3:
140969d5fd8fSJohnny Huang printf("HMAC(SHA512)\n");
141069d5fd8fSJohnny Huang break;
141169d5fd8fSJohnny Huang }
1412181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1413181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
141469d5fd8fSJohnny Huang printf("RSA SHA Type: ");
141569d5fd8fSJohnny Huang switch (key_length) {
141669d5fd8fSJohnny Huang case 0:
141769d5fd8fSJohnny Huang printf("RSA1024\n");
141869d5fd8fSJohnny Huang len = 0x100;
141969d5fd8fSJohnny Huang break;
142069d5fd8fSJohnny Huang case 1:
142169d5fd8fSJohnny Huang printf("RSA2048\n");
142269d5fd8fSJohnny Huang len = 0x200;
142369d5fd8fSJohnny Huang break;
142469d5fd8fSJohnny Huang case 2:
142569d5fd8fSJohnny Huang printf("RSA3072\n");
142669d5fd8fSJohnny Huang len = 0x300;
142769d5fd8fSJohnny Huang break;
142869d5fd8fSJohnny Huang case 3:
142969d5fd8fSJohnny Huang printf("RSA4096\n");
143069d5fd8fSJohnny Huang len = 0x400;
143169d5fd8fSJohnny Huang break;
143269d5fd8fSJohnny Huang }
143369d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length);
143469d5fd8fSJohnny Huang }
14359a4fe690SJohnny Huang if (key_info.need_id)
143669d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id);
1437418822f0SJohnny Huang if (!data)
1438418822f0SJohnny Huang return;
143969d5fd8fSJohnny Huang printf("Key Value:\n");
14409a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
1441418822f0SJohnny Huang buf_print(&data[key_offset], 0x40);
14429a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) {
14439a4fe690SJohnny Huang printf("AES Key:\n");
1444418822f0SJohnny Huang buf_print(&data[key_offset], 0x20);
1445e417205bSJohnny Huang if (info_cb.version == OTP_A0) {
14469a4fe690SJohnny Huang printf("AES IV:\n");
1447418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x10);
14489a4fe690SJohnny Huang }
14499a4fe690SJohnny Huang
14509a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
1451e417205bSJohnny Huang if (info_cb.version == OTP_A0) {
145269d5fd8fSJohnny Huang printf("AES Key:\n");
1453418822f0SJohnny Huang buf_print(&data[key_offset], 0x20);
145469d5fd8fSJohnny Huang printf("AES IV:\n");
1455418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x10);
14565fdde29fSJohnny Huang } else {
14579a4fe690SJohnny Huang printf("AES Key 1:\n");
1458418822f0SJohnny Huang buf_print(&data[key_offset], 0x20);
14599a4fe690SJohnny Huang printf("AES Key 2:\n");
1460418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x20);
14619a4fe690SJohnny Huang }
1462181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
146369d5fd8fSJohnny Huang printf("RSA mod:\n");
1464418822f0SJohnny Huang buf_print(&data[key_offset], len / 2);
146569d5fd8fSJohnny Huang printf("RSA exp:\n");
1466418822f0SJohnny Huang buf_print(&data[key_offset + (len / 2)], len / 2);
1467181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1468181f72d8SJohnny Huang printf("RSA mod:\n");
1469418822f0SJohnny Huang buf_print(&data[key_offset], len / 2);
1470181f72d8SJohnny Huang printf("RSA exp:\n");
1471a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3);
147269d5fd8fSJohnny Huang }
1473418822f0SJohnny Huang }
1474418822f0SJohnny Huang
otp_print_key(u32 * data)1475418822f0SJohnny Huang static void otp_print_key(u32 *data)
1476418822f0SJohnny Huang {
1477418822f0SJohnny Huang int i;
1478418822f0SJohnny Huang int last;
1479418822f0SJohnny Huang u8 *byte_buf;
1480418822f0SJohnny Huang int empty;
1481418822f0SJohnny Huang
1482418822f0SJohnny Huang byte_buf = (u8 *)data;
1483418822f0SJohnny Huang
1484418822f0SJohnny Huang empty = 1;
1485418822f0SJohnny Huang for (i = 0; i < 16; i++) {
1486418822f0SJohnny Huang if (i % 2) {
1487418822f0SJohnny Huang if (data[i] != 0xffffffff)
1488418822f0SJohnny Huang empty = 0;
1489418822f0SJohnny Huang } else {
1490418822f0SJohnny Huang if (data[i] != 0)
1491418822f0SJohnny Huang empty = 0;
1492418822f0SJohnny Huang }
1493418822f0SJohnny Huang }
1494418822f0SJohnny Huang if (empty) {
1495418822f0SJohnny Huang printf("OTP data header is empty\n");
1496418822f0SJohnny Huang return;
1497418822f0SJohnny Huang }
1498418822f0SJohnny Huang
1499418822f0SJohnny Huang for (i = 0; i < 16; i++) {
1500418822f0SJohnny Huang last = (data[i] >> 13) & 1;
1501418822f0SJohnny Huang _otp_print_key(data[i], i, byte_buf);
150269d5fd8fSJohnny Huang if (last)
150369d5fd8fSJohnny Huang break;
150469d5fd8fSJohnny Huang }
150588bd7d58SJohnny Huang }
150688bd7d58SJohnny Huang
otp_print_data_image(struct otp_image_layout * image_layout)150788bd7d58SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout)
150888bd7d58SJohnny Huang {
150988bd7d58SJohnny Huang u32 *buf;
151088bd7d58SJohnny Huang
151188bd7d58SJohnny Huang buf = (u32 *)image_layout->data;
1512418822f0SJohnny Huang otp_print_key(buf);
151388bd7d58SJohnny Huang
1514f347c284SJohnny Huang return OTP_SUCCESS;
1515f347c284SJohnny Huang }
1516f347c284SJohnny Huang
otp_print_key_info(void)151788bd7d58SJohnny Huang static void otp_print_key_info(void)
151888bd7d58SJohnny Huang {
151988bd7d58SJohnny Huang u32 data[2048];
152088bd7d58SJohnny Huang int i;
152188bd7d58SJohnny Huang
152288bd7d58SJohnny Huang for (i = 0; i < 2048 ; i += 2)
152388bd7d58SJohnny Huang otp_read_data(i, &data[i]);
152488bd7d58SJohnny Huang
1525418822f0SJohnny Huang otp_print_key(data);
152688bd7d58SJohnny Huang }
152788bd7d58SJohnny Huang
otp_prog_data(struct otp_image_layout * image_layout,u32 * data)1528b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data)
1529f347c284SJohnny Huang {
1530f347c284SJohnny Huang int i;
1531f347c284SJohnny Huang int ret;
1532f347c284SJohnny Huang u32 *buf;
1533f347c284SJohnny Huang u32 *buf_ignore;
1534f347c284SJohnny Huang
1535f347c284SJohnny Huang buf = (u32 *)image_layout->data;
1536f347c284SJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore;
1537f347c284SJohnny Huang printf("Start Programing...\n");
1538f347c284SJohnny Huang
1539f347c284SJohnny Huang // programing ecc region first
1540f347c284SJohnny Huang for (i = 1792; i < 2046; i += 2) {
1541f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1542f347c284SJohnny Huang if (ret != OTP_SUCCESS) {
1543f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1544f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1545f347c284SJohnny Huang return ret;
1546f347c284SJohnny Huang }
1547f347c284SJohnny Huang }
1548f347c284SJohnny Huang
1549f347c284SJohnny Huang for (i = 0; i < 1792; i += 2) {
1550f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1551f347c284SJohnny Huang if (ret != OTP_SUCCESS) {
1552f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1553f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1554f347c284SJohnny Huang return ret;
1555f347c284SJohnny Huang }
1556f347c284SJohnny Huang }
1557f347c284SJohnny Huang otp_soak(0);
1558f347c284SJohnny Huang return OTP_SUCCESS;
1559f347c284SJohnny Huang }
1560f347c284SJohnny Huang
otp_prog_strap(struct otp_image_layout * image_layout,struct otpstrap_status * otpstrap)1561b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap)
1562f347c284SJohnny Huang {
1563f347c284SJohnny Huang u32 *strap;
1564f347c284SJohnny Huang u32 *strap_ignore;
1565f347c284SJohnny Huang u32 *strap_pro;
1566f347c284SJohnny Huang u32 prog_address;
1567f347c284SJohnny Huang int i;
15687e523e3bSJohnny Huang int bit, pbit, ibit, offset;
1569f347c284SJohnny Huang int fail = 0;
1570f347c284SJohnny Huang int ret;
1571f347c284SJohnny Huang int prog_flag = 0;
1572f347c284SJohnny Huang
1573f347c284SJohnny Huang strap = (u32 *)image_layout->strap;
1574f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro;
1575f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore;
1576f347c284SJohnny Huang
1577f347c284SJohnny Huang for (i = 0; i < 64; i++) {
1578f347c284SJohnny Huang prog_address = 0x800;
1579f347c284SJohnny Huang if (i < 32) {
1580f347c284SJohnny Huang offset = i;
1581f347c284SJohnny Huang bit = (strap[0] >> offset) & 0x1;
1582f347c284SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1;
1583f347c284SJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1;
1584f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
1585f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
1586f347c284SJohnny Huang
1587f347c284SJohnny Huang } else {
1588f347c284SJohnny Huang offset = (i - 32);
1589f347c284SJohnny Huang bit = (strap[1] >> offset) & 0x1;
1590f347c284SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1;
1591f347c284SJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1;
1592f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
1593f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
1594f347c284SJohnny Huang }
1595f347c284SJohnny Huang
1596f347c284SJohnny Huang if (ibit == 1)
1597f347c284SJohnny Huang continue;
1598f347c284SJohnny Huang if (bit == otpstrap[i].value)
1599f347c284SJohnny Huang prog_flag = 0;
1600f347c284SJohnny Huang else
1601f347c284SJohnny Huang prog_flag = 1;
1602f347c284SJohnny Huang
1603f347c284SJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) {
1604f347c284SJohnny Huang fail = 1;
1605f347c284SJohnny Huang continue;
1606f347c284SJohnny Huang }
1607f347c284SJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) {
1608f347c284SJohnny Huang fail = 1;
1609f347c284SJohnny Huang continue;
1610f347c284SJohnny Huang }
1611f347c284SJohnny Huang
1612f347c284SJohnny Huang if (prog_flag) {
1613f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset);
1614f347c284SJohnny Huang if (ret)
1615f347c284SJohnny Huang return OTP_FAILURE;
1616f347c284SJohnny Huang }
1617f347c284SJohnny Huang
1618f347c284SJohnny Huang if (pbit != 0) {
1619f347c284SJohnny Huang prog_address = 0x800;
1620f347c284SJohnny Huang if (i < 32)
1621f347c284SJohnny Huang prog_address |= 0x60c;
1622f347c284SJohnny Huang else
1623f347c284SJohnny Huang prog_address |= 0x60e;
1624f347c284SJohnny Huang
1625f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset);
1626f347c284SJohnny Huang if (ret)
1627f347c284SJohnny Huang return OTP_FAILURE;
1628f347c284SJohnny Huang }
1629f347c284SJohnny Huang }
1630f347c284SJohnny Huang otp_soak(0);
1631f347c284SJohnny Huang if (fail == 1)
1632f347c284SJohnny Huang return OTP_FAILURE;
1633f347c284SJohnny Huang return OTP_SUCCESS;
163469d5fd8fSJohnny Huang }
163569d5fd8fSJohnny Huang
otp_prog_conf(struct otp_image_layout * image_layout,u32 * otp_conf)1636b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf)
163769d5fd8fSJohnny Huang {
1638a6d0d645SJohnny Huang int i, k;
1639d90825e2SJohnny Huang int pass = 0;
1640a219f6deSJohnny Huang u32 prog_address;
1641a219f6deSJohnny Huang u32 compare[2];
1642a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf;
1643a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1644a219f6deSJohnny Huang u32 data_masked;
1645a219f6deSJohnny Huang u32 buf_masked;
16462031a123SJohnny Huang int ret;
164769d5fd8fSJohnny Huang
1648a6d0d645SJohnny Huang printf("Start Programing...\n");
1649d90825e2SJohnny Huang otp_soak(0);
1650bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) {
1651b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i];
16525010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i];
1653a6d0d645SJohnny Huang prog_address = 0x800;
1654a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200;
1655a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2;
1656bb34a7bfSJohnny Huang if (data_masked == buf_masked) {
1657bb34a7bfSJohnny Huang pass = 1;
1658a6d0d645SJohnny Huang continue;
1659bb34a7bfSJohnny Huang }
1660de6fbf1cSJohnny Huang
1661de6fbf1cSJohnny Huang otp_soak(1);
16622031a123SJohnny Huang ret = otp_prog_dw(conf[i], conf_ignore[i], prog_address);
16632031a123SJohnny Huang if (ret)
16642031a123SJohnny Huang return OTP_FAILURE;
1665a6d0d645SJohnny Huang
166669d5fd8fSJohnny Huang pass = 0;
166769d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) {
16685010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1669de6fbf1cSJohnny Huang otp_soak(2);
16702031a123SJohnny Huang ret = otp_prog_dw(compare[0], conf_ignore[i], prog_address);
16712031a123SJohnny Huang if (ret)
16722031a123SJohnny Huang return OTP_FAILURE;
16735010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1674de6fbf1cSJohnny Huang otp_soak(1);
1675de6fbf1cSJohnny Huang } else {
1676de6fbf1cSJohnny Huang pass = 1;
1677de6fbf1cSJohnny Huang break;
1678de6fbf1cSJohnny Huang }
1679a6d0d645SJohnny Huang } else {
168069d5fd8fSJohnny Huang pass = 1;
168169d5fd8fSJohnny Huang break;
168269d5fd8fSJohnny Huang }
168369d5fd8fSJohnny Huang }
1684bb34a7bfSJohnny Huang if (pass == 0) {
1685b64ca396SJohnny Huang printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n",
1686b64ca396SJohnny Huang i, otp_conf[i], conf[i], conf_ignore[i]);
1687bb34a7bfSJohnny Huang break;
1688bb34a7bfSJohnny Huang }
1689a6d0d645SJohnny Huang }
1690a6d0d645SJohnny Huang
1691de6fbf1cSJohnny Huang otp_soak(0);
169269d5fd8fSJohnny Huang if (!pass)
16932a856b9aSJohnny Huang return OTP_FAILURE;
1694a6d0d645SJohnny Huang
16952a856b9aSJohnny Huang return OTP_SUCCESS;
169669d5fd8fSJohnny Huang }
169769d5fd8fSJohnny Huang
otp_prog_scu_protect(struct otp_image_layout * image_layout,u32 * scu_pro)1698b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro)
1699b25f02d2SJohnny Huang {
1700b25f02d2SJohnny Huang int i, k;
1701b25f02d2SJohnny Huang int pass = 0;
1702b25f02d2SJohnny Huang u32 prog_address;
1703b25f02d2SJohnny Huang u32 compare[2];
1704b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro;
1705b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
1706b25f02d2SJohnny Huang u32 data_masked;
1707b25f02d2SJohnny Huang u32 buf_masked;
17082031a123SJohnny Huang int ret;
1709b25f02d2SJohnny Huang
1710b25f02d2SJohnny Huang printf("Start Programing...\n");
1711b25f02d2SJohnny Huang otp_soak(0);
1712b25f02d2SJohnny Huang for (i = 0; i < 2; i++) {
1713b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i];
1714b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i];
1715b25f02d2SJohnny Huang prog_address = 0xe08 + i * 2;
1716b25f02d2SJohnny Huang if (data_masked == buf_masked) {
1717b25f02d2SJohnny Huang pass = 1;
1718b25f02d2SJohnny Huang continue;
1719b25f02d2SJohnny Huang }
1720b25f02d2SJohnny Huang
1721b25f02d2SJohnny Huang otp_soak(1);
17222031a123SJohnny Huang ret = otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address);
17232031a123SJohnny Huang if (ret)
17242031a123SJohnny Huang return OTP_FAILURE;
1725b25f02d2SJohnny Huang pass = 0;
1726b25f02d2SJohnny Huang for (k = 0; k < RETRY; k++) {
1727b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) {
1728b25f02d2SJohnny Huang otp_soak(2);
17292031a123SJohnny Huang ret = otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address);
17302031a123SJohnny Huang if (ret)
17312031a123SJohnny Huang return OTP_FAILURE;
1732b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) {
1733b25f02d2SJohnny Huang otp_soak(1);
1734b25f02d2SJohnny Huang } else {
1735b25f02d2SJohnny Huang pass = 1;
1736b25f02d2SJohnny Huang break;
1737b25f02d2SJohnny Huang }
1738b25f02d2SJohnny Huang } else {
1739b25f02d2SJohnny Huang pass = 1;
1740b25f02d2SJohnny Huang break;
1741b25f02d2SJohnny Huang }
1742b25f02d2SJohnny Huang }
1743b25f02d2SJohnny Huang if (pass == 0) {
1744b489486eSJohnny Huang printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n",
1745b25f02d2SJohnny Huang i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]);
1746b25f02d2SJohnny Huang break;
1747b25f02d2SJohnny Huang }
1748b25f02d2SJohnny Huang }
1749b25f02d2SJohnny Huang
1750b25f02d2SJohnny Huang otp_soak(0);
1751b25f02d2SJohnny Huang if (!pass)
1752b25f02d2SJohnny Huang return OTP_FAILURE;
1753b25f02d2SJohnny Huang
1754b25f02d2SJohnny Huang return OTP_SUCCESS;
1755b25f02d2SJohnny Huang }
1756b25f02d2SJohnny Huang
otp_check_data_image(struct otp_image_layout * image_layout,u32 * data)1757b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data)
1758b64ca396SJohnny Huang {
1759b64ca396SJohnny Huang int data_dw;
1760b64ca396SJohnny Huang u32 data_masked;
1761b64ca396SJohnny Huang u32 buf_masked;
1762b64ca396SJohnny Huang u32 *buf = (u32 *)image_layout->data;
1763b64ca396SJohnny Huang u32 *buf_ignore = (u32 *)image_layout->data_ignore;
1764b64ca396SJohnny Huang int i;
1765b64ca396SJohnny Huang
1766b64ca396SJohnny Huang data_dw = image_layout->data_length / 4;
1767b64ca396SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check.
1768b64ca396SJohnny Huang for (i = 0; i < data_dw - 2; i++) {
1769b64ca396SJohnny Huang data_masked = data[i] & ~buf_ignore[i];
1770b64ca396SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i];
1771b64ca396SJohnny Huang if (data_masked == buf_masked)
1772b64ca396SJohnny Huang continue;
1773b64ca396SJohnny Huang if (i % 2 == 0) {
1774b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) {
1775b64ca396SJohnny Huang continue;
1776b64ca396SJohnny Huang } else {
1777b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n");
1778b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]);
1779b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]);
1780b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]);
1781b64ca396SJohnny Huang return OTP_FAILURE;
1782b64ca396SJohnny Huang }
1783b64ca396SJohnny Huang } else {
1784b64ca396SJohnny Huang if ((data_masked & buf_masked) == buf_masked) {
1785b64ca396SJohnny Huang continue;
1786b64ca396SJohnny Huang } else {
1787b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n");
1788b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]);
1789b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]);
1790b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]);
1791b64ca396SJohnny Huang return OTP_FAILURE;
1792b64ca396SJohnny Huang }
1793b64ca396SJohnny Huang }
1794b64ca396SJohnny Huang }
1795b64ca396SJohnny Huang return OTP_SUCCESS;
1796b64ca396SJohnny Huang }
1797b64ca396SJohnny Huang
otp_check_strap_image(struct otp_image_layout * image_layout,struct otpstrap_status * otpstrap)1798b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap)
1799b64ca396SJohnny Huang {
1800b64ca396SJohnny Huang int i;
1801b64ca396SJohnny Huang u32 *strap;
1802b64ca396SJohnny Huang u32 *strap_ignore;
1803b64ca396SJohnny Huang u32 *strap_pro;
1804b64ca396SJohnny Huang int bit, pbit, ibit;
1805b64ca396SJohnny Huang int fail = 0;
1806b64ca396SJohnny Huang int ret;
1807b64ca396SJohnny Huang
1808b64ca396SJohnny Huang strap = (u32 *)image_layout->strap;
1809b64ca396SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro;
1810b64ca396SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore;
1811b64ca396SJohnny Huang
1812b64ca396SJohnny Huang for (i = 0; i < 64; i++) {
1813b64ca396SJohnny Huang if (i < 32) {
1814b64ca396SJohnny Huang bit = (strap[0] >> i) & 0x1;
1815b64ca396SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1;
1816b64ca396SJohnny Huang pbit = (strap_pro[0] >> i) & 0x1;
1817b64ca396SJohnny Huang } else {
1818b64ca396SJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1;
1819b64ca396SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
1820b64ca396SJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1;
1821b64ca396SJohnny Huang }
1822b64ca396SJohnny Huang
1823b64ca396SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit);
1824b64ca396SJohnny Huang
1825b64ca396SJohnny Huang if (ret == OTP_FAILURE)
1826b64ca396SJohnny Huang fail = 1;
1827b64ca396SJohnny Huang }
1828b64ca396SJohnny Huang if (fail == 1) {
1829b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n");
1830b64ca396SJohnny Huang return OTP_FAILURE;
1831b64ca396SJohnny Huang }
1832b64ca396SJohnny Huang return OTP_SUCCESS;
1833b64ca396SJohnny Huang }
1834b64ca396SJohnny Huang
otp_check_conf_image(struct otp_image_layout * image_layout,u32 * otp_conf)1835b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf)
1836b64ca396SJohnny Huang {
1837b64ca396SJohnny Huang u32 *conf = (u32 *)image_layout->conf;
1838b64ca396SJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1839b64ca396SJohnny Huang u32 data_masked;
1840b64ca396SJohnny Huang u32 buf_masked;
1841b64ca396SJohnny Huang int i;
1842b64ca396SJohnny Huang
1843b64ca396SJohnny Huang for (i = 0; i < 16; i++) {
1844b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i];
1845b64ca396SJohnny Huang buf_masked = conf[i] & ~conf_ignore[i];
1846b64ca396SJohnny Huang if (data_masked == buf_masked)
1847b64ca396SJohnny Huang continue;
1848b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) {
1849b64ca396SJohnny Huang continue;
1850b64ca396SJohnny Huang } else {
1851b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n");
1852b64ca396SJohnny Huang printf("OTPCFG[%X] = %x\n", i, otp_conf[i]);
1853b64ca396SJohnny Huang printf("Input [%X] = %x\n", i, conf[i]);
1854b64ca396SJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]);
1855b64ca396SJohnny Huang return OTP_FAILURE;
1856b64ca396SJohnny Huang }
1857b64ca396SJohnny Huang }
1858b64ca396SJohnny Huang return OTP_SUCCESS;
1859b64ca396SJohnny Huang }
1860b64ca396SJohnny Huang
otp_check_scu_image(struct otp_image_layout * image_layout,u32 * scu_pro)1861b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro)
1862b25f02d2SJohnny Huang {
1863b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro;
1864b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
1865b25f02d2SJohnny Huang u32 data_masked;
1866b25f02d2SJohnny Huang u32 buf_masked;
1867b25f02d2SJohnny Huang int i;
1868b25f02d2SJohnny Huang
1869b25f02d2SJohnny Huang for (i = 0; i < 2; i++) {
1870b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i];
1871b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i];
1872b25f02d2SJohnny Huang if (data_masked == buf_masked)
1873b25f02d2SJohnny Huang continue;
1874b25f02d2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) {
1875b25f02d2SJohnny Huang continue;
1876b25f02d2SJohnny Huang } else {
1877b25f02d2SJohnny Huang printf("Input image can't program into OTP, please check.\n");
1878b489486eSJohnny Huang printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]);
1879b489486eSJohnny Huang printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]);
1880b489486eSJohnny Huang printf("Mask [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]);
1881b25f02d2SJohnny Huang return OTP_FAILURE;
1882b25f02d2SJohnny Huang }
1883b25f02d2SJohnny Huang }
1884b25f02d2SJohnny Huang return OTP_SUCCESS;
1885b25f02d2SJohnny Huang }
1886b25f02d2SJohnny Huang
do_hash(const void * data,int data_len,const char * algo_name,uint8_t * value)1887948e73aaSJoel Stanley static void do_hash(const void *data, int data_len, const char *algo_name, uint8_t *value)
1888948e73aaSJoel Stanley {
1889948e73aaSJoel Stanley struct hash_algo *algo;
1890948e73aaSJoel Stanley
1891948e73aaSJoel Stanley if (hash_lookup_algo(algo_name, &algo)) {
1892948e73aaSJoel Stanley debug("Unsupported hash alogrithm\n");
1893948e73aaSJoel Stanley return;
1894948e73aaSJoel Stanley }
1895948e73aaSJoel Stanley
1896948e73aaSJoel Stanley algo->hash_func_ws(data, data_len, value, algo->chunk_size);
1897948e73aaSJoel Stanley }
1898948e73aaSJoel Stanley
otp_verify_image(u8 * src_buf,u32 length,u8 * digest_buf,int version)1899e7e21c44SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf, int version)
1900696656c6SJohnny Huang {
1901e7e21c44SJohnny Huang u8 digest_ret[48];
1902e7e21c44SJohnny Huang int digest_len;
1903696656c6SJohnny Huang
1904e7e21c44SJohnny Huang switch (version) {
1905e7e21c44SJohnny Huang case 1:
1906948e73aaSJoel Stanley do_hash(src_buf, length, "sha256", digest_ret);
1907e7e21c44SJohnny Huang digest_len = 32;
1908e7e21c44SJohnny Huang break;
1909e7e21c44SJohnny Huang case 2:
1910948e73aaSJoel Stanley do_hash(src_buf, length, "sha384", digest_ret);
1911e7e21c44SJohnny Huang digest_len = 48;
1912e7e21c44SJohnny Huang break;
1913e7e21c44SJohnny Huang default:
1914e7e21c44SJohnny Huang return OTP_FAILURE;
1915e7e21c44SJohnny Huang }
1916696656c6SJohnny Huang
1917e7e21c44SJohnny Huang if (!memcmp(digest_buf, digest_ret, digest_len))
1918f347c284SJohnny Huang return OTP_SUCCESS;
1919f347c284SJohnny Huang return OTP_FAILURE;
1920696656c6SJohnny Huang }
1921696656c6SJohnny Huang
otp_prog_image(int addr,int nconfirm)1922f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm)
192369d5fd8fSJohnny Huang {
192469d5fd8fSJohnny Huang int ret;
192561a6cda7SJohnny Huang int image_soc_ver = 0;
1926696656c6SJohnny Huang struct otp_header *otp_header;
1927696656c6SJohnny Huang struct otp_image_layout image_layout;
1928696656c6SJohnny Huang int image_size;
1929a219f6deSJohnny Huang u8 *buf;
1930a219f6deSJohnny Huang u8 *checksum;
1931b64ca396SJohnny Huang int i;
1932b64ca396SJohnny Huang u32 data[2048];
1933b64ca396SJohnny Huang u32 conf[16];
1934b25f02d2SJohnny Huang u32 scu_pro[2];
1935b64ca396SJohnny Huang struct otpstrap_status otpstrap[64];
193669d5fd8fSJohnny Huang
1937696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1938696656c6SJohnny Huang if (!otp_header) {
1939030cb4a7SJohnny Huang printf("Failed to map physical memory\n");
19402a856b9aSJohnny Huang return OTP_FAILURE;
194169d5fd8fSJohnny Huang }
1942d90825e2SJohnny Huang
1943696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1944696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK);
1945696656c6SJohnny Huang
1946696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1947696656c6SJohnny Huang
1948696656c6SJohnny Huang if (!buf) {
1949030cb4a7SJohnny Huang printf("Failed to map physical memory\n");
1950696656c6SJohnny Huang return OTP_FAILURE;
1951696656c6SJohnny Huang }
1952696656c6SJohnny Huang otp_header = (struct otp_header *)buf;
1953696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset;
1954696656c6SJohnny Huang
1955696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1956030cb4a7SJohnny Huang printf("Image is invalid\n");
1957696656c6SJohnny Huang return OTP_FAILURE;
1958696656c6SJohnny Huang }
1959696656c6SJohnny Huang
19605010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
19615010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
19625010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length;
19635010032bSJohnny Huang
19645010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1965696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
19665010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1967696656c6SJohnny Huang
1968696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
19695010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
19705010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
19715010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
19727e523e3bSJohnny Huang
1973b25f02d2SJohnny Huang image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info);
1974b25f02d2SJohnny Huang image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2);
1975b25f02d2SJohnny Huang image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length;
1976b25f02d2SJohnny Huang
19777e523e3bSJohnny Huang if (otp_header->soc_ver == SOC_AST2600A0) {
19787e523e3bSJohnny Huang image_soc_ver = OTP_A0;
197961a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A1) {
198061a6cda7SJohnny Huang image_soc_ver = OTP_A1;
198161a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A2) {
198261a6cda7SJohnny Huang image_soc_ver = OTP_A2;
198361a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A3) {
198461a6cda7SJohnny Huang image_soc_ver = OTP_A3;
1985696656c6SJohnny Huang } else {
1986030cb4a7SJohnny Huang printf("Image SOC Version is not supported\n");
1987696656c6SJohnny Huang return OTP_FAILURE;
1988696656c6SJohnny Huang }
1989696656c6SJohnny Huang
199061a6cda7SJohnny Huang if (image_soc_ver != info_cb.version) {
19915e096f11SJohnny Huang printf("Image SOC version is not match to HW SOC version\n");
19929a4fe690SJohnny Huang return OTP_FAILURE;
19939a4fe690SJohnny Huang }
19949a4fe690SJohnny Huang
1995e7e21c44SJohnny Huang switch (OTPTOOL_VERSION_MAJOR(otp_header->otptool_ver)) {
1996e7e21c44SJohnny Huang case 1:
1997e7e21c44SJohnny Huang printf("WARNING: OTP image is not generated by otptool v2.x.x\n");
1998e7e21c44SJohnny Huang printf("Please use the latest version of otptool to generate OTP image\n");
1999e7e21c44SJohnny Huang ret = otp_verify_image(buf, image_size, checksum, 1);
2000e7e21c44SJohnny Huang break;
2001e7e21c44SJohnny Huang case 2:
2002e7e21c44SJohnny Huang ret = otp_verify_image(buf, image_size, checksum, 2);
2003e7e21c44SJohnny Huang break;
2004e7e21c44SJohnny Huang default:
2005e7e21c44SJohnny Huang printf("OTP image version is not supported\n");
200661a6cda7SJohnny Huang return OTP_FAILURE;
200761a6cda7SJohnny Huang }
200861a6cda7SJohnny Huang
2009e7e21c44SJohnny Huang if (ret) {
2010030cb4a7SJohnny Huang printf("checksum is invalid\n");
2011696656c6SJohnny Huang return OTP_FAILURE;
2012d90825e2SJohnny Huang }
20137332532cSJohnny Huang
2014030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) {
2015030cb4a7SJohnny Huang printf("OTP memory is locked\n");
2016030cb4a7SJohnny Huang return OTP_FAILURE;
2017030cb4a7SJohnny Huang }
2018b64ca396SJohnny Huang ret = 0;
2019030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) {
2020030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) {
2021030cb4a7SJohnny Huang printf("OTP data region is protected\n");
2022030cb4a7SJohnny Huang ret = -1;
2023030cb4a7SJohnny Huang }
2024030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) {
2025030cb4a7SJohnny Huang printf("OTP secure region is protected\n");
2026030cb4a7SJohnny Huang ret = -1;
2027030cb4a7SJohnny Huang }
2028b64ca396SJohnny Huang printf("Read OTP Data Region:\n");
2029b64ca396SJohnny Huang for (i = 0; i < 2048 ; i += 2)
2030b64ca396SJohnny Huang otp_read_data(i, &data[i]);
2031b64ca396SJohnny Huang
2032b64ca396SJohnny Huang printf("Check writable...\n");
2033b64ca396SJohnny Huang if (otp_check_data_image(&image_layout, data) == OTP_FAILURE)
2034b64ca396SJohnny Huang ret = -1;
2035030cb4a7SJohnny Huang }
2036030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) {
2037030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) {
2038030cb4a7SJohnny Huang printf("OTP config region is protected\n");
2039030cb4a7SJohnny Huang ret = -1;
2040030cb4a7SJohnny Huang }
2041b64ca396SJohnny Huang printf("Read OTP Config Region:\n");
2042b64ca396SJohnny Huang for (i = 0; i < 16 ; i++)
2043b64ca396SJohnny Huang otp_read_conf(i, &conf[i]);
2044b64ca396SJohnny Huang
2045b64ca396SJohnny Huang printf("Check writable...\n");
2046b64ca396SJohnny Huang if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE)
2047b64ca396SJohnny Huang ret = -1;
2048030cb4a7SJohnny Huang }
2049030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) {
2050030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) {
2051030cb4a7SJohnny Huang printf("OTP strap region is protected\n");
2052030cb4a7SJohnny Huang ret = -1;
2053030cb4a7SJohnny Huang }
2054b64ca396SJohnny Huang printf("Read OTP Strap Region:\n");
2055b64ca396SJohnny Huang otp_strap_status(otpstrap);
2056b64ca396SJohnny Huang
2057b64ca396SJohnny Huang printf("Check writable...\n");
2058b64ca396SJohnny Huang if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE)
2059b64ca396SJohnny Huang ret = -1;
2060030cb4a7SJohnny Huang }
2061b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) {
2062b25f02d2SJohnny Huang if (info_cb.pro_sts.pro_strap) {
2063b25f02d2SJohnny Huang printf("OTP strap region is protected\n");
2064b25f02d2SJohnny Huang ret = -1;
2065b25f02d2SJohnny Huang }
2066b25f02d2SJohnny Huang printf("Read SCU Protect Region:\n");
2067b25f02d2SJohnny Huang otp_read_conf(28, &scu_pro[0]);
2068b25f02d2SJohnny Huang otp_read_conf(29, &scu_pro[1]);
2069b25f02d2SJohnny Huang
2070b25f02d2SJohnny Huang printf("Check writable...\n");
2071b25f02d2SJohnny Huang if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE)
2072b25f02d2SJohnny Huang ret = -1;
2073b25f02d2SJohnny Huang }
2074030cb4a7SJohnny Huang if (ret == -1)
2075030cb4a7SJohnny Huang return OTP_FAILURE;
2076b64ca396SJohnny Huang
207769d5fd8fSJohnny Huang if (!nconfirm) {
2078696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) {
20797f795e57SJohnny Huang printf("\nOTP data region :\n");
2080f347c284SJohnny Huang if (otp_print_data_image(&image_layout) < 0) {
208169d5fd8fSJohnny Huang printf("OTP data error, please check.\n");
20822a856b9aSJohnny Huang return OTP_FAILURE;
208369d5fd8fSJohnny Huang }
208469d5fd8fSJohnny Huang }
2085696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) {
20867332532cSJohnny Huang printf("\nOTP configuration region :\n");
2087696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) {
20887332532cSJohnny Huang printf("OTP config error, please check.\n");
20897332532cSJohnny Huang return OTP_FAILURE;
20907332532cSJohnny Huang }
20917332532cSJohnny Huang }
20927adec5f6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) {
20937adec5f6SJohnny Huang printf("\nOTP strap region :\n");
20947adec5f6SJohnny Huang if (otp_print_strap_image(&image_layout) < 0) {
20957adec5f6SJohnny Huang printf("OTP strap error, please check.\n");
20967adec5f6SJohnny Huang return OTP_FAILURE;
20977adec5f6SJohnny Huang }
20987adec5f6SJohnny Huang }
2099b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) {
2100b25f02d2SJohnny Huang printf("\nOTP scu protect region :\n");
2101b25f02d2SJohnny Huang if (otp_print_scu_image(&image_layout) < 0) {
2102b25f02d2SJohnny Huang printf("OTP scu protect error, please check.\n");
2103b25f02d2SJohnny Huang return OTP_FAILURE;
2104b25f02d2SJohnny Huang }
2105b25f02d2SJohnny Huang }
21067332532cSJohnny Huang
210769d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n");
210869d5fd8fSJohnny Huang if (!confirm_yesno()) {
210969d5fd8fSJohnny Huang printf(" Aborting\n");
21102a856b9aSJohnny Huang return OTP_FAILURE;
211169d5fd8fSJohnny Huang }
211269d5fd8fSJohnny Huang }
21137332532cSJohnny Huang
21145010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) {
21155010032bSJohnny Huang printf("programing data region ...\n");
2116b64ca396SJohnny Huang ret = otp_prog_data(&image_layout, data);
21175010032bSJohnny Huang if (ret != 0) {
21185010032bSJohnny Huang printf("Error\n");
21195010032bSJohnny Huang return ret;
21205010032bSJohnny Huang }
2121a219f6deSJohnny Huang printf("Done\n");
21225010032bSJohnny Huang }
21235010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) {
21245010032bSJohnny Huang printf("programing strap region ...\n");
2125b64ca396SJohnny Huang ret = otp_prog_strap(&image_layout, otpstrap);
21265010032bSJohnny Huang if (ret != 0) {
21275010032bSJohnny Huang printf("Error\n");
21285010032bSJohnny Huang return ret;
21295010032bSJohnny Huang }
2130a219f6deSJohnny Huang printf("Done\n");
21315010032bSJohnny Huang }
2132b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) {
2133b25f02d2SJohnny Huang printf("programing scu protect region ...\n");
2134b25f02d2SJohnny Huang ret = otp_prog_scu_protect(&image_layout, scu_pro);
2135b25f02d2SJohnny Huang if (ret != 0) {
2136b25f02d2SJohnny Huang printf("Error\n");
2137b25f02d2SJohnny Huang return ret;
2138b25f02d2SJohnny Huang }
2139b25f02d2SJohnny Huang printf("Done\n");
2140b25f02d2SJohnny Huang }
21415010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) {
21425010032bSJohnny Huang printf("programing configuration region ...\n");
2143b64ca396SJohnny Huang ret = otp_prog_conf(&image_layout, conf);
21445010032bSJohnny Huang if (ret != 0) {
21455010032bSJohnny Huang printf("Error\n");
21465010032bSJohnny Huang return ret;
21475010032bSJohnny Huang }
21485010032bSJohnny Huang printf("Done\n");
21495010032bSJohnny Huang }
2150cd1610b4SJohnny Huang
21517332532cSJohnny Huang return OTP_SUCCESS;
21522a856b9aSJohnny Huang }
21532a856b9aSJohnny Huang
otp_prog_bit(int mode,int otp_dw_offset,int bit_offset,int value,int nconfirm)2154f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
2155cd1610b4SJohnny Huang {
2156a219f6deSJohnny Huang u32 read[2];
2157a219f6deSJohnny Huang u32 prog_address = 0;
215866f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64];
2159cd1610b4SJohnny Huang int otp_bit;
216083655e91SJohnny Huang int ret = 0;
2161cd1610b4SJohnny Huang
2162dacbba92SJohnny Huang otp_soak(0);
2163cd1610b4SJohnny Huang switch (mode) {
2164a6d0d645SJohnny Huang case OTP_REGION_CONF:
2165f347c284SJohnny Huang otp_read_conf(otp_dw_offset, read);
2166cd1610b4SJohnny Huang prog_address = 0x800;
2167cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200;
2168cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2;
2169a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1;
2170cd1610b4SJohnny Huang if (otp_bit == value) {
2171b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value);
2172cd1610b4SJohnny Huang printf("No need to program\n");
21732a856b9aSJohnny Huang return OTP_SUCCESS;
2174cd1610b4SJohnny Huang }
2175cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) {
2176b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
21770dc9a440SJohnny Huang printf("OTP is programmed, which can't be clean\n");
21782a856b9aSJohnny Huang return OTP_FAILURE;
2179cd1610b4SJohnny Huang }
2180b489486eSJohnny Huang printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset);
2181cd1610b4SJohnny Huang break;
2182a6d0d645SJohnny Huang case OTP_REGION_DATA:
2183cd1610b4SJohnny Huang prog_address = otp_dw_offset;
2184cd1610b4SJohnny Huang
2185cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) {
2186a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read);
2187a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1;
2188643b9cfdSJohnny Huang
2189643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) {
2190b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
2191b64ca396SJohnny Huang printf("OTP is programmed, which can't be cleared\n");
2192643b9cfdSJohnny Huang return OTP_FAILURE;
2193643b9cfdSJohnny Huang }
2194cd1610b4SJohnny Huang } else {
2195a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read);
2196a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1;
2197643b9cfdSJohnny Huang
2198643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) {
2199b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
2200b64ca396SJohnny Huang printf("OTP is programmed, which can't be written\n");
2201643b9cfdSJohnny Huang return OTP_FAILURE;
2202643b9cfdSJohnny Huang }
2203cd1610b4SJohnny Huang }
2204cd1610b4SJohnny Huang if (otp_bit == value) {
2205b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value);
2206cd1610b4SJohnny Huang printf("No need to program\n");
22072a856b9aSJohnny Huang return OTP_SUCCESS;
2208cd1610b4SJohnny Huang }
2209643b9cfdSJohnny Huang
2210e00b7fc7SNeal Liu printf("Program OTPDATA0x%X[0x%X] to %d\n", otp_dw_offset, bit_offset, value);
2211cd1610b4SJohnny Huang break;
2212a6d0d645SJohnny Huang case OTP_REGION_STRAP:
22138848d5dcSJohnny Huang otp_strap_status(otpstrap);
22148848d5dcSJohnny Huang otp_print_strap(bit_offset, 1);
22157e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
22168848d5dcSJohnny Huang if (ret == OTP_FAILURE)
22178848d5dcSJohnny Huang return OTP_FAILURE;
22188848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP)
22198848d5dcSJohnny Huang return OTP_SUCCESS;
2220a6af4a17SJohnny Huang
2221cd1610b4SJohnny Huang break;
2222cd1610b4SJohnny Huang }
2223cd1610b4SJohnny Huang
2224cd1610b4SJohnny Huang if (!nconfirm) {
2225cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n");
2226cd1610b4SJohnny Huang if (!confirm_yesno()) {
2227cd1610b4SJohnny Huang printf(" Aborting\n");
22282a856b9aSJohnny Huang return OTP_FAILURE;
2229cd1610b4SJohnny Huang }
2230cd1610b4SJohnny Huang }
2231cd1610b4SJohnny Huang
2232cd1610b4SJohnny Huang switch (mode) {
2233a6d0d645SJohnny Huang case OTP_REGION_STRAP:
2234f347c284SJohnny Huang ret = otp_prog_strap_b(bit_offset, value);
223583655e91SJohnny Huang break;
2236a6d0d645SJohnny Huang case OTP_REGION_CONF:
2237a6d0d645SJohnny Huang case OTP_REGION_DATA:
2238f347c284SJohnny Huang ret = otp_prog_dc_b(value, prog_address, bit_offset);
2239de6fbf1cSJohnny Huang break;
2240de6fbf1cSJohnny Huang }
2241de6fbf1cSJohnny Huang otp_soak(0);
224283655e91SJohnny Huang if (ret) {
22430dc9a440SJohnny Huang printf("OTP cannot be programmed\n");
2244794e27ecSJohnny Huang printf("FAILURE\n");
2245794e27ecSJohnny Huang return OTP_FAILURE;
2246794e27ecSJohnny Huang }
2247794e27ecSJohnny Huang
22489009c25dSJohnny Huang printf("SUCCESS\n");
22492a856b9aSJohnny Huang return OTP_SUCCESS;
2250a219f6deSJohnny Huang }
2251a219f6deSJohnny Huang
otp_update_rid(u32 update_num,int force)2252794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
2253794e27ecSJohnny Huang {
2254794e27ecSJohnny Huang u32 otp_rid[2];
2255a8789b47SJohnny Huang u32 sw_rid[2];
2256794e27ecSJohnny Huang int rid_num = 0;
2257a8789b47SJohnny Huang int sw_rid_num = 0;
2258794e27ecSJohnny Huang int bit_offset;
2259794e27ecSJohnny Huang int dw_offset;
2260794e27ecSJohnny Huang int i;
2261794e27ecSJohnny Huang int ret;
2262794e27ecSJohnny Huang
2263f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]);
2264f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]);
2265794e27ecSJohnny Huang
2266a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0);
2267a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1);
2268a8789b47SJohnny Huang
2269794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid);
2270a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid);
2271a8789b47SJohnny Huang
2272a8789b47SJohnny Huang if (sw_rid_num < 0) {
2273a8789b47SJohnny Huang printf("SW revision id is invalid, please check.\n");
2274a8789b47SJohnny Huang return OTP_FAILURE;
2275a8789b47SJohnny Huang }
2276a8789b47SJohnny Huang
2277a8789b47SJohnny Huang if (update_num > sw_rid_num) {
2278a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num);
2279a8789b47SJohnny Huang printf("update number could not bigger than current SW revision id\n");
2280a8789b47SJohnny Huang return OTP_FAILURE;
2281a8789b47SJohnny Huang }
2282794e27ecSJohnny Huang
2283794e27ecSJohnny Huang if (rid_num < 0) {
2284b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by this command,\n"
2285b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n");
2286794e27ecSJohnny Huang otp_print_revid(otp_rid);
22879009c25dSJohnny Huang return OTP_FAILURE;
22889009c25dSJohnny Huang }
2289cd1610b4SJohnny Huang
2290794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num);
2291794e27ecSJohnny Huang otp_print_revid(otp_rid);
2292794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num);
2293794e27ecSJohnny Huang
2294a8789b47SJohnny Huang if (rid_num > update_num) {
2295a8789b47SJohnny Huang printf("OTP rev_id is bigger than 0x%X\n", update_num);
2296a8789b47SJohnny Huang printf("Skip\n");
2297a8789b47SJohnny Huang return OTP_FAILURE;
2298a8789b47SJohnny Huang } else if (rid_num == update_num) {
2299a8789b47SJohnny Huang printf("OTP rev_id is same as input\n");
2300794e27ecSJohnny Huang printf("Skip\n");
2301794e27ecSJohnny Huang return OTP_FAILURE;
2302794e27ecSJohnny Huang }
2303794e27ecSJohnny Huang
2304794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) {
2305794e27ecSJohnny Huang if (i < 32) {
2306794e27ecSJohnny Huang dw_offset = 0xa;
2307794e27ecSJohnny Huang bit_offset = i;
2308794e27ecSJohnny Huang } else {
2309794e27ecSJohnny Huang dw_offset = 0xb;
2310794e27ecSJohnny Huang bit_offset = i - 32;
2311794e27ecSJohnny Huang }
2312b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset);
2313794e27ecSJohnny Huang if (i + 1 != update_num)
2314794e27ecSJohnny Huang printf(", ");
2315794e27ecSJohnny Huang }
2316794e27ecSJohnny Huang
2317794e27ecSJohnny Huang printf(" will be programmed\n");
2318794e27ecSJohnny Huang if (force == 0) {
2319794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n");
2320794e27ecSJohnny Huang if (!confirm_yesno()) {
2321794e27ecSJohnny Huang printf(" Aborting\n");
2322794e27ecSJohnny Huang return OTP_FAILURE;
2323794e27ecSJohnny Huang }
2324794e27ecSJohnny Huang }
2325794e27ecSJohnny Huang
2326794e27ecSJohnny Huang ret = 0;
2327794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) {
2328794e27ecSJohnny Huang if (i < 32) {
2329794e27ecSJohnny Huang dw_offset = 0xa04;
2330794e27ecSJohnny Huang bit_offset = i;
2331794e27ecSJohnny Huang } else {
2332794e27ecSJohnny Huang dw_offset = 0xa06;
2333794e27ecSJohnny Huang bit_offset = i - 32;
2334794e27ecSJohnny Huang }
2335f347c284SJohnny Huang if (otp_prog_dc_b(1, dw_offset, bit_offset)) {
2336b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset);
2337794e27ecSJohnny Huang ret = OTP_FAILURE;
2338794e27ecSJohnny Huang break;
2339794e27ecSJohnny Huang }
2340794e27ecSJohnny Huang }
2341061d3279SJohnny Huang otp_soak(0);
2342f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]);
2343f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]);
2344794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid);
2345794e27ecSJohnny Huang if (rid_num >= 0)
2346794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num);
2347794e27ecSJohnny Huang else
2348794e27ecSJohnny Huang printf("OTP revision ID\n");
2349794e27ecSJohnny Huang otp_print_revid(otp_rid);
2350794e27ecSJohnny Huang if (!ret)
2351794e27ecSJohnny Huang printf("SUCCESS\n");
2352794e27ecSJohnny Huang else
2353794e27ecSJohnny Huang printf("FAILED\n");
2354794e27ecSJohnny Huang return ret;
2355794e27ecSJohnny Huang }
2356794e27ecSJohnny Huang
otp_retire_key(u32 retire_id,int force)2357883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force)
2358883625c5SJohnny Huang {
2359883625c5SJohnny Huang u32 otpcfg4;
2360883625c5SJohnny Huang u32 krb;
2361883625c5SJohnny Huang u32 krb_b;
2362883625c5SJohnny Huang u32 krb_or;
2363883625c5SJohnny Huang u32 current_id;
2364883625c5SJohnny Huang
2365883625c5SJohnny Huang otp_read_conf(4, &otpcfg4);
2366883625c5SJohnny Huang current_id = readl(SEC_KEY_NUM) & 7;
2367883625c5SJohnny Huang krb = otpcfg4 & 0xff;
2368883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff;
2369883625c5SJohnny Huang krb_or = krb | krb_b;
2370883625c5SJohnny Huang
2371883625c5SJohnny Huang printf("current Key ID: 0x%x\n", current_id);
2372883625c5SJohnny Huang printf("input retire ID: 0x%x\n", retire_id);
2373883625c5SJohnny Huang printf("OTPCFG0x4 = 0x%X\n", otpcfg4);
2374883625c5SJohnny Huang
2375883625c5SJohnny Huang if (info_cb.pro_sts.pro_key_ret) {
2376883625c5SJohnny Huang printf("OTPCFG4 is protected\n");
2377883625c5SJohnny Huang return OTP_FAILURE;
2378883625c5SJohnny Huang }
2379883625c5SJohnny Huang
2380883625c5SJohnny Huang if (retire_id >= current_id) {
2381883625c5SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n");
2382883625c5SJohnny Huang return OTP_FAILURE;
2383883625c5SJohnny Huang }
2384883625c5SJohnny Huang
2385883625c5SJohnny Huang if (krb_or & (1 << retire_id)) {
2386883625c5SJohnny Huang printf("Key 0x%X already retired\n", retire_id);
2387883625c5SJohnny Huang return OTP_SUCCESS;
2388883625c5SJohnny Huang }
2389883625c5SJohnny Huang
2390883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id);
2391883625c5SJohnny Huang if (force == 0) {
2392883625c5SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n");
2393883625c5SJohnny Huang if (!confirm_yesno()) {
2394883625c5SJohnny Huang printf(" Aborting\n");
2395883625c5SJohnny Huang return OTP_FAILURE;
2396883625c5SJohnny Huang }
2397883625c5SJohnny Huang }
2398883625c5SJohnny Huang
2399883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) {
2400883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed\n", retire_id);
2401883625c5SJohnny Huang printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16);
2402883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE)
2403883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16);
2404883625c5SJohnny Huang }
2405883625c5SJohnny Huang
2406883625c5SJohnny Huang otp_soak(0);
2407883625c5SJohnny Huang otp_read_conf(4, &otpcfg4);
2408883625c5SJohnny Huang krb = otpcfg4 & 0xff;
2409883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff;
2410883625c5SJohnny Huang krb_or = krb | krb_b;
2411883625c5SJohnny Huang if (krb_or & (1 << retire_id)) {
2412883625c5SJohnny Huang printf("SUCCESS\n");
2413883625c5SJohnny Huang return OTP_SUCCESS;
2414883625c5SJohnny Huang }
2415883625c5SJohnny Huang printf("FAILED\n");
2416883625c5SJohnny Huang return OTP_FAILURE;
2417883625c5SJohnny Huang }
2418883625c5SJohnny Huang
parse_config(struct sb_info * si)2419e7e21c44SJohnny Huang static int parse_config(struct sb_info *si)
2420e7e21c44SJohnny Huang {
2421e7e21c44SJohnny Huang int i;
2422e7e21c44SJohnny Huang u32 cfg0, cfg3, cfg4;
2423e7e21c44SJohnny Huang u32 sb_mode;
2424e7e21c44SJohnny Huang u32 key_retire;
2425e7e21c44SJohnny Huang u32 rsa_len;
2426e7e21c44SJohnny Huang u32 sha_len;
2427e7e21c44SJohnny Huang
2428e7e21c44SJohnny Huang otp_read_conf(0, &cfg0);
2429e7e21c44SJohnny Huang otp_read_conf(3, &cfg3);
2430e7e21c44SJohnny Huang otp_read_conf(4, &cfg4);
2431e7e21c44SJohnny Huang
2432e7e21c44SJohnny Huang sb_mode = (cfg0 >> 7) & 0x1;
2433e7e21c44SJohnny Huang si->enc_flag = (cfg0 >> 27) & 0x1;
2434e7e21c44SJohnny Huang key_retire = (cfg4 & 0x7f) | ((cfg4 >> 16) & 0x7f);
2435e7e21c44SJohnny Huang
2436e7e21c44SJohnny Huang if ((cfg0 >> 16) & 0x3f)
2437e7e21c44SJohnny Huang si->secure_region = 1;
2438e7e21c44SJohnny Huang else
2439e7e21c44SJohnny Huang si->secure_region = 0;
2440e7e21c44SJohnny Huang
2441e7e21c44SJohnny Huang si->header_offset = cfg3 & 0xffff;
2442e7e21c44SJohnny Huang if (si->header_offset == 0)
2443e7e21c44SJohnny Huang si->header_offset = 0x20;
2444e7e21c44SJohnny Huang
2445e7e21c44SJohnny Huang for (i = 0; i < 8; i++) {
2446e7e21c44SJohnny Huang if ((key_retire >> i) & 0x1)
2447e7e21c44SJohnny Huang si->retire_list[i] = 1;
2448e7e21c44SJohnny Huang else
2449e7e21c44SJohnny Huang si->retire_list[i] = 0;
2450e7e21c44SJohnny Huang }
2451e7e21c44SJohnny Huang
2452e7e21c44SJohnny Huang if (sb_mode == 0) {
2453e7e21c44SJohnny Huang printf("Mode GCM is not supported.\n");
2454e7e21c44SJohnny Huang return OTP_FAILURE;
2455e7e21c44SJohnny Huang }
2456e7e21c44SJohnny Huang
2457e7e21c44SJohnny Huang if (si->enc_flag)
2458e7e21c44SJohnny Huang printf("Algorithm: AES_RSA_SHA\n");
2459e7e21c44SJohnny Huang else
2460e7e21c44SJohnny Huang printf("Algorithm: RSA_SHA\n");
2461e7e21c44SJohnny Huang
2462e7e21c44SJohnny Huang rsa_len = (cfg0 >> 10) & 0x3;
2463e7e21c44SJohnny Huang sha_len = (cfg0 >> 12) & 0x3;
2464e7e21c44SJohnny Huang
2465e7e21c44SJohnny Huang if (rsa_len == 0) {
2466e7e21c44SJohnny Huang si->rsa_algo = 1024;
2467e7e21c44SJohnny Huang printf("RSA length: 1024\n");
2468e7e21c44SJohnny Huang } else if (rsa_len == 1) {
2469e7e21c44SJohnny Huang si->rsa_algo = 2048;
2470e7e21c44SJohnny Huang printf("RSA length: 2048\n");
2471e7e21c44SJohnny Huang } else if (rsa_len == 2) {
2472e7e21c44SJohnny Huang si->rsa_algo = 3072;
2473e7e21c44SJohnny Huang printf("RSA length: 3072\n");
2474e7e21c44SJohnny Huang } else {
2475e7e21c44SJohnny Huang si->rsa_algo = 4096;
2476e7e21c44SJohnny Huang printf("RSA length: 4096\n");
2477e7e21c44SJohnny Huang }
2478e7e21c44SJohnny Huang if (sha_len == 0) {
2479e7e21c44SJohnny Huang si->sha_algo = 224;
2480e7e21c44SJohnny Huang si->digest_len = 28;
2481e7e21c44SJohnny Huang printf("HASH length: 224\n");
2482e7e21c44SJohnny Huang } else if (sha_len == 1) {
2483e7e21c44SJohnny Huang si->sha_algo = 256;
2484e7e21c44SJohnny Huang si->digest_len = 32;
2485e7e21c44SJohnny Huang printf("HASH length: 256\n");
2486e7e21c44SJohnny Huang } else if (sha_len == 2) {
2487e7e21c44SJohnny Huang si->sha_algo = 384;
2488e7e21c44SJohnny Huang si->digest_len = 48;
2489e7e21c44SJohnny Huang printf("HASH length: 384\n");
2490e7e21c44SJohnny Huang } else {
2491e7e21c44SJohnny Huang si->sha_algo = 512;
2492e7e21c44SJohnny Huang si->digest_len = 64;
2493e7e21c44SJohnny Huang printf("HASH length: 512\n");
2494e7e21c44SJohnny Huang }
2495e7e21c44SJohnny Huang return OTP_SUCCESS;
2496e7e21c44SJohnny Huang }
2497e7e21c44SJohnny Huang
parse_data(struct key_list * kl,int * key_num,struct sb_info * si,u32 * data)2498e7e21c44SJohnny Huang static void parse_data(struct key_list *kl, int *key_num, struct sb_info *si, u32 *data)
2499e7e21c44SJohnny Huang {
2500e7e21c44SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info;
2501e7e21c44SJohnny Huang int i, j;
2502e7e21c44SJohnny Huang int id = 0;
2503e7e21c44SJohnny Huang u32 h;
2504e7e21c44SJohnny Huang u32 t;
2505e7e21c44SJohnny Huang
2506e7e21c44SJohnny Huang *key_num = 0;
2507e7e21c44SJohnny Huang for (i = 0; i < 16; i++) {
2508e7e21c44SJohnny Huang h = data[i];
2509e7e21c44SJohnny Huang t = (h >> 14) & 0xf;
2510e7e21c44SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) {
2511e7e21c44SJohnny Huang if (t == key_info_array[j].value) {
2512e7e21c44SJohnny Huang kl[*key_num].key_info = &key_info_array[j];
2513e7e21c44SJohnny Huang kl[*key_num].offset = h & 0x1ff8;
2514e7e21c44SJohnny Huang id = h & 0x7;
2515e7e21c44SJohnny Huang kl[*key_num].id = id;
2516e7e21c44SJohnny Huang if (si->retire_list[id] == 1)
2517e7e21c44SJohnny Huang kl[*key_num].retire = 1;
2518e7e21c44SJohnny Huang else
2519e7e21c44SJohnny Huang kl[*key_num].retire = 0;
2520e7e21c44SJohnny Huang (*key_num)++;
2521e7e21c44SJohnny Huang break;
2522e7e21c44SJohnny Huang }
2523e7e21c44SJohnny Huang }
2524e7e21c44SJohnny Huang if ((data[i] >> 13) & 1)
2525e7e21c44SJohnny Huang break;
2526e7e21c44SJohnny Huang }
2527e7e21c44SJohnny Huang }
2528e7e21c44SJohnny Huang
sb_sha(struct sb_info * si,u8 * sec_image,u32 sign_image_size,u8 * digest_ret)2529e7e21c44SJohnny Huang static int sb_sha(struct sb_info *si, u8 *sec_image, u32 sign_image_size, u8 *digest_ret)
2530e7e21c44SJohnny Huang {
2531e7e21c44SJohnny Huang switch (si->sha_algo) {
2532e7e21c44SJohnny Huang case 224:
2533e7e21c44SJohnny Huang printf("otp verify does not support SHA224\n");
2534e7e21c44SJohnny Huang return OTP_FAILURE;
2535e7e21c44SJohnny Huang case 256:
2536948e73aaSJoel Stanley do_hash(sec_image, sign_image_size, "sha256", digest_ret);
2537e7e21c44SJohnny Huang break;
2538e7e21c44SJohnny Huang case 384:
2539948e73aaSJoel Stanley do_hash(sec_image, sign_image_size, "sha384", digest_ret);
2540e7e21c44SJohnny Huang break;
2541e7e21c44SJohnny Huang case 512:
2542948e73aaSJoel Stanley do_hash(sec_image, sign_image_size, "sha512", digest_ret);
2543e7e21c44SJohnny Huang break;
2544e7e21c44SJohnny Huang default:
2545e7e21c44SJohnny Huang printf("SHA Algorithm is invalid\n");
2546e7e21c44SJohnny Huang return OTP_FAILURE;
2547e7e21c44SJohnny Huang }
2548e7e21c44SJohnny Huang return 0;
2549e7e21c44SJohnny Huang }
2550e7e21c44SJohnny Huang
mode2_verify(u8 * sec_image,u32 sign_image_size,u8 * signature,u8 * rsa_m,int order,u8 * digest,struct sb_info * si,struct udevice * mod_exp_dev)2551e7e21c44SJohnny Huang static int mode2_verify(u8 *sec_image, u32 sign_image_size,
2552e7e21c44SJohnny Huang u8 *signature, u8 *rsa_m,
2553e7e21c44SJohnny Huang int order, u8 *digest,
2554e7e21c44SJohnny Huang struct sb_info *si, struct udevice *mod_exp_dev)
2555e7e21c44SJohnny Huang {
2556e7e21c44SJohnny Huang struct key_prop prop;
2557e7e21c44SJohnny Huang u8 rsa_e[3] = "\x01\x00\x01";
2558e7e21c44SJohnny Huang u8 sign_ret[512];
2559e7e21c44SJohnny Huang u8 rsa_m_rev[512];
2560e7e21c44SJohnny Huang u8 signature_rev[512];
2561e7e21c44SJohnny Huang u8 tmp;
2562e7e21c44SJohnny Huang u32 rsa_len = si->rsa_algo / 8;
2563e7e21c44SJohnny Huang int i;
2564e7e21c44SJohnny Huang int ret;
2565e7e21c44SJohnny Huang
2566e7e21c44SJohnny Huang memset(&prop, 0, sizeof(struct key_prop));
2567e7e21c44SJohnny Huang
2568e7e21c44SJohnny Huang if (order == OTP_LIT_END) {
2569e7e21c44SJohnny Huang memset(rsa_m_rev, 0, 512);
2570e7e21c44SJohnny Huang memset(signature_rev, 0, 512);
2571e7e21c44SJohnny Huang for (i = 0; i < rsa_len; i++) {
2572e7e21c44SJohnny Huang rsa_m_rev[i] = rsa_m[rsa_len - 1 - i];
2573e7e21c44SJohnny Huang signature_rev[i] = signature[rsa_len - 1 - i];
2574e7e21c44SJohnny Huang }
2575e7e21c44SJohnny Huang prop.modulus = rsa_m_rev;
2576e7e21c44SJohnny Huang prop.num_bits = si->rsa_algo;
2577e7e21c44SJohnny Huang prop.public_exponent = rsa_e;
2578e7e21c44SJohnny Huang prop.exp_len = 3;
2579e7e21c44SJohnny Huang ret = rsa_mod_exp(mod_exp_dev, signature_rev, rsa_len, &prop, sign_ret);
2580e7e21c44SJohnny Huang } else {
2581e7e21c44SJohnny Huang prop.modulus = rsa_m;
2582e7e21c44SJohnny Huang prop.num_bits = si->rsa_algo;
2583e7e21c44SJohnny Huang prop.public_exponent = rsa_e;
2584e7e21c44SJohnny Huang prop.exp_len = 3;
2585e7e21c44SJohnny Huang ret = rsa_mod_exp(mod_exp_dev, signature, rsa_len, &prop, sign_ret);
2586e7e21c44SJohnny Huang }
2587e7e21c44SJohnny Huang
2588e7e21c44SJohnny Huang if (ret) {
2589e7e21c44SJohnny Huang printf("rsa_mod_exp error: %d\n", ret);
2590e7e21c44SJohnny Huang return OTP_FAILURE;
2591e7e21c44SJohnny Huang }
2592e7e21c44SJohnny Huang
2593e7e21c44SJohnny Huang if (order == OTP_LIT_END) {
2594e7e21c44SJohnny Huang for (i = 0; i < rsa_len / 2; i++) {
2595e7e21c44SJohnny Huang tmp = sign_ret[i];
2596e7e21c44SJohnny Huang sign_ret[i] = sign_ret[rsa_len - 1 - i];
2597e7e21c44SJohnny Huang sign_ret[rsa_len - 1 - i] = tmp;
2598e7e21c44SJohnny Huang }
2599e7e21c44SJohnny Huang ret = memcmp(digest, sign_ret, si->digest_len);
2600e7e21c44SJohnny Huang } else {
2601e7e21c44SJohnny Huang ret = memcmp(digest, sign_ret + (rsa_len - si->digest_len), si->digest_len);
2602e7e21c44SJohnny Huang }
2603e7e21c44SJohnny Huang
2604e7e21c44SJohnny Huang if (ret)
2605e7e21c44SJohnny Huang return OTP_FAILURE;
2606e7e21c44SJohnny Huang return 0;
2607e7e21c44SJohnny Huang }
2608e7e21c44SJohnny Huang
otp_verify_boot_image(phys_addr_t addr)2609e7e21c44SJohnny Huang static int otp_verify_boot_image(phys_addr_t addr)
2610e7e21c44SJohnny Huang {
2611e7e21c44SJohnny Huang struct udevice *mod_exp_dev;
2612e7e21c44SJohnny Huang struct sb_info si;
2613e7e21c44SJohnny Huang struct key_list kl[16];
2614e7e21c44SJohnny Huang struct sb_header *sh;
2615e7e21c44SJohnny Huang u32 data[2048];
2616e7e21c44SJohnny Huang u8 digest[64];
2617e7e21c44SJohnny Huang u8 *sec_image;
2618e7e21c44SJohnny Huang u8 *signature;
2619e7e21c44SJohnny Huang u8 *key;
2620e7e21c44SJohnny Huang u32 otp_rid[2];
2621e7e21c44SJohnny Huang u32 sw_rid[2];
2622e7e21c44SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid;
2623e7e21c44SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid;
2624e7e21c44SJohnny Huang int key_num;
2625e7e21c44SJohnny Huang int ret;
2626e7e21c44SJohnny Huang int i;
2627e7e21c44SJohnny Huang int pass = 0;
2628e7e21c44SJohnny Huang
262909f2a38fSJoel Stanley ret = uclass_get_device(UCLASS_MOD_EXP, 0, &mod_exp_dev);
2630e7e21c44SJohnny Huang if (ret) {
263109f2a38fSJoel Stanley printf("RSA: Can't find RSA driver\n");
2632e7e21c44SJohnny Huang return OTP_FAILURE;
2633e7e21c44SJohnny Huang }
2634e7e21c44SJohnny Huang
2635e7e21c44SJohnny Huang for (i = 0; i < 2048 ; i += 2)
2636e7e21c44SJohnny Huang otp_read_data(i, &data[i]);
2637e7e21c44SJohnny Huang if (parse_config(&si))
2638e7e21c44SJohnny Huang return OTP_FAILURE;
2639e7e21c44SJohnny Huang parse_data(kl, &key_num, &si, data);
2640e7e21c44SJohnny Huang otp_read_conf(10, &otp_rid[0]);
2641e7e21c44SJohnny Huang otp_read_conf(11, &otp_rid[1]);
2642e7e21c44SJohnny Huang
2643e7e21c44SJohnny Huang sec_image = (u8 *)addr;
2644e7e21c44SJohnny Huang sh = (struct sb_header *)(sec_image + si.header_offset);
2645e7e21c44SJohnny Huang signature = sec_image + sh->signature_offset;
2646e7e21c44SJohnny Huang
2647e7e21c44SJohnny Huang if (si.secure_region)
2648e7e21c44SJohnny Huang printf("WARNING: Secure Region is enabled, the verification may not correct.\n");
2649e7e21c44SJohnny Huang
2650e7e21c44SJohnny Huang if (sh->sign_image_size % 512) {
2651e7e21c44SJohnny Huang printf("ERROR: The sign_image_size should be 512 bytes aligned\n");
2652e7e21c44SJohnny Huang return OTP_FAILURE;
2653e7e21c44SJohnny Huang }
2654e7e21c44SJohnny Huang
2655e7e21c44SJohnny Huang printf("Check revision ID: ");
2656e7e21c44SJohnny Huang
2657e7e21c44SJohnny Huang sw_rid[0] = sh->revision_low;
2658e7e21c44SJohnny Huang sw_rid[1] = sh->revision_high;
2659e7e21c44SJohnny Huang
2660e7e21c44SJohnny Huang if (*otp_rid64 > *sw_rid64) {
2661e7e21c44SJohnny Huang printf("FAIL\n");
2662e7e21c44SJohnny Huang printf("Header revision_low: %x\n", sh->revision_low);
2663e7e21c44SJohnny Huang printf("Header revision_high: %x\n", sh->revision_high);
2664e7e21c44SJohnny Huang printf("OTP revision_low: %x\n", otp_rid[0]);
2665e7e21c44SJohnny Huang printf("OTP revision_high: %x\n", otp_rid[1]);
2666e7e21c44SJohnny Huang return OTP_FAILURE;
2667e7e21c44SJohnny Huang }
2668e7e21c44SJohnny Huang printf("PASS\n");
2669e7e21c44SJohnny Huang
2670e7e21c44SJohnny Huang printf("Check secure image header: ");
2671e7e21c44SJohnny Huang if (((sh->aes_data_offset + sh->enc_offset + sh->sign_image_size +
2672e7e21c44SJohnny Huang sh->signature_offset + sh->revision_high + sh->revision_low +
2673e7e21c44SJohnny Huang sh->reserved + sh->bl1_header_checksum) & 0xffffffff) != 0) {
2674e7e21c44SJohnny Huang printf("FAIL\n");
2675e7e21c44SJohnny Huang printf("aes_data_offset: %x\n", sh->aes_data_offset);
2676e7e21c44SJohnny Huang printf("enc_offset: %x\n", sh->enc_offset);
2677e7e21c44SJohnny Huang printf("sign_image_size: %x\n", sh->sign_image_size);
2678e7e21c44SJohnny Huang printf("signature_offset: %x\n", sh->signature_offset);
2679e7e21c44SJohnny Huang printf("revision_high: %x\n", sh->revision_high);
2680e7e21c44SJohnny Huang printf("revision_low: %x\n", sh->revision_low);
2681e7e21c44SJohnny Huang printf("reserved: %x\n", sh->reserved);
2682e7e21c44SJohnny Huang printf("bl1_header_checksum: %x\n", sh->bl1_header_checksum);
2683e7e21c44SJohnny Huang return OTP_FAILURE;
2684e7e21c44SJohnny Huang }
2685e7e21c44SJohnny Huang printf("PASS\n");
2686e7e21c44SJohnny Huang
2687e7e21c44SJohnny Huang ret = sb_sha(&si, sec_image, sh->sign_image_size, digest);
2688e7e21c44SJohnny Huang if (ret)
2689e7e21c44SJohnny Huang return OTP_FAILURE;
2690e7e21c44SJohnny Huang
2691e7e21c44SJohnny Huang printf("Verifying secure image\n");
2692e7e21c44SJohnny Huang for (i = 0; i < key_num; i++) {
2693e7e21c44SJohnny Huang if (kl[i].key_info->key_type != OTP_KEY_TYPE_RSA_PUB)
2694e7e21c44SJohnny Huang continue;
2695e7e21c44SJohnny Huang printf(" Key %d\n", kl[i].id);
2696e7e21c44SJohnny Huang if (kl[i].retire) {
2697e7e21c44SJohnny Huang printf(" Key %d is retired.\n", kl[i].id);
2698e7e21c44SJohnny Huang continue;
2699e7e21c44SJohnny Huang }
2700e7e21c44SJohnny Huang key = (u8 *)data + kl[i].offset;
2701e7e21c44SJohnny Huang if (!mode2_verify(sec_image, sh->sign_image_size,
2702e7e21c44SJohnny Huang signature, key, kl[i].key_info->order, digest,
2703e7e21c44SJohnny Huang &si, mod_exp_dev)) {
2704e7e21c44SJohnny Huang pass = 1;
2705e7e21c44SJohnny Huang break;
2706e7e21c44SJohnny Huang }
2707e7e21c44SJohnny Huang }
2708e7e21c44SJohnny Huang if (pass) {
2709e7e21c44SJohnny Huang printf(" OEM DSS RSA public keys\n");
2710e7e21c44SJohnny Huang printf(" ID: %d\n", kl[i].id);
2711e7e21c44SJohnny Huang if (kl[i].key_info->order == OTP_BIG_END)
2712e7e21c44SJohnny Huang printf(" Big endian\n");
2713e7e21c44SJohnny Huang else
2714e7e21c44SJohnny Huang printf(" Little endian\n");
2715e7e21c44SJohnny Huang printf("Verify secure image: PASS\n");
2716e7e21c44SJohnny Huang return OTP_SUCCESS;
2717e7e21c44SJohnny Huang }
2718e7e21c44SJohnny Huang printf("Verify secure image: FAIL\n");
2719e7e21c44SJohnny Huang return OTP_FAILURE;
2720e7e21c44SJohnny Huang }
2721e7e21c44SJohnny Huang
otp_invalid_key(u32 header_offset,int force)2722418822f0SJohnny Huang static int otp_invalid_key(u32 header_offset, int force)
2723418822f0SJohnny Huang {
2724418822f0SJohnny Huang int i;
2725418822f0SJohnny Huang int ret;
2726418822f0SJohnny Huang u32 header_list[16];
2727418822f0SJohnny Huang u32 header;
2728418822f0SJohnny Huang u32 key_type;
2729418822f0SJohnny Huang u32 prog_val;
2730418822f0SJohnny Huang
2731418822f0SJohnny Huang for (i = 0; i < 16 ; i += 2)
2732418822f0SJohnny Huang otp_read_data(i, &header_list[i]);
2733418822f0SJohnny Huang header = header_list[header_offset];
2734418822f0SJohnny Huang key_type = (header >> 14) & 0xf;
2735418822f0SJohnny Huang _otp_print_key(header, header_offset, NULL);
2736418822f0SJohnny Huang if (key_type == 0 || key_type == 0xf) {
2737418822f0SJohnny Huang printf("Key[%d] already invalid\n", header_offset);
2738418822f0SJohnny Huang return OTP_SUCCESS;
2739418822f0SJohnny Huang }
2740418822f0SJohnny Huang
2741418822f0SJohnny Huang printf("Key[%d] will be invalid\n", header_offset);
2742418822f0SJohnny Huang if (force == 0) {
2743418822f0SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n");
2744418822f0SJohnny Huang if (!confirm_yesno()) {
2745418822f0SJohnny Huang printf(" Aborting\n");
2746418822f0SJohnny Huang return OTP_FAILURE;
2747418822f0SJohnny Huang }
2748418822f0SJohnny Huang }
2749418822f0SJohnny Huang
2750418822f0SJohnny Huang if (header_offset % 2)
2751418822f0SJohnny Huang prog_val = 0;
2752418822f0SJohnny Huang else
2753418822f0SJohnny Huang prog_val = 1;
2754418822f0SJohnny Huang for (i = 14; i <= 17; i++) {
2755418822f0SJohnny Huang ret = otp_prog_dc_b(prog_val, header_offset, i);
2756418822f0SJohnny Huang if (ret) {
2757418822f0SJohnny Huang printf("OTPDATA0x%x[%d] programming failed\n", header_offset, i);
2758418822f0SJohnny Huang return OTP_FAILURE;
2759418822f0SJohnny Huang }
2760418822f0SJohnny Huang }
2761418822f0SJohnny Huang
2762418822f0SJohnny Huang printf("SUCCESS\n");
2763418822f0SJohnny Huang return OTP_SUCCESS;
2764418822f0SJohnny Huang }
2765418822f0SJohnny Huang
do_otpread(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])27662a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
276769d5fd8fSJohnny Huang {
2768a219f6deSJohnny Huang u32 offset, count;
27692a856b9aSJohnny Huang int ret;
277069d5fd8fSJohnny Huang
27712a856b9aSJohnny Huang if (argc == 4) {
27722a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16);
27732a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16);
27742a856b9aSJohnny Huang } else if (argc == 3) {
27752a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16);
27762a856b9aSJohnny Huang count = 1;
27772a856b9aSJohnny Huang } else {
277869d5fd8fSJohnny Huang return CMD_RET_USAGE;
277969d5fd8fSJohnny Huang }
278069d5fd8fSJohnny Huang
2781030cb4a7SJohnny Huang if (!strcmp(argv[1], "conf"))
2782f347c284SJohnny Huang ret = otp_print_conf(offset, count);
2783030cb4a7SJohnny Huang else if (!strcmp(argv[1], "data"))
27842a856b9aSJohnny Huang ret = otp_print_data(offset, count);
2785030cb4a7SJohnny Huang else if (!strcmp(argv[1], "strap"))
27862a856b9aSJohnny Huang ret = otp_print_strap(offset, count);
2787030cb4a7SJohnny Huang else
27882a856b9aSJohnny Huang return CMD_RET_USAGE;
278969d5fd8fSJohnny Huang
27902a856b9aSJohnny Huang if (ret == OTP_SUCCESS)
27912a856b9aSJohnny Huang return CMD_RET_SUCCESS;
27922a856b9aSJohnny Huang return CMD_RET_USAGE;
27932a856b9aSJohnny Huang }
27942a856b9aSJohnny Huang
do_otpprog(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])27952a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
27962a856b9aSJohnny Huang {
27972a856b9aSJohnny Huang phys_addr_t addr;
27982a856b9aSJohnny Huang int ret;
27992a856b9aSJohnny Huang
2800de6b0cc4SJohnny Huang if (argc == 3) {
2801ed071a2bSJohnny Huang if (strcmp(argv[1], "o"))
28022a856b9aSJohnny Huang return CMD_RET_USAGE;
28032a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16);
2804f347c284SJohnny Huang ret = otp_prog_image(addr, 1);
2805de6b0cc4SJohnny Huang } else if (argc == 2) {
28062a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16);
2807f347c284SJohnny Huang ret = otp_prog_image(addr, 0);
28082a856b9aSJohnny Huang } else {
28092a856b9aSJohnny Huang return CMD_RET_USAGE;
28102a856b9aSJohnny Huang }
28112a856b9aSJohnny Huang
28122a856b9aSJohnny Huang if (ret == OTP_SUCCESS)
28132a856b9aSJohnny Huang return CMD_RET_SUCCESS;
28142a856b9aSJohnny Huang else if (ret == OTP_FAILURE)
28152a856b9aSJohnny Huang return CMD_RET_FAILURE;
28162a856b9aSJohnny Huang else
28172a856b9aSJohnny Huang return CMD_RET_USAGE;
28182a856b9aSJohnny Huang }
28192a856b9aSJohnny Huang
do_otppb(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])28202a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
28212a856b9aSJohnny Huang {
28222a856b9aSJohnny Huang int mode = 0;
28232a856b9aSJohnny Huang int nconfirm = 0;
28242a856b9aSJohnny Huang int otp_addr = 0;
28252a856b9aSJohnny Huang int bit_offset;
28262a856b9aSJohnny Huang int value;
28272a856b9aSJohnny Huang int ret;
2828030cb4a7SJohnny Huang u32 otp_strap_pro;
28292a856b9aSJohnny Huang
28302a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6)
28312a856b9aSJohnny Huang return CMD_RET_USAGE;
28322a856b9aSJohnny Huang
28332a856b9aSJohnny Huang /* Drop the pb cmd */
28342a856b9aSJohnny Huang argc--;
28352a856b9aSJohnny Huang argv++;
28362a856b9aSJohnny Huang
28372a856b9aSJohnny Huang if (!strcmp(argv[0], "conf"))
2838a6d0d645SJohnny Huang mode = OTP_REGION_CONF;
28392a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap"))
2840a6d0d645SJohnny Huang mode = OTP_REGION_STRAP;
28412a856b9aSJohnny Huang else if (!strcmp(argv[0], "data"))
2842a6d0d645SJohnny Huang mode = OTP_REGION_DATA;
2843cd1610b4SJohnny Huang else
28442a856b9aSJohnny Huang return CMD_RET_USAGE;
28452a856b9aSJohnny Huang
28462a856b9aSJohnny Huang /* Drop the region cmd */
28472a856b9aSJohnny Huang argc--;
28482a856b9aSJohnny Huang argv++;
28492a856b9aSJohnny Huang
2850ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) {
2851cd1610b4SJohnny Huang nconfirm = 1;
28522a856b9aSJohnny Huang /* Drop the force option */
28532a856b9aSJohnny Huang argc--;
28542a856b9aSJohnny Huang argv++;
28552a856b9aSJohnny Huang }
2856cd1610b4SJohnny Huang
2857a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) {
28582a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16);
28592a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16);
28600808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1))
28612a856b9aSJohnny Huang return CMD_RET_USAGE;
2862cd1610b4SJohnny Huang } else {
28632a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16);
28642a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16);
28652a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16);
28660808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1))
28672a856b9aSJohnny Huang return CMD_RET_USAGE;
28680808cc55SJohnny Huang if (mode == OTP_REGION_DATA) {
286978855207SJohnny Huang if (otp_addr >= 0x800)
28700808cc55SJohnny Huang return CMD_RET_USAGE;
28710808cc55SJohnny Huang } else {
287278855207SJohnny Huang if (otp_addr >= 0x20)
28730808cc55SJohnny Huang return CMD_RET_USAGE;
28740808cc55SJohnny Huang }
2875cd1610b4SJohnny Huang }
2876cd1610b4SJohnny Huang if (value != 0 && value != 1)
28772a856b9aSJohnny Huang return CMD_RET_USAGE;
2878cd1610b4SJohnny Huang
2879030cb4a7SJohnny Huang ret = 0;
2880030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) {
2881030cb4a7SJohnny Huang printf("OTP memory is locked\n");
2882030cb4a7SJohnny Huang return CMD_RET_FAILURE;
2883030cb4a7SJohnny Huang }
2884030cb4a7SJohnny Huang if (mode == OTP_REGION_DATA) {
2885030cb4a7SJohnny Huang if (info_cb.pro_sts.sec_size == 0) {
2886030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) {
2887030cb4a7SJohnny Huang printf("OTP data region is protected\n");
2888030cb4a7SJohnny Huang ret = -1;
2889030cb4a7SJohnny Huang }
2890030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) {
2891030cb4a7SJohnny Huang printf("OTP secure region is not readable, skip it to prevent unpredictable result\n");
2892030cb4a7SJohnny Huang ret = -1;
2893030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size) {
2894030cb4a7SJohnny Huang // header region(0x0~0x40) is still readable even secure region is set.
2895030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) {
2896030cb4a7SJohnny Huang printf("OTP secure region is protected\n");
2897030cb4a7SJohnny Huang ret = -1;
2898030cb4a7SJohnny Huang }
2899030cb4a7SJohnny Huang } else if (info_cb.pro_sts.pro_data) {
2900030cb4a7SJohnny Huang printf("OTP data region is protected\n");
2901030cb4a7SJohnny Huang ret = -1;
2902030cb4a7SJohnny Huang }
2903030cb4a7SJohnny Huang } else if (mode == OTP_REGION_CONF) {
2904030cb4a7SJohnny Huang if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) {
2905030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) {
2906030cb4a7SJohnny Huang printf("OTP config region is protected\n");
2907030cb4a7SJohnny Huang ret = -1;
2908030cb4a7SJohnny Huang }
2909030cb4a7SJohnny Huang } else if (otp_addr == 10 || otp_addr == 11) {
2910030cb4a7SJohnny Huang u32 otp_rid[2];
2911030cb4a7SJohnny Huang u32 sw_rid[2];
2912030cb4a7SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid;
2913030cb4a7SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid;
2914030cb4a7SJohnny Huang
2915030cb4a7SJohnny Huang otp_read_conf(10, &otp_rid[0]);
2916030cb4a7SJohnny Huang otp_read_conf(11, &otp_rid[1]);
2917030cb4a7SJohnny Huang sw_rid[0] = readl(SW_REV_ID0);
2918030cb4a7SJohnny Huang sw_rid[1] = readl(SW_REV_ID1);
2919030cb4a7SJohnny Huang
2920030cb4a7SJohnny Huang if (otp_addr == 10)
2921030cb4a7SJohnny Huang otp_rid[0] |= 1 << bit_offset;
2922030cb4a7SJohnny Huang else
2923030cb4a7SJohnny Huang otp_rid[1] |= 1 << bit_offset;
2924030cb4a7SJohnny Huang
2925030cb4a7SJohnny Huang if (*otp_rid64 > *sw_rid64) {
2926030cb4a7SJohnny Huang printf("update number could not bigger than current SW revision id\n");
2927030cb4a7SJohnny Huang ret = -1;
2928030cb4a7SJohnny Huang }
2929030cb4a7SJohnny Huang } else if (otp_addr == 4) {
2930030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_key_ret) {
2931030cb4a7SJohnny Huang printf("OTPCFG4 is protected\n");
2932030cb4a7SJohnny Huang ret = -1;
2933030cb4a7SJohnny Huang } else {
2934030cb4a7SJohnny Huang if ((bit_offset >= 0 && bit_offset <= 7) ||
2935030cb4a7SJohnny Huang (bit_offset >= 16 && bit_offset <= 23)) {
2936030cb4a7SJohnny Huang u32 key_num;
2937030cb4a7SJohnny Huang u32 retire;
2938030cb4a7SJohnny Huang
2939030cb4a7SJohnny Huang key_num = readl(SEC_KEY_NUM) & 3;
2940030cb4a7SJohnny Huang if (bit_offset >= 16)
2941030cb4a7SJohnny Huang retire = bit_offset - 16;
2942030cb4a7SJohnny Huang else
2943030cb4a7SJohnny Huang retire = bit_offset;
2944030cb4a7SJohnny Huang if (retire >= key_num) {
2945030cb4a7SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n");
2946030cb4a7SJohnny Huang ret = -1;
2947030cb4a7SJohnny Huang }
2948030cb4a7SJohnny Huang }
2949030cb4a7SJohnny Huang }
2950030cb4a7SJohnny Huang } else if (otp_addr >= 16 && otp_addr <= 31) {
2951030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) {
2952030cb4a7SJohnny Huang printf("OTP strap region is protected\n");
2953030cb4a7SJohnny Huang ret = -1;
2954030cb4a7SJohnny Huang } else if ((otp_addr < 30 && info_cb.version == OTP_A0) ||
2955030cb4a7SJohnny Huang (otp_addr < 28 && info_cb.version != OTP_A0)) {
2956030cb4a7SJohnny Huang if (otp_addr % 2 == 0)
2957030cb4a7SJohnny Huang otp_read_conf(30, &otp_strap_pro);
2958030cb4a7SJohnny Huang else
2959030cb4a7SJohnny Huang otp_read_conf(31, &otp_strap_pro);
2960030cb4a7SJohnny Huang if (otp_strap_pro >> bit_offset & 0x1) {
2961b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset);
2962030cb4a7SJohnny Huang ret = -1;
2963030cb4a7SJohnny Huang }
2964030cb4a7SJohnny Huang }
2965030cb4a7SJohnny Huang }
2966030cb4a7SJohnny Huang } else if (mode == OTP_REGION_STRAP) {
2967030cb4a7SJohnny Huang // per bit protection will check in otp_strap_bit_confirm
2968030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) {
2969030cb4a7SJohnny Huang printf("OTP strap region is protected\n");
2970030cb4a7SJohnny Huang ret = -1;
2971030cb4a7SJohnny Huang }
2972030cb4a7SJohnny Huang }
2973030cb4a7SJohnny Huang
2974030cb4a7SJohnny Huang if (ret == -1)
2975030cb4a7SJohnny Huang return CMD_RET_FAILURE;
2976030cb4a7SJohnny Huang
2977f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
29782a856b9aSJohnny Huang
29792a856b9aSJohnny Huang if (ret == OTP_SUCCESS)
29802a856b9aSJohnny Huang return CMD_RET_SUCCESS;
29812a856b9aSJohnny Huang else if (ret == OTP_FAILURE)
29822a856b9aSJohnny Huang return CMD_RET_FAILURE;
29832a856b9aSJohnny Huang else
29842a856b9aSJohnny Huang return CMD_RET_USAGE;
29852a856b9aSJohnny Huang }
29862a856b9aSJohnny Huang
do_otpcmp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])29872a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
29882a856b9aSJohnny Huang {
29892a856b9aSJohnny Huang phys_addr_t addr;
29902a856b9aSJohnny Huang int otp_addr = 0;
2991b8590031SJohnny Huang int ret;
29922a856b9aSJohnny Huang
29932a856b9aSJohnny Huang if (argc != 3)
29942a856b9aSJohnny Huang return CMD_RET_USAGE;
29952a856b9aSJohnny Huang
29962a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16);
29972a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16);
2998b8590031SJohnny Huang ret = otp_compare(otp_addr, addr);
2999b8590031SJohnny Huang if (ret == 0) {
300069d5fd8fSJohnny Huang printf("Compare pass\n");
30012a856b9aSJohnny Huang return CMD_RET_SUCCESS;
3002a219f6deSJohnny Huang }
300369d5fd8fSJohnny Huang printf("Compare fail\n");
30042a856b9aSJohnny Huang return CMD_RET_FAILURE;
300569d5fd8fSJohnny Huang }
300669d5fd8fSJohnny Huang
do_otpinfo(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])300766f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
300866f2f8e5SJohnny Huang {
3009a8bd6d8cSJohnny Huang int view = 0;
30102d4b0742SJohnny Huang int input;
3011a8bd6d8cSJohnny Huang
3012a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3)
301366f2f8e5SJohnny Huang return CMD_RET_USAGE;
301466f2f8e5SJohnny Huang
30152d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) {
30162d4b0742SJohnny Huang if (argc == 3) {
30172d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16);
30182d4b0742SJohnny Huang otp_print_conf_info(input);
30192d4b0742SJohnny Huang } else {
30202d4b0742SJohnny Huang otp_print_conf_info(-1);
30212d4b0742SJohnny Huang }
30222d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) {
30232d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) {
3024a8bd6d8cSJohnny Huang view = 1;
3025a8bd6d8cSJohnny Huang /* Drop the view option */
3026a8bd6d8cSJohnny Huang argc--;
3027a8bd6d8cSJohnny Huang argv++;
3028a8bd6d8cSJohnny Huang }
3029b458cd62SJohnny Huang otp_print_strap_info(view);
30300dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) {
30310dc9a440SJohnny Huang otp_print_scu_info();
303288bd7d58SJohnny Huang } else if (!strcmp(argv[1], "key")) {
303388bd7d58SJohnny Huang otp_print_key_info();
303466f2f8e5SJohnny Huang } else {
303566f2f8e5SJohnny Huang return CMD_RET_USAGE;
303666f2f8e5SJohnny Huang }
30372d4b0742SJohnny Huang
303866f2f8e5SJohnny Huang return CMD_RET_SUCCESS;
303966f2f8e5SJohnny Huang }
304066f2f8e5SJohnny Huang
do_otpprotect(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])30410dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3042737ed20bSJohnny Huang {
30430dc9a440SJohnny Huang u32 input;
30440dc9a440SJohnny Huang u32 bit_offset;
3045e14b073cSJohnny Huang u32 prog_address;
3046030cb4a7SJohnny Huang char force;
304783655e91SJohnny Huang int ret;
3048a219f6deSJohnny Huang
3049737ed20bSJohnny Huang if (argc != 3 && argc != 2)
3050737ed20bSJohnny Huang return CMD_RET_USAGE;
3051737ed20bSJohnny Huang
3052e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) {
3053737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16);
3054030cb4a7SJohnny Huang force = 1;
3055737ed20bSJohnny Huang } else {
3056737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16);
3057030cb4a7SJohnny Huang force = 0;
3058737ed20bSJohnny Huang }
3059737ed20bSJohnny Huang
3060737ed20bSJohnny Huang if (input < 32) {
3061737ed20bSJohnny Huang bit_offset = input;
30620dc9a440SJohnny Huang prog_address = 0xe0c;
3063737ed20bSJohnny Huang } else if (input < 64) {
3064737ed20bSJohnny Huang bit_offset = input - 32;
30650dc9a440SJohnny Huang prog_address = 0xe0e;
3066737ed20bSJohnny Huang } else {
3067737ed20bSJohnny Huang return CMD_RET_USAGE;
3068737ed20bSJohnny Huang }
3069737ed20bSJohnny Huang
3070030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) {
3071030cb4a7SJohnny Huang printf("OTP strap region is protected\n");
3072030cb4a7SJohnny Huang return CMD_RET_FAILURE;
3073030cb4a7SJohnny Huang }
3074030cb4a7SJohnny Huang
3075030cb4a7SJohnny Huang if (!force) {
3076b489486eSJohnny Huang printf("OTPSTRAP[0x%X] will be protected\n", input);
3077030cb4a7SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n");
3078030cb4a7SJohnny Huang if (!confirm_yesno()) {
3079030cb4a7SJohnny Huang printf(" Aborting\n");
3080030cb4a7SJohnny Huang return CMD_RET_FAILURE;
3081030cb4a7SJohnny Huang }
3082030cb4a7SJohnny Huang }
3083030cb4a7SJohnny Huang
3084e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) {
3085b489486eSJohnny Huang printf("OTPSTRAP[0x%X] already protected\n", input);
3086e14b073cSJohnny Huang return CMD_RET_SUCCESS;
3087e14b073cSJohnny Huang }
3088de6fbf1cSJohnny Huang
3089f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset);
3090de6fbf1cSJohnny Huang otp_soak(0);
309183655e91SJohnny Huang
309283655e91SJohnny Huang if (ret) {
3093b489486eSJohnny Huang printf("Protect OTPSTRAP[0x%X] fail\n", input);
3094737ed20bSJohnny Huang return CMD_RET_FAILURE;
3095737ed20bSJohnny Huang }
30969a4fe690SJohnny Huang
3097b489486eSJohnny Huang printf("OTPSTRAP[0x%X] is protected\n", input);
3098794e27ecSJohnny Huang return CMD_RET_SUCCESS;
3099794e27ecSJohnny Huang }
3100794e27ecSJohnny Huang
do_otp_scuprotect(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])31010dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3102e14b073cSJohnny Huang {
31030dc9a440SJohnny Huang u32 scu_offset;
31040dc9a440SJohnny Huang u32 bit_offset;
31050dc9a440SJohnny Huang u32 conf_offset;
31060dc9a440SJohnny Huang u32 prog_address;
31070dc9a440SJohnny Huang char force;
31080dc9a440SJohnny Huang int ret;
31090dc9a440SJohnny Huang
31100dc9a440SJohnny Huang if (argc != 4 && argc != 3)
31110dc9a440SJohnny Huang return CMD_RET_USAGE;
31120dc9a440SJohnny Huang
31130dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) {
31140dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16);
31150dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16);
31160dc9a440SJohnny Huang force = 1;
31170dc9a440SJohnny Huang } else {
31180dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16);
31190dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16);
31200dc9a440SJohnny Huang force = 0;
31210dc9a440SJohnny Huang }
31220dc9a440SJohnny Huang if (scu_offset == 0x500) {
31230dc9a440SJohnny Huang prog_address = 0xe08;
31240dc9a440SJohnny Huang conf_offset = 28;
31250dc9a440SJohnny Huang } else if (scu_offset == 0x510) {
31260dc9a440SJohnny Huang prog_address = 0xe0a;
31270dc9a440SJohnny Huang conf_offset = 29;
31280dc9a440SJohnny Huang } else {
31290dc9a440SJohnny Huang return CMD_RET_USAGE;
31300dc9a440SJohnny Huang }
31310dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31)
31320dc9a440SJohnny Huang return CMD_RET_USAGE;
3133030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) {
3134030cb4a7SJohnny Huang printf("OTP strap region is protected\n");
3135030cb4a7SJohnny Huang return CMD_RET_FAILURE;
3136030cb4a7SJohnny Huang }
31370dc9a440SJohnny Huang if (!force) {
3138b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset);
3139b489486eSJohnny Huang printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset);
31400dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n");
31410dc9a440SJohnny Huang if (!confirm_yesno()) {
31420dc9a440SJohnny Huang printf(" Aborting\n");
31430dc9a440SJohnny Huang return CMD_RET_FAILURE;
31440dc9a440SJohnny Huang }
3145e14b073cSJohnny Huang }
3146e14b073cSJohnny Huang
31470dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) {
3148b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset);
31490dc9a440SJohnny Huang return CMD_RET_SUCCESS;
31500dc9a440SJohnny Huang }
31510dc9a440SJohnny Huang
31520dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset);
31530dc9a440SJohnny Huang otp_soak(0);
31540dc9a440SJohnny Huang
31550dc9a440SJohnny Huang if (ret) {
3156b489486eSJohnny Huang printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset);
31570dc9a440SJohnny Huang return CMD_RET_FAILURE;
31580dc9a440SJohnny Huang }
31590dc9a440SJohnny Huang
3160b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset);
31610dc9a440SJohnny Huang return CMD_RET_SUCCESS;
3162e14b073cSJohnny Huang }
3163e14b073cSJohnny Huang
do_otpver(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])3164f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3165f67375f7SJohnny Huang {
3166e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name);
3167f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER);
3168f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER);
3169f67375f7SJohnny Huang
3170f67375f7SJohnny Huang return CMD_RET_SUCCESS;
3171f67375f7SJohnny Huang }
3172f67375f7SJohnny Huang
do_otpupdate(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])3173794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3174794e27ecSJohnny Huang {
3175794e27ecSJohnny Huang u32 update_num;
3176794e27ecSJohnny Huang int force = 0;
3177794e27ecSJohnny Huang int ret;
3178794e27ecSJohnny Huang
3179794e27ecSJohnny Huang if (argc == 3) {
3180794e27ecSJohnny Huang if (strcmp(argv[1], "o"))
3181794e27ecSJohnny Huang return CMD_RET_USAGE;
3182794e27ecSJohnny Huang force = 1;
3183794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16);
3184794e27ecSJohnny Huang } else if (argc == 2) {
3185794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16);
3186794e27ecSJohnny Huang } else {
3187794e27ecSJohnny Huang return CMD_RET_USAGE;
3188794e27ecSJohnny Huang }
3189794e27ecSJohnny Huang
3190794e27ecSJohnny Huang if (update_num > 64)
3191794e27ecSJohnny Huang return CMD_RET_USAGE;
3192794e27ecSJohnny Huang ret = otp_update_rid(update_num, force);
3193b8590031SJohnny Huang
3194794e27ecSJohnny Huang if (ret)
3195794e27ecSJohnny Huang return CMD_RET_FAILURE;
3196794e27ecSJohnny Huang return CMD_RET_SUCCESS;
3197794e27ecSJohnny Huang }
3198794e27ecSJohnny Huang
do_otprid(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])3199794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3200794e27ecSJohnny Huang {
3201794e27ecSJohnny Huang u32 otp_rid[2];
3202a8789b47SJohnny Huang u32 sw_rid[2];
3203794e27ecSJohnny Huang int rid_num = 0;
3204a8789b47SJohnny Huang int sw_rid_num = 0;
3205794e27ecSJohnny Huang int ret;
3206794e27ecSJohnny Huang
3207794e27ecSJohnny Huang if (argc != 1)
3208794e27ecSJohnny Huang return CMD_RET_USAGE;
3209794e27ecSJohnny Huang
3210f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]);
3211f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]);
3212794e27ecSJohnny Huang
3213a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0);
3214a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1);
3215794e27ecSJohnny Huang
3216a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid);
3217a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid);
3218a8789b47SJohnny Huang
3219030cb4a7SJohnny Huang if (sw_rid_num < 0) {
3220030cb4a7SJohnny Huang printf("SW revision id is invalid, please check.\n");
3221030cb4a7SJohnny Huang printf("SEC68:0x%x\n", sw_rid[0]);
3222030cb4a7SJohnny Huang printf("SEC6C:0x%x\n", sw_rid[1]);
3223030cb4a7SJohnny Huang } else {
3224a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num);
3225030cb4a7SJohnny Huang }
3226794e27ecSJohnny Huang if (rid_num >= 0) {
3227794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num);
3228794e27ecSJohnny Huang ret = CMD_RET_SUCCESS;
3229794e27ecSJohnny Huang } else {
3230b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by 'otp update',\n"
3231b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n"
3232794e27ecSJohnny Huang "current OTP revision ID\n");
3233794e27ecSJohnny Huang ret = CMD_RET_FAILURE;
3234794e27ecSJohnny Huang }
3235794e27ecSJohnny Huang otp_print_revid(otp_rid);
3236794e27ecSJohnny Huang
3237794e27ecSJohnny Huang return ret;
3238794e27ecSJohnny Huang }
3239794e27ecSJohnny Huang
do_otpretire(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])3240883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3241883625c5SJohnny Huang {
3242883625c5SJohnny Huang u32 retire_id;
3243883625c5SJohnny Huang int force = 0;
3244883625c5SJohnny Huang int ret;
3245883625c5SJohnny Huang
3246883625c5SJohnny Huang if (argc == 3) {
3247883625c5SJohnny Huang if (strcmp(argv[1], "o"))
3248883625c5SJohnny Huang return CMD_RET_USAGE;
3249883625c5SJohnny Huang force = 1;
3250883625c5SJohnny Huang retire_id = simple_strtoul(argv[2], NULL, 16);
3251883625c5SJohnny Huang } else if (argc == 2) {
3252883625c5SJohnny Huang retire_id = simple_strtoul(argv[1], NULL, 16);
3253883625c5SJohnny Huang } else {
3254883625c5SJohnny Huang return CMD_RET_USAGE;
3255883625c5SJohnny Huang }
3256883625c5SJohnny Huang
3257883625c5SJohnny Huang if (retire_id > 7)
3258883625c5SJohnny Huang return CMD_RET_USAGE;
3259883625c5SJohnny Huang ret = otp_retire_key(retire_id, force);
3260883625c5SJohnny Huang
3261883625c5SJohnny Huang if (ret)
3262883625c5SJohnny Huang return CMD_RET_FAILURE;
3263883625c5SJohnny Huang return CMD_RET_SUCCESS;
3264883625c5SJohnny Huang }
3265883625c5SJohnny Huang
do_otpverify(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])3266e7e21c44SJohnny Huang static int do_otpverify(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3267e7e21c44SJohnny Huang {
3268e7e21c44SJohnny Huang phys_addr_t addr;
3269e7e21c44SJohnny Huang int ret;
3270e7e21c44SJohnny Huang
3271e7e21c44SJohnny Huang if (argc == 2) {
3272e7e21c44SJohnny Huang addr = simple_strtoul(argv[1], NULL, 16);
3273e7e21c44SJohnny Huang ret = otp_verify_boot_image(addr);
3274e7e21c44SJohnny Huang } else {
3275e7e21c44SJohnny Huang return CMD_RET_USAGE;
3276e7e21c44SJohnny Huang }
3277e7e21c44SJohnny Huang
3278e7e21c44SJohnny Huang if (ret == OTP_SUCCESS)
3279e7e21c44SJohnny Huang return CMD_RET_SUCCESS;
3280e7e21c44SJohnny Huang else if (ret == OTP_FAILURE)
3281e7e21c44SJohnny Huang return CMD_RET_FAILURE;
3282e7e21c44SJohnny Huang else
3283e7e21c44SJohnny Huang return CMD_RET_USAGE;
3284e7e21c44SJohnny Huang }
3285e7e21c44SJohnny Huang
do_otpinvalid(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])3286418822f0SJohnny Huang static int do_otpinvalid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3287418822f0SJohnny Huang {
3288418822f0SJohnny Huang u32 header_offset;
3289418822f0SJohnny Huang int force = 0;
3290418822f0SJohnny Huang int ret;
3291418822f0SJohnny Huang
3292418822f0SJohnny Huang if (argc == 3) {
3293418822f0SJohnny Huang if (strcmp(argv[1], "o"))
3294418822f0SJohnny Huang return CMD_RET_USAGE;
3295418822f0SJohnny Huang force = 1;
3296418822f0SJohnny Huang header_offset = simple_strtoul(argv[2], NULL, 16);
3297418822f0SJohnny Huang } else if (argc == 2) {
3298418822f0SJohnny Huang header_offset = simple_strtoul(argv[1], NULL, 16);
3299418822f0SJohnny Huang } else {
3300418822f0SJohnny Huang return CMD_RET_USAGE;
3301418822f0SJohnny Huang }
3302418822f0SJohnny Huang
3303418822f0SJohnny Huang if (header_offset > 16)
3304418822f0SJohnny Huang return CMD_RET_USAGE;
3305418822f0SJohnny Huang ret = otp_invalid_key(header_offset, force);
3306418822f0SJohnny Huang
3307418822f0SJohnny Huang if (ret)
3308418822f0SJohnny Huang return CMD_RET_FAILURE;
3309418822f0SJohnny Huang return CMD_RET_SUCCESS;
3310418822f0SJohnny Huang }
3311418822f0SJohnny Huang
33122a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
3313f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
33142a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
3315a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
3316de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
33172a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
3318737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
33190dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""),
33202a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
3321794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
3322794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
3323883625c5SJohnny Huang U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""),
3324e7e21c44SJohnny Huang U_BOOT_CMD_MKENT(verify, 2, 0, do_otpverify, "", ""),
3325418822f0SJohnny Huang U_BOOT_CMD_MKENT(invalid, 3, 0, do_otpinvalid, "", ""),
33262a856b9aSJohnny Huang };
33272a856b9aSJohnny Huang
do_ast_otp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])33282a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
33292a856b9aSJohnny Huang {
3330030cb4a7SJohnny Huang struct otp_pro_sts *pro_sts;
33312a856b9aSJohnny Huang cmd_tbl_t *cp;
3332a219f6deSJohnny Huang u32 ver;
3333e14b073cSJohnny Huang int ret;
3334030cb4a7SJohnny Huang u32 otp_conf0;
33352a856b9aSJohnny Huang
33362a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
33372a856b9aSJohnny Huang
3338737ed20bSJohnny Huang /* Drop the otp command */
33392a856b9aSJohnny Huang argc--;
33402a856b9aSJohnny Huang argv++;
33412a856b9aSJohnny Huang
3342a219f6deSJohnny Huang if (!cp || argc > cp->maxargs)
33432a856b9aSJohnny Huang return CMD_RET_USAGE;
33442a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
33452a856b9aSJohnny Huang return CMD_RET_SUCCESS;
33462a856b9aSJohnny Huang
33470dae9d52SJohnny Huang ver = chip_version();
33480dae9d52SJohnny Huang switch (ver) {
3349e417205bSJohnny Huang case OTP_A0:
3350e417205bSJohnny Huang info_cb.version = OTP_A0;
33519a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info;
33529a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
33539a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info;
33549a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
33559a4fe690SJohnny Huang info_cb.key_info = a0_key_type;
33569a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
3357e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0");
33580dae9d52SJohnny Huang break;
3359e417205bSJohnny Huang case OTP_A1:
3360e417205bSJohnny Huang info_cb.version = OTP_A1;
33613cb28812SJohnny Huang info_cb.conf_info = a1_conf_info;
33623cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
33633cb28812SJohnny Huang info_cb.strap_info = a1_strap_info;
33643cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
33659a4fe690SJohnny Huang info_cb.key_info = a1_key_type;
33669a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
33670dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info;
33680dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
3369e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1");
33700dae9d52SJohnny Huang break;
3371e417205bSJohnny Huang case OTP_A2:
3372e417205bSJohnny Huang info_cb.version = OTP_A2;
33735fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info;
33745fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
3375fed30023SJohnny Huang info_cb.strap_info = a1_strap_info;
3376fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
33775fdde29fSJohnny Huang info_cb.key_info = a2_key_type;
33785fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
33790dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info;
33800dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
3381e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2");
33820dae9d52SJohnny Huang break;
3383e417205bSJohnny Huang case OTP_A3:
3384e417205bSJohnny Huang info_cb.version = OTP_A3;
3385b63af886SJohnny Huang info_cb.conf_info = a3_conf_info;
3386b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info);
3387fed30023SJohnny Huang info_cb.strap_info = a1_strap_info;
3388fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
3389181f72d8SJohnny Huang info_cb.key_info = a3_key_type;
3390181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
33910dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info;
33920dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
3393e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3");
339464b66712SJohnny Huang break;
33950dae9d52SJohnny Huang default:
3396f1be5099SJohnny Huang printf("SOC is not supported\n");
33970dae9d52SJohnny Huang return CMD_RET_FAILURE;
33989a4fe690SJohnny Huang }
33999a4fe690SJohnny Huang
3400030cb4a7SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
3401030cb4a7SJohnny Huang otp_read_conf(0, &otp_conf0);
3402030cb4a7SJohnny Huang pro_sts = &info_cb.pro_sts;
3403030cb4a7SJohnny Huang
3404030cb4a7SJohnny Huang pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1;
3405030cb4a7SJohnny Huang pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1;
3406030cb4a7SJohnny Huang pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1;
3407030cb4a7SJohnny Huang pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1;
3408030cb4a7SJohnny Huang pro_sts->pro_data = (otp_conf0 >> 23) & 0x1;
3409030cb4a7SJohnny Huang pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1;
3410030cb4a7SJohnny Huang pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5;
3411030cb4a7SJohnny Huang
3412e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv);
3413b8590031SJohnny Huang writel(1, OTP_PROTECT_KEY); //protect otp controller
3414e14b073cSJohnny Huang
3415e14b073cSJohnny Huang return ret;
341669d5fd8fSJohnny Huang }
341769d5fd8fSJohnny Huang
3418a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp,
341969d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system",
3420f67375f7SJohnny Huang "version\n"
3421f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n"
34222a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n"
34232d4b0742SJohnny Huang "otp info strap [v]\n"
34242d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n"
34250dc9a440SJohnny Huang "otp info scu\n"
342688bd7d58SJohnny Huang "otp info key\n"
3427de6b0cc4SJohnny Huang "otp prog [o] <addr>\n"
3428ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
3429ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n"
3430ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n"
34310dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n"
3432794e27ecSJohnny Huang "otp update [o] <revision_id>\n"
3433794e27ecSJohnny Huang "otp rid\n"
3434883625c5SJohnny Huang "otp retire [o] <key_id>\n"
3435e7e21c44SJohnny Huang "otp verify <addr>\n"
3436418822f0SJohnny Huang "otp invalid [o] <header_offset>\n"
343769d5fd8fSJohnny Huang );
3438