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 <config.h>
7 #include <fdt_support.h>
8 #include <image.h>
9 #include <imx_container.h>
10 #include <log.h>
11 #include <spl.h>
12 #include <spl_load.h>
13 #include <asm/io.h>
14 #include <mapmem.h>
15 #include <nand.h>
16 #include <linux/libfdt_env.h>
17 #include <fdt.h>
18 
spl_nand_get_uboot_raw_page(void)19 uint32_t __weak spl_nand_get_uboot_raw_page(void)
20 {
21 	return CONFIG_SYS_NAND_U_BOOT_OFFS;
22 }
23 
24 #if defined(CONFIG_SPL_NAND_RAW_ONLY)
spl_nand_load_image(struct spl_image_info * spl_image,struct spl_boot_device * bootdev)25 static int spl_nand_load_image(struct spl_image_info *spl_image,
26 			struct spl_boot_device *bootdev)
27 {
28 	nand_init();
29 
30 	printf("Loading U-Boot from 0x%08x (size 0x%08x) to 0x%08x\n",
31 	       CONFIG_SYS_NAND_U_BOOT_OFFS, CFG_SYS_NAND_U_BOOT_SIZE,
32 	       CFG_SYS_NAND_U_BOOT_DST);
33 
34 	nand_spl_load_image(spl_nand_get_uboot_raw_page(),
35 			    CFG_SYS_NAND_U_BOOT_SIZE,
36 			    map_sysmem(CFG_SYS_NAND_U_BOOT_DST,
37 				       CFG_SYS_NAND_U_BOOT_SIZE));
38 	spl_set_header_raw_uboot(spl_image);
39 	nand_deselect();
40 
41 	return 0;
42 }
43 #else
44 
nand_spl_adjust_offset(u32 sector,u32 offs)45 __weak u32 nand_spl_adjust_offset(u32 sector, u32 offs)
46 {
47 	return offs;
48 }
49 
spl_nand_read(struct spl_load_info * load,ulong offs,ulong size,void * dst)50 static ulong spl_nand_read(struct spl_load_info *load, ulong offs, ulong size,
51 			   void *dst)
52 {
53 	int err;
54 	ulong sector;
55 
56 	debug("%s: offs %lx, size %lx, dst %p\n",
57 	      __func__, offs, size, dst);
58 
59 	sector = *(int *)load->priv;
60 	offs = sector + nand_spl_adjust_offset(sector, offs - sector);
61 	err = nand_spl_load_image(offs, size, dst);
62 	spl_set_bl_len(load, nand_page_size());
63 	if (err)
64 		return 0;
65 
66 	return size;
67 }
68 
spl_nand_load_element(struct spl_image_info * spl_image,struct spl_boot_device * bootdev,int offset)69 static int spl_nand_load_element(struct spl_image_info *spl_image,
70 				 struct spl_boot_device *bootdev, int offset)
71 {
72 	struct spl_load_info load;
73 
74 	spl_load_init(&load, spl_nand_read, &offset, 1);
75 	return spl_load(spl_image, bootdev, &load, 0, offset);
76 }
77 
spl_nand_load_image(struct spl_image_info * spl_image,struct spl_boot_device * bootdev)78 static int spl_nand_load_image(struct spl_image_info *spl_image,
79 			       struct spl_boot_device *bootdev)
80 {
81 	int err;
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 #if CONFIG_IS_ENABLED(OS_BOOT)
91 	if (!spl_start_uboot()) {
92 		int *src, *dst;
93 		struct legacy_img_hdr *header =
94 			spl_get_load_buffer(0, sizeof(*header));
95 
96 		/*
97 		 * load parameter image
98 		 * load to temp position since nand_spl_load_image reads
99 		 * a whole block which is typically larger than
100 		 * CONFIG_CMD_SPL_WRITE_SIZE therefore may overwrite
101 		 * following sections like BSS
102 		 */
103 		nand_spl_load_image(CONFIG_CMD_SPL_NAND_OFS,
104 			CONFIG_CMD_SPL_WRITE_SIZE,
105 			(void *)CONFIG_TEXT_BASE);
106 		/* copy to destintion */
107 		for (dst = (int *)CONFIG_SPL_PAYLOAD_ARGS_ADDR,
108 		     src = (int *)CONFIG_TEXT_BASE;
109 			src < (int *)(CONFIG_TEXT_BASE +
110 				      CONFIG_CMD_SPL_WRITE_SIZE);
111 		     src++, dst++) {
112 			writel(readl(src), dst);
113 		}
114 
115 		/* load linux */
116 		nand_spl_load_image(CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
117 			sizeof(*header), (void *)header);
118 		err = spl_parse_image_header(spl_image, bootdev, header);
119 		if (err)
120 			return err;
121 		if (header->ih_os == IH_OS_LINUX) {
122 			/* happy - was a linux */
123 			err = nand_spl_load_image(
124 				CONFIG_SYS_NAND_SPL_KERNEL_OFFS,
125 				spl_image->size,
126 				(void *)spl_image->load_addr);
127 			nand_deselect();
128 			return err;
129 		} else {
130 			puts("The Expected Linux image was not "
131 				"found. Please check your NAND "
132 				"configuration.\n");
133 			puts("Trying to start u-boot now...\n");
134 		}
135 	}
136 #endif
137 #ifdef CONFIG_NAND_ENV_DST
138 	spl_nand_load_element(spl_image, bootdev, CONFIG_ENV_OFFSET);
139 #ifdef CONFIG_ENV_OFFSET_REDUND
140 	spl_nand_load_element(spl_image, bootdev, CONFIG_ENV_OFFSET_REDUND);
141 #endif
142 #endif
143 	/* Load u-boot */
144 	err = spl_nand_load_element(spl_image, bootdev, spl_nand_get_uboot_raw_page());
145 #ifdef CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
146 #if CONFIG_SYS_NAND_U_BOOT_OFFS != CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND
147 	if (err)
148 		err = spl_nand_load_element(spl_image, bootdev,
149 					    CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND);
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);
158