Files
gk-sdk/source/bootloader/product/update/auto_update_adapter.c
T

1304 lines
29 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) LOTUS. All rights reserved. */
#include <common.h>
#include <sparse_format.h>
#if (CONFIG_AUTO_UPDATE == 1)
#if (CONFIG_AUTO_USB_UPDATE == 1 || CONFIG_AUTO_SD_UPDATE == 1)
#include <command.h>
#include <malloc.h>
#include <fat.h>
#include <console.h>
#include <linux/io.h>
#include "update_comm.h"
#include "au_nand_flash.h"
#include "au_spinor_flash.h"
#include "au_emmc_flash.h"
#if (UBOOTVERSION == 201611)
#include <environment.h>
#endif
//#define CONFIG_XMEDIA_UPGRADE_BY_SEGMENT 1
#if CONFIG_XMEDIA_UPGRADE_BY_SEGMENT
#define SECTION_SIZE 0x1000000 // 16M
#endif
/* possible names of files on the medium. */
#define AU_CONFIG "config"
#define CONFIG_MAX_SIZE 2048
#define ENV_MAX_LEN (CONFIG_MAX_SIZE / 2)
/* where to load files into memory */
#ifdef CONFIG_BOOT_STORE_ADDR
#define LOAD_ADDR CONFIG_BOOT_STORE_ADDR
#endif
#define MIN(x, y) ((x) > (y) ? (y) : (x))
#include "chip_adapter.h"
typedef enum {
FS_RAW,
FS_JFFS2,
FS_YAFFS2,
FS_EXT4,
FS_UBI,
FS_BUTT
} FS_TYPE;
struct au_store {
loff_t exp_len;
loff_t act_len;
loff_t file_pos;
loff_t file_size;
};
struct au_flash {
unsigned long part_start;
unsigned long part_offset;
unsigned long part_size;
unsigned long write_len;
};
struct au_image {
void *addr;
unsigned long addr_size;
struct au_store store;
struct au_flash flash;
};
static int au_flash_init(int boot_type)
{
int ret = UP_FAILURE;
switch (boot_type) {
case AD_BOOTFROM_SPINOR:
printf("spinor init...\n");
ret = au_spinor_flash_init();
break;
case AD_BOOTFROM_NAND:
printf("nand init...\n");
ret = au_nand_flash_init();
break;
case AD_BOOTFROM_EMMC:
printf("emmc init...\n");
ret = au_emmc_flash_init();
break;
default:
printf("%s: Unkonw flash type.\n", __func__);
}
return ret;
}
static int au_flash_erase(int boot_type, unsigned long offset, unsigned long len)
{
int ret = UP_FAILURE;
switch (boot_type) {
case AD_BOOTFROM_SPINOR:
printf("spinor erase...\n");
ret = au_spinor_flash_erase(offset, len);
break;
case AD_BOOTFROM_NAND:
printf("nand erase...\n");
ret = au_nand_flash_erase(offset, len);
break;
case AD_BOOTFROM_EMMC:
printf("emmc erase...\n");
ret = au_emmc_flash_erase(offset, len);
break;
default:
printf("%s: Unkonw flash type.\n", __func__);
}
return ret;
}
static int au_flash_naked_write(int boot_type, unsigned long offset,
unsigned long len, unsigned long lim, unsigned char* buf)
{
int ret = UP_FAILURE;
switch (boot_type) {
case AD_BOOTFROM_SPINOR:
printf("spinor write...\n");
ret = au_spinor_flash_write(offset, len, lim, buf);
break;
case AD_BOOTFROM_NAND:
printf("nand write...\n");
ret = au_nand_flash_write(offset, len, lim, buf);
break;
case AD_BOOTFROM_EMMC:
printf("emmc write...\n");
ret = au_emmc_flash_write(offset, len, lim, buf);
break;
default:
printf("%s: Unkonw flash type.\n", __func__);
}
return ret;
}
static int au_spinor_fs_write(int fs_type, unsigned long offset,
unsigned long len, unsigned long lim, unsigned char* buf)
{
int ret = UP_FAILURE;
switch (fs_type) {
case FS_JFFS2:
printf("spinor jffs2 write...\n");
ret = au_spinor_flash_jffs_write(offset, len, lim, buf);
break;
case FS_UBI:
printf("spinor ubifs write...\n");
ret = au_spinor_flash_ubifs_write(offset, len, lim, buf);
break;
default:
printf("%s: Unsupport fs type.\n", __func__);
}
return ret;
}
static int au_nand_fs_write(int fs_type, unsigned long offset,
unsigned long len, unsigned long lim, unsigned char* buf)
{
int ret = UP_FAILURE;
switch (fs_type) {
case FS_YAFFS2:
printf("nand yaffs2 write...\n");
ret = au_nand_flash_yaffs_write(offset, len, lim, buf);
break;
case FS_UBI:
printf("nand ubifs write...\n");
ret = au_nand_flash_ubifs_write(offset, len, lim, buf);
break;
default:
printf("%s: Unsupport fs type.\n", __func__);
}
return ret;
}
static int au_emmc_fs_write(int fs_type, unsigned long offset,
unsigned long len, unsigned long lim, unsigned char* buf)
{
int ret = UP_FAILURE;
switch (fs_type) {
case FS_EXT4:
printf("emmc ext4 write...\n");
ret = au_emmc_flash_ext4_write(offset, len, lim, buf);
break;
default:
printf("%s: Unsupport fs type.\n", __func__);
}
return ret;
}
static int au_flash_fs_write(int boot_type, int fs_type, unsigned long offset,
unsigned long len, unsigned long lim, unsigned char* buf)
{
int ret = UP_FAILURE;
switch (boot_type) {
case AD_BOOTFROM_SPINOR:
ret = au_spinor_fs_write(fs_type, offset, len, lim, buf);
break;
case AD_BOOTFROM_NAND:
ret = au_nand_fs_write(fs_type, offset, len, lim, buf);
break;
case AD_BOOTFROM_EMMC:
ret = au_emmc_fs_write(fs_type, offset, len, lim, buf);
break;
default:
printf("%s: Unkonw flash type.\n", __func__);
}
return ret;
}
static unsigned long au_flash_get_page_size(int boot_type, int with_oob)
{
unsigned long page_size = 1;
if (boot_type == AD_BOOTFROM_NAND) {
page_size = (unsigned long)au_nand_flash_get_page_size(with_oob);
} else if (boot_type == AD_BOOTFROM_EMMC){
page_size = (unsigned long)au_emmc_flash_get_block_size();
}
return page_size;
}
static unsigned long au_flash_get_erase_size(int boot_type)
{
int erase_size = 1;
if (boot_type == AD_BOOTFROM_NAND) {
erase_size = au_nand_flash_get_erase_size();
}
return erase_size;
}
static int au_flash_get_bad_blkcnt(int boot_type, unsigned long start, unsigned long len)
{
int count = 0;
if (boot_type == AD_BOOTFROM_NAND) {
count = au_nand_flash_get_bad_blkcnt(start, len);
}
return count;
}
/*
* pick up env form config file and set env
* fail:return -1;
* ok: return 0;
*/
static int env_pick_up(const char *envname, const char *buffer)
{
char *str, *str_s, *str_e;
char env[ENV_MAX_LEN];
str = strstr(buffer, envname);
if (!str) {
printf("ERROR:%s not found!\n", envname);
return UP_FAILURE;
}
str_s = strchr(str, '\'');
if (!str_s) {
printf("ERROR:%s Invalid configuration.\n", envname);
return UP_FAILURE;
}
str_e = strchr(++str_s, '\'');
if (!str_e){
printf("ERROR:%s Invalid configuration.\n", envname);
return UP_FAILURE;
}
if ((unsigned long)(str_e - str_s) > ENV_MAX_LEN) {
printf("ERROR:%s too long!\n", envname);
return UP_FAILURE;
}
strncpy(env, str_s, (size_t)(str_e - str_s));
env[(size_t)(str_e - str_s)] = '\0';
#if (UBOOTVERSION == 202001)
env_set((char *)envname, env);
#elif (UBOOTVERSION == 201611)
setenv((char *)envname, env);
#else
printf("%s:invalid uboot version!\n", __func__);
return UP_FAILURE;
#endif
return UP_SUCCESS;
}
/*
* pick up bootargs and bootcmd from config file and save env
* fail:return -1;
* ok: return 0;
*/
static int get_env_from_config(void)
{
char *aufile = AU_CONFIG;
int ret;
long sz = file_fat_read(aufile, (void *)LOAD_ADDR, CONFIG_MAX_SIZE);
if (sz <= 0) {
printf("ERROR:%s not found!\n", aufile);
return UP_FAILURE;
} else {
debug_print("Load config to %08x, size=%ld.\n", LOAD_ADDR, sz);
}
ret = env_pick_up("bootargs", (char *)LOAD_ADDR);
if (ret < 0) {
return UP_FAILURE;
}
#if 0
ret = env_pick_up("bootcmd", (char *)LOAD_ADDR);
if (ret < 0) {
return UP_FAILURE;
}
#endif
return UP_SUCCESS;
}
/* max. number of files which could interest us */
#define AU_MAXFILES 32
#define NAME_MAX_LEN 0x20
#define DECI_VALUE 10
#define STR_STEPS 2
#define SIZE_M (1024 * 1024)
#define SIZE_K 1024
struct flash_layout {
long start;
long end;
} flash_layout_t;
struct mtd_part_s {
char *str;
int unit;
struct mtd_part_s *next;
};
/* sizes of flash areas for each file */
long ausize[AU_MAXFILES] = {0};
/* array of flash areas start and end addresses */
struct flash_layout aufl_layout[AU_MAXFILES];
/* pointers to file names */
char *aufile[AU_MAXFILES] = {0};
unsigned long aufile_size[AU_MAXFILES] = {0};
char aufile_table[AU_MAXFILES][NAME_MAX_LEN];
/*
* insert node to list
*/
static struct mtd_part_s *list_insert(struct mtd_part_s *head, struct mtd_part_s *node)
{
struct mtd_part_s *p = head;
if (!head)
head = node;
while (p) {
if (p->next == NULL) {
p->next = node;
break;
}
p = p->next;
}
return head;
}
/*
* sort list by str
*/
struct mtd_part_s *mtd_list_sort(struct mtd_part_s *head)
{
int flag;
struct mtd_part_s *p, *pt1, *pt2;
if (!head)
return NULL;
if (head->next == NULL)
return head;
do {
flag = 0;
if ((uintptr_t)(head->str) >= (uintptr_t)
(head->next->str)) {
pt1 = head->next->next;
pt2 = head->next;
pt2->next = head;
head->next = pt1;
head = pt2;
}
for (p = head; p->next->next != NULL; p = p->next) {
if ((uintptr_t)(p->next->str) >= (uintptr_t)
(p->next->next->str)) {
pt1 = p->next->next->next;
pt2 = p->next->next;
pt2->next = p->next;
p->next->next = pt1;
p->next = pt2;
flag = 1;
}
}
} while (flag);
return head;
}
/*
* get mtd parttion info list from env string
*/
static struct mtd_part_s *get_mtd_parts(char *env)
{
char *str = NULL;
struct mtd_part_s *part_p = NULL;
struct mtd_part_s *head = NULL;
if (env == NULL) {
printf("env is null!\n");
return NULL;
}
str = env;
while ((str = strstr(str, "M("))) {
part_p = malloc(sizeof(struct mtd_part_s));
if (part_p == NULL)
return NULL;
part_p->str = str;
part_p->unit = SIZE_M;
part_p->next = NULL;
head = list_insert(head, part_p);
str++;
}
str = env;
while ((str = strstr(str, "K("))) {
part_p = malloc(sizeof(struct mtd_part_s));
if (part_p == NULL)
return NULL;
part_p->str = str;
part_p->unit = SIZE_K;
part_p->next = NULL;
head = list_insert(head, part_p);
str++;
}
head = mtd_list_sort(head);
return head;
}
static unsigned long get_mtd_part_size(const char *str_num)
{
unsigned long size = 0;
int k;
int j = 0;
int num;
while (*str_num >= '0' && *str_num <= '9') {
k = j;
num = *str_num - '0';
while (k) {
num *= DECI_VALUE;
k--;
}
size += num;
j++;
str_num--;
}
return size;
}
static int bootargs_analyze(void)
{
int i;
long start = 0;
char *str = NULL;
char *str_0 = NULL;
char *envp = NULL;
char env[ENV_MAX_LEN] = {0};
struct mtd_part_s *part_p = NULL;
#if (UBOOTVERSION == 202001)
envp = env_get("bootargs");
#elif (UBOOTVERSION == 201611)
envp = getenv("bootargs");
#else
printf("%s:ERROR:invalid uboot version!\n", __func__);
return UP_FAILURE;
#endif
if (envp == NULL) {
printf("ERROR:bootargs is NULL!\n");
return UP_FAILURE;
}
if (strlen(envp) > ENV_MAX_LEN - 1) {
printf("ERROR:bootargs is too long!\n");
return UP_FAILURE;
}
memset(ausize, 0, sizeof(ausize));
memset(aufl_layout, 0, sizeof(aufl_layout));
strcpy(env, envp);
str = env;
str_0 = env;
i = 0;
part_p = get_mtd_parts(env);
while (part_p) {
if (i >= AU_MAXFILES) {
printf("ERROR:Num of partition is more than %0d!\n",
AU_MAXFILES);
break;
}
str = part_p->str;
ausize[i] = get_mtd_part_size(str - 1) * part_p->unit;
aufl_layout[i].start = start;
aufl_layout[i].end = start + ausize[i] - 1;
start += ausize[i];
str += STR_STEPS;
str_0 = strstr(str, ")");
if ((unsigned long)(str_0 - str) > NAME_MAX_LEN) {
printf("file name len is too long\n");
return UP_FAILURE;
}
strncpy(aufile_table[i], str, (unsigned long)(str_0 - str));
aufile_table[i][str_0 - str] = '\0';
aufile[i] = &(aufile_table[i][0]);
printf("\n[%0d]=%-16s start=0x%08lx end=0x%08lx size=0x%08lx",
i, aufile_table[i],
(unsigned long)(aufl_layout[i].start),
(unsigned long)(aufl_layout[i].end),
(unsigned long)ausize[i]);
i++;
part_p = part_p->next;
}
if (i == 0) {
printf("ERROR:Can't find valid partition info!\n");
return UP_FAILURE;
}
return UP_SUCCESS;
}
/*
* offset [param in] : offset within the partition
* success : return 0
* failure : return 1
*/
static int au_do_update(char* file_name, struct au_image* param)
{
int rc = 0;
char *buf = NULL;
void *pbuf = NULL;
int boot_type = get_boot_info();
unsigned long start = param->flash.part_start;
unsigned long part_len = param->flash.part_size;
unsigned long offset = param->flash.part_offset;
/* offset on the entire flash */
unsigned long write_offset = start + offset;
unsigned long write_len = param->flash.write_len;
/* when writing for the first time, erase the entire partition */
if (!offset) {
/* erase the address range. */
if (au_flash_erase(boot_type, start, part_len) == UP_FAILURE) {
printf("sector erase failed\n");
return UP_FAILURE;
}
}
buf = map_physmem((unsigned long)LOAD_ADDR, write_len, MAP_WRBACK);
if (!buf) {
printf("Failed to map physical memory\n");
return UP_FAILURE;
}
/* write the whole file to flash;uboot and rootfs image have head
* kernel has head,it's head also be writed to flash
*/
pbuf = buf;
/* copy the data from RAM to FLASH */
if (strstr(file_name, "yaffs2")) {
rc = au_flash_fs_write(boot_type, FS_YAFFS2, write_offset, write_len, part_len, pbuf);
} else if (strstr(file_name, "ext4")) {
rc = au_flash_fs_write(boot_type, FS_EXT4, write_offset, write_len, part_len, pbuf);
} else if (strstr(file_name, "ubifs")) {
rc = au_flash_fs_write(boot_type, FS_UBI, write_offset, write_len, part_len, pbuf);
} else if (strstr(file_name, "jffs2")) {
rc = au_flash_fs_write(boot_type, FS_JFFS2, write_offset, write_len, part_len, pbuf);
} else {
printf("write flash at 0x%lx, size 0x%lx\n", write_offset, write_len);
rc = au_flash_naked_write(boot_type, write_offset, write_len, part_len, pbuf);
}
if (rc != UP_SUCCESS) {
printf("write flash failed\n");
return UP_FAILURE;
}
unmap_physmem(buf, part_len);
return UP_SUCCESS;
}
static int init_param(unsigned int idx, loff_t file_size, struct au_image* param)
{
unsigned long long addr_size = get_ddr_size();
unsigned long part_size = aufl_layout[idx].end - aufl_layout[idx].start + 1;
unsigned long mem_size;
#ifdef CONFIG_XMEDIA_UPGRADE_BY_SEGMENT
mem_size = SECTION_SIZE;
#else
mem_size = part_size;
#endif
addr_size = addr_size - (CONFIG_BOOT_STORE_ADDR - CONFIG_SYS_SDRAM_BASE) - 0x100000;
mem_size = MIN(mem_size, addr_size);
if (part_size < file_size) {
printf("error: the written file exceeds the partition size\n");
return -1;
}
param->addr = (void*)LOAD_ADDR;
param->addr_size = mem_size;
param->store.file_pos = 0;
param->store.act_len = 0;
param->store.file_size = file_size;
param->store.exp_len = MIN(mem_size, file_size);
param->flash.part_start = aufl_layout[idx].start;
param->flash.part_size = part_size;
param->flash.part_offset = 0;
param->flash.write_len = 0;
return 0;
}
static void set_expect_len(char* file_name, struct au_image* param)
{
unsigned long page_size = 1;
int boot_type = get_boot_info();
if (strstr(file_name, "yaffs2")) {
page_size = au_flash_get_page_size(boot_type, 1);
} else {
page_size = au_flash_get_page_size(boot_type, 0);
}
if (param->addr_size < param->store.file_size) {
param->store.exp_len = (param->addr_size / page_size) * page_size;
} else {
param->store.exp_len = param->store.file_size;
}
}
static void set_write_len(char* file_name, struct au_image* param)
{
if (param->addr_size < param->store.file_size) {
param->flash.write_len = param->store.act_len;
} else {
if (strstr(file_name, "ext4")) {
param->flash.write_len = param->flash.part_size;
} else {
param->flash.write_len = param->store.act_len;
}
}
//printf("write_len: %lu\n", param->flash.write_len);
}
static void set_flash_offset(char* file_name, struct au_image* param)
{
unsigned long sec_yaffs;
unsigned long page_size;
unsigned long erase_size;
unsigned long offset = 0;
unsigned long write_start = param->flash.part_start + param->flash.part_offset;
int bad_blkcnt = 0;
int boot_type = get_boot_info();
sec_yaffs = au_flash_get_page_size(boot_type, 1);
page_size = au_flash_get_page_size(boot_type, 0);
bad_blkcnt = au_flash_get_bad_blkcnt(boot_type, write_start, param->flash.write_len);
erase_size = au_flash_get_erase_size(boot_type);
if (strstr(file_name, "yaffs2")) {
if (param->flash.write_len % sec_yaffs) {
offset = (param->flash.write_len / sec_yaffs + 1) * page_size;
} else {
offset = (param->flash.write_len / sec_yaffs) * page_size;
}
} else {
if (param->flash.write_len % page_size) {
offset = (param->flash.write_len / page_size + 1) * page_size;
} else {
offset = param->flash.write_len / page_size * page_size;
}
}
if (bad_blkcnt) {
printf("Found %d bad blocks\n", bad_blkcnt);
}
offset += (bad_blkcnt * erase_size);
param->flash.part_offset += offset;
//printf("offset: %lu\n", param->flash.part_offset);
}
static int check_mem(unsigned long mem_start, unsigned long size)
{
unsigned long long soc_addr_start = CONFIG_SYS_SDRAM_BASE;
unsigned long long soc_addr_size = get_ddr_size;
unsigned long long soc_addr_end = soc_addr_start + soc_addr_size;
if (mem_start < soc_addr_start) {
printf("Invliad memory addr\n");
return -1;
}
if ((mem_start + size) > soc_addr_end) {
printf("Memory out of bounds.\n");
return -1;
}
return 0;
}
static int get_image(char* file_name, struct au_image* param)
{
set_expect_len(file_name, param);
if (check_mem((unsigned long)param->addr, param->store.exp_len) < 0) {
return -1;
}
memset(param->addr, 0xff, param->store.exp_len);
file_fat_read_at(file_name,
param->store.file_pos,
param->addr,
param->store.exp_len,
&(param->store.act_len));
printf("read %s, exp_len:%lld, act_len:%lld\n",
file_name, param->store.exp_len, param->store.act_len);
set_write_len(file_name, param);
if (param->store.act_len <= 0) {
printf("read %s failed!\n", file_name);
return -1;;
}
param->store.file_pos += param->store.act_len;
return 0;
}
static int check_flash_part(int idx, char* file_name, unsigned long file_size)
{
int bad_block_count;
unsigned int pages_len;
unsigned long part_start = aufl_layout[idx].start;
unsigned long part_end = aufl_layout[idx].end;
unsigned long part_size = part_end - part_start + 1;
int boot_type = get_boot_info();
unsigned int page_size = au_flash_get_page_size(boot_type, 1);
unsigned int write_size = au_flash_get_page_size(boot_type, 0);
unsigned int erase_size = au_flash_get_erase_size(boot_type);
if (part_size < file_size) {
printf("error: the written file exceeds the partition size\n");
return -1;
}
if (strstr(file_name, "yaffs2")) {
if (file_size % page_size) {
pages_len = (file_size / page_size + 1) * write_size;
} else {
pages_len = (file_size / page_size) * write_size;
}
} else {
if (file_size % page_size) {
pages_len = (file_size / write_size + 1) * write_size;
} else {
pages_len = (file_size / write_size) * write_size;
}
}
bad_block_count = au_flash_get_bad_blkcnt(boot_type, part_start, pages_len);
if ((part_end + 1) < (part_start + file_size + (bad_block_count * erase_size))) {
printf("The actual length of the partition is greater\
than the specified value due to the address\
offset caused by bad blocks.\n");
return -1;
}
return 0;
}
static int do_update_ordinary_img(char* img_name, struct au_image* param)
{
int res = -1;
do {
if (get_image(img_name, param) < 0) {
break;
}
/* this is really not a good idea, but it's what the */
/* customer wants. */
do {
res = au_do_update(img_name, param);
/* let the user break out of the loop */
if (ctrlc() || had_ctrlc()) {
clear_ctrlc();
break;
}
set_flash_offset(img_name, param);
} while (res < 0);
} while (param->store.file_size > param->store.file_pos);
return res;
}
static int do_update_special_img(char* img_name, struct au_image* param)
{
int i;
loff_t act_size;
unsigned int tmp_addr_size;
unsigned int exp_size, raw_size;
unsigned int total_chunks;
//unsigned int total_blks;
char *tmp_addr = NULL;
unsigned int tmp_addr_pos = 0;
chunk_header_t chunk_header = {0};
sparse_header_t sparse_header = {0};
int boot_type = get_boot_info();
unsigned long block_size = au_flash_get_page_size(boot_type, 0);
file_fat_read_at(img_name, 0, &sparse_header, sizeof(sparse_header_t), &act_size);
if (act_size != sparse_header.file_hdr_sz) {
printf("Error: file_fat_read sparse_header fail.\n");
return -1;
}
if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
/* For unsparse ext4 image. */
return do_update_ordinary_img(img_name, param);
} else {
/* For sparse ext4 image. */
param->store.file_pos += sparse_header.file_hdr_sz;
//total_blks = sparse_header.total_blks;
total_chunks = sparse_header.total_chunks;
memset(param->addr, 0xFF, param->addr_size);
tmp_addr_pos = 0;
tmp_addr_size = (param->addr_size / block_size) * block_size;
for (i = 0; i < total_chunks; i++) {
file_fat_read_at(img_name, param->store.file_pos, &chunk_header, sizeof(chunk_header_t), &act_size);
if (act_size != sparse_header.chunk_hdr_sz) {
printf("Error: file_fat_read chunk_header fail.\n");
return -1;
}
param->store.file_pos += sparse_header.chunk_hdr_sz;
switch (chunk_header.chunk_type) {
case CHUNK_TYPE_RAW:
//printf("R->chunk:%d, offset:%lu, number: %u\n", i, param->flash.part_offset, chunk_header.chunk_sz);
raw_size = chunk_header.total_sz - sparse_header.chunk_hdr_sz;
if (raw_size > (tmp_addr_size - tmp_addr_pos)) {
do {
exp_size = tmp_addr_size - tmp_addr_pos;
exp_size = (exp_size > raw_size ? raw_size : exp_size);
tmp_addr = (char*)param->addr + tmp_addr_pos;
file_fat_read_at(img_name, param->store.file_pos, tmp_addr, exp_size, &act_size);
if (exp_size != act_size) {
printf("Error: file_fat_read raw fail\n");
return -1;
}
tmp_addr_pos += act_size;
param->store.file_pos += act_size;
raw_size -= act_size;
if (tmp_addr_pos) {
param->flash.write_len = tmp_addr_pos;
if (au_do_update("raw", param) != UP_SUCCESS) {
return -1;
} else {
param->flash.part_offset += tmp_addr_pos;
tmp_addr_pos = 0;
}
}
} while (raw_size);
} else {
// exp_size = chunk_header.chunk_sz * sparse_header.blk_sz;
exp_size = raw_size;
tmp_addr = (char*)param->addr + tmp_addr_pos;
file_fat_read_at(img_name, param->store.file_pos, tmp_addr, exp_size, &act_size);
if (exp_size != act_size) {
printf("Error: file_fat_read raw fail\n");
return -1;
}
tmp_addr_pos += act_size;
param->store.file_pos += act_size;
}
break;
case CHUNK_TYPE_DONT_CARE:
//printf("D->chunk:%d, offset:%lu, number: %u\n", i, param->flash.part_offset, chunk_header.chunk_sz);
if (tmp_addr_pos) {
param->flash.write_len = tmp_addr_pos;
if (au_do_update("raw", param) != UP_SUCCESS) {
return -1;
} else {
param->flash.part_offset += tmp_addr_pos;
tmp_addr_pos = 0;
}
}
raw_size = chunk_header.chunk_sz * sparse_header.blk_sz;
param->flash.part_offset += raw_size;
break;
case CHUNK_TYPE_FILL:
printf("Error: Unsupport chunk type.\n");
break;
default:
printf("Error: Unkonw chunk type.\n");
break;
}
if (tmp_addr_pos == tmp_addr_size) {
param->flash.write_len = tmp_addr_pos;
if (au_do_update("raw", param) != UP_SUCCESS) {
return -1;
} else {
param->flash.part_offset += tmp_addr_pos;
tmp_addr_pos = 0;
}
}
}
if (tmp_addr_pos) {
param->flash.write_len = tmp_addr_pos;
if (au_do_update("raw", param) != UP_SUCCESS) {
return -1;
} else {
param->flash.part_offset += tmp_addr_pos;
tmp_addr_pos = 0;
}
}
}
return 0;
}
/*
* If none of the update file(u-boot, bootargs, kernel or rootfs) was found
* in the medium, return -1;
* Others, return 0;
*/
static int update_to_flash(void)
{
int i;
int res = -1;
int updatefile_found = 0;
struct au_image param = {0};
loff_t file_size = 0;
/* just loop thru all the possible files */
for (i = 0; i < AU_MAXFILES && aufile[i] != NULL; i++) {
printf("\n");
if (!fat_exists(aufile[i])) {
printf("%s not found!\n", aufile[i]);
continue;
}
/* get file's real size */
if (!fat_size(aufile[i], &file_size)) {
//file_size = ALIGN((unsigned long)file_size, CONFIG_SYS_CACHELINE_SIZE);
} else {
printf("get file size of %s failed!\n", aufile[i]);
continue;
}
printf("%s size=0x%08llx\n", aufile[i], file_size);
if (check_flash_part(i, aufile[i], file_size) < 0) {
continue;
}
if (init_param(i, file_size, &param) < 0) {
continue;
}
if ((strstr(aufile[i], "ext4")) && (param.addr_size < param.store.file_size)) {
res = do_update_special_img(aufile[i], &param);
} else {
res = do_update_ordinary_img(aufile[i], &param);
}
if (res == 0)
updatefile_found = 1;
}
if (updatefile_found == 1)
return UP_SUCCESS;
else
return UP_FAILURE;
}
#endif // CONFIG_AUTO_SD_UPDATE || CONFIG_AUTO_USB_UPDATE
#if (CONFIG_AUTO_SD_UPDATE == 1)
#ifndef CONFIG_MMC
#error "should have defined CONFIG_MMC"
#endif
#include "store_mmc.h"
static int is_mmc(void)
{
const char dev_name[8] = "mmc";
int part_no = 0;
int dev_no = 0;
struct blk_desc *stor_dev;
if (store_mmc_init() != UP_SUCCESS) {
return UP_FALSE;
}
dev_no = mmc_get_target_dev();
if (dev_no < 0) {
return UP_FALSE;
}
stor_dev = blk_get_dev(dev_name, dev_no);
if (stor_dev == NULL) {
printf("Unknown device type!\n");
return UP_FALSE;
}
retry:
debug_print("device name %s, device [%d], part[%d].\n", dev_name, dev_no, part_no);
if (fat_register_device(stor_dev, part_no) != 0) {
printf("Unable to use %s %d:%d for fatls\n", dev_name, dev_no, part_no);
if (++part_no <= 4) {
goto retry;
}
return UP_FALSE;
}
#if 0
if (file_fat_detectfs() != 0) {
printf("file_fat_detectfs failed\n");
return UP_FALSE;
}
return UP_TRUE;
#else
if (fat_exists("u-boot.bin") || fat_exists("config")) {
return UP_TRUE;
} else if (++part_no <= 4) {
goto retry;
} else {
printf("File not found\n");
}
return UP_FALSE;
#endif
}
static int update_by_mmc(void)
{
int boot_type = get_boot_info();
int state = UP_FAILURE;
int old_ctrlc;
if (is_mmc() != UP_TRUE) {
store_mmc_deinit();
return UP_FAILURE;
}
if (au_flash_init(boot_type) == UP_FAILURE) {
store_mmc_deinit();
return UP_FAILURE;
}
if (get_env_from_config() == UP_FAILURE) {
printf("Try to use old env!\n");
}
if (bootargs_analyze() == UP_FAILURE) {
printf("ERROR:bootargs analyze fail!\n");
store_mmc_deinit();
return UP_FAILURE;
}
/*
* make sure that we see CTRL-C
* and save the old state
*/
old_ctrlc = disable_ctrlc(0);
state = update_to_flash();
/* restore the old state */
disable_ctrlc(old_ctrlc);
store_mmc_deinit();
return state;
}
#endif // CONFIG_AUTO_SD_UPDATE
#if (CONFIG_AUTO_USB_UPDATE == 1)
#ifndef CONFIG_XMEDIA_MC
#if !defined CONFIG_USB_OHCI && !defined CONFIG_USB_XHCI_HCD
#error "should have defined CONFIG_USB_OHCI or CONFIG_USB_XHCI"
#endif
#endif
#ifndef CONFIG_USB_STORAGE
#error "should have defined CONFIG_USB_STORAGE"
#endif
#include "store_usb.h"
static int is_usb(void)
{
const char dev_name[8] = "usb";
int part_no = 0;
const int dev_no = 0;
struct blk_desc *stor_dev = NULL;
if (store_usb_init() != UP_SUCCESS) {
return UP_FALSE;
}
debug_print("device name %s, device[%d] part[%d].\n", dev_name, dev_no, part_no);
stor_dev = blk_get_dev(dev_name, dev_no);
if (stor_dev == NULL) {
printf("Unknown device type!\n");
return UP_FALSE;
}
retry:
if (fat_register_device(stor_dev, part_no) != 0) {
printf("Unable to use %s %d:%d for fatls\n", dev_name, dev_no, part_no);
if (++part_no < 4) {
goto retry;
}
return UP_FALSE;
}
#if 0
if (file_fat_detectfs() != 0) {
printf("file_fat_detectfs failed\n");
return UP_FALSE;
}
return UP_TRUE;
#else
if (fat_exists("u-boot.bin") || fat_exists("config")) {
return UP_TRUE;
} else if (++part_no <= 4) {
goto retry;
} else {
printf("File not found\n");
}
return UP_FALSE;
#endif
}
static int update_by_usb(void)
{
int boot_type = get_boot_info();
int state = UP_FAILURE;
int old_ctrlc;
if (is_usb() != UP_TRUE) {
store_usb_deinit();
return UP_FAILURE;
}
if (au_flash_init(boot_type) == UP_FAILURE) {
store_usb_deinit();
return UP_FAILURE;
}
if (get_env_from_config() == UP_FAILURE) {
printf("Try to use old env!\n");
}
if (bootargs_analyze() == UP_FAILURE) {
printf("ERROR:bootargs analyze fail!\n");
store_usb_deinit();
return UP_FAILURE;
}
/*
* make sure that we see CTRL-C
* and save the old state
*/
old_ctrlc = disable_ctrlc(0);
state = update_to_flash();
/* restore the old state */
disable_ctrlc(old_ctrlc);
store_usb_deinit();
return state;
}
#endif // CONFIG_AUTO_USB_UPDATE
int do_auto_update(void)
{
#if (CONFIG_AUTO_SD_UPDATE == 1)
if (update_by_mmc() == UP_SUCCESS) {
return 0;
}
#endif
#if (CONFIG_AUTO_USB_UPDATE == 1)
if (update_by_usb() == UP_SUCCESS){
return 0;
}
#endif
return -1;
}
#endif // CONFIG_AUTO_UPDATE