// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #define CMD_EFUSE_WRITE 0 #define CMD_EFUSE_READ 1 #define CMD_EFUSE_READ_CALI 2 #define CMD_EFUSE_READ_CALI_ITEM 3 #define CMD_EFUSE_SECURE_BOOT_SET 6 #define CMD_EFUSE_PASSWORD_SET 7 #define CMD_EFUSE_CUSTOMER_ID_SET 8 #define CMD_EFUSE_CHECK_PATTERN_ITEM 10 #define CMD_EFUSE_AMLOGIC_SET 20 int cmd_efuse(int argc, char * const argv[], char *buf) { int i, action = -1; u64 offset; u32 size = 0, max_size; char *end; char *s; int ret; long lAddr1, lAddr2; unsigned long nType = 0; if (strncmp(argv[1], "read", 4) == 0) { action = CMD_EFUSE_READ; } else if (strncmp(argv[1], "cali_read", 9) == 0) { action = CMD_EFUSE_READ_CALI; } else if (strncmp(argv[1], "item_read", 9) == 0) { action = CMD_EFUSE_READ_CALI_ITEM; goto efuse_action; } else if (strncmp(argv[1], "check", 9) == 0) { action = CMD_EFUSE_CHECK_PATTERN_ITEM; goto efuse_action; } else if (strncmp(argv[1], "write", 5) == 0) { action = CMD_EFUSE_WRITE; } else if (strncmp(argv[1], "secure_boot_set", 15) == 0) { action = CMD_EFUSE_SECURE_BOOT_SET; goto efuse_action; } else if (strncmp(argv[1], "password_set", 12) == 0) { action = CMD_EFUSE_PASSWORD_SET; goto efuse_action; } else if (strncmp(argv[1], "customer_id_set", 15) == 0) { action = CMD_EFUSE_CUSTOMER_ID_SET; goto efuse_action; } else if (strncmp(argv[1], "amlogic_set", 11) == 0) { action = CMD_EFUSE_AMLOGIC_SET; goto efuse_action; } else{ printf("%s arg error\n", argv[1]); return CMD_RET_USAGE; } if (argc < 4) return CMD_RET_USAGE; /*check efuse user data max size*/ offset = simple_strtoul(argv[2], &end, 16); size = simple_strtoul(argv[3], &end, 16); printf("%s: offset is %lld size is %d\n", __func__, offset, size); max_size = efuse_get_max(); if (!size) { printf("\n error: size is zero!!!\n"); return -1; } if (offset > max_size) { printf("\n error: offset is too large!!!\n"); printf("\n offset should be less than %d!\n", max_size); return -1; } if (offset + size > max_size) { printf("\n error: offset + size is too large!!!\n"); printf("\n offset + size should be less than %d!\n", max_size); return -1; } efuse_action: /* efuse read */ if (action == CMD_EFUSE_READ) { memset(buf, 0, size); ret = efuse_read_usr(buf, size, (loff_t *)&offset); if (ret == -1) { printf("ERROR: efuse read user data fail!\n"); return -1; } if (ret != size) printf("ERROR: read %d byte(s) not %d byte(s) data\n", ret, size); printf("efuse read data"); for (i = 0; i < size; i++) { if (i % 16 == 0) printf("\n"); printf(":%02x", buf[i]); } printf("\n"); } else if (action == CMD_EFUSE_READ_CALI) { memset(buf, 0, size); ret = efuse_read_cali(buf, size, offset); if (ret == -1) { printf("ERROR: efuse read cali data fail!\n"); return -1; } if (ret != size) printf("ERROR: read %d byte(s) not %d byte(s) data\n", ret, size); printf("efuse read cali data"); for (i = 0; i < size; i++) { if (i % 16 == 0) printf("\n"); printf(":%02x", buf[i]); } printf("\n"); } else if (action == CMD_EFUSE_READ_CALI_ITEM) { s = argv[2]; ret = efuse_get_cali_item(s); if (ret < 0) { printf("ERROR: efuse read cali item data fail!\n"); return -1; } printf("efuse %s cali data=0x%x\n",s,ret); } else if (action == CMD_EFUSE_CHECK_PATTERN_ITEM) { s = argv[2]; ret = efuse_check_pattern_item(s); if (ret < 0) { printf("ERROR: efuse check pattern fail!\n"); return -1; } printf("efuse %s %s\n", s, ret > 0 ? "has been written" : "is not write"); return ret == 0 ? 1 : 0; //cmd return 0: written, 1: not write } /* efuse write */ else if (action == CMD_EFUSE_WRITE) { if (argc < 5) { printf("arg count error\n"); return CMD_RET_USAGE; } memset(buf, 0, size); s = argv[4]; memcpy(buf, s, strlen(s)); if (efuse_write_usr(buf, size, (loff_t *)&offset) < 0) { printf("error: efuse write fail.\n"); return -1; } else { printf("%s written done.\n", __func__); } } else if (CMD_EFUSE_SECURE_BOOT_SET == action || CMD_EFUSE_AMLOGIC_SET == action \ || CMD_EFUSE_PASSWORD_SET == action || CMD_EFUSE_CUSTOMER_ID_SET == action) { lAddr1 = GXB_IMG_LOAD_ADDR; if (argc > 2) lAddr1 = simple_strtoul(argv[2], &end, 16); lAddr2 = get_sharemem_info(GET_SHARE_MEM_INPUT_BASE); memcpy((void *)lAddr2, (void *)lAddr1, GXB_EFUSE_PATTERN_SIZE<<1); flush_cache(lAddr2, GXB_EFUSE_PATTERN_SIZE<<1); switch (action) { case CMD_EFUSE_SECURE_BOOT_SET: nType = AML_D_P_W_EFUSE_SECURE_BOOT; break; case CMD_EFUSE_AMLOGIC_SET: nType = AML_D_P_W_EFUSE_AMLOGIC; break; case CMD_EFUSE_PASSWORD_SET: nType = AML_D_P_W_EFUSE_PASSWORD; break; case CMD_EFUSE_CUSTOMER_ID_SET: nType = AML_D_P_W_EFUSE_CUSTOMER_ID; break; } ret = aml_sec_boot_check(nType, lAddr2, GXB_EFUSE_PATTERN_SIZE<<1, 0); if (ret) printf("aml log : EFUSE pattern programming fail [%d]!\n", ret); else printf("aml log : EFUSE pattern programming success!\n"); return ret; } else { /* * This part of the code is necessary to prevent unknown errors */ /* coverity[dead_error_begin] */ printf("arg error\n"); return CMD_RET_USAGE; } return 0; } int do_efuse(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { char buf[EFUSE_BYTES]; memset(buf, 0, sizeof(buf)); if (argc < 2) return CMD_RET_USAGE; return cmd_efuse(argc, argv, buf); } static char efuse_help_text[] = "[read/write offset size [data]]\n" " [cali_read] -read from cali\n" " example: [efuse cali_read 0 7]; offset is 0,size is 7. \n" " [item_read] -read cali item\n" " [item_read sensor/saradc/mipicsi/hdmirx/eth/cvbs/earcrx/earctx]\n" " [check] -check if pattern is write\n" " [check dgpk1|dgpk2|aud_id]\n" " [read/write] - read or write 'size' data from\n" " 'offset' from efuse user data ;\n" " [offset] - the offset byte from the beginning\n" " of efuse user data zone;\n" " [size] - data size\n" " [data] - the optional argument for 'write',\n" " data is treated as characters\n" " examples: efuse write 0xc 0xd abcdABCD1234\n" "[amlogic_set addr]\n"; U_BOOT_CMD( efuse, 5, 1, do_efuse, "efuse commands", efuse_help_text ); #ifdef CONFIG_EFUSE_OBJ_API static char *efuse_obj_err_parse(uint32_t efuse_obj_err_status) { char *err_char = NULL; switch (efuse_obj_err_status) { case EFUSE_OBJ_ERR_INVALID_DATA: err_char = "invalid data"; break; case EFUSE_OBJ_ERR_NOT_FOUND: err_char = "field not found"; break; case EFUSE_OBJ_ERR_SIZE: err_char = "size not match"; break; case EFUSE_OBJ_ERR_NOT_SUPPORT: err_char = "not support"; break; case EFUSE_OBJ_ERR_ACCESS: err_char = "access denied"; break; case EFUSE_OBJ_ERR_WRITE_PROTECTED: err_char = "write protected"; break; case EFUSE_OBJ_ERR_TAG: err_char = "invalid encrypted data tag. check device pub key and re-encrypt"; break; case EFUSE_OBJ_ERR_INTERNAL: case EFUSE_OBJ_ERR_OTHER_INTERNAL: err_char = "internal error"; break; default: err_char = "unknown error"; break; } return err_char; } int do_efuse_obj(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { uint32_t rc = CMD_RET_FAILURE; char *name = NULL; if (argc < 3 || argc > 4) { printf("Invalid number of arguments %d\n", argc); return CMD_RET_USAGE; } memset(&efuse_field, 0, sizeof(efuse_field)); if (strcmp(argv[1], "get") == 0) { // $0 get field if (argc == 3) { name = argv[2]; rc = efuse_obj_get_data(name); if (rc == EFUSE_OBJ_SUCCESS) { int i; for (i = 0; i < efuse_field.size; i++) printf("%02x%s", efuse_field.data[i], ((i && i % 16 == 15) || (i == efuse_field.size - 1) ? "\n" : " ")); rc = CMD_RET_SUCCESS; } else { printf("Error getting eFUSE object: %s: %d\n", efuse_obj_err_parse(rc), rc); rc = CMD_RET_FAILURE; } } else { printf("Error: too many arguments %d\n", argc); rc = CMD_RET_USAGE; } } else if (strcmp(argv[1], "set") == 0) { // $0 set field data if (argc == 4) { name = argv[2]; char *data = argv[3]; rc = efuse_obj_set_data(name, data); if (rc == EFUSE_OBJ_SUCCESS) { rc = CMD_RET_SUCCESS; } else { printf("Error setting eFUSE object: %s: %d\n", efuse_obj_err_parse(rc), rc); rc = CMD_RET_FAILURE; } } else { printf("Error: too few arguments %d\n", argc); rc = CMD_RET_USAGE; } #if (IS_ENABLED(CONFIG_AMPK)) } else if (strcmp(argv[1], "set_enc") == 0) { // $0 set field data if (argc == 4) { name = argv[2]; char *data = argv[3]; rc = efuse_obj_set_enc_data(name, data); if (rc == EFUSE_OBJ_SUCCESS) { rc = CMD_RET_SUCCESS; } else { printf("Error setting eFUSE object: %s: %d\n", efuse_obj_err_parse(rc), rc); rc = CMD_RET_FAILURE; } } else { printf("Error: too few arguments %d\n", argc); rc = CMD_RET_USAGE; } #endif /* CONFIG_AMPK */ } else if (strcmp(argv[1], "lock") == 0) { // $0 lock field if (argc == 3) { name = argv[2]; rc = efuse_obj_lock(name); if (rc == EFUSE_OBJ_SUCCESS) { rc = CMD_RET_SUCCESS; } else { printf("Error setting eFUSE object: %s: %d\n", efuse_obj_err_parse(rc), rc); rc = CMD_RET_FAILURE; } } else { printf("Error: too many arguments %d\n", argc); rc = CMD_RET_USAGE; } } else if (strcmp(argv[1], "get_lock") == 0) { // $0 get_lock field if (argc == 3) { name = argv[2]; rc = efuse_obj_get_lock(name); if (rc == EFUSE_OBJ_SUCCESS) { int i; for (i = 0; i < efuse_field.size; i++) printf("%02x%s", efuse_field.data[i], ((i && i % 16 == 15) || (i == efuse_field.size - 1) ? "\n" : " ")); rc = CMD_RET_SUCCESS; } else { printf("Error getting eFUSE object: %s: %d\n", efuse_obj_err_parse(rc), rc); rc = CMD_RET_FAILURE; } } else { printf("Error: too many arguments %d\n", argc); rc = CMD_RET_USAGE; } } else { printf("Error: cmd %s not supported\n", argv[1]); rc = CMD_RET_USAGE; } return rc; } static char efuse_obj_help_text[] = "[set | get | lock | get_lock] {}\n" "\n" "get FIELD Get field value. FIELD is the field name\n" " expected_data is an optional expected data\n" "set FIELD DATA Set field to data. DATA is in continuous\n" " hexdump format, e.g. aabb1122\n" #if defined(CONFIG_AMPK) "set_enc FIELD ENC_DATA Set field to encrypted data. ENC_DATA is in continuous\n" " hexdump format, e.g. aabb1122\n" #endif /* CONFIG_AMPK */ "lock FIELD Lock field. Program exits with status 0 if success\n" "get_lock FIELD Check if field is locked. Program exits with\n" " status 1 if locked, or 0 if unlocked\n" " expected_result is 00 or 01, an optional expected lock result\n" "\n"; U_BOOT_CMD(efuse_obj, 4, 0, do_efuse_obj, "eFUSE object program commands", efuse_obj_help_text ); #endif /* CONFIG_EFUSE_OBJ_API */ #ifdef CONFIG_EFUSE_MRK_GET_CHECKNUM int do_efuse_mrk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { uint32_t rc = CMD_RET_FAILURE; char name[16]; uint32_t checknum = 0; if (argc != 2) { printf("Invalid number of arguments %d\n", argc); return CMD_RET_USAGE; } memset(name, 0, sizeof(name)); strncpy(name, argv[1], sizeof(name) - 1); rc = efuse_mrk_get_checknum(name, 0, &checknum); if (!rc) { printf("%s: 0x%08x\n", argv[1], checknum); rc = CMD_RET_SUCCESS; } else if (rc == EFUSE_MRK_CHECKNUM_NOT_SUPPORTED) { printf("MRK field %s not supported\n", argv[1]); } else { printf("get mrk checknum for %s failed, MRK field may not be written\n", argv[1]); } return rc; } int do_efuse_mrk_long(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { uint32_t rc = CMD_RET_FAILURE; char name[16]; uint32_t checknum[4]; if (argc != 2) { printf("Invalid number of arguments %d\n", argc); return CMD_RET_USAGE; } memset(name, 0, sizeof(name)); strncpy(name, argv[1], sizeof(name) - 1); rc = efuse_mrk_get_checknum(name, 1, &checknum[0]); if (!rc) { printf("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n", argv[1], checknum[0], checknum[1], checknum[2], checknum[3]); rc = CMD_RET_SUCCESS; } else if (rc == EFUSE_MRK_CHECKNUM_NOT_SUPPORTED) { printf("MRK field %s not supported\n", argv[1]); } else { printf("get mrk checknum for %s failed, MRK field may not be written\n", argv[1]); } return rc; } static char efuse_mrk_help_text[] = "\n" "efuse_mrk | efuse_mkr_long,\n" "Supported MRK includes: DVGK, DVUK,\n" "DGPK1, DGPK2,\n" "ETSI_SCK_0, ETSI_SCK_1, ETSI_SCK_2,\n" "SCPU_ETSI_SCK_0, SCPU_ETSI_SCK_1, SEGK\n"; U_BOOT_CMD(efuse_mrk, 2, 0, do_efuse_mrk, "eFUSE mrk checknum", efuse_mrk_help_text ); U_BOOT_CMD(efuse_mrk_long, 2, 0, do_efuse_mrk_long, "eFUSE mrk long checknum", efuse_mrk_help_text ); #endif /* CONFIG_EFUSE_MRK_GET_CHECKNUM */ #ifdef CONFIG_EFUSE_AUDIO_ID_CHECKNUM int do_efuse_audio_id_check(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int rc, i; char buff[512] = {0}; rc = efuse_audio_id_get_checknum(buff, sizeof(buff)); if (rc < 0) { printf("get audio id checknum failed:%d\n", rc); return rc; } for (i = 0; i < sizeof(buff); i++) { printf("%02x", buff[i]); } printf("\n"); return rc; } static char efuse_audio_id_check_help_text[] = "\n" " printf checksum for efuse audio id, which can help to check if audio id is burned correctly\n"; U_BOOT_CMD(efuse_audio_id_check, 2, 0, do_efuse_audio_id_check, "eFUSE audio id checknum", efuse_audio_id_check_help_text ); #endif /* CONFIG_EFUSE_MRK_GET_CHECKNUM */