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