Files
Linux_Drivers/u-boot-2021.10/cmd/cvi_update.c
sam.xiang 3a4bcfca2f [uboot] porting cvitek asic chips:
1. add cvitek folders to u-boot-2021.10
	2. add cv183x/cv182x part
	3. add cv181x/cv180x part

Change-Id: I6dc2e5ff509dbab16bd60bfb3fd61852da5e01f6
2023-03-10 20:31:12 +08:00

320 lines
9.1 KiB
C

#include <common.h>
#include <command.h>
#include <asm/io.h>
#include <imgs.h>
#include <ubifs_uboot.h>
#ifdef CONFIG_NAND_SUPPORT
#include <nand.h>
#endif
#include "cvi_update.h"
#define COMPARE_STRING_LEN 3
#define SD_UPDATE_MAGIC 0x4D474E32
#define ETH_UPDATE_MAGIC 0x4D474E35
#define USB_DRIVE_UPGRADE_MAGIC 0x55425355
#define FIP_UPDATE_MAGIC 0x55464950
#define UPDATE_DONE_MAGIC 0x50524F47
#define OTA_MAGIC 0x5245434F
//#define ALWAYS_USB_DRVIVE_UPGRATE
#define HEADER_SIZE 64
#define SECTOR_SIZE 0x200
#define HEADER_MAGIC "CIMG"
#define MAX_LOADSIZE (16 * 1024 * 1024)
#ifdef CONFIG_CMD_SAVEENV
#define SET_DL_COMPLETE() \
do { \
env_set("dl_flag", "prog"); \
run_command("saveenv", 0); \
} while (0)
#else
#define SET_DL_COMPLETE() writel(0x50524F47, (unsigned int *)UPGRADE_SRAM_ADDR)
#endif /* CONFIG_CMD_SAVEENV */
#ifdef CONFIG_NAND_SUPPORT
static uint32_t lastend;
#endif
uint32_t update_magic;
enum chunk_type_e { dont_care = 0, check_crc };
enum storage_type_e { sd_dl = 0, usb_dl };
static uint32_t bcd2hex4(uint32_t bcd)
{
return ((bcd) & 0x0f) + (((bcd) >> 4) & 0xf0) + (((bcd) >> 8) & 0xf00) + (((bcd) >> 12) & 0xf000);
}
static int _storage_update(enum storage_type_e type);
int _prgImage(char *file, uint32_t chunk_header_size, char *file_name)
{
uint32_t size = *(uint32_t *)((uintptr_t)file + 4);
uint32_t offset = *(uint32_t *)((uintptr_t)file + 8);
#if (defined CONFIG_SPI_FLASH)/* || (defined CONFIG_NAND_SUPPORT)*/
uint32_t part_size = *(uint32_t *)((uintptr_t)file + 12);
#endif
//uint32_t header_crc = *(uint32_t *)((uintptr_t)file + 16);
char cmd[255] = { '\0' };
int ret = 0;
//if (chunk_type == check_crc) {
// uint32_t crc = crc32(
// 0, (unsigned char *)file + chunk_header_size, size);
// if (crc != header_crc) {
// printf("Crc check failed header(0x%08x) img(0x%08x), skip it\n",
// header_crc, crc);
// return 0;
// } else {
// /* Invalidate crc to avoid program garbage */
// *(uint32_t *)((uintptr_t)file + 12) = 0;
// }
//}
#ifdef CONFIG_NAND_SUPPORT
int dev = nand_curr_device;
struct mtd_info *mtd = nand_info[dev];
uint32_t goodblocks = 0, blocks = 0;
// Calculate real offset when programming chunk.
if (offset < lastend)
offset = lastend;
else
lastend = offset;
blocks = (size & (mtd->erasesize - 1)) ? ALIGN(size, mtd->erasesize) : size;
blocks /= mtd->erasesize;
for (; goodblocks < blocks; lastend += mtd->erasesize) {
if (!nand_block_isbad(mtd, lastend))
goodblocks++;
}
//pr_debug("offset:0x%x lastoffset:0x%x, end:0x%x\n", offset, lastend, part_size + offset);
snprintf(cmd, 255, "nand write %p 0x%x 0x%x",
(void *)file + chunk_header_size, offset, size);
#elif defined(CONFIG_SPI_FLASH)
if (update_magic == SD_UPDATE_MAGIC && (!strcmp(file_name, "fip.bin") ||
!strcmp(file_name, "boot.spinor"))) {
snprintf(cmd, 255, "sf update %p 0x%x 0x%x",
(void *)file + chunk_header_size, offset, size);
} else {
snprintf(cmd, 255, "sf erase %#x %#x;", offset, part_size);
pr_debug("%s\n", cmd);
run_command(cmd, 0);
snprintf(cmd, 255, "sf write %p 0x%x 0x%x",
(void *)file + chunk_header_size, offset, size);
}
#else
if (size & (SECTOR_SIZE - 1))
size = ALIGN(size, SECTOR_SIZE);
size = size / SECTOR_SIZE;
offset = offset / SECTOR_SIZE;
snprintf(cmd, 255, "mmc write %p 0x%x 0x%x",
(void *)file + chunk_header_size, offset, size);
#endif
pr_debug("%s\n", cmd);
ret = run_command(cmd, 0);
if (ret)
return 0;
return size;
}
static int _checkHeader(char *file, char strStorage[10])
{
char *magic = (void *)HEADER_ADDR;
uint32_t version = *(uint32_t *)((uintptr_t)HEADER_ADDR + 4);
uint32_t chunk_sz = *(uint32_t *)((uintptr_t)HEADER_ADDR + 8);
uint32_t total_chunk = *(uint32_t *)((uintptr_t)HEADER_ADDR + 12);
uint32_t file_sz = *(uint32_t *)((uintptr_t)HEADER_ADDR + 16);
#ifdef CONFIG_NAND_SUPPORT
char *extra = (void *)((uintptr_t)HEADER_ADDR + 20);
static char prevExtra[EXTRA_FLAG_SIZE + 1] = { '\0' };
#endif
int ret = strncmp(magic, HEADER_MAGIC, 4);
if (ret) {
printf("File:%s Magic number is wrong, skip it\n", file);
return ret;
}
printf("Header Version:%d\n", version);
char cmd[255] = { '\0' };
uint32_t pos = HEADER_SIZE;
#ifdef CONFIG_NAND_SUPPORT
// Erase partition first
if (strncmp(extra, prevExtra, EXTRA_FLAG_SIZE)) {
strncpy(prevExtra, extra, EXTRA_FLAG_SIZE);
snprintf(cmd, 255, "nand erase.part -y %s", prevExtra);
pr_debug("%s\n", cmd);
run_command(cmd, 0);
}
#endif
for (int i = 0; i < total_chunk; i++) {
uint32_t load_size = file_sz > (MAX_LOADSIZE + chunk_sz) ?
MAX_LOADSIZE + chunk_sz :
file_sz;
snprintf(cmd, 255, "fatload %s %p %s 0x%x 0x%x;", strStorage,
(void *)UPDATE_ADDR, file, load_size, pos);
pr_debug("%s\n", cmd);
ret = run_command(cmd, 0);
if (ret)
return ret;
ret = _prgImage((void *)UPDATE_ADDR, chunk_sz, file);
if (ret == 0) {
printf("program file:%s failed\n", file);
break;
}
pos += load_size;
file_sz -= load_size;
}
return 0;
}
static int _storage_update(enum storage_type_e type)
{
int ret = 0;
char cmd[255] = { '\0' };
char strStorage[10] = { '\0' };
if (type == sd_dl) {
printf("Start SD downloading...\n");
// Consider SD card with MBR as default
#if defined(CONFIG_NAND_SUPPORT) || defined(CONFIG_SPI_FLASH)
strlcpy(strStorage, "mmc 0:1", 9);
#elif defined(CONFIG_EMMC_SUPPORT)
strlcpy(strStorage, "mmc 1:1", 9);
#endif
snprintf(cmd, 255, "fatload %s %p fip.bin;", strStorage,
(void *)HEADER_ADDR);
ret = run_command(cmd, 0);
if (ret) {
// Consider SD card without MBR
printf("** Trying use partition 0 (without MBR) **\n");
#if defined(CONFIG_NAND_SUPPORT) || defined(CONFIG_SPI_FLASH)
strlcpy(strStorage, "mmc 0:0", 9);
#elif defined(CONFIG_EMMC_SUPPORT)
strlcpy(strStorage, "mmc 1:0", 9);
#endif
snprintf(cmd, 255, "fatload %s %p fip.bin;", strStorage,
(void *)HEADER_ADDR);
ret = run_command(cmd, 0);
if (ret)
return ret;
}
#if defined(CONFIG_NAND_SUPPORT)
snprintf(cmd, 255, "cvi_sd_update %p spinand fip",
(void *)HEADER_ADDR);
ret = run_command(cmd, 0);
#elif defined(CONFIG_SPI_FLASH)
run_command("sf probe", 0);
snprintf(cmd, 255,
"sf update %p ${fip_PART_OFFSET} ${filesize};",
(void *)HEADER_ADDR);
ret = run_command(cmd, 0);
#elif defined(CONFIG_EMMC_SUPPORT)
// Switch to boot partition
run_command("mmc dev 0 1", 0);
snprintf(cmd, 255, "mmc write %p 0 0x800;",
(void *)HEADER_ADDR);
run_command(cmd, 0);
snprintf(cmd, 255, "mmc write %p 0x800 0x800;;",
(void *)HEADER_ADDR);
run_command(cmd, 0);
printf("Program fip.bin done\n");
// Switch to user partition
run_command("mmc dev 0 0", 0);
#endif
}
for (int i = 1; i < ARRAY_SIZE(imgs); i++) {
snprintf(cmd, 255, "fatload %s %p %s 0x%x 0;", strStorage,
(void *)HEADER_ADDR, imgs[i], HEADER_SIZE);
pr_debug("%s\n", cmd);
ret = run_command(cmd, 0);
if (ret) {
printf("load %s failed, skip it!\n", imgs[i]);
continue;
}
if (_checkHeader(imgs[i], strStorage))
continue;
}
if (ret == 0)
SET_DL_COMPLETE();
return 0;
}
static int _usb_update(uint32_t usb_pid)
{
int ret = 0;
char cmd[255] = { '\0' };
char utask_cmd[255] = { '\0' };
printf("Start USB downloading...\n");
// Clean download flags
writel(0x0, (unsigned int *)BOOT_SOURCE_FLAG_ADDR); //mw.l 0xe00fc00 0x0;
// Always download Fip first
snprintf(utask_cmd, 255, "cvi_utask vid 0x3346 pid 0x%x", usb_pid);
ret = run_command(utask_cmd, 0);
#ifdef CONFIG_NAND_SUPPORT
snprintf(cmd, 255, "cvi_sd_update %p spinand fip", (void *)UPDATE_ADDR);
pr_debug("%s\n", cmd);
ret = run_command(cmd, 0);
#elif defined(CONFIG_SPI_FLASH)
ret = run_command("sf probe", 0);
snprintf(cmd, 255, "sf update %p ${fip_PART_OFFSET} ${fip_PART_SIZE};", (void *)UPDATE_ADDR)
pr_debug("%s\n", cmd);
ret = run_command(cmd, 0);
#else
// Switch to boot partition
run_command("mmc dev 0 1", 0);
snprintf(cmd, 255, "mmc write %p 0 0x800;", (void *)UPDATE_ADDR);
pr_debug("%s\n", cmd);
run_command(cmd, 0);
snprintf(cmd, 255, "mmc write %p 0x800 0x800;", (void *)UPDATE_ADDR);
pr_debug("%s\n", cmd);
run_command(cmd, 0);
printf("Program fip.bin done\n");
// Switch to user partition
run_command("mmc dev 0 0", 0);
#endif
// Since device will reset by host tool, set flag first
SET_DL_COMPLETE();
while (1) {
ret = run_command(utask_cmd, 0);
if (ret) {
pr_debug("cvi_utask failed(%d)\n", ret);
return ret;
}
//_prgImage((void *)UPDATE_ADDR, readl(HEADER_ADDR + 8));
};
return 0;
}
static int do_cvi_update(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
int ret = 1;
uint32_t usb_pid = 0;
if (argc == 1) {
update_magic = readl((unsigned int *)BOOT_SOURCE_FLAG_ADDR);
if (update_magic == SD_UPDATE_MAGIC) {
run_command("env default -a", 0);
ret = _storage_update(sd_dl);
} else if (update_magic == USB_UPDATE_MAGIC) {
run_command("env default -a", 0);
usb_pid = in_be32(UBOOT_PID_SRAM_ADDR);
usb_pid = bcd2hex4(usb_pid);
ret = _usb_update(usb_pid);
}
} else {
printf("Usage:\n%s\n", cmdtp->usage);
}
return ret;
}
U_BOOT_CMD(
cvi_update, 2, 0, do_cvi_update,
"cvi_update [eth, sd, usb]- check boot status and update if necessary\n",
"run cvi_update without parameter will check the boot status and try to update");