blob: 8df0606e63bee4be695b4368101b4069ce9be3c4 [file] [log] [blame]
Zhongfu Luo1e6af102023-07-27 17:23:27 +08001// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2/*
3 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
4 */
5
6#include <config.h>
7#include <common.h>
8#include <command.h>
9#include <malloc.h>
10#include <asm/amlogic/arch/efuse.h>
11#include <asm/amlogic/arch/bl31_apis.h>
12#include <amlogic/aml_efuse.h>
13
14#define CMD_EFUSE_WRITE 0
15#define CMD_EFUSE_READ 1
16#define CMD_EFUSE_READ_CALI 2
17#define CMD_EFUSE_READ_CALI_ITEM 3
18#define CMD_EFUSE_CHECK_PATTERN_ITEM 10
19
20int cmd_efuse(int argc, char * const argv[], char *buf)
21{
22 int i, action = -1;
23 u64 offset;
24 u32 size = 0, max_size;
25 char *end;
26 char *s;
27 int ret;
28
29 if (strncmp(argv[1], "read", 4) == 0) {
30 action = CMD_EFUSE_READ;
31 } else if (strncmp(argv[1], "cali_read", 9) == 0) {
32 action = CMD_EFUSE_READ_CALI;
33 } else if (strncmp(argv[1], "item_read", 9) == 0) {
34 action = CMD_EFUSE_READ_CALI_ITEM;
35 goto efuse_action;
36 } else if (strncmp(argv[1], "check", 9) == 0) {
37 action = CMD_EFUSE_CHECK_PATTERN_ITEM;
38 goto efuse_action;
39 } else if (strncmp(argv[1], "write", 5) == 0) {
40 action = CMD_EFUSE_WRITE;
41 } else{
42 printf("%s arg error\n", argv[1]);
43 return CMD_RET_USAGE;
44 }
45
46 if (argc < 4)
47 return CMD_RET_USAGE;
48 /*check efuse user data max size*/
49 offset = simple_strtoul(argv[2], &end, 16);
50 size = simple_strtoul(argv[3], &end, 16);
51 printf("%s: offset is %lld size is %d\n", __func__, offset, size);
52 max_size = efuse_get_max();
53 if (!size) {
54 printf("\n error: size is zero!!!\n");
55 return -1;
56 }
57 if (offset > max_size) {
58 printf("\n error: offset is too large!!!\n");
59 printf("\n offset should be less than %d!\n", max_size);
60 return -1;
61 }
62 if (offset + size > max_size) {
63 printf("\n error: offset + size is too large!!!\n");
64 printf("\n offset + size should be less than %d!\n", max_size);
65 return -1;
66 }
67
68efuse_action:
69
70 /* efuse read */
71 if (action == CMD_EFUSE_READ) {
72 memset(buf, 0, size);
73 ret = efuse_read_usr(buf, size, (loff_t *)&offset);
74 if (ret == -1) {
75 printf("ERROR: efuse read user data fail!\n");
76 return -1;
77 }
78
79 if (ret != size)
80 printf("ERROR: read %d byte(s) not %d byte(s) data\n",
81 ret, size);
82 printf("efuse read data");
83 for (i = 0; i < size; i++) {
84 if (i % 16 == 0)
85 printf("\n");
86 printf(":%02x", buf[i]);
87 }
88 printf("\n");
89 }
90 else if (action == CMD_EFUSE_READ_CALI) {
91 memset(buf, 0, size);
92 ret = efuse_read_cali(buf, size, offset);
93 if (ret == -1) {
94 printf("ERROR: efuse read cali data fail!\n");
95 return -1;
96 }
97
98 if (ret != size)
99 printf("ERROR: read %d byte(s) not %d byte(s) data\n",
100 ret, size);
101 printf("efuse read cali data");
102 for (i = 0; i < size; i++) {
103 if (i % 16 == 0)
104 printf("\n");
105 printf(":%02x", buf[i]);
106 }
107 printf("\n");
108 }
109 else if (action == CMD_EFUSE_READ_CALI_ITEM) {
110 s = argv[2];
111 ret = efuse_get_cali_item(s);
112 if (ret < 0) {
113 printf("ERROR: efuse read cali item data fail!\n");
114 return -1;
115 }
116 printf("efuse %s cali data=0x%x\n",s,ret);
117 } else if (action == CMD_EFUSE_CHECK_PATTERN_ITEM) {
118 s = argv[2];
119 ret = efuse_check_pattern_item(s);
120 if (ret < 0) {
121 printf("ERROR: efuse check pattern fail!\n");
122 return -1;
123 }
124 printf("efuse %s %s\n", s, ret > 0 ? "has been written" : "is not write");
125 return ret == 0 ? 1 : 0; //cmd return 0: written, 1: not write
126 }
127
128 /* efuse write */
129 else if (action == CMD_EFUSE_WRITE) {
130 if (argc < 5) {
131 printf("arg count error\n");
132 return CMD_RET_USAGE;
133 }
134 memset(buf, 0, size);
135
136 s = argv[4];
137 memcpy(buf, s, strlen(s));
138 if (efuse_write_usr(buf, size, (loff_t *)&offset) < 0) {
139 printf("error: efuse write fail.\n");
140 return -1;
141 } else {
142 printf("%s written done.\n", __func__);
143 }
144 } else {
145 /*
146 * This part of the code is necessary to prevent unknown errors
147 */
148 /* coverity[dead_error_begin] */
149 printf("arg error\n");
150 return CMD_RET_USAGE;
151 }
152
153 return 0;
154}
155
156int do_efuse(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
157{
158 char buf[EFUSE_BYTES];
159
160 memset(buf, 0, sizeof(buf));
161
162 if (argc < 2)
163 return CMD_RET_USAGE;
164
165 return cmd_efuse(argc, argv, buf);
166}
167
168static char efuse_help_text[] =
169 "[read/write offset size [data]]\n"
170 " [cali_read] -read from cali\n"
171 " example: [efuse cali_read 0 7]; offset is 0,size is 7. \n"
172 " [item_read] -read cali item\n"
173 " [item_read sensor/saradc/mipicsi/hdmirx/eth/cvbs/earcrx/earctx]\n"
174 " [check] -check if pattern is write\n"
175 " [check dgpk1|dgpk2|aud_id]\n"
176 " [read/write] - read or write 'size' data from\n"
177 " 'offset' from efuse user data ;\n"
178 " [offset] - the offset byte from the beginning\n"
179 " of efuse user data zone;\n"
180 " [size] - data size\n"
181 " [data] - the optional argument for 'write',\n"
182 " data is treated as characters\n"
183 " examples: efuse write 0xc 0xd abcdABCD1234\n";
184
185U_BOOT_CMD(
186 efuse, 5, 1, do_efuse,
187 "efuse commands", efuse_help_text
188);
189
190#ifdef CONFIG_EFUSE_OBJ_API
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800191static char *efuse_obj_err_parse(uint32_t efuse_obj_err_status)
192{
193 char *err_char = NULL;
194
195 switch (efuse_obj_err_status) {
196 case EFUSE_OBJ_ERR_INVALID_DATA:
197 err_char = "invalid data";
198 break;
199 case EFUSE_OBJ_ERR_NOT_FOUND:
200 err_char = "field not found";
201 break;
202 case EFUSE_OBJ_ERR_SIZE:
203 err_char = "size not match";
204 break;
205 case EFUSE_OBJ_ERR_NOT_SUPPORT:
206 err_char = "not support";
207 break;
208 case EFUSE_OBJ_ERR_ACCESS:
209 err_char = "access denied";
210 break;
211 case EFUSE_OBJ_ERR_WRITE_PROTECTED:
212 err_char = "write protected";
213 break;
Tao Zenge593bf72024-08-02 18:35:08 +0800214#if (IS_ENABLED(CONFIG_AMPK))
Lawrence Mok782ed8c2024-07-10 15:25:06 -0700215 case EFUSE_OBJ_ERR_TAG:
216 err_char = "invalid encrypted data tag. check device pub key and re-encrypt";
217 break;
Tao Zenge593bf72024-08-02 18:35:08 +0800218#endif
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800219 case EFUSE_OBJ_ERR_INTERNAL:
220 case EFUSE_OBJ_ERR_OTHER_INTERNAL:
221 err_char = "internal error";
222 break;
223 default:
224 err_char = "unknown error";
225 break;
226 }
227
228 return err_char;
229}
230
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800231int do_efuse_obj(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
232{
233 uint32_t rc = CMD_RET_FAILURE;
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800234 char *name = NULL;
235
236 if (argc < 3 || argc > 4) {
237 printf("Invalid number of arguments %d\n", argc);
238 return CMD_RET_USAGE;
239 }
240
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800241 memset(&efuse_field, 0, sizeof(efuse_field));
242
243 if (strcmp(argv[1], "get") == 0) {
244 // $0 get field
245 if (argc == 3) {
246 name = argv[2];
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800247 rc = efuse_obj_get_data(name);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800248 if (rc == EFUSE_OBJ_SUCCESS) {
249 int i;
250
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800251 for (i = 0; i < efuse_field.size; i++)
252 printf("%02x%s", efuse_field.data[i],
253 ((i && i % 16 == 15) || (i == efuse_field.size - 1)
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800254 ? "\n" : " "));
255 rc = CMD_RET_SUCCESS;
256 } else {
257 printf("Error getting eFUSE object: %s: %d\n",
258 efuse_obj_err_parse(rc), rc);
259 rc = CMD_RET_FAILURE;
260 }
261 } else {
262 printf("Error: too many arguments %d\n", argc);
263 rc = CMD_RET_USAGE;
264 }
265 } else if (strcmp(argv[1], "set") == 0) {
266 // $0 set field data
267 if (argc == 4) {
268 name = argv[2];
269 char *data = argv[3];
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800270
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800271 rc = efuse_obj_set_data(name, data);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800272 if (rc == EFUSE_OBJ_SUCCESS) {
273 rc = CMD_RET_SUCCESS;
274 } else {
275 printf("Error setting eFUSE object: %s: %d\n",
276 efuse_obj_err_parse(rc), rc);
277 rc = CMD_RET_FAILURE;
278 }
279 } else {
280 printf("Error: too few arguments %d\n", argc);
281 rc = CMD_RET_USAGE;
282 }
Lawrence Mok782ed8c2024-07-10 15:25:06 -0700283#if (IS_ENABLED(CONFIG_AMPK))
284 } else if (strcmp(argv[1], "set_enc") == 0) {
285 // $0 set field data
286 if (argc == 4) {
287 name = argv[2];
288 char *data = argv[3];
289
290 rc = efuse_obj_set_enc_data(name, data);
291 if (rc == EFUSE_OBJ_SUCCESS) {
292 rc = CMD_RET_SUCCESS;
293 } else {
294 printf("Error setting eFUSE object: %s: %d\n",
295 efuse_obj_err_parse(rc), rc);
296 rc = CMD_RET_FAILURE;
297 }
298 } else {
299 printf("Error: too few arguments %d\n", argc);
300 rc = CMD_RET_USAGE;
301 }
302#endif /* CONFIG_AMPK */
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800303 } else if (strcmp(argv[1], "lock") == 0) {
304 // $0 lock field
305 if (argc == 3) {
306 name = argv[2];
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800307 rc = efuse_obj_lock(name);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800308 if (rc == EFUSE_OBJ_SUCCESS) {
309 rc = CMD_RET_SUCCESS;
310 } else {
311 printf("Error setting eFUSE object: %s: %d\n",
312 efuse_obj_err_parse(rc), rc);
313 rc = CMD_RET_FAILURE;
314 }
315 } else {
316 printf("Error: too many arguments %d\n", argc);
317 rc = CMD_RET_USAGE;
318 }
319 } else if (strcmp(argv[1], "get_lock") == 0) {
320 // $0 get_lock field
321 if (argc == 3) {
322 name = argv[2];
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800323 rc = efuse_obj_get_lock(name);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800324 if (rc == EFUSE_OBJ_SUCCESS) {
325 int i;
326
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800327 for (i = 0; i < efuse_field.size; i++)
328 printf("%02x%s", efuse_field.data[i],
329 ((i && i % 16 == 15) || (i == efuse_field.size - 1)
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800330 ? "\n" : " "));
331 rc = CMD_RET_SUCCESS;
332 } else {
333 printf("Error getting eFUSE object: %s: %d\n",
334 efuse_obj_err_parse(rc), rc);
335 rc = CMD_RET_FAILURE;
336 }
337 } else {
338 printf("Error: too many arguments %d\n", argc);
339 rc = CMD_RET_USAGE;
340 }
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800341 } else {
342 printf("Error: cmd %s not supported\n", argv[1]);
343 rc = CMD_RET_USAGE;
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800344 }
345
346 return rc;
347}
348
349static char efuse_obj_help_text[] =
350 "[set | get | lock | get_lock] <FIELD> {<field-value-hexdump-string>}\n"
351 "\n"
352 "get FIELD Get field value. FIELD is the field name\n"
353 " expected_data is an optional expected data\n"
354 "set FIELD DATA Set field to data. DATA is in continuous\n"
355 " hexdump format, e.g. aabb1122\n"
Lawrence Mok782ed8c2024-07-10 15:25:06 -0700356#if defined(CONFIG_AMPK)
357 "set_enc FIELD ENC_DATA Set field to encrypted data. ENC_DATA is in continuous\n"
358 " hexdump format, e.g. aabb1122\n"
359#endif /* CONFIG_AMPK */
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800360 "lock FIELD Lock field. Program exits with status 0 if success\n"
361 "get_lock FIELD Check if field is locked. Program exits with\n"
362 " status 1 if locked, or 0 if unlocked\n"
363 " expected_result is 00 or 01, an optional expected lock result\n"
364 "\n";
365
366U_BOOT_CMD(efuse_obj, 4, 0, do_efuse_obj,
367 "eFUSE object program commands", efuse_obj_help_text
368);
369#endif /* CONFIG_EFUSE_OBJ_API */
370
371#ifdef CONFIG_EFUSE_MRK_GET_CHECKNUM
372int do_efuse_mrk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
373{
374 uint32_t rc = CMD_RET_FAILURE;
375 char name[16];
376 uint32_t checknum = 0;
377
378 if (argc != 2) {
379 printf("Invalid number of arguments %d\n", argc);
380 return CMD_RET_USAGE;
381 }
382
383 memset(name, 0, sizeof(name));
384 strncpy(name, argv[1], sizeof(name) - 1);
xia.jin9a4431c2024-08-20 02:52:27 +0000385 rc = efuse_mrk_get_checknum(name, 0, &checknum);
386 if (!rc) {
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800387 printf("%s: 0x%08x\n", argv[1], checknum);
388 rc = CMD_RET_SUCCESS;
xia.jin9a4431c2024-08-20 02:52:27 +0000389 } else if (rc == EFUSE_MRK_CHECKNUM_NOT_SUPPORTED) {
390 printf("MRK field %s not supported\n", argv[1]);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800391 } else {
xia.jin9a4431c2024-08-20 02:52:27 +0000392 printf("get mrk checknum for %s failed, MRK field may not be written\n", argv[1]);
393 }
394
395 return rc;
396}
397
398int do_efuse_mrk_long(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
399{
400 uint32_t rc = CMD_RET_FAILURE;
401 char name[16];
402 uint32_t checknum[4];
403
404 if (argc != 2) {
405 printf("Invalid number of arguments %d\n", argc);
406 return CMD_RET_USAGE;
407 }
408
409 memset(name, 0, sizeof(name));
410 strncpy(name, argv[1], sizeof(name) - 1);
411 rc = efuse_mrk_get_checknum(name, 1, &checknum[0]);
412 if (!rc) {
413 printf("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n",
414 argv[1], checknum[0], checknum[1], checknum[2], checknum[3]);
415 rc = CMD_RET_SUCCESS;
416 } else if (rc == EFUSE_MRK_CHECKNUM_NOT_SUPPORTED) {
417 printf("MRK field %s not supported\n", argv[1]);
418 } else {
419 printf("get mrk checknum for %s failed, MRK field may not be written\n", argv[1]);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800420 }
421
422 return rc;
423}
424
425static char efuse_mrk_help_text[] =
426 "<MRK>\n"
427 "Supported MRK includes: DVGK, DVUK,\n"
428 "DGPK1, DGPK2,\n"
429 "ETSI_SCK_0, ETSI_SCK_1, ETSI_SCK_2,\n"
430 "SCPU_ETSI_SCK_0, SCPU_ETSI_SCK_1, SEGK\n";
431
432U_BOOT_CMD(efuse_mrk, 2, 0, do_efuse_mrk,
433 "eFUSE mrk checknum", efuse_mrk_help_text
434);
xia.jin9a4431c2024-08-20 02:52:27 +0000435
436U_BOOT_CMD(efuse_mrk_long, 2, 0, do_efuse_mrk_long,
437 "eFUSE mrk long checknum", efuse_mrk_help_text
438);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800439#endif /* CONFIG_EFUSE_MRK_GET_CHECKNUM */