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 
spl_nand_get_uboot_raw_page(void)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)
spl_nand_load_image(struct spl_image_info * spl_image,struct spl_boot_device * bootdev)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, CFG_SYS_NAND_U_BOOT_SIZE,
30 	       CFG_SYS_NAND_U_BOOT_DST);
31 
32 	nand_spl_load_image(spl_nand_get_uboot_raw_page(),
33 			    CFG_SYS_NAND_U_BOOT_SIZE,
34 			    (void *)CFG_SYS_NAND_U_BOOT_DST);
35 	spl_set_header_raw_uboot(spl_image);
36 	nand_deselect();
37 
38 	return 0;
39 }
40 #else
41 
spl_nand_fit_read(struct spl_load_info * load,ulong offs,ulong size,void * dst)42 static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs,
43 			       ulong size, void *dst)
44 {
45 	int err;
46 	ulong sector;
47 
48 	sector = *(int *)load->priv;
49 	offs *= load->bl_len;
50 	size *= load->bl_len;
51 	offs = sector + nand_spl_adjust_offset(sector, offs - sector);
52 	err = nand_spl_load_image(offs, size, dst);
53 	if (err)
54 		return 0;
55 
56 	return size / load->bl_len;
57 }
58 
spl_nand_legacy_read(struct spl_load_info * load,ulong offs,ulong size,void * dst)59 static ulong spl_nand_legacy_read(struct spl_load_info *load, ulong offs,
60 				  ulong size, void *dst)
61 {
62 	int err;
63 
64 	debug("%s: offs %lx, size %lx, dst %p\n",
65 	      __func__, offs, size, dst);
66 
67 	err = nand_spl_load_image(offs, size, dst);
68 	if (err)
69 		return 0;
70 
71 	return size;
72 }
73 
nand_get_mtd(void)74 struct mtd_info * __weak nand_get_mtd(void)
75 {
76 	return NULL;
77 }
78 
spl_nand_load_element(struct spl_image_info * spl_image,struct spl_boot_device * bootdev,int offset,struct legacy_img_hdr * header)79 static int spl_nand_load_element(struct spl_image_info *spl_image,
80 				 struct spl_boot_device *bootdev,
81 				 int offset, struct legacy_img_hdr *header)
82 {
83 	struct mtd_info *mtd = nand_get_mtd();
84 	int bl_len = mtd ? mtd->writesize : 1;
85 	int err;
86 
87 	err = nand_spl_load_image(offset, sizeof(*header), (void *)header);
88 	if (err)
89 		return err;
90 
91 	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
92 	    image_get_magic(header) == FDT_MAGIC) {
93 		struct spl_load_info load;
94 
95 		debug("Found FIT\n");
96 		load.dev = NULL;
97 		load.priv = &offset;
98 		load.filename = NULL;
99 		load.bl_len = bl_len;
100 		load.read = spl_nand_fit_read;
101 		return spl_load_simple_fit(spl_image, &load, offset / bl_len, header);
102 	} else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) {
103 		struct spl_load_info load;
104 
105 		load.dev = NULL;
106 		load.priv = NULL;
107 		load.filename = NULL;
108 		load.bl_len = bl_len;
109 		load.read = spl_nand_fit_read;
110 		return spl_load_imx_container(spl_image, &load, offset / bl_len);
111 	} else if (IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_FORMAT) &&
112 		   image_get_magic(header) == IH_MAGIC) {
113 		struct spl_load_info load;
114 
115 		debug("Found legacy image\n");
116 		load.dev = NULL;
117 		load.priv = NULL;
118 		load.filename = NULL;
119 		load.bl_len = 1;
120 		load.read = spl_nand_legacy_read;
121 
122 		return spl_load_legacy_img(spl_image, bootdev, &load, offset, header);
123 	} else {
124 		err = spl_parse_image_header(spl_image, bootdev, header);
125 		if (err)
126 			return err;
127 		return nand_spl_load_image(offset, spl_image->size,
128 					   (void *)(ulong)spl_image->load_addr);
129 	}
130 }
131 
spl_nand_load_image(struct spl_image_info * spl_image,struct spl_boot_device * bootdev)132 static int spl_nand_load_image(struct spl_image_info *spl_image,
133 			       struct spl_boot_device *bootdev)
134 {
135 	int err;
136 	struct legacy_img_hdr *header;
137 	int *src __attribute__((unused));
138 	int *dst __attribute__((unused));
139 
140 #ifdef CONFIG_SPL_NAND_SOFTECC
141 	debug("spl: nand - using sw ecc\n");
142 #else
143 	debug("spl: nand - using hw ecc\n");
144 #endif
145 	nand_init();
146 
147 	header = spl_get_load_buffer(0, sizeof(*header));
148 
149 #if CONFIG_IS_ENABLED(OS_BOOT)
150 	if (!spl_start_uboot()) {
151 		/*
152 		 * load parameter image
153 		 * load to temp position since nand_spl_load_image reads
154 		 * a whole block which is typically larger than
155 		 * CONFIG_CMD_SPL_WRITE_SIZE therefore may overwrite
156 		 * following sections like BSS
157 		 */
158 		nand_spl_load_image(CONFIG_CMD_SPL_NAND_OFS,
159 			CONFIG_CMD_SPL_WRITE_SIZE,
160 			(void *)CONFIG_TEXT_BASE);
161 		/* copy to destintion */
162 		for (dst = (int *)CONFIG_SYS_SPL_ARGS_ADDR,
163 				src = (int *)CONFIG_TEXT_BASE;
164 				src < (int *)(CONFIG_TEXT_BASE +
165 				CONFIG_CMD_SPL_WRITE_SIZE);
166 				src++, dst++) {
167 			writel(readl(src), dst);
168 		}
169 
170 		/* load linux */
171 		nand_spl_load_image(CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
172 			sizeof(*header), (void *)header);
173 		err = spl_parse_image_header(spl_image, bootdev, header);
174 		if (err)
175 			return err;
176 		if (header->ih_os == IH_OS_LINUX) {
177 			/* happy - was a linux */
178 			err = nand_spl_load_image(
179 				CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
180 				spl_image->size,
181 				(void *)spl_image->load_addr);
182 			nand_deselect();
183 			return err;
184 		} else {
185 			puts("The Expected Linux image was not "
186 				"found. Please check your NAND "
187 				"configuration.\n");
188 			puts("Trying to start u-boot now...\n");
189 		}
190 	}
191 #endif
192 #ifdef CONFIG_NAND_ENV_DST
193 	spl_nand_load_element(spl_image, bootdev, CONFIG_ENV_OFFSET, header);
194 #ifdef CONFIG_ENV_OFFSET_REDUND
195 	spl_nand_load_element(spl_image, bootdev, CONFIG_ENV_OFFSET_REDUND, header);
196 #endif
197 #endif
198 	/* Load u-boot */
199 	err = spl_nand_load_element(spl_image, bootdev, spl_nand_get_uboot_raw_page(),
200 				    header);
201 #ifdef CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
202 #if CONFIG_SYS_NAND_U_BOOT_OFFS != CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
203 	if (err)
204 		err = spl_nand_load_element(spl_image, bootdev,
205 					    CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND,
206 					    header);
207 #endif
208 #endif
209 	nand_deselect();
210 	return err;
211 }
212 #endif
213 /* Use priorty 1 so that Ubi can override this */
214 SPL_LOAD_IMAGE_METHOD("NAND", 1, BOOT_DEVICE_NAND, spl_nand_load_image);
215