u-boot/common/spl/spl_nand.c

209 lines
5.4 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011
* Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
*/
#include <common.h>
#include <config.h>
#include <fdt_support.h>
#include <image.h>
arm: imx: Check header before calling spl_load_imx_container Make sure we have an IMX header before calling spl_load_imx_container, since if we don't it will fail with -ENOENT. This allows us to fall back to legacy/raw images if they are also enabled. This is a functional change, one which likely should have been in place from the start, but a functional change nonetheless. Previously, all non-IMX8 images (except FITs without FIT_FULL) would be optimized out if the only image load method enabled supported IMX8 images. With this change, support for other image types now has an effect. There are seven boards with SPL_LOAD_IMX_CONTAINER enabled: three with SPL_BOOTROM_SUPPORT: imx93_11x11_evk_ld imx93_11x11_evk imx8ulp_evk and four with SPL_MMC: deneb imx8qxp_mek giedi imx8qm_mek All of these boards also have SPL_RAW_IMAGE_SUPPORT and SPL_LEGACY_IMAGE_FORMAT enabled as well. However, none have FIT support enabled. Of the six load methods affected by this patch, only SPL_MMC and SPL_BOOTROM_SUPPORT are enabled with SPL_LOAD_IMX_CONTAINER. spl_romapi_load_image_seekable does not support legacy or raw images, so there is no growth. However, mmc_load_image_raw_sector does support loading legacy/raw images. Since these images could not have been booted before, I have disabled support for legacy/raw images on these four boards. This reduces bloat from around 800 bytes to around 200. There are no in-tree boards with SPL_LOAD_IMX_CONTAINER and AHAB_BOOT both enabled, so we do not need to worry about potentially falling back to legacy images in a secure boot scenario. Future work could include merging imx_container.h with imx8image.h, since they appear to define mostly the same structures. Signed-off-by: Sean Anderson <seanga2@gmail.com>
2023-10-14 20:47:44 +00:00
#include <imx_container.h>
#include <log.h>
#include <spl.h>
#include <asm/io.h>
#include <mapmem.h>
#include <nand.h>
#include <linux/libfdt_env.h>
#include <fdt.h>
uint32_t __weak spl_nand_get_uboot_raw_page(void)
{
return CONFIG_SYS_NAND_U_BOOT_OFFS;
}
#if defined(CONFIG_SPL_NAND_RAW_ONLY)
static int spl_nand_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
nand_init();
printf("Loading U-Boot from 0x%08x (size 0x%08x) to 0x%08x\n",
CONFIG_SYS_NAND_U_BOOT_OFFS, CFG_SYS_NAND_U_BOOT_SIZE,
CFG_SYS_NAND_U_BOOT_DST);
nand_spl_load_image(spl_nand_get_uboot_raw_page(),
CFG_SYS_NAND_U_BOOT_SIZE,
map_sysmem(CFG_SYS_NAND_U_BOOT_DST,
CFG_SYS_NAND_U_BOOT_SIZE));
spl_set_header_raw_uboot(spl_image);
nand_deselect();
return 0;
}
#else
static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs,
ulong size, void *dst)
{
int err;
ulong sector;
sector = *(int *)load->priv;
offs = sector + nand_spl_adjust_offset(sector, offs - sector);
err = nand_spl_load_image(offs, size, dst);
if (err)
return 0;
return size;
}
static ulong spl_nand_legacy_read(struct spl_load_info *load, ulong offs,
ulong size, void *dst)
{
int err;
debug("%s: offs %lx, size %lx, dst %p\n",
__func__, offs, size, dst);
err = nand_spl_load_image(offs, size, dst);
if (err)
return 0;
return size;
}
static int spl_nand_load_element(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev,
int offset, struct legacy_img_hdr *header)
{
spl: nand: Set bl_len to page size Since commit 34793598c83 ("mtd: nand: mxs_nand_spl: Remove the page aligned access") there are no longer any users of nand_get_mtd. However, it is still important to know what the page size is so we can allocate a large-enough buffer. If the image size is not page-aligned, we will go off the end of the buffer and clobber some memory. Introduce a new function nand_page_size which returns the page size. For most drivers it is easy to determine the page size. However, a few need to be modified since they only keep the page size around temporarily. It's possible that this patch could cause a regression on some platforms if the offset is non-aligned and there is invalid address space immediately before the load address. spl_load_legacy_img does not (except when compressing) respect bl_len, so only boards with SPL_LOAD_FIT (8 boards) or SPL_LOAD_IMX_CONTAINER (none in tree) would be affected. defconfig CONFIG_TEXT_BASE ======================= ================ am335x_evm 0x80800000 am43xx_evm 0x80800000 am43xx_evm_rtconly 0x80800000 am43xx_evm_usbhost_boot 0x80800000 am43xx_hs_evm 0x80800000 dra7xx_evm 0x80800000 gwventana_nand 0x17800000 imx8mn_bsh_smm_s2 0x40200000 All the sitara boards have DDR mapped at 0x80000000. gwventana is an i.MX6Q which has DDR at 0x10000000. I don't have the IMX8MNRM handy, but on the i.MX8M DDR starts at 0x40000000. Therefore all of these boards can handle a little underflow. Signed-off-by: Sean Anderson <seanga2@gmail.com>
2023-11-04 20:37:44 +00:00
int bl_len;
int err;
err = nand_spl_load_image(offset, sizeof(*header), (void *)header);
if (err)
return err;
spl: nand: Set bl_len to page size Since commit 34793598c83 ("mtd: nand: mxs_nand_spl: Remove the page aligned access") there are no longer any users of nand_get_mtd. However, it is still important to know what the page size is so we can allocate a large-enough buffer. If the image size is not page-aligned, we will go off the end of the buffer and clobber some memory. Introduce a new function nand_page_size which returns the page size. For most drivers it is easy to determine the page size. However, a few need to be modified since they only keep the page size around temporarily. It's possible that this patch could cause a regression on some platforms if the offset is non-aligned and there is invalid address space immediately before the load address. spl_load_legacy_img does not (except when compressing) respect bl_len, so only boards with SPL_LOAD_FIT (8 boards) or SPL_LOAD_IMX_CONTAINER (none in tree) would be affected. defconfig CONFIG_TEXT_BASE ======================= ================ am335x_evm 0x80800000 am43xx_evm 0x80800000 am43xx_evm_rtconly 0x80800000 am43xx_evm_usbhost_boot 0x80800000 am43xx_hs_evm 0x80800000 dra7xx_evm 0x80800000 gwventana_nand 0x17800000 imx8mn_bsh_smm_s2 0x40200000 All the sitara boards have DDR mapped at 0x80000000. gwventana is an i.MX6Q which has DDR at 0x10000000. I don't have the IMX8MNRM handy, but on the i.MX8M DDR starts at 0x40000000. Therefore all of these boards can handle a little underflow. Signed-off-by: Sean Anderson <seanga2@gmail.com>
2023-11-04 20:37:44 +00:00
bl_len = nand_page_size();
if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
image_get_magic(header) == FDT_MAGIC) {
struct spl_load_info load;
debug("Found FIT\n");
load.priv = &offset;
load.filename = NULL;
load.bl_len = bl_len;
load.read = spl_nand_fit_read;
return spl_load_simple_fit(spl_image, &load, offset, header);
arm: imx: Check header before calling spl_load_imx_container Make sure we have an IMX header before calling spl_load_imx_container, since if we don't it will fail with -ENOENT. This allows us to fall back to legacy/raw images if they are also enabled. This is a functional change, one which likely should have been in place from the start, but a functional change nonetheless. Previously, all non-IMX8 images (except FITs without FIT_FULL) would be optimized out if the only image load method enabled supported IMX8 images. With this change, support for other image types now has an effect. There are seven boards with SPL_LOAD_IMX_CONTAINER enabled: three with SPL_BOOTROM_SUPPORT: imx93_11x11_evk_ld imx93_11x11_evk imx8ulp_evk and four with SPL_MMC: deneb imx8qxp_mek giedi imx8qm_mek All of these boards also have SPL_RAW_IMAGE_SUPPORT and SPL_LEGACY_IMAGE_FORMAT enabled as well. However, none have FIT support enabled. Of the six load methods affected by this patch, only SPL_MMC and SPL_BOOTROM_SUPPORT are enabled with SPL_LOAD_IMX_CONTAINER. spl_romapi_load_image_seekable does not support legacy or raw images, so there is no growth. However, mmc_load_image_raw_sector does support loading legacy/raw images. Since these images could not have been booted before, I have disabled support for legacy/raw images on these four boards. This reduces bloat from around 800 bytes to around 200. There are no in-tree boards with SPL_LOAD_IMX_CONTAINER and AHAB_BOOT both enabled, so we do not need to worry about potentially falling back to legacy images in a secure boot scenario. Future work could include merging imx_container.h with imx8image.h, since they appear to define mostly the same structures. Signed-off-by: Sean Anderson <seanga2@gmail.com>
2023-10-14 20:47:44 +00:00
} else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) &&
valid_container_hdr((void *)header)) {
struct spl_load_info load;
load.priv = &offset;
load.filename = NULL;
load.bl_len = bl_len;
load.read = spl_nand_fit_read;
return spl_load_imx_container(spl_image, &load, offset);
} else if (IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_FORMAT) &&
image_get_magic(header) == IH_MAGIC) {
struct spl_load_info load;
debug("Found legacy image\n");
load.filename = NULL;
spl: nand: Set bl_len to page size Since commit 34793598c83 ("mtd: nand: mxs_nand_spl: Remove the page aligned access") there are no longer any users of nand_get_mtd. However, it is still important to know what the page size is so we can allocate a large-enough buffer. If the image size is not page-aligned, we will go off the end of the buffer and clobber some memory. Introduce a new function nand_page_size which returns the page size. For most drivers it is easy to determine the page size. However, a few need to be modified since they only keep the page size around temporarily. It's possible that this patch could cause a regression on some platforms if the offset is non-aligned and there is invalid address space immediately before the load address. spl_load_legacy_img does not (except when compressing) respect bl_len, so only boards with SPL_LOAD_FIT (8 boards) or SPL_LOAD_IMX_CONTAINER (none in tree) would be affected. defconfig CONFIG_TEXT_BASE ======================= ================ am335x_evm 0x80800000 am43xx_evm 0x80800000 am43xx_evm_rtconly 0x80800000 am43xx_evm_usbhost_boot 0x80800000 am43xx_hs_evm 0x80800000 dra7xx_evm 0x80800000 gwventana_nand 0x17800000 imx8mn_bsh_smm_s2 0x40200000 All the sitara boards have DDR mapped at 0x80000000. gwventana is an i.MX6Q which has DDR at 0x10000000. I don't have the IMX8MNRM handy, but on the i.MX8M DDR starts at 0x40000000. Therefore all of these boards can handle a little underflow. Signed-off-by: Sean Anderson <seanga2@gmail.com>
2023-11-04 20:37:44 +00:00
load.bl_len = IS_ENABLED(CONFIG_SPL_LZMA) ? bl_len : 1;
load.read = spl_nand_legacy_read;
return spl_load_legacy_img(spl_image, bootdev, &load, offset, header);
} else {
err = spl_parse_image_header(spl_image, bootdev, header);
if (err)
return err;
return nand_spl_load_image(offset, spl_image->size,
map_sysmem(spl_image->load_addr,
spl_image->size));
}
}
static int spl_nand_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
int err;
struct legacy_img_hdr *header;
int *src __attribute__((unused));
int *dst __attribute__((unused));
#ifdef CONFIG_SPL_NAND_SOFTECC
debug("spl: nand - using sw ecc\n");
#else
debug("spl: nand - using hw ecc\n");
#endif
nand_init();
header = spl_get_load_buffer(0, sizeof(*header));
#if CONFIG_IS_ENABLED(OS_BOOT)
if (!spl_start_uboot()) {
/*
* load parameter image
* load to temp position since nand_spl_load_image reads
* a whole block which is typically larger than
* CONFIG_CMD_SPL_WRITE_SIZE therefore may overwrite
* following sections like BSS
*/
nand_spl_load_image(CONFIG_CMD_SPL_NAND_OFS,
CONFIG_CMD_SPL_WRITE_SIZE,
(void *)CONFIG_TEXT_BASE);
/* copy to destintion */
for (dst = (int *)CONFIG_SPL_PAYLOAD_ARGS_ADDR,
src = (int *)CONFIG_TEXT_BASE;
src < (int *)(CONFIG_TEXT_BASE +
CONFIG_CMD_SPL_WRITE_SIZE);
src++, dst++) {
writel(readl(src), dst);
}
/* load linux */
nand_spl_load_image(CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
sizeof(*header), (void *)header);
err = spl_parse_image_header(spl_image, bootdev, header);
if (err)
return err;
if (header->ih_os == IH_OS_LINUX) {
/* happy - was a linux */
err = nand_spl_load_image(
CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
spl_image->size,
(void *)spl_image->load_addr);
nand_deselect();
return err;
} else {
puts("The Expected Linux image was not "
"found. Please check your NAND "
"configuration.\n");
puts("Trying to start u-boot now...\n");
}
}
#endif
#ifdef CONFIG_NAND_ENV_DST
spl_nand_load_element(spl_image, bootdev, CONFIG_ENV_OFFSET, header);
#ifdef CONFIG_ENV_OFFSET_REDUND
spl_nand_load_element(spl_image, bootdev, CONFIG_ENV_OFFSET_REDUND, header);
#endif
#endif
/* Load u-boot */
err = spl_nand_load_element(spl_image, bootdev, spl_nand_get_uboot_raw_page(),
header);
#ifdef CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
#if CONFIG_SYS_NAND_U_BOOT_OFFS != CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
if (err)
err = spl_nand_load_element(spl_image, bootdev,
CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND,
header);
#endif
#endif
nand_deselect();
return err;
}
#endif
/* Use priorty 1 so that Ubi can override this */
SPL_LOAD_IMAGE_METHOD("NAND", 1, BOOT_DEVICE_NAND, spl_nand_load_image);