mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-27 13:33:40 +00:00
6f4e7d3c75
Booting a payload out of NAND FLASH from the SPL is a crux today, as it requires hard partioned FLASH. Not a brilliant idea with the reliability of todays NAND FLASH chips. The upstream UBI + UBI fastmap implementation which is about to brought to u-boot is too heavy weight for SPLs as it provides way more functionality than needed for a SPL and does not even fit into the restricted SPL areas which are loaded from the SoC boot ROM. So this provides a fast and lightweight implementation of UBI scanning and UBI fastmap attach. The scan and logical to physical block mapping code is developed from scratch, while the fastmap implementation is lifted from the linux kernel source and stripped down to fit the SPL needs. The text foot print on the board which I used for development is: 6854 0 0 6854 1abd drivers/mtd/ubispl/built-in.o Attaching a NAND chip with 4096 physical eraseblocks (4 blocks are reserved for the SPL) takes: In full scan mode: 1172ms In fastmap mode: 95ms The code requires quite some storage. The largest and unknown part of it is the number of fastmap blocks to read. Therefor the data structure is not put into the BSS. The code requires a pointer to free memory handed in which is initialized by the UBI attach code itself. See doc/README.ubispl for further information on how to use it. This shares the ubi-media.h and crc32 implementation of drivers/mtd/ubi There is no way to share the fastmap code, as UBISPL only utilizes the slightly modified functions ubi_attach_fastmap() and ubi_scan_fastmap() from the original kernel ubi fastmap implementation. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ladislav Michl <ladis@linux-mips.org> Acked-by: Heiko Schocher <hs@denx.de> Reviewed-by: Tom Rini <trini@konsulko.com>
141 lines
4.1 KiB
Text
141 lines
4.1 KiB
Text
Lightweight UBI and UBI fastmap support
|
|
|
|
# Copyright (C) Thomas Gleixner <tglx@linutronix.de>
|
|
#
|
|
# SPDX-License-Identifier: GPL 2.0+ BSD-3-Clause
|
|
|
|
Scans the UBI information and loads the requested static volumes into
|
|
memory.
|
|
|
|
Configuration Options:
|
|
|
|
CONFIG_SPL_UBI
|
|
Enables the SPL UBI support
|
|
|
|
CONFIG_SPL_UBI_MAX_VOL_LEBS
|
|
The maximum number of logical eraseblocks which a static volume
|
|
to load can contain. Used for sizing the scan data structure
|
|
|
|
CONFIG_SPL_UBI_MAX_PEB_SIZE
|
|
The maximum physical erase block size. Either a compile time
|
|
constant or runtime detection. Used for sizing the scan data
|
|
structure
|
|
|
|
CONFIG_SPL_UBI_MAX_PEBS
|
|
The maximum physical erase block count. Either a compile time
|
|
constant or runtime detection. Used for sizing the scan data
|
|
structure
|
|
|
|
CONFIG_SPL_UBI_VOL_IDS
|
|
The maximum volume ids which can be loaded. Used for sizing the
|
|
scan data structure.
|
|
|
|
Usage notes:
|
|
|
|
In the board config file define for example:
|
|
|
|
#define CONFIG_SPL_UBI
|
|
#define CONFIG_SPL_UBI_MAX_VOL_LEBS 256
|
|
#define CONFIG_SPL_UBI_MAX_PEB_SIZE (256*1024)
|
|
#define CONFIG_SPL_UBI_MAX_PEBS 4096
|
|
#define CONFIG_SPL_UBI_VOL_IDS 8
|
|
|
|
The size requirement is roughly as follows:
|
|
|
|
2k for the basic data structure
|
|
+ CONFIG_SPL_UBI_VOL_IDS * CONFIG_SPL_UBI_MAX_VOL_LEBS * 8
|
|
+ CONFIG_SPL_UBI_MAX_PEBS * 64
|
|
+ CONFIG_SPL_UBI_MAX_PEB_SIZE * UBI_FM_MAX_BLOCKS
|
|
|
|
The last one is big, but I really don't care in that stage. Real world
|
|
implementations only use the first couple of blocks, but the code
|
|
handles up to UBI_FM_MAX_BLOCKS.
|
|
|
|
Given the above configuration example the requirement is about 5M
|
|
which is usually not a problem to reserve in the RAM along with the
|
|
other areas like the kernel/dts load address.
|
|
|
|
So something like this will do the trick:
|
|
|
|
#define SPL_FINFO_ADDR 0x80800000
|
|
#define SPL_DTB_LOAD_ADDR 0x81800000
|
|
#define SPL_KERNEL_LOAD_ADDR 0x82000000
|
|
|
|
In the board file, implement the following:
|
|
|
|
static struct ubispl_load myvolumes[] = {
|
|
{
|
|
.vol_id = 0, /* kernel volume */
|
|
.load_addr = (void *)SPL_KERNEL_LOAD_ADDR,
|
|
},
|
|
{
|
|
.vol_id = 1, /* DT blob */
|
|
.load_addr = (void *)SPL_DTB_LOAD_ADDR,
|
|
}
|
|
};
|
|
|
|
int spl_start_uboot(void)
|
|
{
|
|
struct ubispl_info info;
|
|
|
|
info.ubi = (struct ubi_scan_info *) SPL_FINFO_ADDR;
|
|
info.fastmap = 1;
|
|
info.read = nand_spl_read_flash;
|
|
|
|
#if COMPILE_TIME_DEFINED
|
|
/*
|
|
* MY_NAND_NR_SPL_PEBS is the number of physical erase blocks
|
|
* in the FLASH which are reserved for the SPL. Think about
|
|
* mtd partitions:
|
|
*
|
|
* part_spl { .start = 0, .end = 4 }
|
|
* part_ubi { .start = 4, .end = NR_PEBS }
|
|
*/
|
|
info.peb_offset = MY_NAND_NR_SPL_PEBS;
|
|
info.peb_size = CONFIG_SYS_NAND_BLOCK_SIZE;
|
|
info.vid_offset = MY_NAND_UBI_VID_OFFS;
|
|
info.leb_start = MY_NAND_UBI_DATA_OFFS;
|
|
info.peb_count = MY_NAND_UBI_NUM_PEBS;
|
|
#else
|
|
get_flash_info(&flash_info);
|
|
info.peb_offset = MY_NAND_NR_SPL_PEBS;
|
|
info.peb_size = flash_info.peb_size;
|
|
|
|
/*
|
|
* The VID and Data offset depend on the capability of the
|
|
* FLASH chip to do subpage writes.
|
|
*
|
|
* If the flash chip supports subpage writes, then the VID
|
|
* header starts at the second subpage. So for 2k pages size
|
|
* with 4 subpages the VID offset is 512. The DATA offset is 2k.
|
|
*
|
|
* If the flash chip does not support subpage writes then the
|
|
* VID offset is FLASH_PAGE_SIZE and the DATA offset
|
|
* 2 * FLASH_PAGE_SIZE
|
|
*/
|
|
info.vid_offset = flash_info.vid_offset;
|
|
info.leb_start = flash_info.data_offset;
|
|
|
|
/*
|
|
* The flash reports the total number of erase blocks, so
|
|
* we need to subtract the number of blocks which are reserved
|
|
* for the SPL itself and not managed by UBI.
|
|
*/
|
|
info.peb_count = flash_info.peb_count - MY_NAND_NR_SPL_PEBS;
|
|
#endif
|
|
|
|
ret = ubispl_load_volumes(&info, myvolumes, ARRAY_SIZE(myvolumes);
|
|
|
|
....
|
|
|
|
}
|
|
|
|
Note: you can load any payload that way. You can even load u-boot from
|
|
UBI, so the only non UBI managed FLASH area is the one which is
|
|
reserved for the SPL itself and read from the SoC ROM.
|
|
|
|
And you can do fallback scenarios:
|
|
|
|
if (ubispl_load_volumes(&info, volumes0, ARRAY_SIZE(volumes0)))
|
|
if (ubispl_load_volumes(&info, volumes1, ARRAY_SIZE(volumes1)))
|
|
ubispl_load_volumes(&info, vol_uboot, ARRAY_SIZE(vol_uboot));
|