| /* |
| * cmd/efuse.c |
| * |
| * Copyright (C) 2018 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| */ |
| |
| #include <config.h> |
| #include <common.h> |
| #include <asm/arch/io.h> |
| #include <command.h> |
| #include <hexdump.h> |
| #include <malloc.h> |
| #include <asm/arch/efuse.h> |
| #include <asm/arch/bl31_apis.h> |
| |
| #define CMD_EFUSE_WRITE 0 |
| #define CMD_EFUSE_READ 1 |
| #define CMD_EFUSE_SECURE_BOOT_SET 6 |
| #define CMD_EFUSE_PASSWORD_SET 7 |
| #define CMD_EFUSE_CUSTOMER_ID_SET 8 |
| |
| #define CMD_EFUSE_AMLOGIC_SET 20 |
| #define CMD_EFUSE_MRK_CHECK 21 |
| |
| |
| int cmd_efuse(int argc, char * const argv[], char *buf) |
| { |
| int i, action = -1; |
| u32 offset; |
| u32 size, max_size; |
| char *end; |
| char *s; |
| int ret; |
| long lAddr1, lAddr2; |
| unsigned long nType; |
| |
| if (strncmp(argv[1], "read", 4) == 0) { |
| action = CMD_EFUSE_READ; |
| } 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 if (strncmp(argv[1], "mrk_check", 9) == 0) { |
| action = CMD_EFUSE_MRK_CHECK; |
| 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 %d 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 */ |
| switch (action) |
| { |
| case 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"); |
| }break; |
| /* efuse write */ |
| case 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__); |
| } |
| |
| }break; |
| //efuse process |
| case CMD_EFUSE_SECURE_BOOT_SET: |
| case CMD_EFUSE_AMLOGIC_SET: |
| case CMD_EFUSE_PASSWORD_SET: |
| case CMD_EFUSE_CUSTOMER_ID_SET: |
| { |
| 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; |
| default: |
| return -1; |
| } |
| |
| 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; |
| }break; |
| case CMD_EFUSE_MRK_CHECK: |
| { |
| |
| #ifdef AML_D_P_MRK_CHECK |
| #define MRK_CHK_ACGK (0x4b474341) |
| #define MRK_CHK_DVGK (0x4b475644) |
| #define MRK_CHK_DVUK (0x4b555644) |
| #define MRK_CHK_ACRK (0x4b524341) |
| |
| #define MRK_CHK_SALT_LEN 8 |
| |
| #define MKL_KL_DEPTH 3 |
| |
| typedef unsigned int mkl_ek128_t[4]; |
| |
| typedef struct { |
| unsigned long nMrkType; |
| unsigned char szReserved[MRK_CHK_SALT_LEN]; |
| unsigned char szSalt[MRK_CHK_SALT_LEN]; |
| unsigned char szCheck[MRK_CHK_SALT_LEN]; |
| mkl_ek128_t * mrk_chk_ekl[MKL_KL_DEPTH]; |
| mkl_ek128_t * mrk_chk_ekh[MKL_KL_DEPTH]; |
| mkl_ek128_t ek3[2]; |
| mkl_ek128_t ek2[2]; |
| mkl_ek128_t ek1[2]; |
| }aml_mrk_chk_t; |
| |
| aml_mrk_chk_t chk = { |
| MRK_CHK_DVGK, //type |
| {0}, |
| {0x45, 0x7f, 0x03, 0x9a, 0x5d, 0x57, 0xc0, 0x24}, //salt |
| {0xcf, 0x1e, 0x21, 0x21, 0x8e, 0xf3, 0xf1, 0x18}, //check |
| //{&mrk_chk_ek3[0],&mrk_chk_ek2[0],&mrk_chk_ek1[0]}, |
| //{&mrk_chk_ek3[1],&mrk_chk_ek2[1],&mrk_chk_ek1[1]}, |
| {0}, |
| {0}, |
| { |
| {0xcebcb44c, 0xf08c2197, 0x6cc856f3, 0x394212f7}, |
| {0xe5554629, 0xa762b526, 0x2ff51eda, 0xeb8541e1}, |
| }, |
| { |
| {0x2b35fd84, 0xf24d6f9a, 0x1255c5f0, 0xb8418ebc}, |
| {0x12175b71, 0xd5f93abb, 0x93f8ebb3, 0xf011d5ec}, |
| }, |
| { |
| {0xe43a4538, 0xd9851fd4, 0x18d8b578, 0xa522842b}, |
| {0x2c762493, 0xf035bb24, 0xb63d8c09, 0xbe48b494}, |
| }, |
| }; |
| |
| if (argc == 4) { |
| // efuse mrk_check <acgk|acrk|dvgk|dvuk> <16-byte check number as 32-char hex string> |
| if (strcmp(argv[2], "acgk") == 0) { |
| chk.nMrkType = MRK_CHK_ACGK; |
| } else if (strcmp(argv[2], "acrk") == 0) { |
| chk.nMrkType = MRK_CHK_ACRK; |
| } else if (strcmp(argv[2], "dvgk") == 0) { |
| chk.nMrkType = MRK_CHK_DVGK; |
| } else if (strcmp(argv[2], "dvuk") == 0) { |
| chk.nMrkType = MRK_CHK_DVUK; |
| } else { |
| printf("bl33: Err: bad mrk type\n"); |
| return -1; |
| } |
| |
| if (strlen(argv[3]) != 32) { |
| printf("bl33: Err: bad check number len\n"); |
| return -1; |
| } |
| if (hex2bin(&chk.szSalt[0], argv[3], 8) || |
| hex2bin(&chk.szCheck[0], &argv[3][0] + 16, 8)) { |
| printf("bl33: Err: bad check number\n"); |
| return -1; |
| } |
| |
| lAddr1 =(unsigned long)&chk; |
| } else { |
| // efuse mrk_check [address of aml_mrk_chk_t] |
| 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); |
| flush_cache(lAddr2, GXB_EFUSE_PATTERN_SIZE); |
| ret = aml_sec_boot_check(AML_D_P_MRK_CHECK, lAddr2, GXB_EFUSE_PATTERN_SIZE, 0); |
| |
| if (ret) |
| printf("aml log : EFUSE mrk_check fail with ERR=0x%x!\n",ret); |
| else |
| printf("aml log : EFUSE mrk_check pass!\n"); |
| #else |
| printf("aml log : SoC not support efuse mrk_check!\n"); |
| ret = -1; |
| #endif |
| return ret; |
| |
| }break; |
| default: |
| { |
| printf("arg error\n"); |
| return CMD_RET_USAGE; |
| }break; |
| } |
| |
| 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" |
| " [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" |
| "mrk_check [address of aml_mrk_chk_t]\n" |
| "mrk_check <acgk|acrk|dvgk|dvuk> <check number as 32-char hex string>\n"; |
| |
| U_BOOT_CMD( |
| efuse, 5, 0 /*repeatable=no*/, do_efuse, |
| "efuse commands", efuse_help_text |
| ); |