]>
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 | ||
96debd1f SG |
21 | static int mmc_load_legacy(struct mmc *mmc, ulong sector, |
22 | struct image_header *header) | |
23 | { | |
24 | u32 image_size_sectors; | |
25 | unsigned long count; | |
7e0f2267 MV |
26 | int ret; |
27 | ||
28 | ret = spl_parse_image_header(header); | |
29 | if (ret) | |
30 | return ret; | |
96debd1f | 31 | |
96debd1f SG |
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 = mmc->block_dev.block_read(&mmc->block_dev, sector, | |
38 | image_size_sectors, | |
39 | (void *)(ulong)spl_image.load_addr); | |
40 | debug("read %x sectors to %x\n", image_size_sectors, | |
41 | spl_image.load_addr); | |
42 | if (count != image_size_sectors) | |
43 | return -EIO; | |
44 | ||
45 | return 0; | |
46 | } | |
47 | ||
96debd1f SG |
48 | static ulong h_spl_load_read(struct spl_load_info *load, ulong sector, |
49 | ulong count, void *buf) | |
50 | { | |
51 | struct mmc *mmc = load->dev; | |
52 | ||
53 | return mmc->block_dev.block_read(&mmc->block_dev, sector, count, buf); | |
54 | } | |
96debd1f | 55 | |
b97300b6 | 56 | static int mmc_load_image_raw_sector(struct mmc *mmc, unsigned long sector) |
9ea5c6ef | 57 | { |
3bc37b6d | 58 | unsigned long count; |
2e222105 | 59 | struct image_header *header; |
96debd1f | 60 | int ret = 0; |
9ea5c6ef SS |
61 | |
62 | header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - | |
91199f4a | 63 | sizeof(struct image_header)); |
9ea5c6ef SS |
64 | |
65 | /* read image header to find the image size & load address */ | |
7c4213f6 | 66 | count = mmc->block_dev.block_read(&mmc->block_dev, sector, 1, header); |
96debd1f SG |
67 | debug("hdr read sector %lx, count=%lu\n", sector, count); |
68 | if (count == 0) { | |
69 | ret = -EIO; | |
9ea5c6ef | 70 | goto end; |
96debd1f | 71 | } |
9ea5c6ef | 72 | |
4976f482 MY |
73 | if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && |
74 | image_get_magic(header) == FDT_MAGIC) { | |
96debd1f SG |
75 | struct spl_load_info load; |
76 | ||
77 | debug("Found FIT\n"); | |
78 | load.dev = mmc; | |
79 | load.priv = NULL; | |
80 | load.bl_len = mmc->read_bl_len; | |
81 | load.read = h_spl_load_read; | |
82 | ret = spl_load_simple_fit(&load, sector, header); | |
4976f482 MY |
83 | } else { |
84 | ret = mmc_load_legacy(mmc, sector, header); | |
fdfa39d3 | 85 | } |
e4c444b3 | 86 | |
9ea5c6ef | 87 | end: |
96debd1f | 88 | if (ret) { |
8112f5fa | 89 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT |
5bbf4099 | 90 | puts("mmc_load_image_raw_sector: mmc block read error\n"); |
8112f5fa | 91 | #endif |
3bc37b6d | 92 | return -1; |
1ec26469 | 93 | } |
3bc37b6d PK |
94 | |
95 | return 0; | |
9ea5c6ef SS |
96 | } |
97 | ||
a1e56cf6 NK |
98 | int spl_mmc_get_device_index(u32 boot_device) |
99 | { | |
100 | switch (boot_device) { | |
101 | case BOOT_DEVICE_MMC1: | |
102 | return 0; | |
103 | case BOOT_DEVICE_MMC2: | |
104 | case BOOT_DEVICE_MMC2_2: | |
105 | return 1; | |
106 | } | |
107 | ||
108 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
109 | printf("spl: unsupported mmc boot device.\n"); | |
110 | #endif | |
111 | ||
112 | return -ENODEV; | |
113 | } | |
114 | ||
99c7a51a | 115 | static int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device) |
4188ba32 | 116 | { |
b4857aa9 | 117 | #ifdef CONFIG_DM_MMC |
4188ba32 | 118 | struct udevice *dev; |
b4857aa9 | 119 | #endif |
a1e56cf6 NK |
120 | int err, mmc_dev; |
121 | ||
122 | mmc_dev = spl_mmc_get_device_index(boot_device); | |
123 | if (mmc_dev < 0) | |
124 | return mmc_dev; | |
4188ba32 NK |
125 | |
126 | err = mmc_initialize(NULL); | |
127 | if (err) { | |
128 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
129 | printf("spl: could not initialize mmc. error: %d\n", err); | |
130 | #endif | |
131 | return err; | |
132 | } | |
133 | ||
b4857aa9 | 134 | #ifdef CONFIG_DM_MMC |
a1e56cf6 | 135 | err = uclass_get_device(UCLASS_MMC, mmc_dev, &dev); |
b4857aa9 SG |
136 | if (!err) |
137 | *mmcp = mmc_get_mmc_dev(dev); | |
4188ba32 | 138 | #else |
b4857aa9 SG |
139 | *mmcp = find_mmc_device(mmc_dev); |
140 | err = *mmcp ? 0 : -ENODEV; | |
141 | #endif | |
4188ba32 NK |
142 | if (err) { |
143 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT | |
b4857aa9 | 144 | printf("spl: could not find mmc device. error: %d\n", err); |
4188ba32 NK |
145 | #endif |
146 | return err; | |
147 | } | |
148 | ||
4188ba32 NK |
149 | return 0; |
150 | } | |
4188ba32 | 151 | |
b97300b6 PK |
152 | #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION |
153 | static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) | |
154 | { | |
155 | disk_partition_t info; | |
3bc37b6d | 156 | int err; |
b97300b6 | 157 | |
3e8bd469 | 158 | err = part_get_info(&mmc->block_dev, partition, &info); |
3bc37b6d | 159 | if (err) { |
b97300b6 | 160 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT |
1ec26469 | 161 | puts("spl: partition error\n"); |
b97300b6 PK |
162 | #endif |
163 | return -1; | |
164 | } | |
165 | ||
4bfcc54c SR |
166 | #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR |
167 | return mmc_load_image_raw_sector(mmc, info.start + | |
168 | CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); | |
169 | #else | |
b97300b6 | 170 | return mmc_load_image_raw_sector(mmc, info.start); |
4bfcc54c | 171 | #endif |
b97300b6 | 172 | } |
d074ebb9 NK |
173 | #else |
174 | #define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION -1 | |
175 | static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) | |
176 | { | |
177 | return -ENOSYS; | |
178 | } | |
b97300b6 PK |
179 | #endif |
180 | ||
2b75b0ad PK |
181 | #ifdef CONFIG_SPL_OS_BOOT |
182 | static int mmc_load_image_raw_os(struct mmc *mmc) | |
183 | { | |
3bc37b6d | 184 | unsigned long count; |
811906ae | 185 | int ret; |
91199f4a | 186 | |
7c4213f6 | 187 | count = mmc->block_dev.block_read(&mmc->block_dev, |
3bc37b6d PK |
188 | CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, |
189 | CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, | |
190 | (void *) CONFIG_SYS_SPL_ARGS_ADDR); | |
191 | if (count == 0) { | |
8112f5fa | 192 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT |
5bbf4099 | 193 | puts("mmc_load_image_raw_os: mmc block read error\n"); |
8112f5fa | 194 | #endif |
2b75b0ad PK |
195 | return -1; |
196 | } | |
197 | ||
811906ae | 198 | ret = mmc_load_image_raw_sector(mmc, |
91199f4a | 199 | CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); |
811906ae LV |
200 | if (ret) |
201 | return ret; | |
202 | ||
203 | if (spl_image.os != IH_OS_LINUX) { | |
204 | puts("Expected Linux image is not found. Trying to start U-boot\n"); | |
205 | return -ENOENT; | |
206 | } | |
207 | ||
208 | return 0; | |
2b75b0ad | 209 | } |
339245b7 NK |
210 | #else |
211 | int spl_start_uboot(void) | |
212 | { | |
213 | return 1; | |
214 | } | |
215 | static int mmc_load_image_raw_os(struct mmc *mmc) | |
216 | { | |
217 | return -ENOSYS; | |
218 | } | |
2b75b0ad PK |
219 | #endif |
220 | ||
f52b7293 NK |
221 | #ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION |
222 | int spl_mmc_do_fs_boot(struct mmc *mmc) | |
223 | { | |
224 | int err = -ENOSYS; | |
225 | ||
226 | #ifdef CONFIG_SPL_FAT_SUPPORT | |
227 | if (!spl_start_uboot()) { | |
228 | err = spl_load_image_fat_os(&mmc->block_dev, | |
229 | CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); | |
230 | if (!err) | |
231 | return err; | |
232 | } | |
233 | #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME | |
234 | err = spl_load_image_fat(&mmc->block_dev, | |
235 | CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, | |
236 | CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); | |
237 | if (!err) | |
238 | return err; | |
239 | #endif | |
240 | #endif | |
241 | #ifdef CONFIG_SPL_EXT_SUPPORT | |
242 | if (!spl_start_uboot()) { | |
243 | err = spl_load_image_ext_os(&mmc->block_dev, | |
244 | CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); | |
245 | if (!err) | |
246 | return err; | |
247 | } | |
248 | #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME | |
249 | err = spl_load_image_ext(&mmc->block_dev, | |
250 | CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, | |
251 | CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); | |
252 | if (!err) | |
253 | return err; | |
254 | #endif | |
255 | #endif | |
256 | ||
257 | #if defined(CONFIG_SPL_FAT_SUPPORT) || defined(CONFIG_SPL_EXT_SUPPORT) | |
258 | err = -ENOENT; | |
259 | #endif | |
260 | ||
261 | return err; | |
262 | } | |
263 | #else | |
264 | int spl_mmc_do_fs_boot(struct mmc *mmc) | |
265 | { | |
266 | return -ENOSYS; | |
267 | } | |
268 | #endif | |
269 | ||
a1e56cf6 | 270 | int spl_mmc_load_image(u32 boot_device) |
9ea5c6ef | 271 | { |
d773a008 | 272 | struct mmc *mmc = NULL; |
9ea5c6ef | 273 | u32 boot_mode; |
dc3dedfe | 274 | int err = 0; |
91199f4a | 275 | __maybe_unused int part; |
9ea5c6ef | 276 | |
a1e56cf6 | 277 | err = spl_mmc_find_device(&mmc, boot_device); |
36afd451 NK |
278 | if (err) |
279 | return err; | |
9ea5c6ef | 280 | |
4188ba32 | 281 | err = mmc_init(mmc); |
9ea5c6ef | 282 | if (err) { |
8112f5fa | 283 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT |
91199f4a | 284 | printf("spl: mmc init failed with error: %d\n", err); |
8112f5fa | 285 | #endif |
36afd451 | 286 | return err; |
9ea5c6ef | 287 | } |
79adb7a2 | 288 | |
37189a19 | 289 | boot_mode = spl_boot_mode(); |
36afd451 | 290 | err = -EINVAL; |
91199f4a | 291 | switch (boot_mode) { |
83cdf6fa NK |
292 | case MMCSD_MODE_EMMCBOOT: |
293 | /* | |
294 | * We need to check what the partition is configured to. | |
295 | * 1 and 2 match up to boot0 / boot1 and 7 is user data | |
296 | * which is the first physical partition (0). | |
297 | */ | |
298 | part = (mmc->part_config >> 3) & PART_ACCESS_MASK; | |
299 | ||
300 | if (part == 7) | |
301 | part = 0; | |
302 | ||
69f45cd5 | 303 | err = blk_dselect_hwpart(mmc_get_blk_desc(mmc), part); |
36afd451 | 304 | if (err) { |
83cdf6fa NK |
305 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT |
306 | puts("spl: mmc partition switch failed\n"); | |
307 | #endif | |
36afd451 | 308 | return err; |
83cdf6fa NK |
309 | } |
310 | /* Fall through */ | |
91199f4a PK |
311 | case MMCSD_MODE_RAW: |
312 | debug("spl: mmc boot mode: raw\n"); | |
313 | ||
91199f4a PK |
314 | if (!spl_start_uboot()) { |
315 | err = mmc_load_image_raw_os(mmc); | |
316 | if (!err) | |
36afd451 | 317 | return err; |
91199f4a | 318 | } |
d074ebb9 | 319 | |
b97300b6 PK |
320 | err = mmc_load_image_raw_partition(mmc, |
321 | CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); | |
3ae8f4c8 | 322 | if (!err) |
36afd451 | 323 | return err; |
d074ebb9 | 324 | #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) |
b97300b6 | 325 | err = mmc_load_image_raw_sector(mmc, |
773b5940 | 326 | CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); |
91199f4a | 327 | if (!err) |
36afd451 | 328 | return err; |
3ae8f4c8 | 329 | #endif |
86a0df73 | 330 | /* If RAW mode fails, try FS mode. */ |
91199f4a PK |
331 | case MMCSD_MODE_FS: |
332 | debug("spl: mmc boot mode: fs\n"); | |
333 | ||
f52b7293 | 334 | err = spl_mmc_do_fs_boot(mmc); |
91199f4a | 335 | if (!err) |
36afd451 | 336 | return err; |
f52b7293 | 337 | |
fd61d399 | 338 | break; |
91199f4a | 339 | case MMCSD_MODE_UNDEFINED: |
8112f5fa | 340 | #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT |
fd61d399 NK |
341 | default: |
342 | puts("spl: mmc: wrong boot mode\n"); | |
8112f5fa | 343 | #endif |
91199f4a | 344 | } |
fd61d399 | 345 | |
36afd451 | 346 | return err; |
9ea5c6ef | 347 | } |