linuxOS_D21X/source/uboot-2021.10/cmd/loadknl.c
2024-11-29 16:13:46 +08:00

263 lines
5.9 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 ArtInChip Technology Co., Ltd
*/
#include <common.h>
#include <command.h>
#include <console.h>
#include <malloc.h>
#include <linux/libfdt.h>
#include <image.h>
#include <bootstage.h>
#include <memalign.h>
#include <mmc.h>
#include <part.h>
#ifdef CONFIG_ARCH_ARTINCHIP
#include <asm/arch/boot_param.h>
#endif
#define LOADKNL_ARGS_MAX 5
#define CMD_MAX_SIZE 128
#define HEAD_DATA_SIZE 0x1000
static unsigned long get_kernel_itb_size(u8 *head)
{
unsigned long siz;
int ret;
ret = fdt_check_header(head);
if (ret) {
printf("Error: Not a valid itb image.\n");
return 0;
}
siz = fdt_totalsize(head);
pr_debug("%s, size %ld\n", __func__, siz);
return siz;
}
#ifdef CONFIG_CMD_MMC
/*
* Load kernel image from partition
* e.g.:
* mmc 0 kernel 0x81000000
*/
static int load_from_mmc_partition(int argc, char *const argv[])
{
char *part, *addr_str;
unsigned long addr, imgsize, bcnt, start, time;
struct blk_desc *desc;
struct disk_partition part_info;
struct mmc *mmc;
int devnum, ret;
u32 n;
ret = 0;
if (argc != 4)
return CMD_RET_USAGE;
devnum = simple_strtoull(argv[1], NULL, 0);
part = argv[2];
addr_str = argv[3];
addr = simple_strtoull(addr_str, NULL, 0);
ret = blk_get_device_by_str(argv[0], argv[1], &desc);
if (ret < 0) {
pr_err("%s, line %d: failed to get blk dev.\n", __func__, __LINE__);
return CMD_RET_FAILURE;
}
ret = part_get_info_by_name(desc, part, &part_info);
if (ret < 0) {
pr_err("%s, line %d: failed to get part.\n", __func__, __LINE__);
return CMD_RET_FAILURE;
}
start = part_info.start;
mmc = find_mmc_device(devnum);
if (!mmc) {
printf("no mmc device at slot %x\n", devnum);
return CMD_RET_FAILURE;
}
if (mmc_init(mmc)) {
printf("Failed to init mmc\n");
return CMD_RET_FAILURE;
}
/* Read first LBA to get itb head */
bcnt = 1;
n = blk_dread(desc, start, bcnt, (void *)addr);
if (n != bcnt) {
printf("Failed to read first data of kernel partition\n");
return CMD_RET_FAILURE;
}
imgsize = get_kernel_itb_size((u8 *)addr);
if (imgsize <= part_info.blksz) {
/* If it is not itb image, read the whole partition */
bcnt = part_info.size;
} else {
imgsize -= part_info.blksz;
/* Round up to blksz alignment */
bcnt = (imgsize + part_info.blksz - 1) / part_info.blksz;
}
start++;
addr += part_info.blksz;
time = get_timer(0);
n = blk_dread(desc, start, bcnt, (void *)addr);
if (n != bcnt) {
printf("Failed to read the rest of kernel partition\n");
return CMD_RET_FAILURE;
}
time = get_timer(time);
if (bcnt && time) {
unsigned long rdsiz, n, d, speed_int, speed_pnt;
rdsiz = bcnt * part_info.blksz;
n = rdsiz * 1000;
d = time * 1024 * 1024;
speed_int = n / d;
speed_pnt = n * 100 / d - speed_int * 100;
pr_info("Read kernel speed (size %lu time %lu ms) %lu.%lu MB/s\n",
rdsiz, time, speed_int, speed_pnt);
}
return 0;
}
#endif
#ifdef CONFIG_CMD_MTD
/*
* e.g.:
* mtd kernel 0x81000000
*/
static int load_from_mtd_partition(int argc, char *const argv[])
{
char *cmdbuf = NULL, *part, *addr_str;
unsigned long addr, size, start, time;
int ret;
if (argc != 3)
return CMD_RET_USAGE;
part = argv[1];
addr_str = argv[2];
addr = simple_strtoull(addr_str, NULL, 0);
cmdbuf = (char *)malloc(CMD_MAX_SIZE);
if (!cmdbuf) {
pr_err("%s: failed to malloc buffer.\n", __func__);
return CMD_RET_FAILURE;
}
/* Read first 4KB to get the total length */
start = 0;
snprintf(cmdbuf, CMD_MAX_SIZE, "mtd read %s %s 0x%lx 0x%x", part,
addr_str, start, HEAD_DATA_SIZE);
ret = run_command(cmdbuf, 0);
if (ret) {
printf("Failed to read first data of kernel partition\n");
goto out;
}
size = get_kernel_itb_size((u8 *)addr) - HEAD_DATA_SIZE;
if (size) {
/* Round up to 4KB alignment */
if (size & 0xFFF)
size = (((size >> 12) + 1) << 12);
/* Read the rest data of kernel image */
start = HEAD_DATA_SIZE;
snprintf(cmdbuf, CMD_MAX_SIZE, "mtd read %s 0x%lx 0x%lx 0x%lx",
part, addr + 0x1000, start, size);
} else {
/*
* Unknown size, read the whole partition
*/
snprintf(cmdbuf, CMD_MAX_SIZE, "mtd read 0x%lx %s", addr, part);
}
time = get_timer(0);
ret = run_command(cmdbuf, 0);
if (ret) {
printf("Failed to read the rest of kernel partition\n");
goto out;
}
time = get_timer(time);
if (size && time) {
unsigned long rdsiz, n, d, speed_int, speed_pnt;
rdsiz = size - start;
n = rdsiz * 1000;
d = time * 1024 * 1024;
speed_int = n / d;
speed_pnt = n * 100 / d - speed_int * 100;
pr_info("Read kernel speed (size %lu time %lu ms) %lu.%lu MB/s\n",
rdsiz, time, speed_int, speed_pnt);
}
out:
if (cmdbuf)
free(cmdbuf);
return ret;
}
#endif
/*
* load kernel from specific partition, and auto-detect the kernel size
*/
static int do_loadknl(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
int ret = CMD_RET_USAGE;
char *ramboot;
if (argc > LOADKNL_ARGS_MAX)
return CMD_RET_USAGE;
if (argv[1] == NULL)
return CMD_RET_USAGE;
/* Don't load from device if it is ramboot,
* In ramboot mode, kernel image already download from host to DDR
*/
ramboot = env_get("ramboot");
if (ramboot)
return 0;
#ifdef CONFIG_ARTINCHIP_DEBUG_BOOT_TIME
u32 *p = (u32 *)BOOT_TIME_UBOOT_LOAD_KERNEL_START;
*p = aic_timer_get_us();
#endif
#ifdef CONFIG_CMD_MMC
if (!strcmp(argv[1], "mmc"))
ret = load_from_mmc_partition(argc - 1, &argv[1]);
#endif
#ifdef CONFIG_CMD_MTD
if (!strcmp(argv[1], "mtd"))
ret = load_from_mtd_partition(argc - 1, &argv[1]);
#endif
#ifdef CONFIG_ARTINCHIP_DEBUG_BOOT_TIME
p = (u32 *)BOOT_TIME_UBOOT_LOAD_KERNEL_DONE;
*p = aic_timer_get_us();
#endif
if (ret)
printf("Load kernel from %s failed.\n", argv[1]);
return ret;
}
U_BOOT_CMD(loadknl, LOADKNL_ARGS_MAX, 0, do_loadknl,
"load kernel itb image from partition",
"[devtype] [partition] [address]\n"
" - devtype: should be mmc, mtd\n"
" - address: memory to store kernel\n"
"e.g.\n"
"loadknl mmc ${boot_devnum} kernel ${knl_addr}\n"
"loadknl mtd kernel ${knl_addr}\n"
);