1ade8a1a6SYing Zhang /* 2ade8a1a6SYing Zhang * (C) Copyright 2010 3ade8a1a6SYing Zhang * Texas Instruments, <www.ti.com> 4ade8a1a6SYing Zhang * 5ade8a1a6SYing Zhang * Aneesh V <aneesh@ti.com> 6ade8a1a6SYing Zhang * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8ade8a1a6SYing Zhang */ 9ade8a1a6SYing Zhang #include <common.h> 10dc3dedfeSSimon Glass #include <dm.h> 11ade8a1a6SYing Zhang #include <spl.h> 1291199f4aSPaul Kocialkowski #include <linux/compiler.h> 1336afd451SNikita Kiryanov #include <errno.h> 14ade8a1a6SYing Zhang #include <asm/u-boot.h> 154188ba32SNikita Kiryanov #include <errno.h> 16ade8a1a6SYing Zhang #include <mmc.h> 17e4c444b3STom Rini #include <image.h> 18ade8a1a6SYing Zhang 19ade8a1a6SYing Zhang DECLARE_GLOBAL_DATA_PTR; 20ade8a1a6SYing Zhang 21b97300b6SPaul Kocialkowski static int mmc_load_image_raw_sector(struct mmc *mmc, unsigned long sector) 22ade8a1a6SYing Zhang { 233bc37b6dSPaul Kocialkowski unsigned long count; 24ade8a1a6SYing Zhang u32 image_size_sectors; 25ade8a1a6SYing Zhang struct image_header *header; 26ade8a1a6SYing Zhang 27ade8a1a6SYing Zhang header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - 28ade8a1a6SYing Zhang sizeof(struct image_header)); 29ade8a1a6SYing Zhang 30ade8a1a6SYing Zhang /* read image header to find the image size & load address */ 317c4213f6SStephen Warren count = mmc->block_dev.block_read(&mmc->block_dev, sector, 1, header); 32fdfa39d3SSimon Glass debug("read sector %lx, count=%lu\n", sector, count); 333bc37b6dSPaul Kocialkowski if (count == 0) 34ade8a1a6SYing Zhang goto end; 35ade8a1a6SYing Zhang 36fdfa39d3SSimon Glass if (image_get_magic(header) != IH_MAGIC) { 37fdfa39d3SSimon Glass puts("bad magic\n"); 38e4c444b3STom Rini return -1; 39fdfa39d3SSimon Glass } 40e4c444b3STom Rini 41ade8a1a6SYing Zhang spl_parse_image_header(header); 42ade8a1a6SYing Zhang 43ade8a1a6SYing Zhang /* convert size to sectors - round up */ 44ade8a1a6SYing Zhang image_size_sectors = (spl_image.size + mmc->read_bl_len - 1) / 45ade8a1a6SYing Zhang mmc->read_bl_len; 46ade8a1a6SYing Zhang 47ade8a1a6SYing Zhang /* Read the header too to avoid extra memcpy */ 487c4213f6SStephen Warren count = mmc->block_dev.block_read(&mmc->block_dev, sector, 497c4213f6SStephen Warren image_size_sectors, 507ef4c45cSGong Qianyu (void *)(ulong)spl_image.load_addr); 51fdfa39d3SSimon Glass debug("read %x sectors to %x\n", image_size_sectors, 52fdfa39d3SSimon Glass spl_image.load_addr); 53ade8a1a6SYing Zhang 54ade8a1a6SYing Zhang end: 551ec26469SPaul Kocialkowski if (count == 0) { 568112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 571ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 588112f5faSPaul Burton #endif 593bc37b6dSPaul Kocialkowski return -1; 601ec26469SPaul Kocialkowski } 613bc37b6dSPaul Kocialkowski 623bc37b6dSPaul Kocialkowski return 0; 63ade8a1a6SYing Zhang } 64ade8a1a6SYing Zhang 65a1e56cf6SNikita Kiryanov int spl_mmc_get_device_index(u32 boot_device) 66a1e56cf6SNikita Kiryanov { 67a1e56cf6SNikita Kiryanov switch (boot_device) { 68a1e56cf6SNikita Kiryanov case BOOT_DEVICE_MMC1: 69a1e56cf6SNikita Kiryanov return 0; 70a1e56cf6SNikita Kiryanov case BOOT_DEVICE_MMC2: 71a1e56cf6SNikita Kiryanov case BOOT_DEVICE_MMC2_2: 72a1e56cf6SNikita Kiryanov return 1; 73a1e56cf6SNikita Kiryanov } 74a1e56cf6SNikita Kiryanov 75a1e56cf6SNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 76a1e56cf6SNikita Kiryanov printf("spl: unsupported mmc boot device.\n"); 77a1e56cf6SNikita Kiryanov #endif 78a1e56cf6SNikita Kiryanov 79a1e56cf6SNikita Kiryanov return -ENODEV; 80a1e56cf6SNikita Kiryanov } 81a1e56cf6SNikita Kiryanov 8299c7a51aSSimon Glass static int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device) 834188ba32SNikita Kiryanov { 84b4857aa9SSimon Glass #ifdef CONFIG_DM_MMC 854188ba32SNikita Kiryanov struct udevice *dev; 86b4857aa9SSimon Glass #endif 87a1e56cf6SNikita Kiryanov int err, mmc_dev; 88a1e56cf6SNikita Kiryanov 89a1e56cf6SNikita Kiryanov mmc_dev = spl_mmc_get_device_index(boot_device); 90a1e56cf6SNikita Kiryanov if (mmc_dev < 0) 91a1e56cf6SNikita Kiryanov return mmc_dev; 924188ba32SNikita Kiryanov 934188ba32SNikita Kiryanov err = mmc_initialize(NULL); 944188ba32SNikita Kiryanov if (err) { 954188ba32SNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 964188ba32SNikita Kiryanov printf("spl: could not initialize mmc. error: %d\n", err); 974188ba32SNikita Kiryanov #endif 984188ba32SNikita Kiryanov return err; 994188ba32SNikita Kiryanov } 1004188ba32SNikita Kiryanov 101b4857aa9SSimon Glass #ifdef CONFIG_DM_MMC 102a1e56cf6SNikita Kiryanov err = uclass_get_device(UCLASS_MMC, mmc_dev, &dev); 103b4857aa9SSimon Glass if (!err) 104b4857aa9SSimon Glass *mmcp = mmc_get_mmc_dev(dev); 105b4857aa9SSimon Glass #else 106b4857aa9SSimon Glass *mmcp = find_mmc_device(mmc_dev); 107b4857aa9SSimon Glass err = *mmcp ? 0 : -ENODEV; 108b4857aa9SSimon Glass #endif 1094188ba32SNikita Kiryanov if (err) { 1104188ba32SNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 1114188ba32SNikita Kiryanov printf("spl: could not find mmc device. error: %d\n", err); 1124188ba32SNikita Kiryanov #endif 1134188ba32SNikita Kiryanov return err; 1144188ba32SNikita Kiryanov } 1154188ba32SNikita Kiryanov 1164188ba32SNikita Kiryanov return 0; 1174188ba32SNikita Kiryanov } 1184188ba32SNikita Kiryanov 119b97300b6SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 120b97300b6SPaul Kocialkowski static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) 121b97300b6SPaul Kocialkowski { 122b97300b6SPaul Kocialkowski disk_partition_t info; 1233bc37b6dSPaul Kocialkowski int err; 124b97300b6SPaul Kocialkowski 125*3e8bd469SSimon Glass err = part_get_info(&mmc->block_dev, partition, &info); 1263bc37b6dSPaul Kocialkowski if (err) { 127b97300b6SPaul Kocialkowski #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 1281ec26469SPaul Kocialkowski puts("spl: partition error\n"); 129b97300b6SPaul Kocialkowski #endif 130b97300b6SPaul Kocialkowski return -1; 131b97300b6SPaul Kocialkowski } 132b97300b6SPaul Kocialkowski 1334bfcc54cSStefan Roese #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 1344bfcc54cSStefan Roese return mmc_load_image_raw_sector(mmc, info.start + 1354bfcc54cSStefan Roese CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 1364bfcc54cSStefan Roese #else 137b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, info.start); 1384bfcc54cSStefan Roese #endif 139b97300b6SPaul Kocialkowski } 140d074ebb9SNikita Kiryanov #else 141d074ebb9SNikita Kiryanov #define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION -1 142d074ebb9SNikita Kiryanov static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) 143d074ebb9SNikita Kiryanov { 144d074ebb9SNikita Kiryanov return -ENOSYS; 145d074ebb9SNikita Kiryanov } 146b97300b6SPaul Kocialkowski #endif 147b97300b6SPaul Kocialkowski 1482b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 1492b75b0adSPeter Korsgaard static int mmc_load_image_raw_os(struct mmc *mmc) 1502b75b0adSPeter Korsgaard { 1513bc37b6dSPaul Kocialkowski unsigned long count; 15291199f4aSPaul Kocialkowski 1537c4213f6SStephen Warren count = mmc->block_dev.block_read(&mmc->block_dev, 1542b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, 1552b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, 15691199f4aSPaul Kocialkowski (void *) CONFIG_SYS_SPL_ARGS_ADDR); 1573bc37b6dSPaul Kocialkowski if (count == 0) { 1588112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 1591ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 1608112f5faSPaul Burton #endif 1612b75b0adSPeter Korsgaard return -1; 1622b75b0adSPeter Korsgaard } 1632b75b0adSPeter Korsgaard 164b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, 165b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); 1662b75b0adSPeter Korsgaard } 167339245b7SNikita Kiryanov #else 168339245b7SNikita Kiryanov int spl_start_uboot(void) 169339245b7SNikita Kiryanov { 170339245b7SNikita Kiryanov return 1; 171339245b7SNikita Kiryanov } 172339245b7SNikita Kiryanov static int mmc_load_image_raw_os(struct mmc *mmc) 173339245b7SNikita Kiryanov { 174339245b7SNikita Kiryanov return -ENOSYS; 175339245b7SNikita Kiryanov } 1762b75b0adSPeter Korsgaard #endif 1772b75b0adSPeter Korsgaard 178f52b7293SNikita Kiryanov #ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 179f52b7293SNikita Kiryanov int spl_mmc_do_fs_boot(struct mmc *mmc) 180f52b7293SNikita Kiryanov { 181f52b7293SNikita Kiryanov int err = -ENOSYS; 182f52b7293SNikita Kiryanov 183f52b7293SNikita Kiryanov #ifdef CONFIG_SPL_FAT_SUPPORT 184f52b7293SNikita Kiryanov if (!spl_start_uboot()) { 185f52b7293SNikita Kiryanov err = spl_load_image_fat_os(&mmc->block_dev, 186f52b7293SNikita Kiryanov CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 187f52b7293SNikita Kiryanov if (!err) 188f52b7293SNikita Kiryanov return err; 189f52b7293SNikita Kiryanov } 190f52b7293SNikita Kiryanov #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 191f52b7293SNikita Kiryanov err = spl_load_image_fat(&mmc->block_dev, 192f52b7293SNikita Kiryanov CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 193f52b7293SNikita Kiryanov CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 194f52b7293SNikita Kiryanov if (!err) 195f52b7293SNikita Kiryanov return err; 196f52b7293SNikita Kiryanov #endif 197f52b7293SNikita Kiryanov #endif 198f52b7293SNikita Kiryanov #ifdef CONFIG_SPL_EXT_SUPPORT 199f52b7293SNikita Kiryanov if (!spl_start_uboot()) { 200f52b7293SNikita Kiryanov err = spl_load_image_ext_os(&mmc->block_dev, 201f52b7293SNikita Kiryanov CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 202f52b7293SNikita Kiryanov if (!err) 203f52b7293SNikita Kiryanov return err; 204f52b7293SNikita Kiryanov } 205f52b7293SNikita Kiryanov #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 206f52b7293SNikita Kiryanov err = spl_load_image_ext(&mmc->block_dev, 207f52b7293SNikita Kiryanov CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 208f52b7293SNikita Kiryanov CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 209f52b7293SNikita Kiryanov if (!err) 210f52b7293SNikita Kiryanov return err; 211f52b7293SNikita Kiryanov #endif 212f52b7293SNikita Kiryanov #endif 213f52b7293SNikita Kiryanov 214f52b7293SNikita Kiryanov #if defined(CONFIG_SPL_FAT_SUPPORT) || defined(CONFIG_SPL_EXT_SUPPORT) 215f52b7293SNikita Kiryanov err = -ENOENT; 216f52b7293SNikita Kiryanov #endif 217f52b7293SNikita Kiryanov 218f52b7293SNikita Kiryanov return err; 219f52b7293SNikita Kiryanov } 220f52b7293SNikita Kiryanov #else 221f52b7293SNikita Kiryanov int spl_mmc_do_fs_boot(struct mmc *mmc) 222f52b7293SNikita Kiryanov { 223f52b7293SNikita Kiryanov return -ENOSYS; 224f52b7293SNikita Kiryanov } 225f52b7293SNikita Kiryanov #endif 226f52b7293SNikita Kiryanov 227a1e56cf6SNikita Kiryanov int spl_mmc_load_image(u32 boot_device) 228ade8a1a6SYing Zhang { 229d773a008SSimon Glass struct mmc *mmc = NULL; 230ade8a1a6SYing Zhang u32 boot_mode; 231dc3dedfeSSimon Glass int err = 0; 23291199f4aSPaul Kocialkowski __maybe_unused int part; 233ade8a1a6SYing Zhang 234a1e56cf6SNikita Kiryanov err = spl_mmc_find_device(&mmc, boot_device); 23536afd451SNikita Kiryanov if (err) 23636afd451SNikita Kiryanov return err; 237ade8a1a6SYing Zhang 238ade8a1a6SYing Zhang err = mmc_init(mmc); 239ade8a1a6SYing Zhang if (err) { 2408112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 24191199f4aSPaul Kocialkowski printf("spl: mmc init failed with error: %d\n", err); 2428112f5faSPaul Burton #endif 24336afd451SNikita Kiryanov return err; 244ade8a1a6SYing Zhang } 24579adb7a2SPeter Korsgaard 246ade8a1a6SYing Zhang boot_mode = spl_boot_mode(); 24736afd451SNikita Kiryanov err = -EINVAL; 24891199f4aSPaul Kocialkowski switch (boot_mode) { 24983cdf6faSNikita Kiryanov case MMCSD_MODE_EMMCBOOT: 25083cdf6faSNikita Kiryanov /* 25183cdf6faSNikita Kiryanov * We need to check what the partition is configured to. 25283cdf6faSNikita Kiryanov * 1 and 2 match up to boot0 / boot1 and 7 is user data 25383cdf6faSNikita Kiryanov * which is the first physical partition (0). 25483cdf6faSNikita Kiryanov */ 25583cdf6faSNikita Kiryanov part = (mmc->part_config >> 3) & PART_ACCESS_MASK; 25683cdf6faSNikita Kiryanov 25783cdf6faSNikita Kiryanov if (part == 7) 25883cdf6faSNikita Kiryanov part = 0; 25983cdf6faSNikita Kiryanov 26036afd451SNikita Kiryanov err = mmc_switch_part(0, part); 26136afd451SNikita Kiryanov if (err) { 26283cdf6faSNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 26383cdf6faSNikita Kiryanov puts("spl: mmc partition switch failed\n"); 26483cdf6faSNikita Kiryanov #endif 26536afd451SNikita Kiryanov return err; 26683cdf6faSNikita Kiryanov } 26783cdf6faSNikita Kiryanov /* Fall through */ 26891199f4aSPaul Kocialkowski case MMCSD_MODE_RAW: 26991199f4aSPaul Kocialkowski debug("spl: mmc boot mode: raw\n"); 27091199f4aSPaul Kocialkowski 27191199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 27291199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 27391199f4aSPaul Kocialkowski if (!err) 27436afd451SNikita Kiryanov return err; 27591199f4aSPaul Kocialkowski } 276d074ebb9SNikita Kiryanov 277b97300b6SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 278b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 27991199f4aSPaul Kocialkowski if (!err) 28036afd451SNikita Kiryanov return err; 281d074ebb9SNikita Kiryanov #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 2823ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 2833ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 2843ae8f4c8SPaul Kocialkowski if (!err) 28536afd451SNikita Kiryanov return err; 2863ae8f4c8SPaul Kocialkowski #endif 28786a0df73SGuillaume GARDET /* If RAW mode fails, try FS mode. */ 28891199f4aSPaul Kocialkowski case MMCSD_MODE_FS: 28991199f4aSPaul Kocialkowski debug("spl: mmc boot mode: fs\n"); 29091199f4aSPaul Kocialkowski 291f52b7293SNikita Kiryanov err = spl_mmc_do_fs_boot(mmc); 29291199f4aSPaul Kocialkowski if (!err) 29336afd451SNikita Kiryanov return err; 294f52b7293SNikita Kiryanov 295fd61d399SNikita Kiryanov break; 2962c84c9a4SGuillaume GARDET case MMCSD_MODE_UNDEFINED: 2978112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 298fd61d399SNikita Kiryanov default: 29991199f4aSPaul Kocialkowski puts("spl: mmc: wrong boot mode\n"); 3008112f5faSPaul Burton #endif 301ade8a1a6SYing Zhang } 302fd61d399SNikita Kiryanov 30336afd451SNikita Kiryanov return err; 304ade8a1a6SYing Zhang } 305