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> 10ade8a1a6SYing Zhang #include <spl.h> 1191199f4aSPaul Kocialkowski #include <linux/compiler.h> 12ade8a1a6SYing Zhang #include <asm/u-boot.h> 13ade8a1a6SYing Zhang #include <mmc.h> 14e4c444b3STom Rini #include <image.h> 15ade8a1a6SYing Zhang 16ade8a1a6SYing Zhang DECLARE_GLOBAL_DATA_PTR; 17ade8a1a6SYing Zhang 18b97300b6SPaul Kocialkowski static int mmc_load_image_raw_sector(struct mmc *mmc, unsigned long sector) 19ade8a1a6SYing Zhang { 203bc37b6dSPaul Kocialkowski unsigned long count; 21ade8a1a6SYing Zhang u32 image_size_sectors; 22ade8a1a6SYing Zhang struct image_header *header; 23ade8a1a6SYing Zhang 24ade8a1a6SYing Zhang header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - 25ade8a1a6SYing Zhang sizeof(struct image_header)); 26ade8a1a6SYing Zhang 27ade8a1a6SYing Zhang /* read image header to find the image size & load address */ 283bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, sector, 1, header); 293bc37b6dSPaul Kocialkowski if (count == 0) 30ade8a1a6SYing Zhang goto end; 31ade8a1a6SYing Zhang 32e4c444b3STom Rini if (image_get_magic(header) != IH_MAGIC) 33e4c444b3STom Rini return -1; 34e4c444b3STom Rini 35ade8a1a6SYing Zhang spl_parse_image_header(header); 36ade8a1a6SYing Zhang 37ade8a1a6SYing Zhang /* convert size to sectors - round up */ 38ade8a1a6SYing Zhang image_size_sectors = (spl_image.size + mmc->read_bl_len - 1) / 39ade8a1a6SYing Zhang mmc->read_bl_len; 40ade8a1a6SYing Zhang 41ade8a1a6SYing Zhang /* Read the header too to avoid extra memcpy */ 423bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, sector, image_size_sectors, 43721931f8SPeter Korsgaard (void *) spl_image.load_addr); 44ade8a1a6SYing Zhang 45ade8a1a6SYing Zhang end: 461ec26469SPaul Kocialkowski if (count == 0) { 478112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 481ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 498112f5faSPaul Burton #endif 503bc37b6dSPaul Kocialkowski return -1; 511ec26469SPaul Kocialkowski } 523bc37b6dSPaul Kocialkowski 533bc37b6dSPaul Kocialkowski return 0; 54ade8a1a6SYing Zhang } 55ade8a1a6SYing Zhang 56b97300b6SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 57b97300b6SPaul Kocialkowski static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) 58b97300b6SPaul Kocialkowski { 59b97300b6SPaul Kocialkowski disk_partition_t info; 603bc37b6dSPaul Kocialkowski int err; 61b97300b6SPaul Kocialkowski 623bc37b6dSPaul Kocialkowski err = get_partition_info(&mmc->block_dev, partition, &info); 633bc37b6dSPaul Kocialkowski if (err) { 64b97300b6SPaul Kocialkowski #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 651ec26469SPaul Kocialkowski puts("spl: partition error\n"); 66b97300b6SPaul Kocialkowski #endif 67b97300b6SPaul Kocialkowski return -1; 68b97300b6SPaul Kocialkowski } 69b97300b6SPaul Kocialkowski 70b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, info.start); 71b97300b6SPaul Kocialkowski } 72b97300b6SPaul Kocialkowski #endif 73b97300b6SPaul Kocialkowski 742b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 752b75b0adSPeter Korsgaard static int mmc_load_image_raw_os(struct mmc *mmc) 762b75b0adSPeter Korsgaard { 773bc37b6dSPaul Kocialkowski unsigned long count; 7891199f4aSPaul Kocialkowski 793bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, 802b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, 812b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, 8291199f4aSPaul Kocialkowski (void *) CONFIG_SYS_SPL_ARGS_ADDR); 833bc37b6dSPaul Kocialkowski if (count == 0) { 848112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 851ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 868112f5faSPaul Burton #endif 872b75b0adSPeter Korsgaard return -1; 882b75b0adSPeter Korsgaard } 892b75b0adSPeter Korsgaard 90b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, 91b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); 922b75b0adSPeter Korsgaard } 932b75b0adSPeter Korsgaard #endif 942b75b0adSPeter Korsgaard 95ade8a1a6SYing Zhang void spl_mmc_load_image(void) 96ade8a1a6SYing Zhang { 97ade8a1a6SYing Zhang struct mmc *mmc; 98ade8a1a6SYing Zhang u32 boot_mode; 9991199f4aSPaul Kocialkowski int err; 10091199f4aSPaul Kocialkowski __maybe_unused int part; 101ade8a1a6SYing Zhang 102ade8a1a6SYing Zhang mmc_initialize(gd->bd); 10391199f4aSPaul Kocialkowski 104ade8a1a6SYing Zhang /* We register only one device. So, the dev id is always 0 */ 105ade8a1a6SYing Zhang mmc = find_mmc_device(0); 106ade8a1a6SYing Zhang if (!mmc) { 1078112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 10891199f4aSPaul Kocialkowski puts("spl: mmc device not found\n"); 1098112f5faSPaul Burton #endif 110ade8a1a6SYing Zhang hang(); 111ade8a1a6SYing Zhang } 112ade8a1a6SYing Zhang 113ade8a1a6SYing Zhang err = mmc_init(mmc); 114ade8a1a6SYing Zhang if (err) { 1158112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 11691199f4aSPaul Kocialkowski printf("spl: mmc init failed with error: %d\n", err); 1178112f5faSPaul Burton #endif 118ade8a1a6SYing Zhang hang(); 119ade8a1a6SYing Zhang } 12079adb7a2SPeter Korsgaard 121ade8a1a6SYing Zhang boot_mode = spl_boot_mode(); 12291199f4aSPaul Kocialkowski switch (boot_mode) { 12391199f4aSPaul Kocialkowski case MMCSD_MODE_RAW: 12491199f4aSPaul Kocialkowski debug("spl: mmc boot mode: raw\n"); 12591199f4aSPaul Kocialkowski 1262b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 12791199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 12891199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 12991199f4aSPaul Kocialkowski if (!err) 13091199f4aSPaul Kocialkowski return; 13191199f4aSPaul Kocialkowski } 1322b75b0adSPeter Korsgaard #endif 133*3ae8f4c8SPaul Kocialkowski #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) 134b97300b6SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 135b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 13691199f4aSPaul Kocialkowski if (!err) 13791199f4aSPaul Kocialkowski return; 138*3ae8f4c8SPaul Kocialkowski #elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 139*3ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 140*3ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 141*3ae8f4c8SPaul Kocialkowski if (!err) 142*3ae8f4c8SPaul Kocialkowski return; 143*3ae8f4c8SPaul Kocialkowski #endif 14491199f4aSPaul Kocialkowski case MMCSD_MODE_FS: 14591199f4aSPaul Kocialkowski debug("spl: mmc boot mode: fs\n"); 14691199f4aSPaul Kocialkowski 147*3ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 148592f9222SGuillaume GARDET #ifdef CONFIG_SPL_FAT_SUPPORT 1497ad2cc79SPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 15091199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 15191199f4aSPaul Kocialkowski err = spl_load_image_fat_os(&mmc->block_dev, 15291199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 15391199f4aSPaul Kocialkowski if (!err) 15491199f4aSPaul Kocialkowski return; 15591199f4aSPaul Kocialkowski } 1567ad2cc79SPeter Korsgaard #endif 157*3ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 158773b5940SDan Murphy err = spl_load_image_fat(&mmc->block_dev, 159e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 160205b4f33SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 16191199f4aSPaul Kocialkowski if (!err) 16291199f4aSPaul Kocialkowski return; 16391199f4aSPaul Kocialkowski #endif 164*3ae8f4c8SPaul Kocialkowski #endif 165592f9222SGuillaume GARDET #ifdef CONFIG_SPL_EXT_SUPPORT 166592f9222SGuillaume GARDET #ifdef CONFIG_SPL_OS_BOOT 16791199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 16891199f4aSPaul Kocialkowski err = spl_load_image_ext_os(&mmc->block_dev, 16991199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 17091199f4aSPaul Kocialkowski if (!err) 17191199f4aSPaul Kocialkowski return; 17291199f4aSPaul Kocialkowski } 173ade8a1a6SYing Zhang #endif 174*3ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 175592f9222SGuillaume GARDET err = spl_load_image_ext(&mmc->block_dev, 176e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 177592f9222SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 17891199f4aSPaul Kocialkowski if (!err) 17991199f4aSPaul Kocialkowski return; 18091199f4aSPaul Kocialkowski #endif 18191199f4aSPaul Kocialkowski #endif 182*3ae8f4c8SPaul Kocialkowski #endif 1837dbe63bcSTom Rini #ifdef CONFIG_SUPPORT_EMMC_BOOT 18491199f4aSPaul Kocialkowski case MMCSD_MODE_EMMCBOOT: 1857dbe63bcSTom Rini /* 1867dbe63bcSTom Rini * We need to check what the partition is configured to. 1877dbe63bcSTom Rini * 1 and 2 match up to boot0 / boot1 and 7 is user data 1887dbe63bcSTom Rini * which is the first physical partition (0). 1897dbe63bcSTom Rini */ 19091199f4aSPaul Kocialkowski part = (mmc->part_config >> 3) & PART_ACCESS_MASK; 1917dbe63bcSTom Rini 1927dbe63bcSTom Rini if (part == 7) 1937dbe63bcSTom Rini part = 0; 1947dbe63bcSTom Rini 1957dbe63bcSTom Rini if (mmc_switch_part(0, part)) { 1967dbe63bcSTom Rini #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 19791199f4aSPaul Kocialkowski puts("spl: mmc partition switch failed\n"); 1987dbe63bcSTom Rini #endif 1997dbe63bcSTom Rini hang(); 2007dbe63bcSTom Rini } 20191199f4aSPaul Kocialkowski 2027dbe63bcSTom Rini #ifdef CONFIG_SPL_OS_BOOT 20391199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 20491199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 20591199f4aSPaul Kocialkowski if (!err) 20691199f4aSPaul Kocialkowski return; 20791199f4aSPaul Kocialkowski } 2087dbe63bcSTom Rini #endif 209*3ae8f4c8SPaul Kocialkowski #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) 210ecb30139SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 211ecb30139SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 21291199f4aSPaul Kocialkowski if (!err) 21391199f4aSPaul Kocialkowski return; 214*3ae8f4c8SPaul Kocialkowski #elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 215*3ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 216*3ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 217*3ae8f4c8SPaul Kocialkowski if (!err) 218*3ae8f4c8SPaul Kocialkowski return; 219*3ae8f4c8SPaul Kocialkowski #endif 2207dbe63bcSTom Rini #endif 2212c84c9a4SGuillaume GARDET case MMCSD_MODE_UNDEFINED: 2222c84c9a4SGuillaume GARDET default: 2238112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 22491199f4aSPaul Kocialkowski if (err) 22591199f4aSPaul Kocialkowski puts("spl: mmc: no boot mode left to try\n"); 22691199f4aSPaul Kocialkowski else 22791199f4aSPaul Kocialkowski puts("spl: mmc: wrong boot mode\n"); 2288112f5faSPaul Burton #endif 229ade8a1a6SYing Zhang hang(); 230ade8a1a6SYing Zhang } 231ade8a1a6SYing Zhang } 232