Il giorno lun 7 apr 2025 alle ore 21:00 Christian Marangi <[email protected]> ha scritto: > > Introduce support for env in generic MTD. Currently we only support SPI > flash based on the lagacy sf cmd that assume SPI flash are always NOR. > This is not the case as to SPI controller also NAND can be attached. > > To support also these flash scenario, add support for storing and > reading ENV from generic MTD device by adding an env driver that > base entirely on the MTD api. > > Introduce a new kconfig CONFIG_ENV_IS_IN_MTD and > CONFIG_ENV_MTD_DEV to define the name of the MTD device as exposed > by mtd list. > > Signed-off-by: Christian Marangi <[email protected]> > --- > env/Kconfig | 33 +++- > env/Makefile | 1 + > env/env.c | 3 + > env/mtd.c | 338 +++++++++++++++++++++++++++++++++++++++++ > include/env_internal.h | 1 + > 5 files changed, 372 insertions(+), 4 deletions(-) > create mode 100644 env/mtd.c > > diff --git a/env/Kconfig b/env/Kconfig > index 4438f0b392c..74678c43334 100644 > --- a/env/Kconfig > +++ b/env/Kconfig > @@ -74,7 +74,7 @@ config ENV_IS_DEFAULT > !ENV_IS_IN_MMC && !ENV_IS_IN_NAND && \ > !ENV_IS_IN_NVRAM && !ENV_IS_IN_ONENAND && \ > !ENV_IS_IN_REMOTE && !ENV_IS_IN_SPI_FLASH && \ > - !ENV_IS_IN_UBI > + !ENV_IS_IN_UBI && !ENV_IS_IN_MTD > select ENV_IS_NOWHERE > > config ENV_IS_NOWHERE > @@ -387,6 +387,25 @@ config ENV_IS_IN_SPI_FLASH > during a "saveenv" operation. CONFIG_ENV_OFFSET_REDUND must be > aligned to an erase sector boundary. > > +config ENV_IS_IN_MTD > + bool "Environment is in MTD flash" > + depends on !CHAIN_OF_TRUST && (SPI_FLASH || DM_SPI_FLASH) > + default y if ARCH_AIROHA > + help > + Define this if you have a MTD Flash memory device which you > + want to use for the environment. > + > + - CONFIG_ENV_MTD_DEV: > + > + Specifies which SPI NAND device the environment is stored in. > + > + - CONFIG_ENV_OFFSET: > + - CONFIG_ENV_SIZE: > + > + These two #defines specify the offset and size of the > + environment area within the MTD Flash. > + CONFIG_ENV_OFFSET must be aligned to an erase sector boundary. > + > config ENV_SECT_SIZE_AUTO > bool "Use automatically detected sector size" > depends on ENV_IS_IN_SPI_FLASH > @@ -562,8 +581,8 @@ config ENV_EXT4_FILE > config ENV_ADDR > hex "Environment address" > depends on ENV_IS_IN_FLASH || ENV_IS_IN_NVRAM || ENV_IS_IN_ONENAND || > \ > - ENV_IS_IN_REMOTE || ENV_IS_IN_SPI_FLASH > - default 0x0 if ENV_IS_IN_SPI_FLASH > + ENV_IS_IN_REMOTE || ENV_IS_IN_SPI_FLASH || ENV_IS_IN_MTD > + default 0x0 if ENV_IS_IN_SPI_FLASH || ENV_IS_IN_MTD > help > Offset from the start of the device (or partition) > > @@ -577,7 +596,7 @@ config ENV_ADDR_REDUND > config ENV_OFFSET > hex "Environment offset" > depends on ENV_IS_IN_EEPROM || ENV_IS_IN_MMC || ENV_IS_IN_NAND || \ > - ENV_IS_IN_SPI_FLASH > + ENV_IS_IN_SPI_FLASH || ENV_IS_IN_MTD > default 0x3f8000 if ARCH_ROCKCHIP && ENV_IS_IN_MMC > default 0x140000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH > default 0xF0000 if ARCH_SUNXI > @@ -666,6 +685,12 @@ config SYS_RELOC_GD_ENV_ADDR > Relocate the early env_addr pointer so we know it is not inside > the binary. Some systems need this and for the rest, it doesn't > hurt. > > +config ENV_MTD_DEV > + string "mtd device name" > + depends on ENV_IS_IN_MTD > + help > + MTD device name on the platform where the environment is stored. > + > config SYS_MMC_ENV_DEV > int "mmc device number" > depends on ENV_IS_IN_MMC || ENV_IS_IN_FAT || ENV_IS_IN_EXT4 || \ > diff --git a/env/Makefile b/env/Makefile > index a54e924d419..3b9c71d5681 100644 > --- a/env/Makefile > +++ b/env/Makefile > @@ -26,6 +26,7 @@ obj-$(CONFIG_$(PHASE_)ENV_IS_IN_FAT) += fat.o > obj-$(CONFIG_$(PHASE_)ENV_IS_IN_EXT4) += ext4.o > obj-$(CONFIG_$(PHASE_)ENV_IS_IN_NAND) += nand.o > obj-$(CONFIG_$(PHASE_)ENV_IS_IN_SPI_FLASH) += sf.o > +obj-$(CONFIG_$(PHASE_)ENV_IS_IN_MTD) += mtd.o > obj-$(CONFIG_$(PHASE_)ENV_IS_IN_FLASH) += flash.o > > CFLAGS_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc > 2>/dev/null) > diff --git a/env/env.c b/env/env.c > index bcc189e14db..dbaeedc3c3b 100644 > --- a/env/env.c > +++ b/env/env.c > @@ -58,6 +58,9 @@ static enum env_location env_locations[] = { > #ifdef CONFIG_ENV_IS_IN_SPI_FLASH > ENVL_SPI_FLASH, > #endif > +#ifdef CONFIG_ENV_IS_IN_MTD > + ENVL_MTD, > +#endif > #ifdef CONFIG_ENV_IS_IN_UBI > ENVL_UBI, > #endif > diff --git a/env/mtd.c b/env/mtd.c > new file mode 100644 > index 00000000000..721faebd8f2 > --- /dev/null > +++ b/env/mtd.c > @@ -0,0 +1,338 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Author: Christian Marangi <[email protected]> > + */ > +#include <env_internal.h> > +#include <errno.h> > +#include <malloc.h> > +#include <mtd.h> > +#include <asm/cache.h> > +#include <asm/global_data.h> > +#include <linux/mtd/mtd.h> > +#include <u-boot/crc.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +static int setup_mtd_device(struct mtd_info **mtd_env) > +{ > + struct mtd_info *mtd; > + > + mtd_probe_devices(); > + > + mtd = get_mtd_device_nm(CONFIG_ENV_MTD_DEV); > + if (IS_ERR_OR_NULL(mtd)) { > + env_set_default("get_mtd_device_nm() failed", 0); > + return mtd ? PTR_ERR(mtd) : -EINVAL; > + } > + > + *mtd_env = mtd; > + > + return 0; > +} > + > +static int env_mtd_save(void) > +{ > + char *saved_buf, *write_buf, *tmp; > + struct erase_info ei = { }; > + struct mtd_info *mtd_env; > + u32 sect_size, sect_num; > + size_t ret_len = 0; > + u32 write_size; > + env_t env_new; > + int remaining; > + u32 offset; > + int ret; > + > + ret = setup_mtd_device(&mtd_env); > + if (ret) > + return ret; > + > + sect_size = mtd_env->erasesize; > + > + /* Is the sector larger than the env (i.e. embedded) */ > + if (sect_size > CONFIG_ENV_SIZE) { > + saved_buf = malloc(sect_size); > + if (!saved_buf) { > + ret = -ENOMEM; > + goto done; > + } > + > + offset = CONFIG_ENV_OFFSET; > + remaining = sect_size; > + tmp = saved_buf; > + > + while (remaining) { > + /* Skip the block if it is bad */ > + if (!(offset % sect_size) && > + mtd_block_isbad(mtd_env, offset)) { > + offset += sect_size; > + continue; > + } > + > + ret = mtd_read(mtd_env, offset, mtd_env->writesize, > + &ret_len, tmp); > + if (ret) > + goto done; > + > + tmp += ret_len; > + offset += ret_len; > + remaining -= ret_len; > + } > + } > + > + ret = env_export(&env_new); > + if (ret) > + goto done; > + > + sect_num = DIV_ROUND_UP(CONFIG_ENV_SIZE, sect_size); > + > + ei.mtd = mtd_env; > + ei.addr = CONFIG_ENV_OFFSET; > + ei.len = sect_num * sect_size; > + > + puts("Erasing MTD..."); > + ret = mtd_erase(mtd_env, &ei); > + if (ret) > + goto done; > + > + if (sect_size > CONFIG_ENV_SIZE) { > + memcpy(saved_buf, &env_new, CONFIG_ENV_SIZE); > + write_size = sect_size; > + write_buf = saved_buf; > + } else { > + write_size = sect_num * sect_size; > + write_buf = (char *)&env_new; > + } > + > + offset = CONFIG_ENV_OFFSET; > + remaining = sect_size; > + tmp = write_buf; > + > + puts("Writing to MTD..."); > + while (remaining) { > + /* Skip the block if it is bad */ > + if (!(offset % sect_size) && > + mtd_block_isbad(mtd_env, offset)) { > + offset += sect_size; > + continue; > + } > + > + ret = mtd_write(mtd_env, offset, mtd_env->writesize, > + &ret_len, tmp); > + if (ret) > + goto done; > + > + offset += mtd_env->writesize; > + remaining -= ret_len; > + tmp += ret_len; > + } > + > + ret = 0; > + puts("done\n"); > + > +done: > + if (saved_buf) > + free(saved_buf); > + > + return ret; > +} > + > +static int env_mtd_load(void) > +{ > + struct mtd_info *mtd_env; > + char *buf, *tmp; > + size_t ret_len; > + int remaining; > + u32 sect_size; > + u32 offset; > + int ret; > + > + buf = (char *)memalign(ARCH_DMA_MINALIGN, CONFIG_ENV_SIZE); > + if (!buf) { > + env_set_default("memalign() failed", 0); > + return -EIO; > + } > + > + ret = setup_mtd_device(&mtd_env); > + if (ret) > + goto out; > + > + sect_size = mtd_env->erasesize; > + > + offset = CONFIG_ENV_OFFSET; > + remaining = CONFIG_ENV_SIZE; > + tmp = buf; > + > + while (remaining) { > + /* Skip the block if it is bad */ > + if (!(offset % sect_size) && > + mtd_block_isbad(mtd_env, offset)) { > + offset += sect_size; > + continue; > + } > + > + ret = mtd_read(mtd_env, offset, mtd_env->writesize, > + &ret_len, tmp); > + if (ret) { > + env_set_default("mtd_read() failed", 1); > + goto out; > + } > + > + tmp += ret_len; > + offset += ret_len; > + remaining -= ret_len; > + } > + > + ret = env_import(buf, 1, H_EXTERNAL); > + if (!ret) > + gd->env_valid = ENV_VALID; > + > +out: > + free(buf); > + > + return ret; > +} > + > +static int env_mtd_erase(void) > +{ > + struct mtd_info *mtd_env; > + u32 sect_size, sect_num; > + char *saved_buf, *tmp; > + struct erase_info ei; > + size_t ret_len; > + int remaining; > + u32 offset; > + int ret; > + > + ret = setup_mtd_device(&mtd_env); > + if (ret) > + return ret; > + > + sect_size = mtd_env->erasesize; > + > + /* Is the sector larger than the env (i.e. embedded) */ > + if (sect_size > CONFIG_ENV_SIZE) { > + saved_buf = malloc(sect_size); > + if (!saved_buf) { > + ret = -ENOMEM; > + goto done; > + } > + > + offset = CONFIG_ENV_OFFSET; > + remaining = sect_size; > + tmp = saved_buf; > + > + while (remaining) { > + /* Skip the block if it is bad */ > + if (!(offset % sect_size) && > + mtd_block_isbad(mtd_env, offset)) { > + offset += sect_size; > + continue; > + } > + > + ret = mtd_read(mtd_env, offset, mtd_env->writesize, > + &ret_len, tmp); > + if (ret) > + goto done; > + > + tmp += ret_len; > + offset += ret_len; > + remaining -= ret_len; > + } > + } > + > + sect_num = DIV_ROUND_UP(CONFIG_ENV_SIZE, sect_size); > + > + ei.mtd = mtd_env; > + ei.addr = CONFIG_ENV_OFFSET; > + ei.len = sect_num * sect_size; > + > + ret = mtd_erase(mtd_env, &ei); > + if (ret) > + goto done; > + > + if (sect_size > CONFIG_ENV_SIZE) { > + memset(saved_buf, 0, CONFIG_ENV_SIZE); > + > + offset = CONFIG_ENV_OFFSET; > + remaining = sect_size; > + tmp = saved_buf; > + > + while (remaining) { > + /* Skip the block if it is bad */ > + if (!(offset % sect_size) && > + mtd_block_isbad(mtd_env, offset)) { > + offset += sect_size; > + continue; > + } > + > + ret = mtd_write(mtd_env, offset, mtd_env->writesize, > + &ret_len, tmp); > + if (ret) > + goto done; > + > + offset += mtd_env->writesize; > + remaining -= ret_len; > + tmp += ret_len; > + } > + } > + > + ret = 0; > + > +done: > + if (saved_buf) > + free(saved_buf); > + > + return ret; > +} > + > +__weak void *env_mtd_get_env_addr(void) > +{ > + return (void *)CONFIG_ENV_ADDR; > +} > + > +/* > + * Check if Environment on CONFIG_ENV_ADDR is valid. > + */ > +static int env_mtd_init_addr(void) > +{ > + env_t *env_ptr = (env_t *)env_mtd_get_env_addr(); > + > + if (!env_ptr) > + return -ENOENT; > + > + if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { > + gd->env_addr = (ulong)&env_ptr->data; > + gd->env_valid = ENV_VALID; > + } else { > + gd->env_valid = ENV_INVALID; > + } > + > + return 0; > +} > + > +static int env_mtd_init(void) > +{ > + int ret; > + > + ret = env_mtd_init_addr(); > + if (ret != -ENOENT) > + return ret; > + > + /* > + * return here -ENOENT, so env_init() > + * can set the init bit and later if no > + * other Environment storage is defined > + * can set the default environment > + */ > + return -ENOENT; > +} > + > +U_BOOT_ENV_LOCATION(mtd) = { > + .location = ENVL_MTD, > + ENV_NAME("MTD") > + .load = env_mtd_load, > + .save = ENV_SAVE_PTR(env_mtd_save), > + .erase = ENV_ERASE_PTR(env_mtd_erase), > + .init = env_mtd_init, > +}; > diff --git a/include/env_internal.h b/include/env_internal.h > index c1c0727e4d0..ee939ba4293 100644 > --- a/include/env_internal.h > +++ b/include/env_internal.h > @@ -113,6 +113,7 @@ enum env_location { > ENVL_ONENAND, > ENVL_REMOTE, > ENVL_SPI_FLASH, > + ENVL_MTD, > ENVL_UBI, > ENVL_NOWHERE, > > -- > 2.48.1 >
Any news for this?

