| #include "../v2_burning_i.h" |
| #include "usb_pcd.h" |
| #include "platform.h" |
| #include <partition_table.h> |
| #include <asm/cpu_id.h> |
| |
| #define MYDBG(fmt ...) printf("OPT]"fmt) |
| |
| #ifdef CONFIG_CMD_AML |
| #define USB_BURN_POWER_CONTROL 1 |
| #endif// #ifdef CONFIG_CMD_AML |
| |
| static inline int str2long(const char *p, unsigned long *num) |
| { |
| char *endptr; |
| *num = simple_strtoul(p, &endptr, 0); |
| return (*p != '\0' && *endptr == '\0') ? 1 : 0; |
| } |
| |
| static inline int str2longlong(char *p, unsigned long long *num) |
| { |
| char *endptr; |
| |
| *num = simple_strtoull(p, &endptr, 16); |
| if (*endptr != '\0') |
| { |
| switch (*endptr) |
| { |
| case 'g': |
| case 'G': |
| *num<<=10; |
| case 'm': |
| case 'M': |
| *num<<=10; |
| case 'k': |
| case 'K': |
| *num<<=10; |
| endptr++; |
| break; |
| } |
| } |
| |
| return (*p != '\0' && *endptr == '\0') ? 1 : 0; |
| } |
| |
| static int opimus_func_write_bootloader(unsigned long addr) |
| { |
| int ret = 0; |
| loff_t size = 0; |
| |
| size = 0x60000;//FIXME: 256K at most ?? |
| |
| ret = store_boot_write((u8*)addr, (loff_t)0, size); |
| |
| return ret; |
| } |
| |
| //[0]write_raw_img [1]part_name [2]address, [3]offset, [4]size |
| int opimus_func_write_raw_img(int argc, char *argv[], char *info) |
| { |
| int ret = 0; |
| u64 addr; |
| u64 off, size; |
| const char* partName = argv[1]; |
| |
| if (strcmp(partName, "bootloader") == 0) |
| { |
| addr = simple_strtoul(argv[2], NULL, 0); |
| return opimus_func_write_bootloader(addr); |
| } |
| |
| addr = simple_strtoull(argv[2], NULL, 0); |
| off = simple_strtoull(argv[3], NULL, 0); |
| size = simple_strtoul(argv[4], NULL, 0); |
| |
| printf("write_raw_img part %s offset 0x%x, size 0x%x, addr 0x%llx\n", argv[1], (u32)off, (u32)size, addr); |
| ret = store_write_ops((u8*)partName, (u8*)addr, off, size); |
| |
| return ret; |
| } |
| |
| |
| //read_raw_img partName memAddr partOffset readSzInBytes |
| int opimus_func_read_raw_img(int argc, char *argv[], char *info) |
| { |
| int ret = 0; |
| unsigned long addr; |
| u64 off, size; |
| unsigned char* partName = (unsigned char*)argv[1]; |
| |
| MYDBG("%s, %s, %s, %s\n", __func__, argv[0], argv[1], argv[2]); |
| |
| if (!(str2long(argv[2], &addr))) |
| { |
| sprintf(info, "failed:'%s' is not a number\n", argv[2]); |
| return -1; |
| } |
| if (!(str2longlong(argv[3], &off))) |
| { |
| sprintf(info, "failed:'%s' is not a number\n", argv[3]); |
| return -1; |
| } |
| if (!(str2longlong(argv[4], &size))) |
| { |
| sprintf(info, "failed:'%s' is not a number\n", argv[4]); |
| return -1; |
| } |
| |
| ret = store_read_ops(partName, (u8*)addr, off, size); |
| |
| return ret; |
| } |
| |
| int optimus_simg2part (int argc, char * const argv[], char *info) |
| { |
| int ret = -1; |
| const char* partition_name = argv[1]; |
| u8* simg_addr = (u8*)simple_strtoul(argv[2], NULL, 16); |
| u32 pktSz = simple_strtoul(argv[3], NULL, 0); |
| const unsigned memAddrTop = OPTIMUS_DOWNLOAD_SPARSE_INFO_FOR_VERIFY;//this address backup the chunk info, don't overwrite it! |
| |
| if (argc < 4) { |
| sprintf(info, "failed: used [%s partName memAddr, pktSz]\n", argv[0]); |
| DWN_ERR(info); |
| return __LINE__; |
| } |
| if (!pktSz || !simg_addr) { |
| sprintf(info, "simg_addr(%s) or pktSz(%s)error\n", argv[2], argv[3]); |
| DWN_ERR(info); |
| return __LINE__; |
| } |
| |
| if ((unsigned long)simg_addr + pktSz > memAddrTop) { |
| sprintf(info, "failed:simg_addr(0x%p) + pktSz(0x%x) > memAddrTop(0x%x)\n", simg_addr, pktSz, memAddrTop); |
| DWN_ERR(info); |
| return __LINE__; |
| } |
| |
| #if 0 |
| ret = simg_write_to_partition(partition_name, simg_addr); |
| #else /* ----- not 0 ----- */ |
| #if 0 |
| ret = optimus_simg_probe(simg_addr, pktSz); |
| if (!ret) { |
| sprintf(info, "failed:format error, not a sparse image at addr %s\n", argv[2]); |
| DWN_ERR(info); |
| return __LINE__; |
| } |
| #endif /* ----- 0 ----- */ |
| ret = optimus_parse_img_download_info(partition_name, pktSz, "sparse", "store", 0); |
| if (ret) { |
| sprintf(info, "failed:init download info for part(%s)\n", partition_name); |
| DWN_ERR(info); |
| return __LINE__; |
| } |
| unsigned writeLen = optimus_download_img_data(simg_addr, pktSz, info); |
| if (writeLen != pktSz) { |
| DWN_ERR("failed when burn simg!, want(0x%x), write(0x%x)\n", pktSz, writeLen); |
| return __LINE__; |
| } |
| #endif /* ----- not 0 ----- */ |
| |
| return ret; |
| } |
| |
| int optimus_sha1sum (int argc, char * const argv[], char *info) |
| { |
| unsigned buffermax = 64<<20; |
| unsigned char* sha1_addr = (u8*)0x81000000; |
| int ret = -1; |
| char *partition_name; |
| unsigned long long Bits_need_read = 0,partition_offset = 0; |
| unsigned long long verify_len = 0; |
| u8 output[20]; |
| char *sha1_verify = NULL; |
| char sha1_value[41]; |
| int i = 1; |
| |
| memset(sha1_value, 0, sizeof(sha1_value)); |
| |
| if (3 == argc) //test to sha1sum memory: sha1sum memAddr, length |
| { |
| unsigned verify_len = 0; |
| unsigned char* pBuf = NULL; |
| |
| pBuf = (unsigned char*)simple_strtoul(argv[1], NULL, 0); |
| verify_len = simple_strtoul(argv[2], NULL, 0); |
| |
| printf("Gen sha1sum: addr 0x%p, len 0x%x\n", pBuf, verify_len); |
| sha1_csum(pBuf, verify_len, output); |
| |
| sprintf(sha1_value, "%02x", output[0]); |
| for (i = 1; i < 20; ++i) |
| { |
| sprintf(sha1_value, "%02x", output[0]); |
| for (; i < 20; ++i) |
| { |
| sprintf(sha1_value, "%s%02x", sha1_value, output[i]); |
| } |
| /*sprintf(sha1_value, "%s%02x", sha1_value, output[i]);*/ |
| } |
| printf("gen sha1sum %s\n", sha1_value); |
| return 0; |
| } |
| |
| if (argc != 4)//argv:cmd,partition_name,verify_len,sha1_verify |
| { |
| printf("bad args---sha1sum cmd need 3 args\n"); |
| strcpy(info, "failed:need 3 args"); |
| return -1; |
| } |
| |
| partition_name = argv[1]; |
| |
| verify_len = simple_strtoull (argv[2], NULL, 10); |
| sha1_verify = argv[3]; |
| |
| //circularly verify 128M datas readed in memory 0x81000000 |
| sha1_context ctx; |
| sha1_starts (&ctx); |
| |
| Bits_need_read = verify_len; |
| partition_offset = 0; |
| while (Bits_need_read > buffermax) |
| { |
| ret = store_read_ops((unsigned char*)partition_name, (unsigned char *) sha1_addr, partition_offset, buffermax); |
| if (ret) { |
| DWN_ERR("Fail to read data from %s at offset %llx size %x\n", partition_name, partition_offset, buffermax); |
| return __LINE__; |
| } |
| sha1_update (&ctx, (unsigned char *) sha1_addr, buffermax); |
| Bits_need_read = Bits_need_read - buffermax; |
| partition_offset += buffermax; |
| printf("current Bits_need_read is 0x%llx, buffermax is : 0x%x\n",Bits_need_read,buffermax); |
| for (i = 0; i < 5; i++)sprintf(sha1_value,"%s%08x", sha1_value, (unsigned)ctx.state[i]) ;//5*8=40 |
| printf("current sha1_value is %s\n", sha1_value); |
| } |
| |
| ret = store_read_ops((unsigned char*)partition_name, (unsigned char *) sha1_addr, partition_offset, Bits_need_read); |
| if (ret) { |
| DWN_ERR("Fail to read data from %s at offset %llx size %x\n", partition_name, partition_offset, buffermax); |
| return __LINE__; |
| } |
| |
| sha1_update (&ctx, (unsigned char *) sha1_addr, Bits_need_read); |
| sha1_finish (&ctx, output); |
| //????????????? |
| printf("SHA1 for %s %p,verify_len:0x%llx ==>",partition_name, sha1_addr,verify_len); |
| |
| for (i = 0; i < 20; i++) |
| { |
| printf("%02x", output[i]); |
| //sha1_value[i] = output[i]; |
| sprintf(sha1_value,"%s%02x", sha1_value, output[i]); |
| } |
| //sha1_value[21] = '\0'; |
| printf("\n"); |
| |
| printf("sha1_verify= %s\n", sha1_verify); |
| printf("sha1_value = %s\n", sha1_value); |
| if (strncmp(sha1_verify, sha1_value, 40) == 0) |
| { |
| ret = 0; |
| strcpy(info, "success"); |
| } |
| else |
| { |
| ret = -1; |
| strcpy(info, "failed"); |
| } |
| |
| return ret; |
| } |
| |
| |
| int optimus_mem_md (int argc, char * const argv[], char *info) |
| { |
| ulong addr, length = 0x100; |
| int size; |
| int rc = 0; |
| |
| if ((size = cmd_get_data_size(argv[0], 4)) < 0) |
| return 1; |
| |
| /* Address is specified since argc > 1 |
| */ |
| addr = simple_strtoul(argv[1], NULL, 16); |
| |
| /* If another parameter, it is the length to display. |
| * Length is the number of objects, not number of bytes. |
| */ |
| if (argc > 2) |
| length = simple_strtoul(argv[2], NULL, 16); |
| |
| /* Print the lines. */ |
| print_buffer(addr, (void*)addr, size, length, 16/size); |
| strcpy(info, "success"); |
| return rc; |
| } |
| |
| int set_low_power_for_usb_burn(int arg, char* buff) |
| { |
| if (OPTIMUS_WORK_MODE_USB_PRODUCE == optimus_work_mode_get()) { |
| return 0;//just return ok as usb producing mode as LCD not initialized yet! |
| } |
| |
| #if defined(CONFIG_VIDEO_AMLLCD) |
| int ret1=0; |
| //axp to low power off LCD, no-charging |
| MYDBG("To close LCD\n"); |
| ret1 = run_command("video dev disable", 0); |
| if (ret1) { |
| if (buff) sprintf(buff, "Fail to close back light") ; |
| printf("Fail to close back light\n"); |
| /*return __LINE__;*/ |
| } |
| #endif// #if defined(CONFIG_VIDEO_AMLLCD) |
| |
| #if USB_BURN_POWER_CONTROL |
| int ret2=0; |
| //limit vbus curretn to 500mA, i.e, if hub is 4A, 8 devices at most, arg3 to not set_env as it's not inited yet!! |
| MYDBG("set_usbcur_limit 500 0\n"); |
| ret2 = run_command("set_usbcur_limit 500 0", 0); |
| if (ret2) { |
| if (buff) sprintf(buff, "Fail to set_usb_cur_limit") ; |
| printf("Fail to set_usb_cur_limit\n"); |
| return __LINE__; |
| } |
| #endif//#if USB_BURN_POWER_CONTROL |
| |
| return 0; |
| } |
| |
| int cb_4_dis_connect_intr(void) |
| { |
| if (optimus_burn_complete(OPTIMUS_BURN_COMPLETE__QUERY)) |
| { |
| close_usb_phy_clock(0);//disconnect to avoid k200 platfrom which can't relally poweroff |
| DWN_MSG("User Want poweroff after disconnect\n"); |
| optimus_poweroff(); |
| } |
| |
| return 0; |
| } |
| |
| static int _cpu_temp_in_valid_range(int argc, char* argv[], char* errInfo) |
| { |
| int ret = 0; |
| int minTemp = 0; |
| int maxTemp = 0; |
| int cpu_temp = 0; |
| char* env_cpu_temp = NULL; |
| |
| if (3 > argc) { |
| sprintf(errInfo, "argc %d < 3 is invalid\n", argc); |
| return __LINE__; |
| } |
| minTemp = simple_strtol(argv[1], NULL, 0); |
| maxTemp = simple_strtol(argv[2], NULL, 0); |
| if (minTemp <=0 || maxTemp <= 0 || minTemp >= maxTemp) { |
| sprintf(errInfo, "Invalid:minTemp=%s, maxTemp=%s\n", argv[1], argv[2]); |
| return __LINE__; |
| } |
| ret = run_command("read_temp", 0); |
| if (ret < 0) { |
| sprintf(errInfo, "cmd[cpu_temp] failed\n"); |
| return __LINE__; |
| } |
| env_cpu_temp = getenv("tempa"); |
| if (!env_cpu_temp) { |
| sprintf(errInfo, "Can't get cpu_temp, cpu is not calibrated.\n"); |
| return __LINE__; |
| } |
| cpu_temp = simple_strtol(env_cpu_temp, NULL, 0); |
| ret = (cpu_temp >= minTemp && cpu_temp <= maxTemp) ? 0 : __LINE__; |
| if (!ret) { |
| sprintf(errInfo, "%s", env_cpu_temp); |
| } |
| else{ |
| sprintf(errInfo, "%s is out of temp range[%d, %d], errInfo[%s]\n", env_cpu_temp, minTemp, maxTemp, getenv("err_info_tempa")); |
| } |
| |
| return ret; |
| } |
| |
| static int _get_chipid(char* buff) |
| { |
| int i = 0; |
| unsigned char chipid[16]; |
| int ret = get_chip_id(chipid, 16); |
| if ( ret ) { |
| DWN_ERR("_get_chipid %d", ret); |
| return ret; |
| } |
| |
| buff[0] = ':', buff[1]='\0'; |
| for (; i < 12; ++i) { |
| sprintf(buff, "%s%02x", buff, chipid[15-i]); |
| } |
| return 0; |
| } |
| |
| int optimus_working (const char *cmd, char* buff) |
| { |
| static char cmdBuf[CMD_BUFF_SIZE] = {0}; |
| int ret = 0; |
| int argc = 33; |
| char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ |
| /*printf("reboot_mode [%8x, %8x]\n", P_AO_RTI_STATUS_REG1);*/ |
| const char* optCmd = NULL; |
| |
| memset(buff, 0, CMD_BUFF_SIZE); |
| memcpy(cmdBuf, cmd, CMD_BUFF_SIZE); |
| if ((argc = cli_simple_parse_line(cmdBuf, argv)) == 0) |
| { |
| strcpy(buff, "failed:no command at all"); |
| printf("no command at all\n"); |
| return -1; /* no command at all */ |
| } |
| optCmd = argv[0]; |
| |
| if (!strcmp("low_power", optCmd)) |
| { |
| ret = set_low_power_for_usb_burn(1, buff); |
| } |
| else if(strcmp(optCmd, "disk_initial") == 0) |
| { |
| unsigned erase = argc > 1 ? simple_strtoul(argv[1], NULL, 0) : 0; |
| |
| ret = optimus_storage_init(erase); |
| } |
| else if(!strcmp(optCmd, "bootloader_is_old")) |
| { |
| ret = is_tpl_loaded_from_usb(); |
| if (ret)sprintf(buff, "Failed, bootloader is new\n") ; |
| } |
| else if(!strcmp(optCmd, "erase_bootloader")) |
| { |
| ret = optimus_erase_bootloader("usb"); |
| |
| if (ret)sprintf(buff, "Failed to erase bootloader\n") ; |
| } |
| else if(strcmp(optCmd, "write_raw_img") == 0) |
| { |
| ret = opimus_func_write_raw_img(argc, argv, buff); |
| } |
| else if(strcmp(optCmd, "read_raw_img") == 0) |
| { |
| ret = opimus_func_read_raw_img(argc, argv, buff); |
| } |
| else if(strcmp(optCmd, "simg2part") == 0) |
| { |
| ret = optimus_simg2part(argc, argv, buff); |
| } |
| else if(strcmp(optCmd, "reset") == 0) |
| { |
| close_usb_phy_clock(0); |
| optimus_reset(OPTIMUS_BURN_COMPLETE__REBOOT_NORMAL); |
| } |
| else if(strcmp(optCmd, "poweroff") == 0) |
| { |
| optimus_poweroff(); |
| } |
| else if(strncmp(optCmd, "md", 2) == 0) |
| { |
| ret = optimus_mem_md(argc, argv, buff); |
| } |
| else if(!strcmp(optCmd, "download") || !strcmp("upload", optCmd)) |
| { |
| ret = optimus_parse_download_cmd(argc, argv); |
| } |
| else if(!strcmp("key", optCmd)) |
| { |
| ret = v2_key_command(argc, argv, buff); |
| } |
| else if(!strcmp("verify", optCmd)) |
| { |
| ret = optimus_media_download_verify(argc, argv, buff); |
| } |
| else if(!strcmp("save_setting", optCmd)) |
| { |
| ret = optimus_set_burn_complete_flag(); |
| } |
| else if(!strcmp("burn_complete", optCmd)) |
| { |
| unsigned choice = simple_strtoul(argv[1], NULL, 0);//0 is poweroff, 1 is reset system |
| |
| if (OPTIMUS_BURN_COMPLETE__POWEROFF_AFTER_DISCONNECT != choice) {//disconnect except OPTIMUS_BURN_COMPLETE__POWEROFF_AFTER_DISCONNECT |
| close_usb_phy_clock(0);//some platform can't poweroff but dis-connect needed by pc |
| } |
| ret = optimus_burn_complete(choice); |
| } |
| else if(strncmp(cmd,"sha1sum",(sizeof("sha1sum")-1)) == 0) |
| { |
| ret = optimus_sha1sum(argc, argv, buff); |
| } |
| else if(!strcmp(optCmd, "support_tempcontrol")) |
| { |
| #ifndef CONFIG_CMD_CPU_TEMP |
| ret = __LINE__; |
| #else |
| ret = 0; |
| #endif// #ifdef CONFIG_CMD_CPU_TEMP |
| sprintf(buff + 7, "cpu temp control cmd %s supported.\n", ret ? "NOT" : "DO");//7 == strlen("failed") |
| } |
| else if(!strcmp(optCmd, "tempcontrol")) |
| { |
| ret = _cpu_temp_in_valid_range(argc, argv, buff + 7); |
| } |
| else if(!strcmp(optCmd, "get_chipid")) |
| { |
| ret = _get_chipid(buff + 7); |
| } |
| else |
| { |
| int flag = 0; |
| ret = run_command(cmd, flag); |
| DWN_MSG("ret = %d\n", ret); |
| /*ret = ret < 0 ? ret : 0;*/ |
| } |
| |
| if (ret) |
| { |
| memcpy(buff, "failed:", strlen("failed:"));//use memcpy but not strcpy to not overwrite storage/key info |
| } |
| else |
| { |
| memcpy(buff, "success", strlen("success"));//use memcpy but not strcpy to not overwrite storage/key info |
| } |
| |
| printf("[info]%s\n",buff); |
| return ret; |
| } |
| |