Merge branch '2019-06-14-master-imports'
[oweals/u-boot.git] / common / spl / spl_nand.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2011
4  * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
5  */
6 #include <common.h>
7 #include <config.h>
8 #include <spl.h>
9 #include <asm/io.h>
10 #include <nand.h>
11 #include <linux/libfdt_env.h>
12 #include <fdt.h>
13
14 #if defined(CONFIG_SPL_NAND_RAW_ONLY)
15 static int spl_nand_load_image(struct spl_image_info *spl_image,
16                         struct spl_boot_device *bootdev)
17 {
18         nand_init();
19
20         printf("Loading U-Boot from 0x%08x (size 0x%08x) to 0x%08x\n",
21                CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
22                CONFIG_SYS_NAND_U_BOOT_DST);
23
24         nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,
25                             CONFIG_SYS_NAND_U_BOOT_SIZE,
26                             (void *)CONFIG_SYS_NAND_U_BOOT_DST);
27         spl_set_header_raw_uboot(spl_image);
28         nand_deselect();
29
30         return 0;
31 }
32 #else
33
34 static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs,
35                                ulong size, void *dst)
36 {
37         int ret;
38
39         ret = nand_spl_load_image(offs, size, dst);
40         if (!ret)
41                 return size;
42         else
43                 return 0;
44 }
45
46 static int spl_nand_load_element(struct spl_image_info *spl_image,
47                                  int offset, struct image_header *header)
48 {
49         int err;
50
51         err = nand_spl_load_image(offset, sizeof(*header), (void *)header);
52         if (err)
53                 return err;
54
55         if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
56             image_get_magic(header) == FDT_MAGIC) {
57                 struct spl_load_info load;
58
59                 debug("Found FIT\n");
60                 load.dev = NULL;
61                 load.priv = NULL;
62                 load.filename = NULL;
63                 load.bl_len = 1;
64                 load.read = spl_nand_fit_read;
65                 return spl_load_simple_fit(spl_image, &load, offset, header);
66         } else {
67                 err = spl_parse_image_header(spl_image, header);
68                 if (err)
69                         return err;
70                 return nand_spl_load_image(offset, spl_image->size,
71                                            (void *)(ulong)spl_image->load_addr);
72         }
73 }
74
75 static int spl_nand_load_image(struct spl_image_info *spl_image,
76                                struct spl_boot_device *bootdev)
77 {
78         int err;
79         struct image_header *header;
80         int *src __attribute__((unused));
81         int *dst __attribute__((unused));
82
83 #ifdef CONFIG_SPL_NAND_SOFTECC
84         debug("spl: nand - using sw ecc\n");
85 #else
86         debug("spl: nand - using hw ecc\n");
87 #endif
88         nand_init();
89
90         header = spl_get_load_buffer(0, sizeof(*header));
91
92 #ifdef CONFIG_SPL_OS_BOOT
93         if (!spl_start_uboot()) {
94                 /*
95                  * load parameter image
96                  * load to temp position since nand_spl_load_image reads
97                  * a whole block which is typically larger than
98                  * CONFIG_CMD_SPL_WRITE_SIZE therefore may overwrite
99                  * following sections like BSS
100                  */
101                 nand_spl_load_image(CONFIG_CMD_SPL_NAND_OFS,
102                         CONFIG_CMD_SPL_WRITE_SIZE,
103                         (void *)CONFIG_SYS_TEXT_BASE);
104                 /* copy to destintion */
105                 for (dst = (int *)CONFIG_SYS_SPL_ARGS_ADDR,
106                                 src = (int *)CONFIG_SYS_TEXT_BASE;
107                                 src < (int *)(CONFIG_SYS_TEXT_BASE +
108                                 CONFIG_CMD_SPL_WRITE_SIZE);
109                                 src++, dst++) {
110                         writel(readl(src), dst);
111                 }
112
113                 /* load linux */
114                 nand_spl_load_image(CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
115                         sizeof(*header), (void *)header);
116                 err = spl_parse_image_header(spl_image, header);
117                 if (err)
118                         return err;
119                 if (header->ih_os == IH_OS_LINUX) {
120                         /* happy - was a linux */
121                         err = nand_spl_load_image(
122                                 CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
123                                 spl_image->size,
124                                 (void *)spl_image->load_addr);
125                         nand_deselect();
126                         return err;
127                 } else {
128                         puts("The Expected Linux image was not "
129                                 "found. Please check your NAND "
130                                 "configuration.\n");
131                         puts("Trying to start u-boot now...\n");
132                 }
133         }
134 #endif
135 #ifdef CONFIG_NAND_ENV_DST
136         spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET, header);
137 #ifdef CONFIG_ENV_OFFSET_REDUND
138         spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET_REDUND, header);
139 #endif
140 #endif
141         /* Load u-boot */
142         err = spl_nand_load_element(spl_image, CONFIG_SYS_NAND_U_BOOT_OFFS,
143                                     header);
144 #ifdef CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
145 #if CONFIG_SYS_NAND_U_BOOT_OFFS != CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
146         if (err)
147                 err = spl_nand_load_element(spl_image,
148                                             CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND,
149                                             header);
150 #endif
151 #endif
152         nand_deselect();
153         return err;
154 }
155 #endif
156 /* Use priorty 1 so that Ubi can override this */
157 SPL_LOAD_IMAGE_METHOD("NAND", 1, BOOT_DEVICE_NAND, spl_nand_load_image);