Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2011 * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de> */ #include <config.h> #include <fdt_support.h> #include <image.h> #include <imx_container.h> #include <log.h> #include <spl.h> #include <spl_load.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 __weak u32 nand_spl_adjust_offset(u32 sector, u32 offs) { return offs; } static ulong spl_nand_read(struct spl_load_info *load, ulong offs, ulong size, void *dst) { int err; ulong sector; debug("%s: offs %lx, size %lx, dst %p\n", __func__, offs, size, dst); sector = *(int *)load->priv; offs = sector + nand_spl_adjust_offset(sector, offs - sector); err = nand_spl_load_image(offs, size, dst); spl_set_bl_len(load, nand_page_size()); 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 spl_load_info load; spl_load_init(&load, spl_nand_read, &offset, 1); return spl_load(spl_image, bootdev, &load, 0, offset); } #if IS_ENABLED(CONFIG_SPL_OS_BOOT) static int spl_nand_load_image_os(struct spl_image_info *spl_image, struct spl_boot_device *bootdev) { int err; struct legacy_img_hdr *header = spl_get_load_buffer(0, sizeof(*header)); /* 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) return -EINVAL; /* 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(); if (err) return err; #if IS_ENABLED(CONFIG_SPL_OS_BOOT_ARGS) /* * 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 */ int *src, *dst; 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); } #endif return 0; } #endif static int spl_nand_load_image(struct spl_image_info *spl_image, struct spl_boot_device *bootdev) { int err; #ifdef CONFIG_SPL_NAND_SOFTECC debug("spl: nand - using sw ecc\n"); #else debug("spl: nand - using hw ecc\n"); #endif nand_init(); #if CONFIG_IS_ENABLED(OS_BOOT) if (!spl_start_uboot()) { err = spl_nand_load_image_os(spl_image, bootdev); if (!err) return 0; printf("%s: Failed in falcon boot: %d", __func__, err); if (IS_ENABLED(CONFIG_SPL_OS_BOOT_SECURE)) return err; printf("Fallback to U-Boot\n"); } #endif #ifdef CONFIG_NAND_ENV_DST spl_nand_load_element(spl_image, bootdev, CONFIG_ENV_OFFSET); #ifdef CONFIG_ENV_OFFSET_REDUND spl_nand_load_element(spl_image, bootdev, CONFIG_ENV_OFFSET_REDUND); #endif #endif /* Load u-boot */ err = spl_nand_load_element(spl_image, bootdev, spl_nand_get_uboot_raw_page()); #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); #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); |