blob: db706cded2657e2ad3dac81854c9a595d43debda [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;
Lawrence Mok782ed8c2024-07-10 15:25:06 -0700214 case EFUSE_OBJ_ERR_TAG:
215 err_char = "invalid encrypted data tag. check device pub key and re-encrypt";
216 break;
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800217 case EFUSE_OBJ_ERR_INTERNAL:
218 case EFUSE_OBJ_ERR_OTHER_INTERNAL:
219 err_char = "internal error";
220 break;
221 default:
222 err_char = "unknown error";
223 break;
224 }
225
226 return err_char;
227}
228
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800229int do_efuse_obj(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
230{
231 uint32_t rc = CMD_RET_FAILURE;
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800232 char *name = NULL;
233
234 if (argc < 3 || argc > 4) {
235 printf("Invalid number of arguments %d\n", argc);
236 return CMD_RET_USAGE;
237 }
238
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800239 memset(&efuse_field, 0, sizeof(efuse_field));
240
241 if (strcmp(argv[1], "get") == 0) {
242 // $0 get field
243 if (argc == 3) {
244 name = argv[2];
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800245 rc = efuse_obj_get_data(name);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800246 if (rc == EFUSE_OBJ_SUCCESS) {
247 int i;
248
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800249 for (i = 0; i < efuse_field.size; i++)
250 printf("%02x%s", efuse_field.data[i],
251 ((i && i % 16 == 15) || (i == efuse_field.size - 1)
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800252 ? "\n" : " "));
253 rc = CMD_RET_SUCCESS;
254 } else {
255 printf("Error getting eFUSE object: %s: %d\n",
256 efuse_obj_err_parse(rc), rc);
257 rc = CMD_RET_FAILURE;
258 }
259 } else {
260 printf("Error: too many arguments %d\n", argc);
261 rc = CMD_RET_USAGE;
262 }
263 } else if (strcmp(argv[1], "set") == 0) {
264 // $0 set field data
265 if (argc == 4) {
266 name = argv[2];
267 char *data = argv[3];
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800268
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800269 rc = efuse_obj_set_data(name, data);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800270 if (rc == EFUSE_OBJ_SUCCESS) {
271 rc = CMD_RET_SUCCESS;
272 } else {
273 printf("Error setting eFUSE object: %s: %d\n",
274 efuse_obj_err_parse(rc), rc);
275 rc = CMD_RET_FAILURE;
276 }
277 } else {
278 printf("Error: too few arguments %d\n", argc);
279 rc = CMD_RET_USAGE;
280 }
Lawrence Mok782ed8c2024-07-10 15:25:06 -0700281#if (IS_ENABLED(CONFIG_AMPK))
282 } else if (strcmp(argv[1], "set_enc") == 0) {
283 // $0 set field data
284 if (argc == 4) {
285 name = argv[2];
286 char *data = argv[3];
287
288 rc = efuse_obj_set_enc_data(name, data);
289 if (rc == EFUSE_OBJ_SUCCESS) {
290 rc = CMD_RET_SUCCESS;
291 } else {
292 printf("Error setting eFUSE object: %s: %d\n",
293 efuse_obj_err_parse(rc), rc);
294 rc = CMD_RET_FAILURE;
295 }
296 } else {
297 printf("Error: too few arguments %d\n", argc);
298 rc = CMD_RET_USAGE;
299 }
300#endif /* CONFIG_AMPK */
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800301 } else if (strcmp(argv[1], "lock") == 0) {
302 // $0 lock field
303 if (argc == 3) {
304 name = argv[2];
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800305 rc = efuse_obj_lock(name);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800306 if (rc == EFUSE_OBJ_SUCCESS) {
307 rc = CMD_RET_SUCCESS;
308 } else {
309 printf("Error setting eFUSE object: %s: %d\n",
310 efuse_obj_err_parse(rc), rc);
311 rc = CMD_RET_FAILURE;
312 }
313 } else {
314 printf("Error: too many arguments %d\n", argc);
315 rc = CMD_RET_USAGE;
316 }
317 } else if (strcmp(argv[1], "get_lock") == 0) {
318 // $0 get_lock field
319 if (argc == 3) {
320 name = argv[2];
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800321 rc = efuse_obj_get_lock(name);
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800322 if (rc == EFUSE_OBJ_SUCCESS) {
323 int i;
324
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800325 for (i = 0; i < efuse_field.size; i++)
326 printf("%02x%s", efuse_field.data[i],
327 ((i && i % 16 == 15) || (i == efuse_field.size - 1)
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800328 ? "\n" : " "));
329 rc = CMD_RET_SUCCESS;
330 } else {
331 printf("Error getting eFUSE object: %s: %d\n",
332 efuse_obj_err_parse(rc), rc);
333 rc = CMD_RET_FAILURE;
334 }
335 } else {
336 printf("Error: too many arguments %d\n", argc);
337 rc = CMD_RET_USAGE;
338 }
Zhongfu Luoc52c81c2024-03-27 11:05:01 +0800339 } else {
340 printf("Error: cmd %s not supported\n", argv[1]);
341 rc = CMD_RET_USAGE;
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800342 }
343
344 return rc;
345}
346
347static char efuse_obj_help_text[] =
348 "[set | get | lock | get_lock] <FIELD> {<field-value-hexdump-string>}\n"
349 "\n"
350 "get FIELD Get field value. FIELD is the field name\n"
351 " expected_data is an optional expected data\n"
352 "set FIELD DATA Set field to data. DATA is in continuous\n"
353 " hexdump format, e.g. aabb1122\n"
Lawrence Mok782ed8c2024-07-10 15:25:06 -0700354#if defined(CONFIG_AMPK)
355 "set_enc FIELD ENC_DATA Set field to encrypted data. ENC_DATA is in continuous\n"
356 " hexdump format, e.g. aabb1122\n"
357#endif /* CONFIG_AMPK */
Zhongfu Luo1e6af102023-07-27 17:23:27 +0800358 "lock FIELD Lock field. Program exits with status 0 if success\n"
359 "get_lock FIELD Check if field is locked. Program exits with\n"
360 " status 1 if locked, or 0 if unlocked\n"
361 " expected_result is 00 or 01, an optional expected lock result\n"
362 "\n";
363
364U_BOOT_CMD(efuse_obj, 4, 0, do_efuse_obj,
365 "eFUSE object program commands", efuse_obj_help_text
366);
367#endif /* CONFIG_EFUSE_OBJ_API */
368
369#ifdef CONFIG_EFUSE_MRK_GET_CHECKNUM
370int do_efuse_mrk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
371{
372 uint32_t rc = CMD_RET_FAILURE;
373 char name[16];
374 uint32_t checknum = 0;
375
376 if (argc != 2) {
377 printf("Invalid number of arguments %d\n", argc);
378 return CMD_RET_USAGE;
379 }
380
381 memset(name, 0, sizeof(name));
382 strncpy(name, argv[1], sizeof(name) - 1);
383 if (!efuse_mrk_get_checknum(name, &checknum)) {
384 printf("%s: 0x%08x\n", argv[1], checknum);
385 rc = CMD_RET_SUCCESS;
386 } else {
387 printf("get mrk checknum for %s failed\n", argv[1]);
388 }
389
390 return rc;
391}
392
393static char efuse_mrk_help_text[] =
394 "<MRK>\n"
395 "Supported MRK includes: DVGK, DVUK,\n"
396 "DGPK1, DGPK2,\n"
397 "ETSI_SCK_0, ETSI_SCK_1, ETSI_SCK_2,\n"
398 "SCPU_ETSI_SCK_0, SCPU_ETSI_SCK_1, SEGK\n";
399
400U_BOOT_CMD(efuse_mrk, 2, 0, do_efuse_mrk,
401 "eFUSE mrk checknum", efuse_mrk_help_text
402);
403#endif /* CONFIG_EFUSE_MRK_GET_CHECKNUM */