sdk-hwV1.3/lichee/brandy-2.0/u-boot-2018/cmd/sunxi_flash.c

318 lines
8.8 KiB
C

/*
* (C) Copyright 2013-2016
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
*
* wangwei <wangwei@allwinnertech.com>
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <config.h>
#include <command.h>
#include <sunxi_board.h>
#include <malloc.h>
#include <memalign.h>
#include <sunxi_flash.h>
#include <part.h>
#include <image.h>
#include <android_image.h>
#include <rtos_image.h>
#include <sys_partition.h>
#include <sprite_download.h>
#include "../sprite/sparse/sparse.h"
DECLARE_GLOBAL_DATA_PTR;
#define SUNXI_FLASH_READ_FIRST_SIZE (32 * 1024)
static int sunxi_flash_read_part(struct blk_desc *desc, disk_partition_t *info,
ulong buffer, ulong load_size)
{
int ret;
u32 rbytes, rblock, testblock;
u32 start_block;
u8 *addr;
image_header_t *uz_hdr;
addr = (void *)buffer;
start_block = (uint)info->start;
#ifdef CONFIG_SUNXI_RTOS
struct rtos_img_hdr *rtos_hdr;
rtos_hdr = (struct rtos_img_hdr *)addr;
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
struct andr_img_hdr *fb_hdr;
fb_hdr = (struct andr_img_hdr *)addr;
#endif
testblock = SUNXI_FLASH_READ_FIRST_SIZE / 512;
ret = blk_dread(desc, start_block, testblock, (u_char *)buffer);
if (ret != testblock) {
return 1;
}
uz_hdr = (image_header_t *)addr;
if (load_size)
rbytes = load_size;
#ifdef CONFIG_ANDROID_BOOT_IMAGE
else if (!memcmp(fb_hdr->magic, ANDR_BOOT_MAGIC, 8)) {
rbytes = android_image_get_end_by_avbfooter();
//image size from avbfooter have higher priority
if (!rbytes) {
rbytes = android_image_get_end(fb_hdr) - (ulong)fb_hdr;
/*secure boot img may attached with an embbed cert*/
rbytes += sunxi_boot_image_get_embbed_cert_len(fb_hdr);
}
}
#endif
else if (image_check_magic(uz_hdr)) {
rbytes = image_get_data_size(uz_hdr) + image_get_header_size();
}
#ifdef CONFIG_SUNXI_RTOS
else if (!memcmp(rtos_hdr->rtos_magic, RTOS_BOOT_MAGIC, 8)) {
rbytes = sizeof(struct rtos_img_hdr) + rtos_hdr->rtos_size;
}
#endif
else {
debug("bad boot image magic, maybe not a boot.img?\n");
rbytes = info->size * 512;
}
rblock = (rbytes + 511) / 512 - testblock;
start_block += testblock;
addr += SUNXI_FLASH_READ_FIRST_SIZE;
ret = blk_dread(desc, start_block, rblock, (u_char *)addr);
ret = (ret == rblock) ? 0 : 1;
sunxi_mem_info((char *)info->name, (void *)buffer, rbytes);
debug("sunxi flash read :offset %x, %d bytes %s\n", (u32)info->start,
rbytes, ret == 0 ? "OK" : "ERROR");
return ret;
}
#include "private_boot0.h"
#include "private_toc.h"
extern int sunxi_flash_upload_boot0(char *buffer, int size, int backup_id);
void reset_boot_dram_update_flag(u32 *dram_para);
int do_sunxi_flash_boot0(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
{
if (argc != 3)
return -1;
uint8_t *boot0_buffer;
uint32_t len;
uint32_t *ptr_newval;
uint32_t new_val;
uint32_t *check_sum;
boot0_file_head_t *boot0 = NULL;
sbrom_toc0_config_t *toc0_config = NULL;
boot0_buffer = malloc(1 * 1024 * 1024);
if (!boot0_buffer) {
pr_err("failed to malloc for boot0\n");
return -1;
}
sunxi_flash_upload_boot0((char *)boot0_buffer, 1 * 1024 * 1024,
0);
/* Check the legitimacy of boot0/sboot */
if (sunxi_get_secureboard() == 0) {
boot0 = (boot0_file_head_t *)boot0_buffer;
if (strncmp((const char *)boot0->boot_head.magic,
BOOT0_MAGIC, MAGIC_SIZE)) {
printf("sunxi sprite: boot0 magic is error\n");
return -1;
}
len = boot0->boot_head.length;
check_sum = &boot0->boot_head.check_sum;
} else {
toc0_private_head_t *toc0 =
(toc0_private_head_t *)boot0_buffer;
if (strncmp((const char *)toc0->name, TOC0_MAGIC,
MAGIC_SIZE)) {
printf("sunxi sprite: toc0 magic is error, need secure image\n");
return -1;
}
len = toc0->length;
if (toc0->items_nr == 3)
toc0_config =
(sbrom_toc0_config_t *)(boot0_buffer +
0xa0);
else
toc0_config =
(sbrom_toc0_config_t *)(boot0_buffer +
0x80);
check_sum = &toc0->check_sum;
}
/* get set value */
new_val = simple_strtoul(argv[2], NULL, 16);
/* Get the location that needs to be modified */
if (!strcmp(argv[1], "force_dram_update_flag")) {
if (sunxi_get_secureboard() == 0) {
ptr_newval = boot0->prvt_head.dram_para;
} else {
ptr_newval = toc0_config->dram_para;
}
if (new_val) {
printf("set dram flag\n");
set_boot_dram_update_flag(ptr_newval);
} else {
printf("reset dram flag\n");
reset_boot_dram_update_flag(ptr_newval);
}
} else if (!strcmp(argv[1], "force_dram_update_size")) {
if (sunxi_get_secureboard() == 0) {
ptr_newval = &boot0->dram_size;
} else {
ptr_newval = &toc0_config->dram_size;
}
*ptr_newval = new_val;
printf("set dram %dM\n", *ptr_newval);
} else {
printf("do_sunxi_flash_boot0:no command\n");
return -1;
}
*check_sum =
sunxi_generate_checksum(boot0_buffer, len, 1, *check_sum);
return sunxi_sprite_download_spl(boot0_buffer, len,
get_boot_storage_type());
return -1;
}
int do_sunxi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
struct blk_desc *desc;
disk_partition_t info = { 0 };
ulong load_addr;
ulong load_size = 0;
char *cmd;
char *part_name;
int ret;
#ifdef CONFIG_SUNXI_SPRITE
static int partdata_format;
#endif
if (!strcmp("boot0", argv[1])) {
argc--;
argv++;
return do_sunxi_flash_boot0(cmdtp, flag, argc, argv);
}
/* at least four arguments please */
if (argc < 4)
goto usage;
#ifdef CONFIG_SUNXI_SPRITE
else if (argc < 5)
partdata_format = 0;
#endif
cmd = argv[1];
part_name = argv[3];
if (strncmp(cmd, "read", strlen("read")) == 0) {
load_addr = (ulong)simple_strtoul(argv[2], NULL, 16);
if (argc == 5)
load_size = (ulong)simple_strtoul(argv[4], NULL, 16);
env_set("boot_from_partion", part_name);
}
#ifdef CONFIG_SUNXI_SPRITE
else if (!strncmp(cmd, "write", strlen("write"))) {
load_addr = (ulong)simple_strtoul(argv[2], NULL, 16);
if (!strncmp(part_name, "boot_package", strlen("boot_package")) ||
!strncmp(part_name, "uboot", strlen("uboot")) ||
!strncmp(part_name, "toc1", strlen("toc1"))) {
return sunxi_sprite_download_uboot((void *)load_addr, get_boot_storage_type(), 0);
} else if (!strncmp(part_name, "boot0", strlen("boot0")) ||
!strncmp(part_name, "toc0", strlen("toc0"))) {
return sunxi_sprite_download_boot0((void *)load_addr, get_boot_storage_type());
}
#if defined(CONFIG_AW_MTD_SPINAND) || defined(CONFIG_AW_MTD_RAWNAND)
if (strncmp(cmd, "write_mtd", strlen("write_mtd")) == 0) {
ret = sunxi_partition_parse(part_name, &info);
if (ret < 0)
return -1;
info.size = (info.size + 511) / 512;
ret = sunxi_flash_phywrite(info.start, info.size, (void *)load_addr);
sunxi_flash_flush();
return ret;
}
#endif
/* write size: indecated on partemeter 1 */
if (sunxi_partition_get_info_byname(part_name, (uint *)&info.start, (uint *)&info.size))
goto usage;
if (argc == 5) {
/* write size: partemeter 2 */
info.size = ALIGN((u32)simple_strtoul(argv[4], NULL, 16), 512)/512;
} else if (argc == 6) {
info.start += ALIGN((u32)simple_strtoul(argv[4], NULL, 16), 512)/512;
info.size = ALIGN((u32)simple_strtoul(argv[5], NULL, 16), 512)/512;
if (simple_strtoul(argv[4], NULL, 16) == 0) {
partdata_format = unsparse_probe((char *)load_addr, info.size*512, (u32)info.start);
pr_msg("partdata_format:%d\n", partdata_format);
}
}
if (partdata_format != ANDROID_FORMAT_DETECT) {
ret = sunxi_flash_write(info.start, info.size, (void *)load_addr);
} else {
ret = unsparse_direct_write((void *)load_addr, (u32)simple_strtoul(argv[5], NULL, 16)) ? 0 : 1;
}
sunxi_flash_flush();
pr_msg("sunxi flash write :offset %lx, %d bytes %s\n", info.start, info.size*512,
ret ? "OK" : "ERROR");
return ret;
}
#endif
else {
goto usage;
}
#if defined(CONFIG_AW_MTD_SPINAND) || defined(CONFIG_AW_MTD_RAWNAND)
if (strncmp(cmd, "read_mtd", strlen("read_mtd")) == 0) {
ret = sunxi_partition_parse(part_name, &info);
if (ret < 0)
return -1;
if (load_size)
info.size = load_size;
info.size = (info.size + 511) / 512;
return sunxi_flash_phyread(info.start, info.size, (void *)load_addr);
}
#endif
desc = blk_get_devnum_by_typename("sunxi_flash", 0);
if (desc == NULL)
return -ENODEV;
ret = sunxi_flash_try_partition(desc, part_name, &info);
if (ret < 0)
return -ENODEV;
pr_msg("partinfo: name %s, start 0x%lx, size 0x%lx\n", info.name,
info.start, info.size);
return sunxi_flash_read_part(desc, &info, load_addr, load_size);
usage:
return cmd_usage(cmdtp);
}
U_BOOT_CMD(sunxi_flash, 6, 1, do_sunxi_flash, "sunxi_flash sub-system",
"sunxi_flash read mem_addr part_name [size]\n"
"sunxi_flash read_mtd mem_addr part_name [size]\n"
"sunxi_flash write <mem_addr> <part_name> [size]\n"
"sunxi_flash write <mem_addr> <part_name> [offset] [size]\n"
"sunxi_flash write_mtd <mem_addr> <part_name>\n"
"sunxi_flash boot0 force_dram_update_size <new_val> \n"
"sunxi_flash boot0 force_dram_update_flag <new_val> \n");