]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * (C) Copyright 2010 | |
3 | * Texas Instruments, <www.ti.com> | |
4 | * | |
5 | * Aneesh V <aneesh@ti.com> | |
6 | * | |
7 | * SPDX-License-Identifier: GPL-2.0+ | |
8 | */ | |
9 | #include <common.h> | |
10 | #include <dm.h> | |
11 | #include <spl.h> | |
12 | #include <linux/compiler.h> | |
13 | #include <errno.h> | |
14 | #include <asm/u-boot.h> | |
15 | #include <errno.h> | |
16 | #include <mmc.h> | |
17 | #include <image.h> | |
18 | ||
19 | DECLARE_GLOBAL_DATA_PTR; | |
20 | ||
21 | static int mmc_load_legacy(struct spl_image_info *spl_image, struct mmc *mmc, | |
22 | ulong sector, struct image_header *header) | |
23 | { | |
24 | u32 image_size_sectors; | |
25 | unsigned long count; | |
26 | int ret; | |
27 | ||
28 | ret = spl_parse_image_header(spl_image, header); | |
29 | if (ret) | |
30 | return ret; | |
31 | ||
32 | /* convert size to sectors - round up */ | |
33 | image_size_sectors = (spl_image->size + mmc->read_bl_len - 1) / | |
34 | mmc->read_bl_len; | |
35 | ||
36 | /* Read the header too to avoid extra memcpy */ | |
37 | count = blk_dread(mmc_get_blk_desc(mmc), sector, image_size_sectors, | |
38 | (void *)(ulong)spl_image->load_addr); | |
39 | debug("read %x sectors to %x\n", image_size_sectors, | |
40 | spl_image->load_addr); | |
41 | if (count != image_size_sectors) | |
42 | return -EIO; | |
43 | ||
44 | return 0; | |
45 | } | |
46 | ||
47 | static ulong h_spl_load_read(struct spl_load_info *load, ulong sector, | |
48 | ulong count, void *buf) | |
49 | { | |
50 | struct mmc *mmc = load->dev; | |
51 | ||
52 | return blk_dread(mmc_get_blk_desc(mmc), sector, count, buf); | |
53 | } | |
54 | ||
55 | static int mmc_load_image_raw_sector(struct spl_image_info *spl_image, | |
56 | struct mmc *mmc, unsigned long sector) | |
57 | { | |
58 | unsigned long count; | |
59 | struct image_header *header; | |
60 | int ret = 0; | |
61 | ||
62 | header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - | |
63 | sizeof(struct image_header)); | |
64 | ||
65 | /* read image header to find the image size & load address */ | |
66 | count = blk_dread(mmc_get_blk_desc(mmc), sector, 1, header); | |
67 | debug("hdr read sector %lx, count=%lu\n", sector, count); | |
68 | if (count == 0) { | |
69 | ret = -EIO; | |
70 | goto end; | |
71 | } | |
72 | ||
73 | if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && | |
74 | image_get_magic(header) == FDT_MAGIC) { | |
75 | struct spl_load_info load; | |
76 | ||
77 | debug("Found FIT\n"); | |
78 | load.dev = mmc; | |
79 | load.priv = NULL; | |
80 | load.filename = NULL; | |
81 | load.bl_len = mmc->read_bl_len; | |
82 | load.read = h_spl_load_read; | |
83 | ret = spl_load_simple_fit(spl_image, &load, sector, header); | |
84 | } else { | |
85 | ret = mmc_load_legacy(spl_image, mmc, sector, header); | |
86 | } | |
87 | ||
88 | end: | |
89 | if (ret) { | |
90 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
91 | puts("mmc_load_image_raw_sector: mmc block read error\n"); | |
92 | #endif | |
93 | return -1; | |
94 | } | |
95 | ||
96 | return 0; | |
97 | } | |
98 | ||
99 | int spl_mmc_get_device_index(u32 boot_device) | |
100 | { | |
101 | switch (boot_device) { | |
102 | case BOOT_DEVICE_MMC1: | |
103 | return 0; | |
104 | case BOOT_DEVICE_MMC2: | |
105 | case BOOT_DEVICE_MMC2_2: | |
106 | return 1; | |
107 | } | |
108 | ||
109 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
110 | printf("spl: unsupported mmc boot device.\n"); | |
111 | #endif | |
112 | ||
113 | return -ENODEV; | |
114 | } | |
115 | ||
116 | static int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device) | |
117 | { | |
118 | #ifdef CONFIG_DM_MMC | |
119 | struct udevice *dev; | |
120 | #endif | |
121 | int err, mmc_dev; | |
122 | ||
123 | mmc_dev = spl_mmc_get_device_index(boot_device); | |
124 | if (mmc_dev < 0) | |
125 | return mmc_dev; | |
126 | ||
127 | err = mmc_initialize(NULL); | |
128 | if (err) { | |
129 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
130 | printf("spl: could not initialize mmc. error: %d\n", err); | |
131 | #endif | |
132 | return err; | |
133 | } | |
134 | ||
135 | #ifdef CONFIG_DM_MMC | |
136 | err = uclass_get_device(UCLASS_MMC, mmc_dev, &dev); | |
137 | if (!err) | |
138 | *mmcp = mmc_get_mmc_dev(dev); | |
139 | #else | |
140 | *mmcp = find_mmc_device(mmc_dev); | |
141 | err = *mmcp ? 0 : -ENODEV; | |
142 | #endif | |
143 | if (err) { | |
144 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
145 | printf("spl: could not find mmc device. error: %d\n", err); | |
146 | #endif | |
147 | return err; | |
148 | } | |
149 | ||
150 | return 0; | |
151 | } | |
152 | ||
153 | #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION | |
154 | static int mmc_load_image_raw_partition(struct spl_image_info *spl_image, | |
155 | struct mmc *mmc, int partition) | |
156 | { | |
157 | disk_partition_t info; | |
158 | int err; | |
159 | ||
160 | err = part_get_info(mmc_get_blk_desc(mmc), partition, &info); | |
161 | if (err) { | |
162 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
163 | puts("spl: partition error\n"); | |
164 | #endif | |
165 | return -1; | |
166 | } | |
167 | ||
168 | #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR | |
169 | return mmc_load_image_raw_sector(spl_image, mmc, | |
170 | info.start + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); | |
171 | #else | |
172 | return mmc_load_image_raw_sector(spl_image, mmc, info.start); | |
173 | #endif | |
174 | } | |
175 | #else | |
176 | #define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION -1 | |
177 | static int mmc_load_image_raw_partition(struct spl_image_info *spl_image, | |
178 | struct mmc *mmc, int partition) | |
179 | { | |
180 | return -ENOSYS; | |
181 | } | |
182 | #endif | |
183 | ||
184 | #ifdef CONFIG_SPL_OS_BOOT | |
185 | static int mmc_load_image_raw_os(struct spl_image_info *spl_image, | |
186 | struct mmc *mmc) | |
187 | { | |
188 | unsigned long count; | |
189 | int ret; | |
190 | ||
191 | count = blk_dread(mmc_get_blk_desc(mmc), | |
192 | CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, | |
193 | CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, | |
194 | (void *) CONFIG_SYS_SPL_ARGS_ADDR); | |
195 | if (count == 0) { | |
196 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
197 | puts("mmc_load_image_raw_os: mmc block read error\n"); | |
198 | #endif | |
199 | return -1; | |
200 | } | |
201 | ||
202 | ret = mmc_load_image_raw_sector(spl_image, mmc, | |
203 | CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); | |
204 | if (ret) | |
205 | return ret; | |
206 | ||
207 | if (spl_image->os != IH_OS_LINUX) { | |
208 | puts("Expected Linux image is not found. Trying to start U-boot\n"); | |
209 | return -ENOENT; | |
210 | } | |
211 | ||
212 | return 0; | |
213 | } | |
214 | #else | |
215 | int spl_start_uboot(void) | |
216 | { | |
217 | return 1; | |
218 | } | |
219 | static int mmc_load_image_raw_os(struct spl_image_info *spl_image, | |
220 | struct mmc *mmc) | |
221 | { | |
222 | return -ENOSYS; | |
223 | } | |
224 | #endif | |
225 | ||
226 | #ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION | |
227 | static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc) | |
228 | { | |
229 | int err = -ENOSYS; | |
230 | ||
231 | #ifdef CONFIG_SPL_FAT_SUPPORT | |
232 | if (!spl_start_uboot()) { | |
233 | err = spl_load_image_fat_os(spl_image, mmc_get_blk_desc(mmc), | |
234 | CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); | |
235 | if (!err) | |
236 | return err; | |
237 | } | |
238 | #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME | |
239 | err = spl_load_image_fat(spl_image, mmc_get_blk_desc(mmc), | |
240 | CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, | |
241 | CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); | |
242 | if (!err) | |
243 | return err; | |
244 | #endif | |
245 | #endif | |
246 | #ifdef CONFIG_SPL_EXT_SUPPORT | |
247 | if (!spl_start_uboot()) { | |
248 | err = spl_load_image_ext_os(spl_image, mmc_get_blk_desc(mmc), | |
249 | CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); | |
250 | if (!err) | |
251 | return err; | |
252 | } | |
253 | #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME | |
254 | err = spl_load_image_ext(spl_image, mmc_get_blk_desc(mmc), | |
255 | CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, | |
256 | CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); | |
257 | if (!err) | |
258 | return err; | |
259 | #endif | |
260 | #endif | |
261 | ||
262 | #if defined(CONFIG_SPL_FAT_SUPPORT) || defined(CONFIG_SPL_EXT_SUPPORT) | |
263 | err = -ENOENT; | |
264 | #endif | |
265 | ||
266 | return err; | |
267 | } | |
268 | #else | |
269 | static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc) | |
270 | { | |
271 | return -ENOSYS; | |
272 | } | |
273 | #endif | |
274 | ||
275 | int spl_mmc_load_image(struct spl_image_info *spl_image, | |
276 | struct spl_boot_device *bootdev) | |
277 | { | |
278 | struct mmc *mmc = NULL; | |
279 | u32 boot_mode; | |
280 | int err = 0; | |
281 | __maybe_unused int part; | |
282 | ||
283 | err = spl_mmc_find_device(&mmc, bootdev->boot_device); | |
284 | if (err) | |
285 | return err; | |
286 | ||
287 | err = mmc_init(mmc); | |
288 | if (err) { | |
289 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
290 | printf("spl: mmc init failed with error: %d\n", err); | |
291 | #endif | |
292 | return err; | |
293 | } | |
294 | ||
295 | boot_mode = spl_boot_mode(bootdev->boot_device); | |
296 | err = -EINVAL; | |
297 | switch (boot_mode) { | |
298 | case MMCSD_MODE_EMMCBOOT: | |
299 | /* | |
300 | * We need to check what the partition is configured to. | |
301 | * 1 and 2 match up to boot0 / boot1 and 7 is user data | |
302 | * which is the first physical partition (0). | |
303 | */ | |
304 | part = (mmc->part_config >> 3) & PART_ACCESS_MASK; | |
305 | ||
306 | if (part == 7) | |
307 | part = 0; | |
308 | ||
309 | if (CONFIG_IS_ENABLED(MMC_TINY)) | |
310 | err = mmc_switch_part(mmc, part); | |
311 | else | |
312 | err = blk_dselect_hwpart(mmc_get_blk_desc(mmc), part); | |
313 | ||
314 | if (err) { | |
315 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
316 | puts("spl: mmc partition switch failed\n"); | |
317 | #endif | |
318 | return err; | |
319 | } | |
320 | /* Fall through */ | |
321 | case MMCSD_MODE_RAW: | |
322 | debug("spl: mmc boot mode: raw\n"); | |
323 | ||
324 | if (!spl_start_uboot()) { | |
325 | err = mmc_load_image_raw_os(spl_image, mmc); | |
326 | if (!err) | |
327 | return err; | |
328 | } | |
329 | ||
330 | err = mmc_load_image_raw_partition(spl_image, mmc, | |
331 | CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); | |
332 | if (!err) | |
333 | return err; | |
334 | #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR | |
335 | err = mmc_load_image_raw_sector(spl_image, mmc, | |
336 | CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); | |
337 | if (!err) | |
338 | return err; | |
339 | #endif | |
340 | /* If RAW mode fails, try FS mode. */ | |
341 | case MMCSD_MODE_FS: | |
342 | debug("spl: mmc boot mode: fs\n"); | |
343 | ||
344 | err = spl_mmc_do_fs_boot(spl_image, mmc); | |
345 | if (!err) | |
346 | return err; | |
347 | ||
348 | break; | |
349 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
350 | default: | |
351 | puts("spl: mmc: wrong boot mode\n"); | |
352 | #endif | |
353 | } | |
354 | ||
355 | return err; | |
356 | } | |
357 | ||
358 | SPL_LOAD_IMAGE_METHOD("MMC1", 0, BOOT_DEVICE_MMC1, spl_mmc_load_image); | |
359 | SPL_LOAD_IMAGE_METHOD("MMC2", 0, BOOT_DEVICE_MMC2, spl_mmc_load_image); | |
360 | SPL_LOAD_IMAGE_METHOD("MMC2_2", 0, BOOT_DEVICE_MMC2_2, spl_mmc_load_image); |