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); 29*fdfa39d3SSimon Glass debug("read sector %lx, count=%lu\n", sector, count); 303bc37b6dSPaul Kocialkowski if (count == 0) 31ade8a1a6SYing Zhang goto end; 32ade8a1a6SYing Zhang 33*fdfa39d3SSimon Glass if (image_get_magic(header) != IH_MAGIC) { 34*fdfa39d3SSimon Glass puts("bad magic\n"); 35e4c444b3STom Rini return -1; 36*fdfa39d3SSimon Glass } 37e4c444b3STom Rini 38ade8a1a6SYing Zhang spl_parse_image_header(header); 39ade8a1a6SYing Zhang 40ade8a1a6SYing Zhang /* convert size to sectors - round up */ 41ade8a1a6SYing Zhang image_size_sectors = (spl_image.size + mmc->read_bl_len - 1) / 42ade8a1a6SYing Zhang mmc->read_bl_len; 43ade8a1a6SYing Zhang 44ade8a1a6SYing Zhang /* Read the header too to avoid extra memcpy */ 453bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, sector, image_size_sectors, 46721931f8SPeter Korsgaard (void *)spl_image.load_addr); 47*fdfa39d3SSimon Glass debug("read %x sectors to %x\n", image_size_sectors, 48*fdfa39d3SSimon Glass spl_image.load_addr); 49ade8a1a6SYing Zhang 50ade8a1a6SYing Zhang end: 511ec26469SPaul Kocialkowski if (count == 0) { 528112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 531ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 548112f5faSPaul Burton #endif 553bc37b6dSPaul Kocialkowski return -1; 561ec26469SPaul Kocialkowski } 573bc37b6dSPaul Kocialkowski 583bc37b6dSPaul Kocialkowski return 0; 59ade8a1a6SYing Zhang } 60ade8a1a6SYing Zhang 61b97300b6SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 62b97300b6SPaul Kocialkowski static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) 63b97300b6SPaul Kocialkowski { 64b97300b6SPaul Kocialkowski disk_partition_t info; 653bc37b6dSPaul Kocialkowski int err; 66b97300b6SPaul Kocialkowski 673bc37b6dSPaul Kocialkowski err = get_partition_info(&mmc->block_dev, partition, &info); 683bc37b6dSPaul Kocialkowski if (err) { 69b97300b6SPaul Kocialkowski #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 701ec26469SPaul Kocialkowski puts("spl: partition error\n"); 71b97300b6SPaul Kocialkowski #endif 72b97300b6SPaul Kocialkowski return -1; 73b97300b6SPaul Kocialkowski } 74b97300b6SPaul Kocialkowski 75b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, info.start); 76b97300b6SPaul Kocialkowski } 77b97300b6SPaul Kocialkowski #endif 78b97300b6SPaul Kocialkowski 792b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 802b75b0adSPeter Korsgaard static int mmc_load_image_raw_os(struct mmc *mmc) 812b75b0adSPeter Korsgaard { 823bc37b6dSPaul Kocialkowski unsigned long count; 8391199f4aSPaul Kocialkowski 843bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, 852b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, 862b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, 8791199f4aSPaul Kocialkowski (void *) CONFIG_SYS_SPL_ARGS_ADDR); 883bc37b6dSPaul Kocialkowski if (count == 0) { 898112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 901ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 918112f5faSPaul Burton #endif 922b75b0adSPeter Korsgaard return -1; 932b75b0adSPeter Korsgaard } 942b75b0adSPeter Korsgaard 95b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, 96b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); 972b75b0adSPeter Korsgaard } 982b75b0adSPeter Korsgaard #endif 992b75b0adSPeter Korsgaard 100ade8a1a6SYing Zhang void spl_mmc_load_image(void) 101ade8a1a6SYing Zhang { 102ade8a1a6SYing Zhang struct mmc *mmc; 103ade8a1a6SYing Zhang u32 boot_mode; 10491199f4aSPaul Kocialkowski int err; 10591199f4aSPaul Kocialkowski __maybe_unused int part; 106ade8a1a6SYing Zhang 107ade8a1a6SYing Zhang mmc_initialize(gd->bd); 10891199f4aSPaul Kocialkowski 109ade8a1a6SYing Zhang /* We register only one device. So, the dev id is always 0 */ 110ade8a1a6SYing Zhang mmc = find_mmc_device(0); 111ade8a1a6SYing Zhang if (!mmc) { 1128112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 11391199f4aSPaul Kocialkowski puts("spl: mmc device not found\n"); 1148112f5faSPaul Burton #endif 115ade8a1a6SYing Zhang hang(); 116ade8a1a6SYing Zhang } 117ade8a1a6SYing Zhang 118ade8a1a6SYing Zhang err = mmc_init(mmc); 119ade8a1a6SYing Zhang if (err) { 1208112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 12191199f4aSPaul Kocialkowski printf("spl: mmc init failed with error: %d\n", err); 1228112f5faSPaul Burton #endif 123ade8a1a6SYing Zhang hang(); 124ade8a1a6SYing Zhang } 12579adb7a2SPeter Korsgaard 126ade8a1a6SYing Zhang boot_mode = spl_boot_mode(); 12791199f4aSPaul Kocialkowski switch (boot_mode) { 12891199f4aSPaul Kocialkowski case MMCSD_MODE_RAW: 12991199f4aSPaul Kocialkowski debug("spl: mmc boot mode: raw\n"); 13091199f4aSPaul Kocialkowski 1312b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 13291199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 13391199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 13491199f4aSPaul Kocialkowski if (!err) 13591199f4aSPaul Kocialkowski return; 13691199f4aSPaul Kocialkowski } 1372b75b0adSPeter Korsgaard #endif 1383ae8f4c8SPaul Kocialkowski #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) 139b97300b6SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 140b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 14191199f4aSPaul Kocialkowski if (!err) 14291199f4aSPaul Kocialkowski return; 1433ae8f4c8SPaul Kocialkowski #elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 1443ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 1453ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 1463ae8f4c8SPaul Kocialkowski if (!err) 1473ae8f4c8SPaul Kocialkowski return; 1483ae8f4c8SPaul Kocialkowski #endif 14991199f4aSPaul Kocialkowski case MMCSD_MODE_FS: 15091199f4aSPaul Kocialkowski debug("spl: mmc boot mode: fs\n"); 15191199f4aSPaul Kocialkowski 1523ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 153592f9222SGuillaume GARDET #ifdef CONFIG_SPL_FAT_SUPPORT 1547ad2cc79SPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 15591199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 15691199f4aSPaul Kocialkowski err = spl_load_image_fat_os(&mmc->block_dev, 15791199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 15891199f4aSPaul Kocialkowski if (!err) 15991199f4aSPaul Kocialkowski return; 16091199f4aSPaul Kocialkowski } 1617ad2cc79SPeter Korsgaard #endif 1623ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 163773b5940SDan Murphy err = spl_load_image_fat(&mmc->block_dev, 164e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 165205b4f33SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 16691199f4aSPaul Kocialkowski if (!err) 16791199f4aSPaul Kocialkowski return; 16891199f4aSPaul Kocialkowski #endif 1693ae8f4c8SPaul Kocialkowski #endif 170592f9222SGuillaume GARDET #ifdef CONFIG_SPL_EXT_SUPPORT 171592f9222SGuillaume GARDET #ifdef CONFIG_SPL_OS_BOOT 17291199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 17391199f4aSPaul Kocialkowski err = spl_load_image_ext_os(&mmc->block_dev, 17491199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 17591199f4aSPaul Kocialkowski if (!err) 17691199f4aSPaul Kocialkowski return; 17791199f4aSPaul Kocialkowski } 178ade8a1a6SYing Zhang #endif 1793ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 180592f9222SGuillaume GARDET err = spl_load_image_ext(&mmc->block_dev, 181e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 182592f9222SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 18391199f4aSPaul Kocialkowski if (!err) 18491199f4aSPaul Kocialkowski return; 18591199f4aSPaul Kocialkowski #endif 18691199f4aSPaul Kocialkowski #endif 1873ae8f4c8SPaul Kocialkowski #endif 1887dbe63bcSTom Rini #ifdef CONFIG_SUPPORT_EMMC_BOOT 18991199f4aSPaul Kocialkowski case MMCSD_MODE_EMMCBOOT: 1907dbe63bcSTom Rini /* 1917dbe63bcSTom Rini * We need to check what the partition is configured to. 1927dbe63bcSTom Rini * 1 and 2 match up to boot0 / boot1 and 7 is user data 1937dbe63bcSTom Rini * which is the first physical partition (0). 1947dbe63bcSTom Rini */ 19591199f4aSPaul Kocialkowski part = (mmc->part_config >> 3) & PART_ACCESS_MASK; 1967dbe63bcSTom Rini 1977dbe63bcSTom Rini if (part == 7) 1987dbe63bcSTom Rini part = 0; 1997dbe63bcSTom Rini 2007dbe63bcSTom Rini if (mmc_switch_part(0, part)) { 2017dbe63bcSTom Rini #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 20291199f4aSPaul Kocialkowski puts("spl: mmc partition switch failed\n"); 2037dbe63bcSTom Rini #endif 2047dbe63bcSTom Rini hang(); 2057dbe63bcSTom Rini } 20691199f4aSPaul Kocialkowski 2077dbe63bcSTom Rini #ifdef CONFIG_SPL_OS_BOOT 20891199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 20991199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 21091199f4aSPaul Kocialkowski if (!err) 21191199f4aSPaul Kocialkowski return; 21291199f4aSPaul Kocialkowski } 2137dbe63bcSTom Rini #endif 2143ae8f4c8SPaul Kocialkowski #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) 215ecb30139SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 216ecb30139SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 21791199f4aSPaul Kocialkowski if (!err) 21891199f4aSPaul Kocialkowski return; 2193ae8f4c8SPaul Kocialkowski #elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 2203ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 2213ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 2223ae8f4c8SPaul Kocialkowski if (!err) 2233ae8f4c8SPaul Kocialkowski return; 2243ae8f4c8SPaul Kocialkowski #endif 2257dbe63bcSTom Rini #endif 2262c84c9a4SGuillaume GARDET case MMCSD_MODE_UNDEFINED: 2272c84c9a4SGuillaume GARDET default: 2288112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 22991199f4aSPaul Kocialkowski if (err) 23091199f4aSPaul Kocialkowski puts("spl: mmc: no boot mode left to try\n"); 23191199f4aSPaul Kocialkowski else 23291199f4aSPaul Kocialkowski puts("spl: mmc: wrong boot mode\n"); 2338112f5faSPaul Burton #endif 234ade8a1a6SYing Zhang hang(); 235ade8a1a6SYing Zhang } 236ade8a1a6SYing Zhang } 237