Merge tag 'u-boot-at91-2022.07-a' of https://source.denx.de/u-boot/custodians/u-boot...
[platform/kernel/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 <fdt_support.h>
9 #include <image.h>
10 #include <log.h>
11 #include <spl.h>
12 #include <asm/io.h>
13 #include <nand.h>
14 #include <linux/libfdt_env.h>
15 #include <fdt.h>
16
17 uint32_t __weak spl_nand_get_uboot_raw_page(void)
18 {
19         return CONFIG_SYS_NAND_U_BOOT_OFFS;
20 }
21
22 #if defined(CONFIG_SPL_NAND_RAW_ONLY)
23 static int spl_nand_load_image(struct spl_image_info *spl_image,
24                         struct spl_boot_device *bootdev)
25 {
26         nand_init();
27
28         printf("Loading U-Boot from 0x%08x (size 0x%08x) to 0x%08x\n",
29                CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
30                CONFIG_SYS_NAND_U_BOOT_DST);
31
32         nand_spl_load_image(spl_nand_get_uboot_raw_page(),
33                             CONFIG_SYS_NAND_U_BOOT_SIZE,
34                             (void *)CONFIG_SYS_NAND_U_BOOT_DST);
35         spl_set_header_raw_uboot(spl_image);
36         nand_deselect();
37
38         return 0;
39 }
40 #else
41
42 static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs,
43                                ulong size, void *dst)
44 {
45         int err;
46 #ifdef CONFIG_SYS_NAND_BLOCK_SIZE
47         ulong sector;
48
49         sector = *(int *)load->priv;
50         offs = sector + nand_spl_adjust_offset(sector, offs - sector);
51 #else
52         offs *= load->bl_len;
53         size *= load->bl_len;
54 #endif
55         err = nand_spl_load_image(offs, size, dst);
56         if (err)
57                 return 0;
58
59         return size / load->bl_len;
60 }
61
62 struct mtd_info * __weak nand_get_mtd(void)
63 {
64         return NULL;
65 }
66
67 static int spl_nand_load_element(struct spl_image_info *spl_image,
68                                  struct spl_boot_device *bootdev,
69                                  int offset, struct image_header *header)
70 {
71         struct mtd_info *mtd = nand_get_mtd();
72         int bl_len = mtd ? mtd->writesize : 1;
73         int err;
74
75         err = nand_spl_load_image(offset, sizeof(*header), (void *)header);
76         if (err)
77                 return err;
78
79         if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
80             image_get_magic(header) == FDT_MAGIC) {
81                 struct spl_load_info load;
82
83                 debug("Found FIT\n");
84                 load.dev = NULL;
85                 load.priv = &offset;
86                 load.filename = NULL;
87                 load.bl_len = bl_len;
88                 load.read = spl_nand_fit_read;
89                 return spl_load_simple_fit(spl_image, &load, offset / bl_len, header);
90         } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) {
91                 struct spl_load_info load;
92
93                 load.dev = NULL;
94                 load.priv = NULL;
95                 load.filename = NULL;
96                 load.bl_len = bl_len;
97                 load.read = spl_nand_fit_read;
98                 return spl_load_imx_container(spl_image, &load, offset / bl_len);
99         } else {
100                 err = spl_parse_image_header(spl_image, bootdev, header);
101                 if (err)
102                         return err;
103                 return nand_spl_load_image(offset, spl_image->size,
104                                            (void *)(ulong)spl_image->load_addr);
105         }
106 }
107
108 static int spl_nand_load_image(struct spl_image_info *spl_image,
109                                struct spl_boot_device *bootdev)
110 {
111         int err;
112         struct image_header *header;
113         int *src __attribute__((unused));
114         int *dst __attribute__((unused));
115
116 #ifdef CONFIG_SPL_NAND_SOFTECC
117         debug("spl: nand - using sw ecc\n");
118 #else
119         debug("spl: nand - using hw ecc\n");
120 #endif
121         nand_init();
122
123         header = spl_get_load_buffer(0, sizeof(*header));
124
125 #if CONFIG_IS_ENABLED(OS_BOOT)
126         if (!spl_start_uboot()) {
127                 /*
128                  * load parameter image
129                  * load to temp position since nand_spl_load_image reads
130                  * a whole block which is typically larger than
131                  * CONFIG_CMD_SPL_WRITE_SIZE therefore may overwrite
132                  * following sections like BSS
133                  */
134                 nand_spl_load_image(CONFIG_CMD_SPL_NAND_OFS,
135                         CONFIG_CMD_SPL_WRITE_SIZE,
136                         (void *)CONFIG_SYS_TEXT_BASE);
137                 /* copy to destintion */
138                 for (dst = (int *)CONFIG_SYS_SPL_ARGS_ADDR,
139                                 src = (int *)CONFIG_SYS_TEXT_BASE;
140                                 src < (int *)(CONFIG_SYS_TEXT_BASE +
141                                 CONFIG_CMD_SPL_WRITE_SIZE);
142                                 src++, dst++) {
143                         writel(readl(src), dst);
144                 }
145
146                 /* load linux */
147                 nand_spl_load_image(CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
148                         sizeof(*header), (void *)header);
149                 err = spl_parse_image_header(spl_image, bootdev, header);
150                 if (err)
151                         return err;
152                 if (header->ih_os == IH_OS_LINUX) {
153                         /* happy - was a linux */
154                         err = nand_spl_load_image(
155                                 CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
156                                 spl_image->size,
157                                 (void *)spl_image->load_addr);
158                         nand_deselect();
159                         return err;
160                 } else {
161                         puts("The Expected Linux image was not "
162                                 "found. Please check your NAND "
163                                 "configuration.\n");
164                         puts("Trying to start u-boot now...\n");
165                 }
166         }
167 #endif
168 #ifdef CONFIG_NAND_ENV_DST
169         spl_nand_load_element(spl_image, bootdev, CONFIG_ENV_OFFSET, header);
170 #ifdef CONFIG_ENV_OFFSET_REDUND
171         spl_nand_load_element(spl_image, bootdev, CONFIG_ENV_OFFSET_REDUND, header);
172 #endif
173 #endif
174         /* Load u-boot */
175         err = spl_nand_load_element(spl_image, bootdev, spl_nand_get_uboot_raw_page(),
176                                     header);
177 #ifdef CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
178 #if CONFIG_SYS_NAND_U_BOOT_OFFS != CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
179         if (err)
180                 err = spl_nand_load_element(spl_image, bootdev,
181                                             CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND,
182                                             header);
183 #endif
184 #endif
185         nand_deselect();
186         return err;
187 }
188 #endif
189 /* Use priorty 1 so that Ubi can override this */
190 SPL_LOAD_IMAGE_METHOD("NAND", 1, BOOT_DEVICE_NAND, spl_nand_load_image);