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

434 lines
9.9 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
*/
/* #define DEBUG */
#include <common.h>
#ifdef CONFIG_SUNXI_UBIFS
#include <ubi_uboot.h>
#endif
#include <command.h>
#include <environment.h>
#include <fdtdec.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <memalign.h>
#include <sunxi_flash.h>
#include <part.h>
#include <search.h>
#include <errno.h>
#include <sunxi_board.h>
DECLARE_GLOBAL_DATA_PTR;
const uchar sunxi_sprite_environment[] = {
#ifdef SUNXI_SPRITE_ENV_SETTINGS
SUNXI_SPRITE_ENV_SETTINGS
#endif
"\0"
};
static void use_sprite_env(void)
{
extern struct hsearch_data env_htab;
if (himport_r(&env_htab, (char *)sunxi_sprite_environment,
sizeof(sunxi_sprite_environment), '\0', H_INTERACTIVE, 0,
0, NULL) == 0)
pr_err("Environment import failed: errno = %d\n", errno);
gd->flags |= GD_FLG_ENV_READY;
return;
}
#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
static inline int write_env(struct blk_desc *desc, uint blk_cnt, uint blk_start,
const void *buffer)
{
uint n;
n = blk_dwrite(desc, blk_start, blk_cnt, (u_char *)buffer);
return (n == blk_cnt) ? 0 : -1;
}
#if 0//def CONFIG_SUNXI_UBIFS
static int env_sunxi_flash_save(void)
{
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
int ret;
ret = env_export(env_new);
if (ret)
goto fini;
printf("Writing to env...\n");
if (ubi_volume_write("env", (u_char *)env_new,
CONFIG_ENV_SIZE)) {
printf("failed\n");
ret = 1;
goto fini;
}
ret = 0;
fini:
return ret;
}
#else
#ifdef CONFIG_SUNXI_REDUNDAND_ENVIRONMENT
static int env_sunxi_flash_save(void)
{
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
int ret;
struct blk_desc *desc;
disk_partition_t info = { 0 };
desc = blk_get_devnum_by_typename("sunxi_flash", 0);
if (desc == NULL)
return -ENODEV;
ret = env_export(env_new);
if (ret)
goto fini;
if (gd->env_valid == ENV_VALID) {
puts("Writing to redundant env... ");
ret = sunxi_flash_try_partition(desc, CONFIG_SUNXI_ENV_REDUNDAND_PARTITION, &info);
if (ret < 0)
return -ENODEV;
if (write_env(desc, (CONFIG_ENV_SIZE + 511) / 512, (uint)info.start,
(u_char *)env_new)) {
puts("failed\n");
ret = 1;
goto fini;
}
} else {
puts("Writing to env... ");
ret = sunxi_flash_try_partition(desc, CONFIG_SUNXI_ENV_PARTITION, &info);
if (ret < 0)
return -ENODEV;
if (write_env(desc, (CONFIG_ENV_SIZE + 511) / 512, (uint)info.start,
(u_char *)env_new)) {
puts("failed\n");
ret = 1;
goto fini;
}
}
sunxi_flash_write_end();
sunxi_flash_flush();
ret = 0;
gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
fini:
return ret;
}
#else
static int env_sunxi_flash_save(void)
{
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
int ret;
struct blk_desc *desc;
disk_partition_t info = { 0 };
desc = blk_get_devnum_by_typename("sunxi_flash", 0);
if (desc == NULL)
return -ENODEV;
ret = sunxi_flash_try_partition(desc, "env", &info);
if (ret < 0)
return -ENODEV;
ret = env_export(env_new);
if (ret)
goto fini;
printf("Writing to env...\n");
#ifdef CONFIG_SUNXI_ENV_BACKUP
if ((uint)info.size >= ((CONFIG_ENV_SIZE * 2)/512)) {
char backup_buf[CONFIG_ENV_SIZE*2];
memcpy(backup_buf, env_new, CONFIG_ENV_SIZE);
memcpy((backup_buf+CONFIG_ENV_SIZE), env_new, CONFIG_ENV_SIZE);
if (write_env(desc, (CONFIG_ENV_SIZE*2 + 511) / 512, (uint)info.start,
(u_char *)backup_buf)) {
puts("failed\n");
ret = 1;
goto fini;
}
} else {
printf("env size is %u\n", (uint)info.size);
puts("env partition is too small!\n");
puts("can't enabled backup env functions\n");
if (write_env(desc, (CONFIG_ENV_SIZE + 511) / 512, (uint)info.start,
(u_char *)env_new)) {
puts("failed\n");
ret = 1;
goto fini;
}
}
#else
if (write_env(desc, (CONFIG_ENV_SIZE + 511) / 512, (uint)info.start,
(u_char *)env_new)) {
puts("failed\n");
ret = 1;
goto fini;
}
#endif /* CONFIG_SUNXI_ENV_BACKUP */
sunxi_flash_write_end();
sunxi_flash_flush();
ret = 0;
fini:
return ret;
}
#endif /* CONFIG_SUNXI_REDUNDAND_ENVIRONMENT */
#endif
#endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
#if 0//def CONFIG_SUNXI_UBIFS
static int env_sunxi_flash_load(void)
{
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
int ret;
char *errmsg = "!no device";
int workmode = get_boot_work_mode();
if ((workmode & WORK_MODE_PRODUCT) &&
(!(workmode & WORK_MODE_UPDATE))) {
use_sprite_env();
return 0;
}
ret = ubi_volume_read("env", buf, (CONFIG_ENV_SIZE + 511)/512);
if(ret)
goto err;
ret = env_import(buf, 1);
err:
if (ret)
set_default_env(errmsg);
return ret;
}
#else
static inline int read_env(struct blk_desc *desc, uint blk_cnt, uint blk_start,
const void *buffer)
{
uint n;
n = blk_dread(desc, blk_start, blk_cnt, (uchar *)buffer);
return (n == blk_cnt) ? 0 : -1;
}
#ifdef CONFIG_SUNXI_REDUNDAND_ENVIRONMENT
static int env_sunxi_flash_load(void)
{
ALLOC_CACHE_ALIGN_BUFFER(char, env1_buf, CONFIG_ENV_SIZE);
ALLOC_CACHE_ALIGN_BUFFER(char, env2_buf, CONFIG_ENV_SIZE);
struct blk_desc *desc;
disk_partition_t info = { 0 };
int ret;
char *errmsg = "!no device";
int workmode = get_boot_work_mode();
char ids[MTDIDS_MAXLEN];
char parts[MTDPARTS_MAXLEN];
char partition[PARTITION_MAXLEN];
if ((workmode & WORK_MODE_PRODUCT) &&
(!(workmode & WORK_MODE_UPDATE))) {
use_sprite_env();
return 0;
}
desc = blk_get_devnum_by_typename("sunxi_flash", 0);
if (desc == NULL) {
ret = -ENODEV;
goto err;
}
int read1_fail, read2_fail;
env_t *tmp_env1, *tmp_env2;
memset(env1_buf, 0x0, CONFIG_ENV_SIZE);
memset(env2_buf, 0x0, CONFIG_ENV_SIZE);
tmp_env1 = (env_t *)env1_buf;
tmp_env2 = (env_t *)env2_buf;
ret = sunxi_flash_try_partition(desc, CONFIG_SUNXI_ENV_PARTITION, &info);
if (ret < 0) {
printf("Can't find %s partition\n", CONFIG_SUNXI_ENV_PARTITION);
ret = -ENODEV;
goto err;
}
read1_fail = read_env(desc, (CONFIG_ENV_SIZE + 511) / 512, (uint)info.start, env1_buf);
if (read1_fail)
printf("\n** Unable to read env data from %s partition **\n",
CONFIG_SUNXI_ENV_PARTITION);
memset(&info, 0x0, sizeof(disk_partition_t));
ret = sunxi_flash_try_partition(desc, CONFIG_SUNXI_ENV_REDUNDAND_PARTITION, &info);
if (ret < 0) {
printf("Can't find %s partition\n", CONFIG_SUNXI_ENV_REDUNDAND_PARTITION);
ret = -ENODEV;
goto err;
}
read2_fail = read_env(desc, (CONFIG_ENV_SIZE + 511) / 512, (uint)info.start, env2_buf);
if (read2_fail)
printf("\n** Unable to read env data from %s partition **\n",
CONFIG_SUNXI_ENV_REDUNDAND_PARTITION);
strcpy(ids, env_get("mtdids"));
strcpy(parts, env_get("mtdparts"));
strcpy(partition, env_get("partition"));
ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
read2_fail);
err:
if (ret)
set_default_env(errmsg);
env_set("mtdids", ids);
env_set("mtdparts", parts);
env_set("partition", partition);
return ret;
}
#else
#ifdef CONFIG_SUNXI_ENV_BACKUP
uint32_t env_calc_crc(const char *buf);
uint32_t env_get_crc(const char *buf);
#endif
static int env_sunxi_flash_load(void)
{
#ifdef CONFIG_SUNXI_ENV_BACKUP
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE*2);
#else
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
#endif
struct blk_desc *desc;
disk_partition_t info = { 0 };
int ret;
char *errmsg = "!no device";
int workmode = get_boot_work_mode();
char ids[MTDIDS_MAXLEN];
char parts[MTDPARTS_MAXLEN];
char partition[PARTITION_MAXLEN];
if ((workmode & WORK_MODE_PRODUCT) &&
(!(workmode & WORK_MODE_UPDATE))) {
use_sprite_env();
return 0;
}
desc = blk_get_devnum_by_typename("sunxi_flash", 0);
if (desc == NULL) {
ret = -ENODEV;
goto err;
}
ret = sunxi_flash_try_partition(desc, "env", &info);
/* printf ("name:%s start:0x%x, size: 0x%x\n", info.name, (u32)info.start, (u32)info.size); */
if (ret < 0) {
ret = -ENODEV;
goto err;
}
strcpy(ids, env_get("mtdids"));
strcpy(parts, env_get("mtdparts"));
strcpy(partition, env_get("partition"));
#ifdef CONFIG_SUNXI_ENV_BACKUP
if (read_env(desc, (CONFIG_ENV_SIZE*2 + 511) / 512, (uint)info.start,
buf)) {
#else
if (read_env(desc, (CONFIG_ENV_SIZE + 511) / 512, (uint)info.start,
buf)) {
#endif
errmsg = "!read failed";
ret = -EIO;
goto err;
}
#ifdef CONFIG_SUNXI_ENV_BACKUP
char *normal_buf_p = buf;
char *backup_buf_p = buf;
//point to backup area
backup_buf_p += CONFIG_ENV_SIZE;
uint32_t crc = env_get_crc(normal_buf_p);
uint32_t crc_b = env_get_crc(backup_buf_p);
uint32_t crc_value = env_calc_crc(normal_buf_p);
uint32_t crc_b_value = env_calc_crc(backup_buf_p);
if ((uint)info.size >= ((CONFIG_ENV_SIZE * 2)/512)) {
if ((crc_value == crc) && (crc_b_value == crc_b)) {
env_import(normal_buf_p, 0);
if (crc != crc_b) {
puts("env and backup env are not synchronized,now to synchronize\n");
env_save();
}
} else if ((crc_value != crc) && (crc_b_value == crc_b)) {
puts("env check CRC fail\n");
puts("Now use backup env\n");
env_import(backup_buf_p, 0);
env_save();
} else if ((crc_value == crc) && (crc_b_value != crc_b)) {
puts("backup env check CRC fail\n");
puts("Now update backup env\n");
env_import(normal_buf_p, 0);
env_save();
} else if ((crc_value != crc) && (crc_b_value != crc_b)) {
puts("env and backup env all check CRC fail\n");
puts("Now set env to default\n");
errmsg = "!bad CRC";
set_default_env(errmsg);
env_save();
goto err;
}
} else {
printf("env size is %u\n", (uint)info.size);
puts("env partition is too small!\n");
puts("can't enabled backup env functions\n");
env_import(normal_buf_p, 1);
}
#else
ret = env_import(buf, 1);
#endif
err:
if (ret)
set_default_env(errmsg);
env_set("mtdids", ids);
env_set("mtdparts", parts);
env_set("partition", partition);
return ret;
}
#endif /* CONFIG_SUNXI_REDUNDAND_ENVIRONMENT */
#endif
U_BOOT_ENV_LOCATION(sunxi_flash) = {
.location = ENVL_SUNXI_FLASH,
ENV_NAME("SUNXI_FLASH").load = env_sunxi_flash_load,
.save = env_save_ptr(env_sunxi_flash_save),
};