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>
10332967aeSYifeng Zhao #include <spl_rkfw.h>
11d97b4ce8STom Rini #include <asm/io.h>
12d97b4ce8STom Rini #include <nand.h>
130e00a84cSMasahiro Yamada #include <linux/libfdt_env.h>
148bd88772SLokesh Vutla #include <fdt.h>
15d97b4ce8STom Rini
160c3117b1SHeiko Schocher #if defined(CONFIG_SPL_NAND_RAW_ONLY)
spl_nand_load_image(struct spl_image_info * spl_image,struct spl_boot_device * bootdev)172a2ee2acSSimon Glass int spl_nand_load_image(struct spl_image_info *spl_image,
182a2ee2acSSimon Glass struct spl_boot_device *bootdev)
190c3117b1SHeiko Schocher {
200c3117b1SHeiko Schocher nand_init();
210c3117b1SHeiko Schocher
220c3117b1SHeiko Schocher nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,
230c3117b1SHeiko Schocher CONFIG_SYS_NAND_U_BOOT_SIZE,
240c3117b1SHeiko Schocher (void *)CONFIG_SYS_NAND_U_BOOT_DST);
252a2ee2acSSimon Glass spl_set_header_raw_uboot(spl_image);
260c3117b1SHeiko Schocher nand_deselect();
2736afd451SNikita Kiryanov
2836afd451SNikita Kiryanov return 0;
290c3117b1SHeiko Schocher }
300c3117b1SHeiko Schocher #else
318bd88772SLokesh Vutla
spl_nand_fit_read(struct spl_load_info * load,ulong offs,ulong size,void * dst)328bd88772SLokesh Vutla static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs,
338bd88772SLokesh Vutla ulong size, void *dst)
348bd88772SLokesh Vutla {
358bd88772SLokesh Vutla int ret;
368bd88772SLokesh Vutla
378bd88772SLokesh Vutla ret = nand_spl_load_image(offs, size, dst);
388bd88772SLokesh Vutla if (!ret)
398bd88772SLokesh Vutla return size;
408bd88772SLokesh Vutla else
418bd88772SLokesh Vutla return 0;
428bd88772SLokesh Vutla }
438bd88772SLokesh Vutla
44332967aeSYifeng Zhao #ifdef CONFIG_SPL_LOAD_RKFW
spl_nand_rkfw_read(struct spl_load_info * load,ulong offs,ulong size,void * dst)45332967aeSYifeng Zhao static ulong spl_nand_rkfw_read(struct spl_load_info *load, ulong offs,
46332967aeSYifeng Zhao ulong size, void *dst)
47332967aeSYifeng Zhao {
48332967aeSYifeng Zhao int ret;
49332967aeSYifeng Zhao
50332967aeSYifeng Zhao ret = nand_spl_load_image(offs * 512, size * 512, dst);
51332967aeSYifeng Zhao if (!ret)
52332967aeSYifeng Zhao return size;
53332967aeSYifeng Zhao else
54332967aeSYifeng Zhao return 0;
55332967aeSYifeng Zhao }
56332967aeSYifeng Zhao #endif
57332967aeSYifeng Zhao
spl_nand_load_element(struct spl_image_info * spl_image,int offset,struct image_header * header)582a2ee2acSSimon Glass static int spl_nand_load_element(struct spl_image_info *spl_image,
592a2ee2acSSimon Glass int offset, struct image_header *header)
60483ab3dcSNikita Kiryanov {
61483ab3dcSNikita Kiryanov int err;
62483ab3dcSNikita Kiryanov
63332967aeSYifeng Zhao #ifdef CONFIG_SPL_LOAD_RKFW
64332967aeSYifeng Zhao struct spl_load_info load;
65332967aeSYifeng Zhao int ret;
66332967aeSYifeng Zhao
67332967aeSYifeng Zhao load.dev = NULL;
68332967aeSYifeng Zhao load.priv = NULL;
69332967aeSYifeng Zhao load.filename = NULL;
70332967aeSYifeng Zhao load.bl_len = 1;
71332967aeSYifeng Zhao load.read = spl_nand_rkfw_read;
72332967aeSYifeng Zhao
73*34f805b8SJoseph Chen ret = spl_load_rkfw_image(spl_image, &load);
74332967aeSYifeng Zhao if (!ret || ret != -EAGAIN)
75332967aeSYifeng Zhao return ret;
76332967aeSYifeng Zhao #endif
77483ab3dcSNikita Kiryanov err = nand_spl_load_image(offset, sizeof(*header), (void *)header);
78483ab3dcSNikita Kiryanov if (err)
79483ab3dcSNikita Kiryanov return err;
80483ab3dcSNikita Kiryanov
8122c7c1a8SJoseph Chen #ifdef CONFIG_SPL_FIT_IMAGE_MULTIPLE
8222c7c1a8SJoseph Chen if ((IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
8322c7c1a8SJoseph Chen image_get_magic(header) == FDT_MAGIC) ||
8422c7c1a8SJoseph Chen CONFIG_SPL_FIT_IMAGE_MULTIPLE > 1) {
8522c7c1a8SJoseph Chen #else
868bd88772SLokesh Vutla if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
878bd88772SLokesh Vutla image_get_magic(header) == FDT_MAGIC) {
8822c7c1a8SJoseph Chen #endif
898bd88772SLokesh Vutla struct spl_load_info load;
908bd88772SLokesh Vutla
918bd88772SLokesh Vutla debug("Found FIT\n");
928bd88772SLokesh Vutla load.dev = NULL;
938bd88772SLokesh Vutla load.priv = NULL;
948bd88772SLokesh Vutla load.filename = NULL;
958bd88772SLokesh Vutla load.bl_len = 1;
968bd88772SLokesh Vutla load.read = spl_nand_fit_read;
97f4d7d859SSimon Glass return spl_load_simple_fit(spl_image, &load, offset, header);
988bd88772SLokesh Vutla } else {
992a2ee2acSSimon Glass err = spl_parse_image_header(spl_image, header);
1007e0f2267SMarek Vasut if (err)
1017e0f2267SMarek Vasut return err;
1022a2ee2acSSimon Glass return nand_spl_load_image(offset, spl_image->size,
1032a2ee2acSSimon Glass (void *)(ulong)spl_image->load_addr);
1048bd88772SLokesh Vutla }
105483ab3dcSNikita Kiryanov }
106483ab3dcSNikita Kiryanov
1072a2ee2acSSimon Glass static int spl_nand_load_image(struct spl_image_info *spl_image,
1082a2ee2acSSimon Glass struct spl_boot_device *bootdev)
109d97b4ce8STom Rini {
11036afd451SNikita Kiryanov int err;
111d97b4ce8STom Rini struct image_header *header;
112d97b4ce8STom Rini int *src __attribute__((unused));
113d97b4ce8STom Rini int *dst __attribute__((unused));
114d97b4ce8STom Rini
1158122d216SAhmed Samir Khalil #ifdef CONFIG_SPL_NAND_SOFTECC
1168122d216SAhmed Samir Khalil debug("spl: nand - using sw ecc\n");
1178122d216SAhmed Samir Khalil #else
118d97b4ce8STom Rini debug("spl: nand - using hw ecc\n");
1198122d216SAhmed Samir Khalil #endif
120d97b4ce8STom Rini nand_init();
121d97b4ce8STom Rini
122d97b4ce8STom Rini /*use CONFIG_SYS_TEXT_BASE as temporary storage area */
123d97b4ce8STom Rini header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
124d97b4ce8STom Rini #ifdef CONFIG_SPL_OS_BOOT
125d97b4ce8STom Rini if (!spl_start_uboot()) {
126d97b4ce8STom Rini /*
127d97b4ce8STom Rini * load parameter image
128d97b4ce8STom Rini * load to temp position since nand_spl_load_image reads
129d97b4ce8STom Rini * a whole block which is typically larger than
130d97b4ce8STom Rini * CONFIG_CMD_SPL_WRITE_SIZE therefore may overwrite
131d97b4ce8STom Rini * following sections like BSS
132d97b4ce8STom Rini */
133d97b4ce8STom Rini nand_spl_load_image(CONFIG_CMD_SPL_NAND_OFS,
134d97b4ce8STom Rini CONFIG_CMD_SPL_WRITE_SIZE,
135d97b4ce8STom Rini (void *)CONFIG_SYS_TEXT_BASE);
136d97b4ce8STom Rini /* copy to destintion */
137d97b4ce8STom Rini for (dst = (int *)CONFIG_SYS_SPL_ARGS_ADDR,
138d97b4ce8STom Rini src = (int *)CONFIG_SYS_TEXT_BASE;
139d97b4ce8STom Rini src < (int *)(CONFIG_SYS_TEXT_BASE +
140d97b4ce8STom Rini CONFIG_CMD_SPL_WRITE_SIZE);
141d97b4ce8STom Rini src++, dst++) {
142d97b4ce8STom Rini writel(readl(src), dst);
143d97b4ce8STom Rini }
144d97b4ce8STom Rini
145d97b4ce8STom Rini /* load linux */
146d97b4ce8STom Rini nand_spl_load_image(CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
147c13bb167SMasahiro Yamada sizeof(*header), (void *)header);
1482a2ee2acSSimon Glass err = spl_parse_image_header(spl_image, header);
1497e0f2267SMarek Vasut if (err)
1507e0f2267SMarek Vasut return err;
151d97b4ce8STom Rini if (header->ih_os == IH_OS_LINUX) {
152d97b4ce8STom Rini /* happy - was a linux */
15336afd451SNikita Kiryanov err = nand_spl_load_image(
15436afd451SNikita Kiryanov CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
1552a2ee2acSSimon Glass spl_image->size,
1562a2ee2acSSimon Glass (void *)spl_image->load_addr);
157d97b4ce8STom Rini nand_deselect();
15836afd451SNikita Kiryanov return err;
159d97b4ce8STom Rini } else {
160d97b4ce8STom Rini puts("The Expected Linux image was not "
161d97b4ce8STom Rini "found. Please check your NAND "
162d97b4ce8STom Rini "configuration.\n");
163d97b4ce8STom Rini puts("Trying to start u-boot now...\n");
164d97b4ce8STom Rini }
165d97b4ce8STom Rini }
166d97b4ce8STom Rini #endif
167d97b4ce8STom Rini #ifdef CONFIG_NAND_ENV_DST
1682a2ee2acSSimon Glass spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET, header);
169d97b4ce8STom Rini #ifdef CONFIG_ENV_OFFSET_REDUND
1702a2ee2acSSimon Glass spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET_REDUND, header);
171d97b4ce8STom Rini #endif
172d97b4ce8STom Rini #endif
173d97b4ce8STom Rini /* Load u-boot */
1742a2ee2acSSimon Glass err = spl_nand_load_element(spl_image, CONFIG_SYS_NAND_U_BOOT_OFFS,
1752a2ee2acSSimon Glass header);
17680ef700fSBoris Brezillon #ifdef CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
17780ef700fSBoris Brezillon #if CONFIG_SYS_NAND_U_BOOT_OFFS != CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
17880ef700fSBoris Brezillon if (err)
1792a2ee2acSSimon Glass err = spl_nand_load_element(spl_image,
1802a2ee2acSSimon Glass CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND,
18180ef700fSBoris Brezillon header);
18280ef700fSBoris Brezillon #endif
18380ef700fSBoris Brezillon #endif
184d97b4ce8STom Rini nand_deselect();
18536afd451SNikita Kiryanov return err;
186d97b4ce8STom Rini }
1870c3117b1SHeiko Schocher #endif
188d5c2b11cSSimon Glass /* Use priorty 1 so that Ubi can override this */
189ebc4ef61SSimon Glass SPL_LOAD_IMAGE_METHOD("NAND", 1, BOOT_DEVICE_NAND, spl_nand_load_image);
190