env: add a common env driver for block device

The driver implementation refers to env/mmc.c, the storage media
binding to block layer can use it(Nand/Nor Flash...).

Support configure:
	- CONFIG_ENV_OFFSET
	- CONFIG_ENV_SIZE
	- CONFIG_ENV_OFFSET_REDUND (optional)
	- CONFIG_ENV_SIZE_REDUND (optional)
	- CONFIG_SYS_MMC_ENV_PART (optional)

Change-Id: Ibb16f0dd7af1331f454784968fbdc9002f4b769c
Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
This commit is contained in:
Joseph Chen 2019-04-08 20:22:19 +08:00 committed by Jianhong Chen
parent 1712dc5c34
commit 2ba7147f80
6 changed files with 330 additions and 1 deletions

View File

@ -52,9 +52,10 @@ DECLARE_GLOBAL_DATA_PTR;
!defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \ !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \
!defined(CONFIG_ENV_IS_IN_REMOTE) && \ !defined(CONFIG_ENV_IS_IN_REMOTE) && \
!defined(CONFIG_ENV_IS_IN_UBI) && \ !defined(CONFIG_ENV_IS_IN_UBI) && \
!defined(CONFIG_ENV_IS_IN_BLK_DEV) && \
!defined(CONFIG_ENV_IS_NOWHERE) !defined(CONFIG_ENV_IS_NOWHERE)
# error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|MMC|FAT|EXT4|\ # error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|MMC|FAT|EXT4|\
NAND|NVRAM|ONENAND|SATA|SPI_FLASH|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE NAND|NVRAM|ONENAND|SATA|SPI_FLASH|REMOTE|UBI|BLK_DEV} or CONFIG_ENV_IS_NOWHERE
#endif #endif
/* /*

34
env/Kconfig vendored
View File

@ -358,6 +358,40 @@ config ENV_IS_IN_UBI
You will probably want to define these to avoid a really noisy system You will probably want to define these to avoid a really noisy system
when storing the env in UBI. when storing the env in UBI.
config ENV_IS_IN_BLK_DEV
bool "Environment in a block device"
depends on !CHAIN_OF_TRUST && CONFIG_BLK
help
Define this if you have an Block device which you want to use for the
environment.
- CONFIG_ENV_OFFSET:
- CONFIG_ENV_SIZE:
These two #defines specify the offset and size of the environment
area within the specified Block device. These two values are in units
of bytes, but must be aligned to an Block sector boundary.
- CONFIG_ENV_OFFSET_REDUND (optional):
Specifies a second storage area, of CONFIG_ENV_SIZE size, used to
hold a redundant copy of the environment data. This provides a
valid backup copy in case the other copy is corrupted, e.g. due
to a power failure during a "saveenv" operation. This is handled
in the same way as CONFIG_ENV_OFFSET.
- CONFIG_ENV_SIZE_REDUND (optional):
This value need not be set, even when CONFIG_ENV_OFFSET_REDUND is
set. If this value is set, it must be set to the same value as
CONFIG_ENV_SIZE.
- CONFIG_SYS_MMC_ENV_PART (optional):
Specifies which MMC partition the environment is stored in. If not
set, defaults to partition 0, the user area. Common values might be
1 (first MMC boot partition), 2 (second MMC boot partition).
endchoice endchoice
config ENV_AES config ENV_AES

1
env/Makefile vendored
View File

@ -27,6 +27,7 @@ obj-$(CONFIG_ENV_IS_IN_SATA) += sata.o
obj-$(CONFIG_ENV_IS_IN_SPI_FLASH) += sf.o obj-$(CONFIG_ENV_IS_IN_SPI_FLASH) += sf.o
obj-$(CONFIG_ENV_IS_IN_REMOTE) += remote.o obj-$(CONFIG_ENV_IS_IN_REMOTE) += remote.o
obj-$(CONFIG_ENV_IS_IN_UBI) += ubi.o obj-$(CONFIG_ENV_IS_IN_UBI) += ubi.o
obj-$(CONFIG_ENV_IS_IN_BLK_DEV) += env_blk.o
obj-$(CONFIG_ENV_IS_NOWHERE) += nowhere.o obj-$(CONFIG_ENV_IS_NOWHERE) += nowhere.o
endif endif

2
env/env.c vendored
View File

@ -46,6 +46,8 @@ static enum env_location env_get_default_location(void)
return ENVL_SPI_FLASH; return ENVL_SPI_FLASH;
else if IS_ENABLED(CONFIG_ENV_IS_IN_UBI) else if IS_ENABLED(CONFIG_ENV_IS_IN_UBI)
return ENVL_UBI; return ENVL_UBI;
else if IS_ENABLED(CONFIG_ENV_IS_IN_BLK_DEV)
return ENVL_BLK;
else if IS_ENABLED(CONFIG_ENV_IS_NOWHERE) else if IS_ENABLED(CONFIG_ENV_IS_NOWHERE)
return ENVL_NOWHERE; return ENVL_NOWHERE;
else else

290
env/env_blk.c vendored Normal file
View File

@ -0,0 +1,290 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
*/
#include <common.h>
#include <environment.h>
#include <memalign.h>
#include <boot_rkimg.h>
#define __STR(X) #X
#define STR(X) __STR(X)
#if defined(CONFIG_ENV_SIZE_REDUND) && \
(CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
#error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
#endif
DECLARE_GLOBAL_DATA_PTR;
int get_env_addr(struct blk_desc *blk_desc, int copy, u32 *env_addr)
{
s64 offset = CONFIG_ENV_OFFSET;
#if defined(CONFIG_ENV_OFFSET_REDUND)
if (copy)
offset = CONFIG_ENV_OFFSET_REDUND;
#endif
if (offset < 0)
return -EINVAL;
*env_addr = offset;
return 0;
}
int get_env_dev(void)
{
return CONFIG_SYS_MMC_ENV_DEV;
}
#ifdef CONFIG_SYS_MMC_ENV_PART
static unsigned char env_org_hwpart;
int get_env_part(void)
{
return CONFIG_SYS_MMC_ENV_PART;
}
static const char *init_blk_hwpart_for_env(struct blk_desc *blk_desc)
{
enum if_type if_type;
const char *devtype;
int devnum, devpart, ret;
devtype = env_get("devtype");
devnum = env_get_ulong("devnum", 10, 0);
devpart = get_env_part();
if_type = if_typename_to_iftype(devtype);
env_org_hwpart = blk_desc->hwpart;
ret = blk_select_hwpart_devnum(if_type, devnum, devpart);
if (ret)
return "!Partition switch failed";
return NULL;
}
static void fini_blk_hwpart_for_env(void)
{
enum if_type if_type;
const char *devtype;
int devnum;
devtype = env_get("devtype");
devnum = env_get_ulong("devnum", 10, 0);
if_type = if_typename_to_iftype(devtype);
blk_select_hwpart_devnum(if_type, devnum, env_org_hwpart);
}
#else
static inline const char *init_blk_hwpart_for_env(struct blk_desc *blk_desc)
{ return NULL; }
static inline void fini_blk_hwpart_for_env(void) {}
#endif
#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
static inline int write_env(struct blk_desc *blk_desc, unsigned long size,
unsigned long offset, const void *buffer)
{
uint blk_start, blk_cnt, n;
blk_start = ALIGN(offset, blk_desc->blksz) / blk_desc->blksz;
blk_cnt = ALIGN(size, blk_desc->blksz) / blk_desc->blksz;
n = blk_dwrite(blk_desc, blk_start, blk_cnt, (u_char *)buffer);
return (n == blk_cnt) ? 0 : -1;
}
static int env_blk_save(void)
{
ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
struct blk_desc *blk_desc;
const char *errmsg = NULL;
int ret, copy = 0;
u32 offset;
blk_desc = rockchip_get_bootdev();
if (!blk_desc) {
puts("Can't find bootdev\n");
return -EIO;
}
errmsg = init_blk_hwpart_for_env(blk_desc);
if (errmsg) {
puts(errmsg);
return -EIO;
}
ret = env_export(env_new);
if (ret)
goto fini;
#ifdef CONFIG_ENV_OFFSET_REDUND
if (gd->env_valid == ENV_VALID)
copy = 1;
#endif
if (get_env_addr(blk_desc, copy, &offset)) {
ret = 1;
goto fini;
}
printf("Writing to %s%s(%s)... ", copy ? "redundant " : "",
env_get("devtype"), env_get("devnum"));
if (write_env(blk_desc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
puts("failed\n");
ret = 1;
goto fini;
}
puts("done\n");
ret = 0;
#ifdef CONFIG_ENV_OFFSET_REDUND
gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
#endif
fini:
fini_blk_hwpart_for_env();
return ret;
}
#endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
static inline int read_env(struct blk_desc *blk_desc, unsigned long size,
unsigned long offset, const void *buffer)
{
uint blk_start, blk_cnt, n;
blk_start = ALIGN(offset, blk_desc->blksz) / blk_desc->blksz;
blk_cnt = ALIGN(size, blk_desc->blksz) / blk_desc->blksz;
n = blk_dread(blk_desc, blk_start, blk_cnt, (uchar *)buffer);
return (n == blk_cnt) ? 0 : -1;
}
#ifdef CONFIG_ENV_OFFSET_REDUND
static int env_blk_load(void)
{
#if !defined(ENV_IS_EMBEDDED)
struct blk_desc *blk_desc;
const char *errmsg = NULL;
int read1_fail = 0, read2_fail = 0;
u32 offset1, offset2;
int ret;
ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
blk_desc = rockchip_get_bootdev();
if (!blk_desc) {
puts("Can't find bootdev\n");
return -EIO;
}
errmsg = init_blk_hwpart_for_env(blk_desc);
if (errmsg) {
ret = -EIO;
goto err;
}
if (get_env_addr(blk_desc, 0, &offset1) ||
get_env_addr(blk_desc, 1, &offset2)) {
ret = -EIO;
goto fini;
}
read1_fail = read_env(blk_desc, CONFIG_ENV_SIZE, offset1, tmp_env1);
read2_fail = read_env(blk_desc, CONFIG_ENV_SIZE, offset2, tmp_env2);
if (read1_fail && read2_fail)
puts("*** Error - No Valid Environment Area found\n");
else if (read1_fail || read2_fail)
puts("*** Warning - some problems detected "
"reading environment; recovered successfully\n");
if (read1_fail && read2_fail) {
errmsg = "!bad CRC";
ret = -EIO;
goto fini;
} else if (!read1_fail && read2_fail) {
gd->env_valid = ENV_VALID;
env_import((char *)tmp_env1, 1);
} else if (read1_fail && !read2_fail) {
gd->env_valid = ENV_REDUND;
env_import((char *)tmp_env2, 1);
} else {
env_import_redund((char *)tmp_env1, (char *)tmp_env2);
}
ret = 0;
fini:
fini_blk_hwpart_for_env();
err:
if (ret)
set_default_env(errmsg);
#endif
return ret;
}
#else /* ! CONFIG_ENV_OFFSET_REDUND */
static int env_blk_load(void)
{
#if !defined(ENV_IS_EMBEDDED)
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
struct blk_desc *blk_desc;
const char *errmsg = NULL;
u32 offset;
int ret;
blk_desc = rockchip_get_bootdev();
if (!blk_desc) {
puts("Can't find bootdev\n");
return -EIO;
}
errmsg = init_blk_hwpart_for_env(blk_desc);
if (errmsg) {
ret = -EIO;
puts(errmsg);
goto err;
}
if (get_env_addr(blk_desc, 0, &offset)) {
ret = -EIO;
goto fini;
}
if (read_env(blk_desc, CONFIG_ENV_SIZE, offset, buf)) {
errmsg = "!read failed";
ret = -EIO;
goto fini;
}
env_import(buf, 1);
ret = 0;
fini:
fini_blk_hwpart_for_env();
err:
if (ret)
set_default_env(errmsg);
#endif
return ret;
}
#endif /* CONFIG_ENV_OFFSET_REDUND */
U_BOOT_ENV_LOCATION(env_blk) = {
.location = ENVL_BLK,
ENV_NAME("ENV_BLK")
.load = env_blk_load,
#ifndef CONFIG_SPL_BUILD
.save = env_save_ptr(env_blk_save),
#endif
};

View File

@ -210,6 +210,7 @@ enum env_location {
ENVL_SPI_FLASH, ENVL_SPI_FLASH,
ENVL_UBI, ENVL_UBI,
ENVL_NOWHERE, ENVL_NOWHERE,
ENVL_BLK,
ENVL_COUNT, ENVL_COUNT,
ENVL_UNKNOWN, ENVL_UNKNOWN,