183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2d97b4ce8STom Rini /*
3d97b4ce8STom Rini * Copyright (C) 2011
4d97b4ce8STom Rini * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
5d97b4ce8STom Rini */
6d97b4ce8STom Rini #include <common.h>
7d97b4ce8STom Rini #include <config.h>
8d97b4ce8STom Rini #include <spl.h>
9d97b4ce8STom Rini #include <asm/io.h>
10d97b4ce8STom Rini #include <nand.h>
11b08c8c48SMasahiro Yamada #include <linux/libfdt_env.h>
128bd88772SLokesh Vutla #include <fdt.h>
13d97b4ce8STom Rini
140c3117b1SHeiko Schocher #if defined(CONFIG_SPL_NAND_RAW_ONLY)
spl_nand_load_image(struct spl_image_info * spl_image,struct spl_boot_device * bootdev)1525dabd73SMichael Trimarchi static int spl_nand_load_image(struct spl_image_info *spl_image,
162a2ee2acSSimon Glass struct spl_boot_device *bootdev)
170c3117b1SHeiko Schocher {
180c3117b1SHeiko Schocher nand_init();
190c3117b1SHeiko Schocher
200c3117b1SHeiko Schocher nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,
210c3117b1SHeiko Schocher CONFIG_SYS_NAND_U_BOOT_SIZE,
220c3117b1SHeiko Schocher (void *)CONFIG_SYS_NAND_U_BOOT_DST);
232a2ee2acSSimon Glass spl_set_header_raw_uboot(spl_image);
240c3117b1SHeiko Schocher nand_deselect();
2536afd451SNikita Kiryanov
2636afd451SNikita Kiryanov return 0;
270c3117b1SHeiko Schocher }
280c3117b1SHeiko Schocher #else
298bd88772SLokesh Vutla
spl_nand_fit_read(struct spl_load_info * load,ulong offs,ulong size,void * dst)308bd88772SLokesh Vutla static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs,
318bd88772SLokesh Vutla ulong size, void *dst)
328bd88772SLokesh Vutla {
338bd88772SLokesh Vutla int ret;
348bd88772SLokesh Vutla
358bd88772SLokesh Vutla ret = nand_spl_load_image(offs, size, dst);
368bd88772SLokesh Vutla if (!ret)
378bd88772SLokesh Vutla return size;
388bd88772SLokesh Vutla else
398bd88772SLokesh Vutla return 0;
408bd88772SLokesh Vutla }
418bd88772SLokesh Vutla
spl_nand_load_element(struct spl_image_info * spl_image,int offset,struct image_header * header)422a2ee2acSSimon Glass static int spl_nand_load_element(struct spl_image_info *spl_image,
432a2ee2acSSimon Glass int offset, struct image_header *header)
44483ab3dcSNikita Kiryanov {
45483ab3dcSNikita Kiryanov int err;
46483ab3dcSNikita Kiryanov
47483ab3dcSNikita Kiryanov err = nand_spl_load_image(offset, sizeof(*header), (void *)header);
48483ab3dcSNikita Kiryanov if (err)
49483ab3dcSNikita Kiryanov return err;
50483ab3dcSNikita Kiryanov
518bd88772SLokesh Vutla if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
528bd88772SLokesh Vutla image_get_magic(header) == FDT_MAGIC) {
538bd88772SLokesh Vutla struct spl_load_info load;
548bd88772SLokesh Vutla
558bd88772SLokesh Vutla debug("Found FIT\n");
568bd88772SLokesh Vutla load.dev = NULL;
578bd88772SLokesh Vutla load.priv = NULL;
588bd88772SLokesh Vutla load.filename = NULL;
598bd88772SLokesh Vutla load.bl_len = 1;
608bd88772SLokesh Vutla load.read = spl_nand_fit_read;
61f4d7d859SSimon Glass return spl_load_simple_fit(spl_image, &load, offset, header);
628bd88772SLokesh Vutla } else {
632a2ee2acSSimon Glass err = spl_parse_image_header(spl_image, header);
647e0f2267SMarek Vasut if (err)
657e0f2267SMarek Vasut return err;
662a2ee2acSSimon Glass return nand_spl_load_image(offset, spl_image->size,
672a2ee2acSSimon Glass (void *)(ulong)spl_image->load_addr);
688bd88772SLokesh Vutla }
69483ab3dcSNikita Kiryanov }
70483ab3dcSNikita Kiryanov
spl_nand_load_image(struct spl_image_info * spl_image,struct spl_boot_device * bootdev)712a2ee2acSSimon Glass static int spl_nand_load_image(struct spl_image_info *spl_image,
722a2ee2acSSimon Glass struct spl_boot_device *bootdev)
73d97b4ce8STom Rini {
7436afd451SNikita Kiryanov int err;
75d97b4ce8STom Rini struct image_header *header;
76d97b4ce8STom Rini int *src __attribute__((unused));
77d97b4ce8STom Rini int *dst __attribute__((unused));
78d97b4ce8STom Rini
798122d216SAhmed Samir Khalil #ifdef CONFIG_SPL_NAND_SOFTECC
808122d216SAhmed Samir Khalil debug("spl: nand - using sw ecc\n");
818122d216SAhmed Samir Khalil #else
82d97b4ce8STom Rini debug("spl: nand - using hw ecc\n");
838122d216SAhmed Samir Khalil #endif
84d97b4ce8STom Rini nand_init();
85d97b4ce8STom Rini
86*04ce5427SMarek Vasut header = spl_get_load_buffer(0, sizeof(*header));
87*04ce5427SMarek Vasut
88d97b4ce8STom Rini #ifdef CONFIG_SPL_OS_BOOT
89d97b4ce8STom Rini if (!spl_start_uboot()) {
90d97b4ce8STom Rini /*
91d97b4ce8STom Rini * load parameter image
92d97b4ce8STom Rini * load to temp position since nand_spl_load_image reads
93d97b4ce8STom Rini * a whole block which is typically larger than
94d97b4ce8STom Rini * CONFIG_CMD_SPL_WRITE_SIZE therefore may overwrite
95d97b4ce8STom Rini * following sections like BSS
96d97b4ce8STom Rini */
97d97b4ce8STom Rini nand_spl_load_image(CONFIG_CMD_SPL_NAND_OFS,
98d97b4ce8STom Rini CONFIG_CMD_SPL_WRITE_SIZE,
99d97b4ce8STom Rini (void *)CONFIG_SYS_TEXT_BASE);
100d97b4ce8STom Rini /* copy to destintion */
101d97b4ce8STom Rini for (dst = (int *)CONFIG_SYS_SPL_ARGS_ADDR,
102d97b4ce8STom Rini src = (int *)CONFIG_SYS_TEXT_BASE;
103d97b4ce8STom Rini src < (int *)(CONFIG_SYS_TEXT_BASE +
104d97b4ce8STom Rini CONFIG_CMD_SPL_WRITE_SIZE);
105d97b4ce8STom Rini src++, dst++) {
106d97b4ce8STom Rini writel(readl(src), dst);
107d97b4ce8STom Rini }
108d97b4ce8STom Rini
109d97b4ce8STom Rini /* load linux */
110d97b4ce8STom Rini nand_spl_load_image(CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
111c13bb167SMasahiro Yamada sizeof(*header), (void *)header);
1122a2ee2acSSimon Glass err = spl_parse_image_header(spl_image, header);
1137e0f2267SMarek Vasut if (err)
1147e0f2267SMarek Vasut return err;
115d97b4ce8STom Rini if (header->ih_os == IH_OS_LINUX) {
116d97b4ce8STom Rini /* happy - was a linux */
11736afd451SNikita Kiryanov err = nand_spl_load_image(
11836afd451SNikita Kiryanov CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
1192a2ee2acSSimon Glass spl_image->size,
1202a2ee2acSSimon Glass (void *)spl_image->load_addr);
121d97b4ce8STom Rini nand_deselect();
12236afd451SNikita Kiryanov return err;
123d97b4ce8STom Rini } else {
124d97b4ce8STom Rini puts("The Expected Linux image was not "
125d97b4ce8STom Rini "found. Please check your NAND "
126d97b4ce8STom Rini "configuration.\n");
127d97b4ce8STom Rini puts("Trying to start u-boot now...\n");
128d97b4ce8STom Rini }
129d97b4ce8STom Rini }
130d97b4ce8STom Rini #endif
131d97b4ce8STom Rini #ifdef CONFIG_NAND_ENV_DST
1322a2ee2acSSimon Glass spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET, header);
133d97b4ce8STom Rini #ifdef CONFIG_ENV_OFFSET_REDUND
1342a2ee2acSSimon Glass spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET_REDUND, header);
135d97b4ce8STom Rini #endif
136d97b4ce8STom Rini #endif
137d97b4ce8STom Rini /* Load u-boot */
1382a2ee2acSSimon Glass err = spl_nand_load_element(spl_image, CONFIG_SYS_NAND_U_BOOT_OFFS,
1392a2ee2acSSimon Glass header);
14080ef700fSBoris Brezillon #ifdef CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
14180ef700fSBoris Brezillon #if CONFIG_SYS_NAND_U_BOOT_OFFS != CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
14280ef700fSBoris Brezillon if (err)
1432a2ee2acSSimon Glass err = spl_nand_load_element(spl_image,
1442a2ee2acSSimon Glass CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND,
14580ef700fSBoris Brezillon header);
14680ef700fSBoris Brezillon #endif
14780ef700fSBoris Brezillon #endif
148d97b4ce8STom Rini nand_deselect();
14936afd451SNikita Kiryanov return err;
150d97b4ce8STom Rini }
1510c3117b1SHeiko Schocher #endif
152d5c2b11cSSimon Glass /* Use priorty 1 so that Ubi can override this */
153ebc4ef61SSimon Glass SPL_LOAD_IMAGE_METHOD("NAND", 1, BOOT_DEVICE_NAND, spl_nand_load_image);
154