GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
obj-$(CONFIG_CMD_HW_GUNZIP) += cmd_hw_gunzip.o
obj-$(if $(CONFIG_LOTUS_DISABLE_DOWNLOAD),,y) += download_process.o
obj-y += getinfo.o
obj-y += misc.o
obj-$(CONFIG_EXT4_SPARSE) += unsparse.o
obj-y += shutdown.o
obj-$(CONFIG_QS_MCU) += mcu.o
+280
View File
@@ -0,0 +1,280 @@
#define pr_fmt(fmt) "%s: " fmt, "HW GUNZIP"
#include <common.h>
#include <memalign.h>
#include <linux/lotus/hw_decompress.h>
#include <mmc.h>
#include <linux/lotus/flash_read.h>
#include <asm/cache.h>
#include <usb.h>
#include <linux/lotus/timestamp.h>
#include <irq_func.h>
#include <dm/device.h>
#include <serial.h>
#include <linux/lotus/tags.h>
#include <linux/ctype.h>
#define HW_GUNZIP_STEP_MIN 0x20000
#define DEFAULT_STEP (256 * 1024)
static bool decomp_done = false;
int decompress_by_step(void *dst, uint dst_len, void *src, uint *z_len,
ulong offset, uint step)
{
uint cur_read_size = step;
uchar *buffer = src;
hw_decompress_op_type op_type;
uint cur_offset;
int ret = -1;
int head_size = sizeof(image_header_t) + HW_GZIP_HEAD_SIZE;
uint size;
if (!dst || !buffer)
return -EINVAL;
if (!step)
step = DEFAULT_STEP;
cur_read_size = step;
ret = flash_read(offset, cur_read_size, buffer);
if (ret < 0) {
pr_err("Fail to read from flash\n");
goto out;
}
size = image_get_size((image_header_t *)buffer) + sizeof(image_header_t);
if (size < step) {
pr_err("Invalid image size, %u(size) less than %u(step)\n", size, step);
return -EINVAL;
}
dcache_disable();
hw_dec_init();
ret = hw_dec_decompress_ex(HW_DECOMPRESS_OP_START,
dst, &dst_len, buffer + head_size, cur_read_size - head_size);
if (ret != 0) {
pr_err("hw decompress start failed(%d)\n", ret);
goto out;
}
cur_offset = cur_read_size;
while (cur_offset < size) {
if ((cur_offset + step) < size) {
cur_read_size = step;
op_type = HW_DECOMPRESS_OP_CONTINUE;
} else {
cur_read_size = size - cur_offset;
op_type = HW_DECOMPRESS_OP_END;
}
ret = flash_read(offset + cur_offset, cur_read_size, buffer + cur_offset);
if (ret < 0) {
pr_err("Read flash failed(%d).\n", ret);
goto out;
}
pr_debug("Decompress 0x%p to 0x%p, size 0x%x\n", buffer + cur_offset, dst, cur_read_size);
ret = hw_dec_decompress_ex(op_type,
dst, &dst_len, buffer + cur_offset, cur_read_size);
if (ret != 0) {
pr_err("hw decompress failed.(%d)\n", ret);
goto out;
}
cur_offset += cur_read_size;
}
if (z_len)
*z_len = size;
ret = 0;
out:
hw_dec_uinit();
dcache_enable();
return ret;
}
int hw_gunzip(void *dst, uint dst_len, void *src, uint *src_len)
{
int ret = 0;
if (decomp_done)
return 0;
dcache_disable();
hw_dec_init();
ret = hw_dec_decompress_ex(HW_DECOMPRESS_OP_ONCE, (uchar *)dst,
&dst_len, (uchar *)src, *src_len);
if (ret != 0) {
pr_err("hw decompress fail!\n");
goto out;
}
out:
hw_dec_uinit();
dcache_enable();
return ret;
}
static int do_hw_gunzip(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
int ret;
if (argc != 3)
return CMD_RET_USAGE;
uintptr_t src = simple_strtoul(argv[1], NULL, 16); /* 1: src argc, 16: base */
uintptr_t dst = simple_strtoul(argv[2], NULL, 16); /* 2: dst argc, 16: base */
if (src & 0xf || dst & 0xf) {
pr_err("src[0x%lx] or dst[0x%lx] NOT 16Byte-aligned!\n", src, dst);
return CMD_RET_USAGE;
}
uint magic_num0 = *(uint *)(src + HEAD_MAGIC_NUM0_OFFSET);
uint magic_num1 = *(uint *)(src + HEAD_MAGIC_NUM1_OFFSET);
if ((magic_num0 != HEAD_MAGIC_NUM0) || (magic_num1 != HEAD_MAGIC_NUM1)) {
pr_err("Invalid image!\n");
return CMD_RET_FAILURE;
}
uint comp_len = *(uint *)(src + COMPRESSED_SIZE_OFFSET);
uint uncomp_len = *(uint *)(src + UNCOMPRESSED_SIZE_OFFSET);
ret = hw_gunzip((void *)dst, uncomp_len, (uchar *)(src + HW_GZIP_HEAD_SIZE), &comp_len);
if (ret != 0) {
pr_err("hw gunzip fail!(%d)\n", ret);
return CMD_RET_FAILURE;
}
return 1;
}
static int read_dtb(ulong offset, uint image_size,
ulong src_addr, uint src_size)
{
int ret;
if (src_size & (FLASH_ALIGNED_SIZE - 1))
src_size = src_size & ~(FLASH_ALIGNED_SIZE - 1);
ret = flash_read(offset + src_size, image_size - src_size,
(uchar *)(src_addr + src_size));
if (ret < 0) {
pr_err("read DTB file failed(0x%x).\n", ret);
return -1;
}
return 0;
}
static int do_boothz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
uchar *src_addr = NULL;
uchar *dst_addr = NULL;
ulong offset;
uint image_size;
uint step;
int ret;
char *sub_cmd = NULL;
char bootm_str[30];
uint z_len = 0;
switch (argc) {
case 5:
step = DEFAULT_STEP;
break;
case 6:
if (isdigit(*(argv[5]))) {
step = \
(uint)(uintptr_t)simple_strtoul(argv[5], NULL, 16);
} else {
step = DEFAULT_STEP;
sub_cmd = argv[5];
}
break;
case 7:
if (isdigit(*(argv[5])) || !isdigit(*(argv[6]))) {
return CMD_RET_USAGE;
}
sub_cmd = argv[5];
step = \
(uint)(uintptr_t)simple_strtoul(argv[6], NULL, 16);
default:
return CMD_RET_USAGE;
}
if (step < HW_GUNZIP_STEP_MIN) {
pr_err("step less than 0x%x!\n", HW_GUNZIP_STEP_MIN);
ret = CMD_RET_USAGE;
goto out;
}
if ((step % HW_GUNZIP_STEP_MIN) != 0) {
pr_err("step should be aligned with 0x%x!\n", HW_GUNZIP_STEP_MIN);
ret = CMD_RET_USAGE;
goto out;
}
src_addr = (uchar *)(uintptr_t)simple_strtoul(argv[1], NULL, 16);
dst_addr = (uchar *)(uintptr_t)simple_strtoul(argv[2], NULL, 16);
offset = (ulong)simple_strtoul(argv[3], NULL, 16);
image_size = (ulong)simple_strtoul(argv[4], NULL, 16);
ret = decompress_by_step(dst_addr, CONFIG_SYS_BOOTM_LEN, src_addr, &z_len, offset, step);
if (ret != 0) {
pr_err("Fail to get image from flash(%d)\n", ret);
goto out;
}
decomp_done = true;
ret = read_dtb(offset, image_size, (ulong)src_addr, z_len);
if (ret != 0) {
goto out;
}
if (sub_cmd)
run_command(sub_cmd, 0);
memset(bootm_str, 0, sizeof(bootm_str));
snprintf(bootm_str, sizeof(bootm_str), "bootm 0x%p", src_addr);
pr_info("%s\n", bootm_str);
run_command(bootm_str, 0);
out:
return ret;
}
U_BOOT_CMD(
hwgunzip, 3, 0, do_hw_gunzip,
"uncompress file with hardware IP, eg:[ugzip compress_addr uncompress_addr]",
"hwgunzip <src> <dst>\n"
"src and dst must be 16Byte-aligned"
);
U_BOOT_CMD(
boothz, 7, 0, do_boothz,
"Read and decompress image by hardware: boothz <src> <dst> <flash offset> <size> [sub command | chunk size]",
"<src> <dst> <flash offset> <size> [sub command | chunk size]\n"
" <src> <dst> <flash offset> <size> <sub command> <chunk size>\n"
" - Read image from <flash offset> to <src>, and decompress to <dst> by hardware decompressed module.\n"
" eg:\n"
" boothz 0x41000000 0x40008000 0x100000 0x400000\n"
" boothz 0x41000000 0x40008000 0x100000 0x400000 xmediaapp\n"
" boothz 0x41000000 0x40008000 0x100000 0x400000 0x40000\n"
" boothz 0x41000000 0x40008000 0x100000 0x400000 xmediaapp 0x40000\n"
" <src> and <dst> is DDR location, and must be 16Byte-aligned;\n"
" <flash offset> and <size> must be flash-block-size-aligned;\n"
" <chunk size> is one step size for reading and decompressing one time;\n"
" <sub command> is a command that will be run after decompressing image and before going to kernel."
);
@@ -0,0 +1,240 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <serial.h>
#include <usb.h>
#include <crc16.h>
#include <linux/lotus/usb.h>
#define XHEAD 0xAB
#define XCMD 0xCD
#define ACK 0xAA /* ACK VALUE */
#define NAK 0x55 /* NAK VALUE */
#define START_FRAME_LEN 5
#define MAX_BUFF_SIZE 1024
#define MAX_SEND_SIZE 20
static char recv_buf[MAX_BUFF_SIZE];
#undef DUMP_SWITCH
#ifdef DUMP_SWITCH
static void dump_buf(char *buf, int len)
{
int i;
char *p = buf;
printf("%s->%d, buf=0x%.8x, len=%d\n",
__FUNCTION__, __LINE__,
(int)(buf), (int)(len));
for (i = 0; i < (len); i++) {
printf("0x%.2x ", *(p + i));
if (!((i + 1) & 0x07))
printf("\n");
}
printf("\n");
}
#endif
static unsigned short calc_crc16(const unsigned char *packet, unsigned long length)
{
unsigned short crc16 = 0;
unsigned long i;
const unsigned short *crc16_table = get_crc16_table();
if (crc16_table == NULL) {
return 0;
}
for (i = 0; i < length; i++)
crc16 = ((crc16 << 8) | /* fetches High or low 8 bit */
packet[i]) ^ crc16_table[(crc16 >> 8) & 0xFF];
for (i = 0; i < 2; i++) /* 2: Cycle and fetches High or low 8 bit */
crc16 = ((crc16 << 8) | 0) ^ crc16_table[(crc16 >> 8) & 0xFF];
return crc16;
}
static int recv_byte(void)
{
if (serial_tstc())
return serial_getc();
return -1;
}
static char recv_data(void)
{
int ret = -1;
while (ret == -1)
ret = recv_byte();
return (char)ret;
}
void download_process(void)
{
int i = 0, cr = 0, ret = -1;
unsigned int head_frame_len = 0;
unsigned int cmd_len = 0;
unsigned char send_buf[MAX_SEND_SIZE] = {0};
unsigned short cksum;
do {
do {
do {
cr = recv_byte();
} while (cr != XHEAD);
head_frame_len = START_FRAME_LEN;
recv_buf[0] = (char)cr;
/* RECV: head frame */
for (i = 0; i < (head_frame_len - 1) && i < (sizeof(recv_buf) - 1); i++) {
recv_buf[i + 1] = recv_data();
}
/* crc check */
cksum = calc_crc16((unsigned char*)recv_buf,3);
if (cksum == (((unsigned char)recv_buf[3] << 8) | (unsigned char)recv_buf[4])) {
/* init */
cmd_len = (unsigned short)(((unsigned char)recv_buf[1] << 8) | (unsigned char)recv_buf[2]) + 3;
if (cmd_len >= sizeof(recv_buf))
goto head_fail;
/* SEND: ack */
send_buf[0] = ACK;
serial_putc(send_buf[0]);
break;
}
head_fail:
/* init */
cmd_len = 0;
memset(recv_buf, 0, sizeof(recv_buf));
/* SEND: nak */
send_buf[0] = NAK;
serial_putc(send_buf[0]);
} while (1);
do {
do {
cr = recv_byte();
} while (cr != XCMD);
recv_buf[0] = (char)cr;
/* RECV: cmd data, cmd_len check in head flow */
for (i = 0;i < (cmd_len - 1); i++) {
recv_buf[i + 1] = recv_data();
}
/* crc check */
cksum = calc_crc16((unsigned char*)recv_buf, cmd_len - 2);
if (cksum == (((unsigned char)recv_buf[cmd_len - 2] << 8) | (unsigned char)recv_buf[cmd_len - 1])) {
/* SEND: ack wait result */
send_buf[0] = ACK;
serial_putc(send_buf[0]);
break;
}
memset(recv_buf, 0, sizeof(recv_buf));
/* SEND: nak */
send_buf[0] = NAK;
serial_putc(send_buf[0]);
#ifdef DUMP_SWITCH
dump_buf(recv_buf, cmd_len);
#endif
} while (1);
/* clean crc */
recv_buf[cmd_len - 1] = 0;
recv_buf[cmd_len - 2] = 0;
/* cmd process */
ret = run_command((recv_buf + 1), 0);
if (ret != 0) {
/* SEND: end flag */
serial_puts("[EOT](ERROR)\n");
} else{
/* SEND: end flag */
serial_puts("[EOT](OK)\n");
}
} while (1);
}
void set_update_mode_flag(int flag)
{
#ifdef REG_UPDATE_MODE_FLAG
writel(flag, REG_UPDATE_MODE_FLAG);
#endif
}
int is_bootstrap(void)
{
if (readl(REG_START_FLAG) == START_MAGIC)
return 1;
else
return 0;
}
void set_bootstrap_flag(u32 flag)
{
writel(flag, REG_START_FLAG);
writel(flag, SYS_CTRL_REG_BASE + REG_SC_DDRT14);
}
void usb_eth_init(void)
{
/* Support usb eth */
run_command("usb start", 0);
}
int is_usb_device_bootstrap(void)
{
if (readl(SYS_CTRL_REG_BASE + REG_SC_SYSBOOT9) == SELF_BOOT_TYPE_USBDEV)
return 1;
else
return 0;
}
void download_boot(void)
{
if (!is_bootstrap())
return;
/* Enable uart output for download */
serial_enable_output(true);
/* Clear flag */
set_bootstrap_flag(0);
if (!is_usb_device_bootstrap())
usb_eth_init();
serial_puts("start download process.\n");
/* Wait cmd from tool */
for (;;) {
if (is_usb_device_bootstrap()) {
/* Clear updata mode flag */
set_update_mode_flag(1);
#ifdef CONFIG_USB_GADGET
udc_connect();
#else
printf("[ERROR]: Downloading boot from usb NOT supported.\n");
#endif
} else
download_process();
}
serial_enable_output(false);
}
+130
View File
@@ -0,0 +1,130 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include <common.h>
#include <command.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <version.h>
#include <asm/io.h>
#if defined(CONFIG_FMC_SPI_NAND) \
|| defined(CONFIG_FMC_NAND)
#include <linux/lotus/nfc_common.h>
#endif
/*****************************************************************************/
#if defined(CONFIG_FMC_SPI_NAND) || defined(CONFIG_FMC_NAND) || \
defined(CONFIG_FMC_SPI_NOR)
static int print_mtd_info(const struct mtd_info_ex *mtd_info,const char *cmd)
{
unsigned int len, ix;
if (mtd_info == NULL || mtd_info->type == 0) { /* no find spi/nand */
printf("no find ");
if (*cmd == 's')
printf("spi");
else if (*cmd == 'n')
printf("nand");
printf("\n");
} else {
printf("Block:%sB ", ultohstr(mtd_info->erasesize));
printf("Chip:%sB*%d ",
ultohstr(mtd_info->chipsize),
mtd_info->numchips);
if (*cmd == 'n') {
printf("Page:%sB ", ultohstr(mtd_info->pagesize));
printf("OOB:%sB ", ultohstr(mtd_info->oobsize));
#if defined(CONFIG_FMC_SPI_NAND) || defined(CONFIG_FMC_NAND)
#ifdef CONFIG_CMD_NAND
printf("ECC:%s ", nand_ecc_name(mtd_info->ecctype));
#endif
#else
printf("ECC:%s ",
get_ecctype_str((mtd_info->ecctype & 0x7)));
#endif
}
printf("\nID:");
len = (mtd_info->id_length > 8 ? 8 : mtd_info->id_length); /* 8:len of max id */
for (ix = 0; ix < len; ix++)
printf("0x%02X ", mtd_info->ids[ix]);
printf("\nName:\"%s\"\n", mtd_info->name);
}
return 0;
}
#endif
static int do_getinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *cmd = NULL;
if (argc < 2) { /* 2:len of argv */
cmd_usage(cmdtp);
return -1;
}
cmd = argv[1];
if (strcmp(cmd, "bootmode") == 0) {
switch (get_boot_media()) {
default:
case BOOT_MEDIA_UNKNOWN:
printf("Boot from unknown device,"
" please check your hardware config.\n");
return -1;
case BOOT_MEDIA_NAND:
printf("nand\n");
break;
case BOOT_MEDIA_SPIFLASH:
printf("spi\n");
break;
case BOOT_MEDIA_EMMC:
printf("emmc\n");
break;
case BOOT_MEDIA_UFS:
printf("ufs\n");
break;
}
return 0;
}
if (strcmp(cmd, "version") == 0) {
printf("version: %s\n", U_BOOT_VERSION);
return 0;
}
#if defined(CONFIG_FMC_SPI_NAND) || defined(CONFIG_FMC_NAND)
if (strcmp(cmd, "nand") == 0) {
struct mtd_info_ex *mtd_info = NULL;
mtd_info = get_nand_info();
return print_mtd_info(mtd_info, cmd);
}
#endif
#ifdef CONFIG_FMC_SPI_NOR
if (strcmp(cmd, "spi") == 0) {
struct mtd_info_ex *mtd_info = NULL;
mtd_info = get_spiflash_info();
return print_mtd_info(mtd_info, cmd);
}
#endif
return 0;
}
U_BOOT_CMD(
getinfo, CONFIG_SYS_MAXARGS, 1, do_getinfo,
"print hardware information",
"bootmode - get start memeory type e.g. nand/spi etc\n"
"getinfo nand - get nand flash information\n"
"getinfo spi - get spi flash information\n"
"getinfo version - get system version\n"
);
@@ -0,0 +1,80 @@
#define pr_fmt(fmt) "%s: " fmt, "LOAD MCU S2"
#include <common.h>
#include <malloc.h>
#include <linux/io.h>
#include <linux/lotus/flash_read.h>
#include <linux/lotus/image.h>
static int do_load_mcu_stage2(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
int ret = -1;
u32 res, aligned_offset, aligned_size;
u32 total_size;
u32 stage1_size;
u32 mcu_offset = CONFIG_MCU_FW_AREA_POS;
struct mcu_fw_head *fw_head = (struct mcu_fw_head *)MCU_SRAM_BASE;
u8 *buf = (u8 *)CONFIG_MCU_FW_BUF_ADDR;
u32 v;
if (CONFIG_LOAD_MCU_FW_FLAG == 0 || CONFIG_MCU_FW_AREA_LEN == 0)
goto error;
if (fw_head->fw_magic != _MCU_FW_MAGIC) {
pr_info("No MCU FW\n");
goto error;
}
total_size = fw_head->fw_total_size;
stage1_size = fw_head->fw_stage1_size;
if (total_size < stage1_size
|| (((total_size + 1024 - 1) >> 10) & (~((1 << 10) - 1))) != 0) {
pr_err("Invalid MCU FW size!Total: %u, Stage1: %u\n", total_size, stage1_size);
goto error;
}
res = mcu_offset & (FLASH_ALIGNED_SIZE - 1);
aligned_offset = rounddown(mcu_offset, FLASH_ALIGNED_SIZE);
aligned_size = roundup(total_size + res, FLASH_ALIGNED_SIZE);
if (aligned_size > CONFIG_MCU_FW_BUF_SIZE) {
pr_err("No buffer for MCU FW!\n");
goto error;
}
ret = flash_read(aligned_offset, aligned_size, buf);
if (ret != 0) {
pr_err("Fail to read MCU area!\n");
goto error;
}
memcpy((void *)MCU_SRAM_BASE + stage1_size, buf + res + stage1_size, total_size - stage1_size);
memmove(buf, buf + res, total_size);
printf("MCU FW location in DDR: 0x%x, 0x%x Bytes\n", (u32)buf, total_size);
v = readl(REG_MCU_FW_DDR_SIZE);
v &= ~((1 << 10) - 1);
v |= (total_size + 1024 - 1) >> 10;
writel(v, REG_MCU_FW_DDR_SIZE);
dsb();
isb();
/* Release MCU to stage2 */
writel(0xbeef0001, SYS_CTRL_REG_BASE + REG_SC_SYSBOOT7);
dsb();
isb();
return 1;
error:
return CMD_RET_FAILURE;
}
U_BOOT_CMD(
loadmcustage2, 1, 0, do_load_mcu_stage2,
"Load MCU Stage2",
"loadmcustage2\n"
""
);
@@ -0,0 +1,84 @@
#include <common.h>
#include <image.h>
#include <linux/compiler.h>
#include <bootm.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <asm/mach-types.h>
#include <linux/libfdt.h>
#include <mapmem.h>
#include <serial.h>
#include <linux/lotus/flash_read.h>
#include <linux/lotus/timestamp.h>
unsigned long ticks2usec(unsigned long ticks)
{
ulong tbclk = get_tbclk();
tbclk /= 1000000;
ticks /= tbclk;
return ((ulong)ticks);
}
unsigned long relocate_dtb(bootm_headers_t *bootm_hdr)
{
image_info_t os;
void *image_buf;
ulong image_size;
if (!bootm_hdr) {
pr_err("Invalid params for %s\n", __func__);
return 0;
}
os = bootm_hdr->os;
image_size = os.image_len;
image_buf = map_sysmem(os.image_start, image_size);
pr_info("Image addr 0x%lX, len 0x%lX\n", (ulong)image_buf, image_size);
memmove((char *)CONFIG_DTB_BASE, (char *)(image_buf + image_size), CONFIG_DTB_MAX_SIZE);
return CONFIG_DTB_BASE;
}
void show_boot_timestamp(void)
{
char *show_timestamp;
TIME_STAMP(0);
stopwatch_trigger();
show_timestamp = env_get("timestamp");
if (*show_timestamp == 'y') {
serial_enable_output(true);
timestamp_print(0);
stopwatch_print();
}
}
#ifndef CONFIG_AUTOBOOT
int board_run_command(const char *cmdline)
{
int ret = -1;
int (*entry)(void *) = (void *)CONFIG_SBL_LOAD_ADDR;
ret = flash_read(CONFIG_SBL_OFFSET, CONFIG_SBL_SIZE, (void *)CONFIG_SBL_LOAD_ADDR);
if (ret != 0) {
pr_err("Fail to read from flash\n");
goto error;
}
printf ("## Starting SBL at 0x%08lX ...\n", (ulong)CONFIG_SBL_LOAD_ADDR);
dsb();
isb();
ret = entry(NULL);
printf ("## SBL terminated, ret = %d\n", ret);
error:
return 1;
}
#endif
+28
View File
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0
#include <common.h>
#define CFG_MAX_SHUTDOWN 10
static struct shutdown_ctrl {
int count;
void (*shutdown[CFG_MAX_SHUTDOWN])(void);
} shutdown_ctrl = {0, {0}, };
void add_shutdown(void (*shutdown)(void))
{
if (shutdown_ctrl.count >= CFG_MAX_SHUTDOWN) {
printf("Can't add shutdown function,"
"Please increase CFG_MAX_SHUTDOWN count\n");
return;
}
shutdown_ctrl.shutdown[shutdown_ctrl.count++]
= shutdown;
}
void do_shutdown(void)
{
int ix;
for (ix = 0; ix < shutdown_ctrl.count; ix++)
shutdown_ctrl.shutdown[ix]();
}
+357
View File
@@ -0,0 +1,357 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include <common.h>
#include <command.h>
#include <div64.h>
#include <mmc.h>
#include <image-sparse.h>
/******************************************************************************/
#ifdef CONFIG_CMD_UFS
#include <ufs.h>
#define UFS_BLKSIZE_SHIFT (12)
#endif
#define EMMC_BLKSIZE_SHIFT (9)
#define SZ_1M_SHIFT (20)
/* #define DEBUG_EXT4 */
/******************************************************************************/
void print_header_info(sparse_header_t *header)
{
#ifdef DEBUG_EXT4
printf("sparse header info:\n");
printf("magic: 0x%x\n", header->magic);
printf("major_version: 0x%x\n", header->major_version);
printf("minor_version: 0x%x\n", header->minor_version);
printf("file_hdr_sz: %d\n", header->file_hdr_sz);
printf("chunk_hdr_sz: %d\n", header->chunk_hdr_sz);
printf("blk_sz: %d\n", header->blk_sz);
printf("total_blks: %d\n", header->total_blks);
printf("total_chunks: %d\n", header->total_chunks);
printf("image_checksum: %d\n", header->image_checksum);
#endif
}
void print_chunk_info(const chunk_header_t *chunk)
{
#ifdef DEBUG_EXT4
printf("\n");
printf("chunk header info:\n");
printf("chunk_type: 0x%x\n", chunk->chunk_type);
printf("chunk_sz: %d\n", chunk->chunk_sz);
printf("total_sz: %d\n", chunk->total_sz);
#endif
}
int get_unspare_header_info(const u8 *pbuf, sparse_header_t *sparse_header, char* is_sparse)
{
memcpy(sparse_header, pbuf, sizeof(sparse_header_t));
if (!is_sparse_image(sparse_header)) {
*is_sparse = 0;
return 0;
}
*is_sparse = 1;
print_header_info(sparse_header);
return 0;
}
static int check_parameter(sparse_header_t *header, u32 cnt, unsigned int type)
{
u64 img_size;
if (!is_sparse_image(header)) {
printf("Invalid sparse format.\n");
return 1;
}
/* check header->blk_sz align to emmc block size */
if (type == 0) /* 0: ext4_unsparse 1: ufs_ext4_unsparse */
if (header->blk_sz & ((1 << EMMC_BLKSIZE_SHIFT) - 1)) {
printf("image blk size %d is not aligned to 512Byte.\n", header->blk_sz);
return 1;
}
#ifdef CONFIG_CMD_UFS
if (type == 1) /* 0: ext4_unsparse 1: ufs_ext4_unsparse */
if (header->blk_sz & ((1 << UFS_BLKSIZE_SHIFT) - 1)) {
printf("image blk size %d is not aligned to 512Byte.\n", header->blk_sz);
return 1;
}
#endif
/* check fs img's real size is larger than partition size */
img_size = (u64)(header->total_blks * header->blk_sz);
if (type == 0) /* 0: ext4_unsparse 1: ufs_ext4_unsparse */
if ((img_size >> EMMC_BLKSIZE_SHIFT) > (u64)cnt) {
printf("partition size %d MB not enough.\n",
(int)(cnt >> (SZ_1M_SHIFT - EMMC_BLKSIZE_SHIFT)));
print_header_info(header);
return 1;
}
#ifdef CONFIG_CMD_UFS
if (type == 1) /* 0: ext4_unsparse 1: ufs_ext4_unsparse */
if ((img_size >> UFS_BLKSIZE_SHIFT) > (u64)cnt) {
printf("partition size %d MB not enough.\n",
(int)(cnt >> (SZ_1M_SHIFT - UFS_BLKSIZE_SHIFT)));
print_header_info(header);
return 1;
}
#endif
return 0;
}
static void print_writing_complete(u64 sparse_len, s32 *percent_complete, u32 cnt, u32 blk, unsigned int type)
{
u64 n;
int percent;
if (type == 0) /* 0: ext4_unsparse 1: ufs_ext4_unsparse */
n = (u64)(sparse_len >> EMMC_BLKSIZE_SHIFT) * 100; /* 100: Percentage for complete */
#ifdef CONFIG_CMD_UFS
if (type == 1) /* 0: ext4_unsparse 1: ufs_ext4_unsparse */
n = (u64)(sparse_len >> UFS_BLKSIZE_SHIFT) * 100; /* 100: Percentage for complete */
#endif
do_div(n, cnt);
percent = (int)n;
if (percent != *percent_complete) {
*percent_complete = percent;
if (type == 0) /* 0: ext4_unsparse 1: ufs_ext4_unsparse */
printf("\rWriting at %d blk# "
"-- %3d%% complete. \n",
(int)(blk + (sparse_len >> EMMC_BLKSIZE_SHIFT)), percent);
#ifdef CONFIG_CMD_UFS
if (type == 1) /* 0: ext4_unsparse 1: ufs_ext4_unsparse */
printf("\rWriting at %d blk# "
"-- %3d%% complete.\n",
(int)(blk + (sparse_len >> UFS_BLKSIZE_SHIFT)), percent);
#endif
}
}
static int check_print_results(u64 dense_len, u64 sparse_len, u32 cnt, unsigned int type)
{
if (type == 0) /* 0: ext4_unsparse 1: ufs_ext4_unsparse */
if (((u64)cnt << EMMC_BLKSIZE_SHIFT) != sparse_len) {
printf("error: partition size %d MB != ext4 image size %d MB\n",
(int)(cnt >> (SZ_1M_SHIFT - EMMC_BLKSIZE_SHIFT)),
(int)(sparse_len >> SZ_1M_SHIFT));
return 1;
}
#ifdef CONFIG_CMD_UFS
if (type == 1) /* 0: ext4_unsparse 1: ufs_ext4_unsparse */
if (((u64)cnt << UFS_BLKSIZE_SHIFT) != sparse_len) {
printf("error: partition size %d MB != ext4 image size %d MB\n",
(int)(cnt >> (SZ_1M_SHIFT - UFS_BLKSIZE_SHIFT)),
(int)(sparse_len >> SZ_1M_SHIFT));
return 1;
}
#endif
printf("sparse: %d MB / %d MB.\n", (int)(dense_len >> SZ_1M_SHIFT), (int)(sparse_len >> SZ_1M_SHIFT));
return 0;
}
int ext4_unsparse(struct mmc *mmc, u32 dev, u8 *pbuf, u32 blk, u32 cnt)
{
u32 i, num;
u64 dense_len = 0;
u64 sparse_len = 0;
u32 chunk_len;
s32 percent_complete = -1;
chunk_header_t *chunk = NULL;
sparse_header_t *header = (sparse_header_t *)pbuf;
check_parameter(header, cnt, 0);
/* skip the sparse header,to visit first chunk */
pbuf += header->file_hdr_sz;
/* to visit each chunk */
for (i = 0; i < header->total_chunks; i++) {
/* here the chunk_header */
chunk = (chunk_header_t *)pbuf;
/* go to next chunk's data */
pbuf += header->chunk_hdr_sz;
switch (chunk->chunk_type) {
case CHUNK_TYPE_RAW:
/* to calculate the length of each chunk */
chunk_len = chunk->chunk_sz * header->blk_sz;
/* verify every chunk to asure it is valid */
if (chunk->total_sz != (chunk_len + header->chunk_hdr_sz)) {
printf("No.%d chunk size error.\n", i);
print_chunk_info(chunk);
return 1;
}
dense_len += chunk_len;
sparse_len += chunk_len;
if (sparse_len > ((u64)cnt << EMMC_BLKSIZE_SHIFT)) {
printf("error: sparse size %d MB is "
"larger than partiton size %d MB.\n",
(int)(sparse_len >> SZ_1M_SHIFT),
(int)(cnt >> (SZ_1M_SHIFT - EMMC_BLKSIZE_SHIFT)));
print_chunk_info(chunk);
return 1;
}
num = blk_dwrite(mmc_get_blk_desc(mmc), blk,
(chunk_len >> EMMC_BLKSIZE_SHIFT), pbuf);
if (num != (chunk_len >> EMMC_BLKSIZE_SHIFT)) {
printf("Raw data: No.%d blocks written: %s.\n", num, "ERROR");
return 1;
}
pbuf += chunk_len;
blk += (chunk_len >> EMMC_BLKSIZE_SHIFT);
break;
case CHUNK_TYPE_DONT_CARE:
if (chunk->total_sz != header->chunk_hdr_sz) {
printf("No.%d chunk size error.\n", i);
print_chunk_info(chunk);
return 1;
}
chunk_len = chunk->chunk_sz * header->blk_sz;
sparse_len += chunk_len;
if (sparse_len > ((u64)cnt << EMMC_BLKSIZE_SHIFT)) {
printf("error: sparse size %d MB is "
"larger than partiton size %d MB.\n",
(int)(sparse_len >> SZ_1M_SHIFT),
(int)(cnt >> (SZ_1M_SHIFT - EMMC_BLKSIZE_SHIFT)));
print_chunk_info(chunk);
return 1;
}
blk += (chunk_len >> EMMC_BLKSIZE_SHIFT);
break;
default:
printf("sparse: unknow chunk type %04x.\n",
chunk->chunk_type);
return 1;
}
print_writing_complete(sparse_len, &percent_complete, cnt, blk, 0);
}
puts("\n");
if (check_print_results(dense_len, sparse_len, cnt, 0))
return 1;
return 0;
}
#ifdef CONFIG_CMD_UFS
int ufs_ext4_unsparse(const u8 *pbuf, u32 blk, u32 cnt)
{
u32 i, num;
u64 dense_len = 0;
u64 sparse_len = 0;
u32 chunk_len;
s32 percent_complete = -1;
chunk_header_t *chunk = NULL;
sparse_header_t *header = (sparse_header_t *)pbuf;
check_parameter(header, cnt, 1);
/* skip the sparse header,to visit first chunk */
pbuf += header->file_hdr_sz;
/* to visit each chunk */
for (i = 0; i < header->total_chunks; i++) {
/* here the chunk_header */
chunk = (chunk_header_t *)pbuf;
/* go to next chunk's data */
pbuf += header->chunk_hdr_sz;
switch (chunk->chunk_type) {
case CHUNK_TYPE_RAW:
/* to calculate the length of each chunk */
chunk_len = chunk->chunk_sz * header->blk_sz;
/* verify every chunk to asure it is valid */
if (chunk->total_sz
!= (chunk_len + header->chunk_hdr_sz)) {
printf("No.%d chunk size error.\n", i);
print_chunk_info(chunk);
return 1;
}
dense_len += chunk_len;
sparse_len += chunk_len;
if (sparse_len > ((u64)cnt << UFS_BLKSIZE_SHIFT)) {
printf("error: sparse size %d MB is "
"larger than partiton size %d MB.\n",
(int)(sparse_len >> SZ_1M_SHIFT),
(int)(cnt >> (SZ_1M_SHIFT - UFS_BLKSIZE_SHIFT)));
print_chunk_info(chunk);
return 1;
}
if (ufs_write_storage((uint64_t)pbuf,
(blk << UFS_BLKSIZE_SHIFT),
chunk_len) == 0)
num = chunk_len >> UFS_BLKSIZE_SHIFT;
else
num = 0;
if (num != (chunk_len >> UFS_BLKSIZE_SHIFT)) {
printf("Raw data: No.%d blocks written: %s.\n",
num, "ERROR");
return 1;
}
pbuf += chunk_len;
blk += (chunk_len >> UFS_BLKSIZE_SHIFT);
break;
case CHUNK_TYPE_DONT_CARE:
if (chunk->total_sz != header->chunk_hdr_sz) {
printf("No.%d chunk size error.\n", i);
print_chunk_info(chunk);
return 1;
}
chunk_len = chunk->chunk_sz * header->blk_sz;
sparse_len += chunk_len;
if (sparse_len > ((u64)cnt << UFS_BLKSIZE_SHIFT)) {
printf("error: sparse size %d MB is "
"larger than partiton size %d MB.\n",
(int)(sparse_len >> SZ_1M_SHIFT),
(int)(cnt >> (SZ_1M_SHIFT - UFS_BLKSIZE_SHIFT)));
print_chunk_info(chunk);
return 1;
}
blk += (chunk_len >> UFS_BLKSIZE_SHIFT);
break;
default:
printf("sparse: unknown chunk type %04x.\n",
chunk->chunk_type);
return 1;
}
print_writing_complete(sparse_len, &percent_complete, cnt, blk, 1);
}
puts("\n");
if (check_print_results(dense_len, sparse_len, cnt, 1))
return 1;
return 0;
}
#endif
+12
View File
@@ -0,0 +1,12 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __UNSPARSE__
#define __UNSPARSE__
int get_unspare_header_info(const u8 *pbuf, sparse_header_t *sparse_header, char *is_sparse);
void print_chunk_info(chunk_header_t *chunk);
int ext4_unsparse(struct mmc *mmc, u32 dev, u8 *pbuf, u32 blk, u32 cnt);
void print_header_info(sparse_header_t *header);
#endif