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