1d97b4ce8STom Rini /* 2d97b4ce8STom Rini * Copyright (C) 2011 3d97b4ce8STom Rini * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de> 4d97b4ce8STom Rini * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 6d97b4ce8STom Rini */ 7d97b4ce8STom Rini #include <common.h> 8d97b4ce8STom Rini #include <config.h> 9d97b4ce8STom Rini #include <spl.h> 10d97b4ce8STom Rini #include <asm/io.h> 11d97b4ce8STom Rini #include <nand.h> 128bd88772SLokesh Vutla #include <libfdt_env.h> 138bd88772SLokesh Vutla #include <fdt.h> 14d97b4ce8STom Rini 150c3117b1SHeiko Schocher #if defined(CONFIG_SPL_NAND_RAW_ONLY) 162a2ee2acSSimon Glass int spl_nand_load_image(struct spl_image_info *spl_image, 172a2ee2acSSimon Glass struct spl_boot_device *bootdev) 180c3117b1SHeiko Schocher { 190c3117b1SHeiko Schocher nand_init(); 200c3117b1SHeiko Schocher 210c3117b1SHeiko Schocher nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, 220c3117b1SHeiko Schocher CONFIG_SYS_NAND_U_BOOT_SIZE, 230c3117b1SHeiko Schocher (void *)CONFIG_SYS_NAND_U_BOOT_DST); 242a2ee2acSSimon Glass spl_set_header_raw_uboot(spl_image); 250c3117b1SHeiko Schocher nand_deselect(); 2636afd451SNikita Kiryanov 2736afd451SNikita Kiryanov return 0; 280c3117b1SHeiko Schocher } 290c3117b1SHeiko Schocher #else 308bd88772SLokesh Vutla 318bd88772SLokesh Vutla static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs, 328bd88772SLokesh Vutla ulong size, void *dst) 338bd88772SLokesh Vutla { 348bd88772SLokesh Vutla int ret; 358bd88772SLokesh Vutla 368bd88772SLokesh Vutla ret = nand_spl_load_image(offs, size, dst); 378bd88772SLokesh Vutla if (!ret) 388bd88772SLokesh Vutla return size; 398bd88772SLokesh Vutla else 408bd88772SLokesh Vutla return 0; 418bd88772SLokesh Vutla } 428bd88772SLokesh Vutla 432a2ee2acSSimon Glass static int spl_nand_load_element(struct spl_image_info *spl_image, 442a2ee2acSSimon Glass int offset, struct image_header *header) 45483ab3dcSNikita Kiryanov { 46483ab3dcSNikita Kiryanov int err; 47483ab3dcSNikita Kiryanov 48483ab3dcSNikita Kiryanov err = nand_spl_load_image(offset, sizeof(*header), (void *)header); 49483ab3dcSNikita Kiryanov if (err) 50483ab3dcSNikita Kiryanov return err; 51483ab3dcSNikita Kiryanov 528bd88772SLokesh Vutla if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && 538bd88772SLokesh Vutla image_get_magic(header) == FDT_MAGIC) { 548bd88772SLokesh Vutla struct spl_load_info load; 558bd88772SLokesh Vutla 568bd88772SLokesh Vutla debug("Found FIT\n"); 578bd88772SLokesh Vutla load.dev = NULL; 588bd88772SLokesh Vutla load.priv = NULL; 598bd88772SLokesh Vutla load.filename = NULL; 608bd88772SLokesh Vutla load.bl_len = 1; 618bd88772SLokesh Vutla load.read = spl_nand_fit_read; 62*f4d7d859SSimon Glass return spl_load_simple_fit(spl_image, &load, offset, header); 638bd88772SLokesh Vutla } else { 642a2ee2acSSimon Glass err = spl_parse_image_header(spl_image, header); 657e0f2267SMarek Vasut if (err) 667e0f2267SMarek Vasut return err; 672a2ee2acSSimon Glass return nand_spl_load_image(offset, spl_image->size, 682a2ee2acSSimon Glass (void *)(ulong)spl_image->load_addr); 698bd88772SLokesh Vutla } 70483ab3dcSNikita Kiryanov } 71483ab3dcSNikita Kiryanov 722a2ee2acSSimon Glass static int spl_nand_load_image(struct spl_image_info *spl_image, 732a2ee2acSSimon Glass struct spl_boot_device *bootdev) 74d97b4ce8STom Rini { 7536afd451SNikita Kiryanov int err; 76d97b4ce8STom Rini struct image_header *header; 77d97b4ce8STom Rini int *src __attribute__((unused)); 78d97b4ce8STom Rini int *dst __attribute__((unused)); 79d97b4ce8STom Rini 808122d216SAhmed Samir Khalil #ifdef CONFIG_SPL_NAND_SOFTECC 818122d216SAhmed Samir Khalil debug("spl: nand - using sw ecc\n"); 828122d216SAhmed Samir Khalil #else 83d97b4ce8STom Rini debug("spl: nand - using hw ecc\n"); 848122d216SAhmed Samir Khalil #endif 85d97b4ce8STom Rini nand_init(); 86d97b4ce8STom Rini 87d97b4ce8STom Rini /*use CONFIG_SYS_TEXT_BASE as temporary storage area */ 88d97b4ce8STom Rini header = (struct image_header *)(CONFIG_SYS_TEXT_BASE); 89d97b4ce8STom Rini #ifdef CONFIG_SPL_OS_BOOT 90d97b4ce8STom Rini if (!spl_start_uboot()) { 91d97b4ce8STom Rini /* 92d97b4ce8STom Rini * load parameter image 93d97b4ce8STom Rini * load to temp position since nand_spl_load_image reads 94d97b4ce8STom Rini * a whole block which is typically larger than 95d97b4ce8STom Rini * CONFIG_CMD_SPL_WRITE_SIZE therefore may overwrite 96d97b4ce8STom Rini * following sections like BSS 97d97b4ce8STom Rini */ 98d97b4ce8STom Rini nand_spl_load_image(CONFIG_CMD_SPL_NAND_OFS, 99d97b4ce8STom Rini CONFIG_CMD_SPL_WRITE_SIZE, 100d97b4ce8STom Rini (void *)CONFIG_SYS_TEXT_BASE); 101d97b4ce8STom Rini /* copy to destintion */ 102d97b4ce8STom Rini for (dst = (int *)CONFIG_SYS_SPL_ARGS_ADDR, 103d97b4ce8STom Rini src = (int *)CONFIG_SYS_TEXT_BASE; 104d97b4ce8STom Rini src < (int *)(CONFIG_SYS_TEXT_BASE + 105d97b4ce8STom Rini CONFIG_CMD_SPL_WRITE_SIZE); 106d97b4ce8STom Rini src++, dst++) { 107d97b4ce8STom Rini writel(readl(src), dst); 108d97b4ce8STom Rini } 109d97b4ce8STom Rini 110d97b4ce8STom Rini /* load linux */ 111d97b4ce8STom Rini nand_spl_load_image(CONFIG_SYS_NAND_SPL_KERNEL_OFFS, 112c13bb167SMasahiro Yamada sizeof(*header), (void *)header); 1132a2ee2acSSimon Glass err = spl_parse_image_header(spl_image, header); 1147e0f2267SMarek Vasut if (err) 1157e0f2267SMarek Vasut return err; 116d97b4ce8STom Rini if (header->ih_os == IH_OS_LINUX) { 117d97b4ce8STom Rini /* happy - was a linux */ 11836afd451SNikita Kiryanov err = nand_spl_load_image( 11936afd451SNikita Kiryanov CONFIG_SYS_NAND_SPL_KERNEL_OFFS, 1202a2ee2acSSimon Glass spl_image->size, 1212a2ee2acSSimon Glass (void *)spl_image->load_addr); 122d97b4ce8STom Rini nand_deselect(); 12336afd451SNikita Kiryanov return err; 124d97b4ce8STom Rini } else { 125d97b4ce8STom Rini puts("The Expected Linux image was not " 126d97b4ce8STom Rini "found. Please check your NAND " 127d97b4ce8STom Rini "configuration.\n"); 128d97b4ce8STom Rini puts("Trying to start u-boot now...\n"); 129d97b4ce8STom Rini } 130d97b4ce8STom Rini } 131d97b4ce8STom Rini #endif 132d97b4ce8STom Rini #ifdef CONFIG_NAND_ENV_DST 1332a2ee2acSSimon Glass spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET, header); 134d97b4ce8STom Rini #ifdef CONFIG_ENV_OFFSET_REDUND 1352a2ee2acSSimon Glass spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET_REDUND, header); 136d97b4ce8STom Rini #endif 137d97b4ce8STom Rini #endif 138d97b4ce8STom Rini /* Load u-boot */ 1392a2ee2acSSimon Glass err = spl_nand_load_element(spl_image, CONFIG_SYS_NAND_U_BOOT_OFFS, 1402a2ee2acSSimon Glass header); 14180ef700fSBoris Brezillon #ifdef CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND 14280ef700fSBoris Brezillon #if CONFIG_SYS_NAND_U_BOOT_OFFS != CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND 14380ef700fSBoris Brezillon if (err) 1442a2ee2acSSimon Glass err = spl_nand_load_element(spl_image, 1452a2ee2acSSimon Glass CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND, 14680ef700fSBoris Brezillon header); 14780ef700fSBoris Brezillon #endif 14880ef700fSBoris Brezillon #endif 149d97b4ce8STom Rini nand_deselect(); 15036afd451SNikita Kiryanov return err; 151d97b4ce8STom Rini } 1520c3117b1SHeiko Schocher #endif 153d5c2b11cSSimon Glass /* Use priorty 1 so that Ubi can override this */ 154d5c2b11cSSimon Glass SPL_LOAD_IMAGE_METHOD(1, BOOT_DEVICE_NAND, spl_nand_load_image); 155