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 */ 313bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, 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 */ 483bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, sector, image_size_sectors, 497ef4c45cSGong Qianyu (void *)(ulong)spl_image.load_addr); 50fdfa39d3SSimon Glass debug("read %x sectors to %x\n", image_size_sectors, 51fdfa39d3SSimon Glass spl_image.load_addr); 52ade8a1a6SYing Zhang 53ade8a1a6SYing Zhang end: 541ec26469SPaul Kocialkowski if (count == 0) { 558112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 561ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 578112f5faSPaul Burton #endif 583bc37b6dSPaul Kocialkowski return -1; 591ec26469SPaul Kocialkowski } 603bc37b6dSPaul Kocialkowski 613bc37b6dSPaul Kocialkowski return 0; 62ade8a1a6SYing Zhang } 63ade8a1a6SYing Zhang 64a1e56cf6SNikita Kiryanov int spl_mmc_get_device_index(u32 boot_device) 65a1e56cf6SNikita Kiryanov { 66a1e56cf6SNikita Kiryanov switch (boot_device) { 67a1e56cf6SNikita Kiryanov case BOOT_DEVICE_MMC1: 68a1e56cf6SNikita Kiryanov return 0; 69a1e56cf6SNikita Kiryanov case BOOT_DEVICE_MMC2: 70a1e56cf6SNikita Kiryanov case BOOT_DEVICE_MMC2_2: 71a1e56cf6SNikita Kiryanov return 1; 72a1e56cf6SNikita Kiryanov } 73a1e56cf6SNikita Kiryanov 74a1e56cf6SNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 75a1e56cf6SNikita Kiryanov printf("spl: unsupported mmc boot device.\n"); 76a1e56cf6SNikita Kiryanov #endif 77a1e56cf6SNikita Kiryanov 78a1e56cf6SNikita Kiryanov return -ENODEV; 79a1e56cf6SNikita Kiryanov } 80a1e56cf6SNikita Kiryanov 8199c7a51aSSimon Glass static int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device) 824188ba32SNikita Kiryanov { 83*b4857aa9SSimon Glass #ifdef CONFIG_DM_MMC 844188ba32SNikita Kiryanov struct udevice *dev; 85*b4857aa9SSimon Glass #endif 86a1e56cf6SNikita Kiryanov int err, mmc_dev; 87a1e56cf6SNikita Kiryanov 88a1e56cf6SNikita Kiryanov mmc_dev = spl_mmc_get_device_index(boot_device); 89a1e56cf6SNikita Kiryanov if (mmc_dev < 0) 90a1e56cf6SNikita Kiryanov return mmc_dev; 914188ba32SNikita Kiryanov 924188ba32SNikita Kiryanov err = mmc_initialize(NULL); 934188ba32SNikita Kiryanov if (err) { 944188ba32SNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 954188ba32SNikita Kiryanov printf("spl: could not initialize mmc. error: %d\n", err); 964188ba32SNikita Kiryanov #endif 974188ba32SNikita Kiryanov return err; 984188ba32SNikita Kiryanov } 994188ba32SNikita Kiryanov 100*b4857aa9SSimon Glass #ifdef CONFIG_DM_MMC 101a1e56cf6SNikita Kiryanov err = uclass_get_device(UCLASS_MMC, mmc_dev, &dev); 102*b4857aa9SSimon Glass if (!err) 103*b4857aa9SSimon Glass *mmcp = mmc_get_mmc_dev(dev); 104*b4857aa9SSimon Glass #else 105*b4857aa9SSimon Glass *mmcp = find_mmc_device(mmc_dev); 106*b4857aa9SSimon Glass err = *mmcp ? 0 : -ENODEV; 107*b4857aa9SSimon Glass #endif 1084188ba32SNikita Kiryanov if (err) { 1094188ba32SNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 1104188ba32SNikita Kiryanov printf("spl: could not find mmc device. error: %d\n", err); 1114188ba32SNikita Kiryanov #endif 1124188ba32SNikita Kiryanov return err; 1134188ba32SNikita Kiryanov } 1144188ba32SNikita Kiryanov 1154188ba32SNikita Kiryanov return 0; 1164188ba32SNikita Kiryanov } 1174188ba32SNikita Kiryanov 118b97300b6SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 119b97300b6SPaul Kocialkowski static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) 120b97300b6SPaul Kocialkowski { 121b97300b6SPaul Kocialkowski disk_partition_t info; 1223bc37b6dSPaul Kocialkowski int err; 123b97300b6SPaul Kocialkowski 1243bc37b6dSPaul Kocialkowski err = get_partition_info(&mmc->block_dev, partition, &info); 1253bc37b6dSPaul Kocialkowski if (err) { 126b97300b6SPaul Kocialkowski #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 1271ec26469SPaul Kocialkowski puts("spl: partition error\n"); 128b97300b6SPaul Kocialkowski #endif 129b97300b6SPaul Kocialkowski return -1; 130b97300b6SPaul Kocialkowski } 131b97300b6SPaul Kocialkowski 1324bfcc54cSStefan Roese #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 1334bfcc54cSStefan Roese return mmc_load_image_raw_sector(mmc, info.start + 1344bfcc54cSStefan Roese CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 1354bfcc54cSStefan Roese #else 136b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, info.start); 1374bfcc54cSStefan Roese #endif 138b97300b6SPaul Kocialkowski } 139d074ebb9SNikita Kiryanov #else 140d074ebb9SNikita Kiryanov #define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION -1 141d074ebb9SNikita Kiryanov static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) 142d074ebb9SNikita Kiryanov { 143d074ebb9SNikita Kiryanov return -ENOSYS; 144d074ebb9SNikita Kiryanov } 145b97300b6SPaul Kocialkowski #endif 146b97300b6SPaul Kocialkowski 1472b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 1482b75b0adSPeter Korsgaard static int mmc_load_image_raw_os(struct mmc *mmc) 1492b75b0adSPeter Korsgaard { 1503bc37b6dSPaul Kocialkowski unsigned long count; 15191199f4aSPaul Kocialkowski 1523bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, 1532b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, 1542b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, 15591199f4aSPaul Kocialkowski (void *) CONFIG_SYS_SPL_ARGS_ADDR); 1563bc37b6dSPaul Kocialkowski if (count == 0) { 1578112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 1581ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 1598112f5faSPaul Burton #endif 1602b75b0adSPeter Korsgaard return -1; 1612b75b0adSPeter Korsgaard } 1622b75b0adSPeter Korsgaard 163b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, 164b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); 1652b75b0adSPeter Korsgaard } 166339245b7SNikita Kiryanov #else 167339245b7SNikita Kiryanov int spl_start_uboot(void) 168339245b7SNikita Kiryanov { 169339245b7SNikita Kiryanov return 1; 170339245b7SNikita Kiryanov } 171339245b7SNikita Kiryanov static int mmc_load_image_raw_os(struct mmc *mmc) 172339245b7SNikita Kiryanov { 173339245b7SNikita Kiryanov return -ENOSYS; 174339245b7SNikita Kiryanov } 1752b75b0adSPeter Korsgaard #endif 1762b75b0adSPeter Korsgaard 177f52b7293SNikita Kiryanov #ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 178f52b7293SNikita Kiryanov int spl_mmc_do_fs_boot(struct mmc *mmc) 179f52b7293SNikita Kiryanov { 180f52b7293SNikita Kiryanov int err = -ENOSYS; 181f52b7293SNikita Kiryanov 182f52b7293SNikita Kiryanov #ifdef CONFIG_SPL_FAT_SUPPORT 183f52b7293SNikita Kiryanov if (!spl_start_uboot()) { 184f52b7293SNikita Kiryanov err = spl_load_image_fat_os(&mmc->block_dev, 185f52b7293SNikita Kiryanov CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 186f52b7293SNikita Kiryanov if (!err) 187f52b7293SNikita Kiryanov return err; 188f52b7293SNikita Kiryanov } 189f52b7293SNikita Kiryanov #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 190f52b7293SNikita Kiryanov err = spl_load_image_fat(&mmc->block_dev, 191f52b7293SNikita Kiryanov CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 192f52b7293SNikita Kiryanov CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 193f52b7293SNikita Kiryanov if (!err) 194f52b7293SNikita Kiryanov return err; 195f52b7293SNikita Kiryanov #endif 196f52b7293SNikita Kiryanov #endif 197f52b7293SNikita Kiryanov #ifdef CONFIG_SPL_EXT_SUPPORT 198f52b7293SNikita Kiryanov if (!spl_start_uboot()) { 199f52b7293SNikita Kiryanov err = spl_load_image_ext_os(&mmc->block_dev, 200f52b7293SNikita Kiryanov CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 201f52b7293SNikita Kiryanov if (!err) 202f52b7293SNikita Kiryanov return err; 203f52b7293SNikita Kiryanov } 204f52b7293SNikita Kiryanov #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 205f52b7293SNikita Kiryanov err = spl_load_image_ext(&mmc->block_dev, 206f52b7293SNikita Kiryanov CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 207f52b7293SNikita Kiryanov CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 208f52b7293SNikita Kiryanov if (!err) 209f52b7293SNikita Kiryanov return err; 210f52b7293SNikita Kiryanov #endif 211f52b7293SNikita Kiryanov #endif 212f52b7293SNikita Kiryanov 213f52b7293SNikita Kiryanov #if defined(CONFIG_SPL_FAT_SUPPORT) || defined(CONFIG_SPL_EXT_SUPPORT) 214f52b7293SNikita Kiryanov err = -ENOENT; 215f52b7293SNikita Kiryanov #endif 216f52b7293SNikita Kiryanov 217f52b7293SNikita Kiryanov return err; 218f52b7293SNikita Kiryanov } 219f52b7293SNikita Kiryanov #else 220f52b7293SNikita Kiryanov int spl_mmc_do_fs_boot(struct mmc *mmc) 221f52b7293SNikita Kiryanov { 222f52b7293SNikita Kiryanov return -ENOSYS; 223f52b7293SNikita Kiryanov } 224f52b7293SNikita Kiryanov #endif 225f52b7293SNikita Kiryanov 226a1e56cf6SNikita Kiryanov int spl_mmc_load_image(u32 boot_device) 227ade8a1a6SYing Zhang { 228d773a008SSimon Glass struct mmc *mmc = NULL; 229ade8a1a6SYing Zhang u32 boot_mode; 230dc3dedfeSSimon Glass int err = 0; 23191199f4aSPaul Kocialkowski __maybe_unused int part; 232ade8a1a6SYing Zhang 233a1e56cf6SNikita Kiryanov err = spl_mmc_find_device(&mmc, boot_device); 23436afd451SNikita Kiryanov if (err) 23536afd451SNikita Kiryanov return err; 236ade8a1a6SYing Zhang 237ade8a1a6SYing Zhang err = mmc_init(mmc); 238ade8a1a6SYing Zhang if (err) { 2398112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 24091199f4aSPaul Kocialkowski printf("spl: mmc init failed with error: %d\n", err); 2418112f5faSPaul Burton #endif 24236afd451SNikita Kiryanov return err; 243ade8a1a6SYing Zhang } 24479adb7a2SPeter Korsgaard 245ade8a1a6SYing Zhang boot_mode = spl_boot_mode(); 24636afd451SNikita Kiryanov err = -EINVAL; 24791199f4aSPaul Kocialkowski switch (boot_mode) { 24883cdf6faSNikita Kiryanov case MMCSD_MODE_EMMCBOOT: 24983cdf6faSNikita Kiryanov /* 25083cdf6faSNikita Kiryanov * We need to check what the partition is configured to. 25183cdf6faSNikita Kiryanov * 1 and 2 match up to boot0 / boot1 and 7 is user data 25283cdf6faSNikita Kiryanov * which is the first physical partition (0). 25383cdf6faSNikita Kiryanov */ 25483cdf6faSNikita Kiryanov part = (mmc->part_config >> 3) & PART_ACCESS_MASK; 25583cdf6faSNikita Kiryanov 25683cdf6faSNikita Kiryanov if (part == 7) 25783cdf6faSNikita Kiryanov part = 0; 25883cdf6faSNikita Kiryanov 25936afd451SNikita Kiryanov err = mmc_switch_part(0, part); 26036afd451SNikita Kiryanov if (err) { 26183cdf6faSNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 26283cdf6faSNikita Kiryanov puts("spl: mmc partition switch failed\n"); 26383cdf6faSNikita Kiryanov #endif 26436afd451SNikita Kiryanov return err; 26583cdf6faSNikita Kiryanov } 26683cdf6faSNikita Kiryanov /* Fall through */ 26791199f4aSPaul Kocialkowski case MMCSD_MODE_RAW: 26891199f4aSPaul Kocialkowski debug("spl: mmc boot mode: raw\n"); 26991199f4aSPaul Kocialkowski 27091199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 27191199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 27291199f4aSPaul Kocialkowski if (!err) 27336afd451SNikita Kiryanov return err; 27491199f4aSPaul Kocialkowski } 275d074ebb9SNikita Kiryanov 276b97300b6SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 277b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 27891199f4aSPaul Kocialkowski if (!err) 27936afd451SNikita Kiryanov return err; 280d074ebb9SNikita Kiryanov #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 2813ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 2823ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 2833ae8f4c8SPaul Kocialkowski if (!err) 28436afd451SNikita Kiryanov return err; 2853ae8f4c8SPaul Kocialkowski #endif 286fd61d399SNikita Kiryanov break; 28791199f4aSPaul Kocialkowski case MMCSD_MODE_FS: 28891199f4aSPaul Kocialkowski debug("spl: mmc boot mode: fs\n"); 28991199f4aSPaul Kocialkowski 290f52b7293SNikita Kiryanov err = spl_mmc_do_fs_boot(mmc); 29191199f4aSPaul Kocialkowski if (!err) 29236afd451SNikita Kiryanov return err; 293f52b7293SNikita Kiryanov 294fd61d399SNikita Kiryanov break; 2952c84c9a4SGuillaume GARDET case MMCSD_MODE_UNDEFINED: 2968112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 297fd61d399SNikita Kiryanov default: 29891199f4aSPaul Kocialkowski puts("spl: mmc: wrong boot mode\n"); 2998112f5faSPaul Burton #endif 300ade8a1a6SYing Zhang } 301fd61d399SNikita Kiryanov 30236afd451SNikita Kiryanov return err; 303ade8a1a6SYing Zhang } 304