linuxOS_D21X/source/uboot-2021.10/cmd/aicupg.c
2024-11-29 16:33:21 +08:00

514 lines
11 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021-2024 ArtInChip Technology Co., Ltd
* Author: Dehuang Wu <dehuang.wu@artinchip.com>
*/
#include <common.h>
#include <command.h>
#include <console.h>
#include <malloc.h>
#include <g_dnl.h>
#include <usb.h>
#include <artinchip/aicupg.h>
#include <artinchip/artinchip_fb.h>
#include <asm/arch/boot_param.h>
#include <config_parse.h>
#include <dm/uclass.h>
#include <env.h>
#include <linux/delay.h>
#if 0
#undef debug
#define debug printf
#endif
#define AICUPG_ARGS_MAX 4
#define WAIT_UPG_MODE_TMO_US 2000000
#if defined(CONFIG_MMC) || defined(CONFIG_SPL_MMC)
static int curr_device = -1;
static int image_header_check(struct image_header_pack *header)
{
/*check header*/
if (strcmp(header->hdr.magic, "AIC.FW") != 0) {
pr_err("Error:image check failed,maybe not have a image in media!\n");
return -1;
}
return 0;
}
#endif
__weak void do_brom_upg(char *upg_mode)
{
printf("%s is not implemented.\n", __func__);
}
void fat_upg_progress(u32 percent)
{
#ifdef CONFIG_PROGRESS_BAR
/* Show to screen */
draw_progress_bar(percent);
#endif
/*
* User can add more code to show the progress in customize way
*/
printf("progress: %d%%\n", percent);
}
#define CHECK_MODE_WAITING 0
#define CHECK_MODE_OK 1
#define CHECK_MODE_TIMEOUT 2
static int check_upg_mode(long start_tm, long tmo)
{
long cur_tm, tm;
int mode;
cur_tm = timer_get_us();
tm = (cur_tm - start_tm);
mode = aicupg_get_upg_mode();
if (mode == UPG_MODE_BURN_USER_ID)
return CHECK_MODE_OK;
if (mode == UPG_MODE_BURN_IMG_FORCE)
return CHECK_MODE_OK;
if (tm < tmo)
return CHECK_MODE_WAITING;
return CHECK_MODE_TIMEOUT;
}
static int do_usb_protocol_upg(int intf)
{
int ret, need_ckmode;
long start_tm;
char *p;
struct upg_init init;
need_ckmode = 0;
init.mode_bits = INIT_MODE(UPG_MODE_FULL_DISK_UPGRADE);
p = env_get("upg_mode");
if (p) {
if (!strcmp(p, "userid")) {
need_ckmode = 1;
init.mode_bits = INIT_MODE(UPG_MODE_BURN_USER_ID);
#ifdef CONFIG_AICUPG_FORCE_USBUPG_SUPPORT
/* Enter burn USERID mode also support force burn image */
init.mode_bits |= INIT_MODE(UPG_MODE_BURN_IMG_FORCE);
#endif
} else if (!strcmp(p, "force")) {
need_ckmode = 1;
init.mode_bits = INIT_MODE(UPG_MODE_BURN_IMG_FORCE);
}
/* Remove this information after used, avoid to be saved
* to env partition
*/
env_set("upg_mode", "");
}
aicupg_initialize(&init);
ret = usb_gadget_initialize(intf);
if (ret) {
printf("USB init failed: %d\n", ret);
return CMD_RET_FAILURE;
}
g_dnl_clear_detach();
ret = g_dnl_register("usb_dnl_aicupg");
if (ret)
return CMD_RET_FAILURE;
start_tm = timer_get_us();
while (1) {
if (g_dnl_detach())
break;
if (ctrlc())
break;
usb_gadget_handle_interrupts(intf);
if (need_ckmode) {
/* Need to check the correct upg mode for Burn UserID
* and Force Image upgrading
*/
int rst = check_upg_mode(start_tm, WAIT_UPG_MODE_TMO_US);
if (rst == CHECK_MODE_TIMEOUT) {
/* Host tool not set the mode in WAIT_UPG_MODE_TMO_US
* exit upg loop and boot kernel
*/
ret = CMD_RET_FAILURE;
goto exit;
} else if (rst == CHECK_MODE_OK) {
/* Update the start time.
* Host tool may change the mode to exit loop
*/
start_tm = timer_get_us();
}
}
}
ret = CMD_RET_SUCCESS;
exit:
g_dnl_unregister();
g_dnl_clear_detach();
usb_gadget_release(intf);
return ret;
}
#if defined(CONFIG_MMC) || defined(CONFIG_SPL_MMC)
static struct mmc *init_mmc_device(int dev, bool force_init)
{
struct mmc *mmc;
mmc = find_mmc_device(dev);
if (!mmc) {
pr_err("no mmc device at slot %x\n", dev);
return NULL;
}
if (!mmc_getcd(mmc))
force_init = true;
if (force_init)
mmc->has_init = 0;
if (mmc_init(mmc))
return NULL;
#ifdef CONFIG_BLOCK_CACHE
struct blk_desc *bd = mmc_get_blk_desc(mmc);
blkcache_invalidate(bd->if_type, bd->devnum);
#endif
return mmc;
}
#endif
static int do_sdcard_upg(int intf)
{
s32 ret = 0;
#if defined(CONFIG_MMC) || defined(CONFIG_SPL_MMC)
struct image_header_pack *hdrpack;
struct mmc *mmc;
char *mmc_type;
u32 cnt, n;
struct disk_partition part_info;
hdrpack = NULL;
/*init MMC */
if (curr_device < 0) {
if (get_mmc_num() > 0) {
curr_device = 0;
} else {
pr_err("No MMC device available\n");
goto err;
}
}
mmc = init_mmc_device(curr_device, false);
if (!mmc) {
pr_err("Init mmc device failed!\n");
goto err;
}
/*SD card upgrade should select SD*/
mmc_type = IS_SD(mmc) ? "SD" : "eMMC";
if (!strcmp(mmc_type, "eMMC")) {
if (get_mmc_num() > 1) {
curr_device = 1;
mmc = init_mmc_device(curr_device, false);
if (!mmc) {
pr_err("Init mmc device failed!\n");
goto err;
}
} else {
pr_err("No SD card is insert!..\n");
goto err;
}
}
/*Set GPT partition*/
ret = aicupg_mmc_create_gpt_part(curr_device, true);
if (ret < 0) {
pr_err("Create GPT partitions failed\n");
goto err;
}
/*load header*/
ret = part_get_info_by_name(mmc_get_blk_desc(mmc), "image",
&part_info);
if (ret == -1) {
pr_err("Get partition information failed.\n");
goto err;
}
hdrpack = (struct image_header_pack *)malloc(sizeof(struct image_header_pack));
if (!hdrpack) {
pr_err("Error, malloc buf failed.\n");
goto err;
}
memset((struct image_header_pack *)hdrpack, 0, sizeof(struct image_header_pack));
cnt = sizeof(struct image_header_pack) / mmc->read_bl_len;
n = blk_dread(mmc_get_blk_desc(mmc), part_info.start, cnt, (void *)hdrpack);
if (n != cnt) {
pr_err("load header failed!\n");
goto err;
}
/*checkout header*/
ret = image_header_check(hdrpack);
if (ret) {
pr_err("check image header failed!\n");
goto err;
}
/*when upgrade emmc,device should different*/
hdrpack->hdr.media_dev_id = curr_device ? 0 : 1;
/*write data to media*/
ret = aicupg_sd_write(&hdrpack->hdr, mmc, part_info);
if (ret == 0) {
pr_err("sd card write data failed!\n");
goto err;
}
free(hdrpack);
ret = CMD_RET_SUCCESS;
return ret;
err:
if (hdrpack)
free(hdrpack);
ret = CMD_RET_FAILURE;
#endif
return ret;
}
static int do_fat_upg(int intf, char *const blktype)
{
int ret = 0;
#if defined(CONFIG_FS_FAT) || defined(CONFIG_SPL_FS_FAT)
struct image_header_pack *hdrpack;
struct mmc *mmc;
loff_t actread;
char num_dev = 0, cur_dev = 0;
char *file_buf;
char image_name[IMG_NAME_MAX_SIZ] = {0};
char protection[PROTECTION_PARTITION_LEN] = {0};
aicupg_fat_set_process_cb(fat_upg_progress);
mmc = NULL;
hdrpack = (struct image_header_pack *)malloc(sizeof(struct image_header_pack));
if (!hdrpack) {
pr_err("Error, malloc hdrpack failed.\n");
return CMD_RET_FAILURE;
}
memset((struct image_header_pack *)hdrpack, 0,
sizeof(struct image_header_pack));
file_buf = (char *)malloc(2048);
if (!file_buf) {
pr_err("Error, malloc buf failed.\n");
goto err;
}
memset((void *)file_buf, 0, 2048);
if (!strcmp(blktype, "mmc")) {
/*init MMC */
if (curr_device < 0) {
if (get_mmc_num() > 0) {
curr_device = 1;
} else {
pr_err("No MMC device available\n");
goto err;
}
}
mmc = init_mmc_device(curr_device, false);
if (!mmc) {
num_dev = uclass_id_count(UCLASS_MMC);
for (cur_dev = 0; !mmc; cur_dev++) {
if (cur_dev == curr_device)
continue;
mmc = init_mmc_device(cur_dev, false);
if (mmc)
break;
if (cur_dev >= num_dev) {
pr_err("Init mmc device failed!\n");
goto err;
}
}
curr_device = cur_dev;
}
printf("curr_device:%d\n", curr_device);
if (curr_device == 0)
ret = fs_set_blk_dev("mmc", "0", FS_TYPE_FAT);
else
ret = fs_set_blk_dev("mmc", "1", FS_TYPE_FAT);
if (ret != 0) {
pr_err("Set blk dev failed!\n");
goto err;
}
#ifdef CONFIG_UPDATE_UDISK_FATFS_ARTINCHIP
} else if (!strcmp(blktype, "udisk")) {
/*usb init*/
if (usb_init() < 0) {
pr_err("usb init failed!\n");
goto err;
}
/* try to recognize storage devices immediately */
ret = usb_stor_scan(1);
if (ret < 0) {
pr_err("No udisk is insert!\n");
goto err;
}
ret = fs_set_blk_dev("usb", "0", FS_TYPE_FAT);
if (ret != 0) {
pr_err("Set blk dev failed!\n");
goto err;
}
#ifdef CONFIG_VIDEO_ARTINCHIP
ret = aic_disp_logo("udiskburn", BD_SDFAT32);
if (ret)
pr_err("Display udisk burn logo failed!\n");;
#endif
#endif
} else {
goto err;
}
/*load header*/
ret = fat_read_file("bootcfg.txt", (void *)file_buf, 0, 2048, &actread);
if (actread == 0 || ret != 0) {
printf("Error:read file bootcfg.txt failed!\n");
goto err;
}
ret = boot_cfg_get_image(file_buf, actread, image_name,
IMG_NAME_MAX_SIZ);
if (ret < 0) {
pr_err("get bootcfg.txt image name failed!\n");
goto err;
}
ret = boot_cfg_get_protection(file_buf, actread, protection,
PROTECTION_PARTITION_LEN);
if (ret < 0)
pr_warn("No protected partition.\n");
else
pr_info("Protected=%s\n", protection);
ret = fat_read_file(image_name, (void *)hdrpack, 0,
sizeof(struct image_header_pack), &actread);
if (actread != sizeof(struct image_header_pack) || ret != 0) {
printf("Error:read file %s failed!\n", image_name);
goto err;
}
/*check header*/
ret = image_header_check(hdrpack);
if (ret) {
pr_err("check image header failed!\n");
goto err;
}
/*write data to media*/
ret = aicupg_fat_write(image_name, protection, &hdrpack->hdr);
if (ret == 0) {
pr_err("fat write data failed!\n");
goto err;
}
#ifdef CONFIG_VIDEO_ARTINCHIP
#ifdef CONFIG_PROGRESS_BAR
ret = 0;
#else
ret = aic_disp_logo("burn_done", BD_SDFAT32);
if (ret)
pr_err("display burn done logo failed\n");
#endif
#endif
puts("\nPlug-out SDCard/UDISK to reboot device.\n");
printf(" CTRL+C exit to command line.\n");
/* Reboot when SDCard/UDISK plug-out */
while (1) {
ret = fat_read_file("bootcfg.txt", (void *)file_buf, 0, 2048,
&actread);
if (actread == 0 || ret != 0) {
mdelay(1000);
do_reset(NULL, 0, 0, 0);
}
if (ctrlc()) {
/* Exit to cmd line */
break;
}
mdelay(100);
}
free(hdrpack);
free(file_buf);
ret = CMD_RET_SUCCESS;
return ret;
err:
if (hdrpack)
free(hdrpack);
if (file_buf)
free(file_buf);
ret = CMD_RET_FAILURE;
#endif
return ret;
}
static int do_aicupg(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *devtype = NULL;
int intf, ret = CMD_RET_USAGE;
if (argc <= 2) {
if (argc == 1)
do_brom_upg("aicusb");
else
do_brom_upg(argv[1]);
return 0;
}
if ((argc < 3) || (argc > AICUPG_ARGS_MAX))
return ret;
devtype = argv[1]; /* mmc usb fat */
if (argc >= 4 && argv[3])
intf = simple_strtoul(argv[3], NULL, 0);
else
intf = simple_strtoul(argv[2], NULL, 0);
if (devtype == NULL)
return ret;
if (!strcmp(devtype, "usb"))
ret = do_usb_protocol_upg(intf);
if (!strcmp(devtype, "mmc"))
ret = do_sdcard_upg(intf);
if (!strcmp(devtype, "fat"))
ret = do_fat_upg(intf, argv[2]);
return ret;
}
U_BOOT_CMD(aicupg, AICUPG_ARGS_MAX, 0, do_aicupg,
"ArtInChip firmware upgrade",
"[devtype] [interface]\n"
" - devtype: should be usb, mmc, fat\n"
" - interface: specify the controller id\n"
"e.g.\n"
"aicupg\n"
" - if no parameter is provided, it will reboot to BROM's upgmode.\n"
"aicupg usb 0\n"
"aicupg mmc 1\n"
"- when devtype is fat: \n"
"[devtype] [blkdev] [interface]\n"
"- blkdev: should be udisk,mmc \n"
"e.g. \n"
"aicupg fat udisk 0\n"
"aicupg fat mmc 1\n"
"aicupg\n"
);