| /* | |
| * common/cmd_efuse.c | |
| * | |
| * Copyright (C) 2015 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 <malloc.h> | |
| #include <asm/arch/efuse.h> | |
| #include <asm/arch/bl31_apis.h> | |
| #include <asm/cpu_id.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 | |
| int cmd_efuse(int argc, char * const argv[], char *buf) | |
| { | |
| int i, action = -1; | |
| uint32_t offset; | |
| uint32_t size, max_size; | |
| char *end; | |
| char *s; | |
| int ret; | |
| long lAddr1, lAddr2; | |
| 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{ | |
| printf("%s arg error\n", argv[1]); | |
| return CMD_RET_USAGE; | |
| } | |
| if ((get_cpu_id().family_id == MESON_CPU_MAJOR_ID_AXG) | |
| &&((action == CMD_EFUSE_READ) || (action == CMD_EFUSE_WRITE))) { | |
| printf("error: AXG not support read/write normal efuse\n"); | |
| return -1; | |
| } | |
| 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 */ | |
| 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"); | |
| } | |
| /* 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) { | |
| /*efuse secure_boot_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); | |
| flush_cache(lAddr2,GXB_EFUSE_PATTERN_SIZE); | |
| ret = aml_sec_boot_check(AML_D_P_W_EFUSE_SECURE_BOOT, lAddr2, | |
| GXB_EFUSE_PATTERN_SIZE, 0); | |
| if (ret) | |
| printf("aml log : Secure boot EFUSE pattern programming fail [%d]!\n", | |
| ret); | |
| else | |
| printf("aml log : Secure boot EFUSE pattern programming success!\n"); | |
| return ret; | |
| } else if (CMD_EFUSE_AMLOGIC_SET == action) { | |
| /*efuse amlogic_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); | |
| flush_cache(lAddr2,GXB_EFUSE_PATTERN_SIZE); | |
| ret = aml_sec_boot_check(AML_D_P_W_EFUSE_AMLOGIC, lAddr2, | |
| GXB_EFUSE_PATTERN_SIZE, 0); | |
| if (ret) | |
| printf("aml log : Amlogic EFUSE pattern programming fail [%d]!\n", | |
| ret); | |
| else | |
| printf("aml log : Amlogic EFUSE pattern programming success!\n"); | |
| return ret; | |
| } else if(CMD_EFUSE_PASSWORD_SET == action) { | |
| /*efuse password_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); | |
| flush_cache(lAddr2,GXB_EFUSE_PATTERN_SIZE); | |
| ret = aml_sec_boot_check(AML_D_P_W_EFUSE_PASSWORD, lAddr2, | |
| GXB_EFUSE_PATTERN_SIZE, 0); | |
| if (ret) | |
| printf("aml log : Password EFUSE pattern programming fail [%d]!\n", | |
| ret); | |
| else | |
| printf("aml log : Password EFUSE pattern programming success!\n"); | |
| return ret; | |
| }else if(CMD_EFUSE_CUSTOMER_ID_SET == action) { | |
| /*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); | |
| flush_cache(lAddr2,GXB_EFUSE_PATTERN_SIZE); | |
| ret = aml_sec_boot_check(AML_D_P_W_EFUSE_CUSTOMER_ID, lAddr2, | |
| GXB_EFUSE_PATTERN_SIZE, 0); | |
| if (ret) | |
| printf("aml log : Customer ID EFUSE pattern programming fail [%d]!\n", | |
| ret); | |
| else | |
| printf("aml log : Customer ID EFUSE pattern programming success!\n"); | |
| return ret; | |
| } | |
| 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[] = | |
| #ifndef CONFIG_AML_MESON_AXG | |
| "[read/write offset size [data]]\n" | |
| " [read/wirte] - 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" | |
| #endif | |
| "[amlogic_set addr]\n"; | |
| U_BOOT_CMD( | |
| efuse, 5, 1, do_efuse, | |
| "efuse commands", efuse_help_text | |
| ); | |
| #include <asm/arch/secure_apb.h> | |
| static int do_query(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
| { | |
| int nReturn = CMD_RET_USAGE; | |
| if (argc < 2) | |
| goto exit; | |
| struct{ | |
| char *szQuery; unsigned long lAddrConfig; unsigned int nMask; unsigned int nNegFlag; | |
| } ArrQuery[] = { | |
| {"SecureBoot",AO_SEC_SD_CFG10,1<<4,0},//SecureBoot : 1:enabled;0:disabled | |
| {"Dolby",AO_SEC_SD_CFG10,1<<16,0}, //Dolby : 1:enabled; 0: disabled | |
| {"DTS",AO_SEC_SD_CFG10,1<<14,0}, //DTS: 1: enabled; 0:disabled | |
| //add more query support here ... | |
| {NULL,0,0,0} | |
| }; | |
| int nIndex; | |
| for (nIndex = 0;nIndex < sizeof(ArrQuery)/sizeof(ArrQuery[0]);++nIndex) | |
| { | |
| if (ArrQuery[nIndex].szQuery) | |
| { | |
| if (!strcmp(ArrQuery[nIndex].szQuery,argv[1])) | |
| { | |
| nReturn = (readl(ArrQuery[nIndex].lAddrConfig) & ArrQuery[nIndex].nMask) ? 1 : 0; | |
| nReturn ^= (ArrQuery[nIndex].nNegFlag ? 1 : 0); | |
| break; | |
| } | |
| } | |
| } | |
| exit: | |
| return nReturn; | |
| } | |
| static char query_text[] = | |
| "[query SecureBoot/Dolby/DTS]\n" | |
| " [SecureBoot] - query SoC is secure boot enabled(1) or not(0)\n" | |
| " [Dolby] - query SoC support Dolby (1) or not(0)\n" | |
| " [DTS] - query SoC support DTS (1) or not(0)\n" | |
| " examples: query SecureBoot\n"; | |
| U_BOOT_CMD( | |
| query, 5, 2, do_query, | |
| "SoC query commands", query_text | |
| ); | |
| /****************************************************/ |