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