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> 10*dc3dedfeSSimon Glass #include <dm.h> 11ade8a1a6SYing Zhang #include <spl.h> 1291199f4aSPaul Kocialkowski #include <linux/compiler.h> 13ade8a1a6SYing Zhang #include <asm/u-boot.h> 14ade8a1a6SYing Zhang #include <mmc.h> 15e4c444b3STom Rini #include <image.h> 16ade8a1a6SYing Zhang 17ade8a1a6SYing Zhang DECLARE_GLOBAL_DATA_PTR; 18ade8a1a6SYing Zhang 19b97300b6SPaul Kocialkowski static int mmc_load_image_raw_sector(struct mmc *mmc, unsigned long sector) 20ade8a1a6SYing Zhang { 213bc37b6dSPaul Kocialkowski unsigned long count; 22ade8a1a6SYing Zhang u32 image_size_sectors; 23ade8a1a6SYing Zhang struct image_header *header; 24ade8a1a6SYing Zhang 25ade8a1a6SYing Zhang header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - 26ade8a1a6SYing Zhang sizeof(struct image_header)); 27ade8a1a6SYing Zhang 28ade8a1a6SYing Zhang /* read image header to find the image size & load address */ 293bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, sector, 1, header); 30fdfa39d3SSimon Glass debug("read sector %lx, count=%lu\n", sector, count); 313bc37b6dSPaul Kocialkowski if (count == 0) 32ade8a1a6SYing Zhang goto end; 33ade8a1a6SYing Zhang 34fdfa39d3SSimon Glass if (image_get_magic(header) != IH_MAGIC) { 35fdfa39d3SSimon Glass puts("bad magic\n"); 36e4c444b3STom Rini return -1; 37fdfa39d3SSimon Glass } 38e4c444b3STom Rini 39ade8a1a6SYing Zhang spl_parse_image_header(header); 40ade8a1a6SYing Zhang 41ade8a1a6SYing Zhang /* convert size to sectors - round up */ 42ade8a1a6SYing Zhang image_size_sectors = (spl_image.size + mmc->read_bl_len - 1) / 43ade8a1a6SYing Zhang mmc->read_bl_len; 44ade8a1a6SYing Zhang 45ade8a1a6SYing Zhang /* Read the header too to avoid extra memcpy */ 463bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, sector, image_size_sectors, 47721931f8SPeter Korsgaard (void *)spl_image.load_addr); 48fdfa39d3SSimon Glass debug("read %x sectors to %x\n", image_size_sectors, 49fdfa39d3SSimon Glass spl_image.load_addr); 50ade8a1a6SYing Zhang 51ade8a1a6SYing Zhang end: 521ec26469SPaul Kocialkowski if (count == 0) { 538112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 541ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 558112f5faSPaul Burton #endif 563bc37b6dSPaul Kocialkowski return -1; 571ec26469SPaul Kocialkowski } 583bc37b6dSPaul Kocialkowski 593bc37b6dSPaul Kocialkowski return 0; 60ade8a1a6SYing Zhang } 61ade8a1a6SYing Zhang 62b97300b6SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 63b97300b6SPaul Kocialkowski static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) 64b97300b6SPaul Kocialkowski { 65b97300b6SPaul Kocialkowski disk_partition_t info; 663bc37b6dSPaul Kocialkowski int err; 67b97300b6SPaul Kocialkowski 683bc37b6dSPaul Kocialkowski err = get_partition_info(&mmc->block_dev, partition, &info); 693bc37b6dSPaul Kocialkowski if (err) { 70b97300b6SPaul Kocialkowski #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 711ec26469SPaul Kocialkowski puts("spl: partition error\n"); 72b97300b6SPaul Kocialkowski #endif 73b97300b6SPaul Kocialkowski return -1; 74b97300b6SPaul Kocialkowski } 75b97300b6SPaul Kocialkowski 76b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, info.start); 77b97300b6SPaul Kocialkowski } 78b97300b6SPaul Kocialkowski #endif 79b97300b6SPaul Kocialkowski 802b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 812b75b0adSPeter Korsgaard static int mmc_load_image_raw_os(struct mmc *mmc) 822b75b0adSPeter Korsgaard { 833bc37b6dSPaul Kocialkowski unsigned long count; 8491199f4aSPaul Kocialkowski 853bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, 862b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, 872b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, 8891199f4aSPaul Kocialkowski (void *) CONFIG_SYS_SPL_ARGS_ADDR); 893bc37b6dSPaul Kocialkowski if (count == 0) { 908112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 911ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 928112f5faSPaul Burton #endif 932b75b0adSPeter Korsgaard return -1; 942b75b0adSPeter Korsgaard } 952b75b0adSPeter Korsgaard 96b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, 97b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); 982b75b0adSPeter Korsgaard } 992b75b0adSPeter Korsgaard #endif 1002b75b0adSPeter Korsgaard 101ade8a1a6SYing Zhang void spl_mmc_load_image(void) 102ade8a1a6SYing Zhang { 103ade8a1a6SYing Zhang struct mmc *mmc; 104ade8a1a6SYing Zhang u32 boot_mode; 105*dc3dedfeSSimon Glass int err = 0; 10691199f4aSPaul Kocialkowski __maybe_unused int part; 107ade8a1a6SYing Zhang 108*dc3dedfeSSimon Glass #ifdef CONFIG_DM_MMC 109*dc3dedfeSSimon Glass struct udevice *dev; 110*dc3dedfeSSimon Glass 111*dc3dedfeSSimon Glass mmc_initialize(NULL); 112*dc3dedfeSSimon Glass err = uclass_get_device(UCLASS_MMC, 0, &dev); 113*dc3dedfeSSimon Glass mmc = NULL; 114*dc3dedfeSSimon Glass if (!err) 115*dc3dedfeSSimon Glass mmc = mmc_get_mmc_dev(dev); 116*dc3dedfeSSimon Glass #else 117ade8a1a6SYing Zhang mmc_initialize(gd->bd); 11891199f4aSPaul Kocialkowski 119ade8a1a6SYing Zhang /* We register only one device. So, the dev id is always 0 */ 120ade8a1a6SYing Zhang mmc = find_mmc_device(0); 121ade8a1a6SYing Zhang if (!mmc) { 1228112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 12391199f4aSPaul Kocialkowski puts("spl: mmc device not found\n"); 1248112f5faSPaul Burton #endif 125ade8a1a6SYing Zhang hang(); 126ade8a1a6SYing Zhang } 127*dc3dedfeSSimon Glass #endif 128ade8a1a6SYing Zhang 129*dc3dedfeSSimon Glass if (!err) 130ade8a1a6SYing Zhang err = mmc_init(mmc); 131*dc3dedfeSSimon Glass 132ade8a1a6SYing Zhang if (err) { 1338112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 13491199f4aSPaul Kocialkowski printf("spl: mmc init failed with error: %d\n", err); 1358112f5faSPaul Burton #endif 136ade8a1a6SYing Zhang hang(); 137ade8a1a6SYing Zhang } 13879adb7a2SPeter Korsgaard 139ade8a1a6SYing Zhang boot_mode = spl_boot_mode(); 14091199f4aSPaul Kocialkowski switch (boot_mode) { 14191199f4aSPaul Kocialkowski case MMCSD_MODE_RAW: 14291199f4aSPaul Kocialkowski debug("spl: mmc boot mode: raw\n"); 14391199f4aSPaul Kocialkowski 1442b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 14591199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 14691199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 14791199f4aSPaul Kocialkowski if (!err) 14891199f4aSPaul Kocialkowski return; 14991199f4aSPaul Kocialkowski } 1502b75b0adSPeter Korsgaard #endif 1513ae8f4c8SPaul Kocialkowski #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) 152b97300b6SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 153b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 15491199f4aSPaul Kocialkowski if (!err) 15591199f4aSPaul Kocialkowski return; 1563ae8f4c8SPaul Kocialkowski #elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 1573ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 1583ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 1593ae8f4c8SPaul Kocialkowski if (!err) 1603ae8f4c8SPaul Kocialkowski return; 1613ae8f4c8SPaul Kocialkowski #endif 16291199f4aSPaul Kocialkowski case MMCSD_MODE_FS: 16391199f4aSPaul Kocialkowski debug("spl: mmc boot mode: fs\n"); 16491199f4aSPaul Kocialkowski 1653ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 166592f9222SGuillaume GARDET #ifdef CONFIG_SPL_FAT_SUPPORT 1677ad2cc79SPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 16891199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 16991199f4aSPaul Kocialkowski err = spl_load_image_fat_os(&mmc->block_dev, 17091199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 17191199f4aSPaul Kocialkowski if (!err) 17291199f4aSPaul Kocialkowski return; 17391199f4aSPaul Kocialkowski } 1747ad2cc79SPeter Korsgaard #endif 1753ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 176773b5940SDan Murphy err = spl_load_image_fat(&mmc->block_dev, 177e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 178205b4f33SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 17991199f4aSPaul Kocialkowski if (!err) 18091199f4aSPaul Kocialkowski return; 18191199f4aSPaul Kocialkowski #endif 1823ae8f4c8SPaul Kocialkowski #endif 183592f9222SGuillaume GARDET #ifdef CONFIG_SPL_EXT_SUPPORT 184592f9222SGuillaume GARDET #ifdef CONFIG_SPL_OS_BOOT 18591199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 18691199f4aSPaul Kocialkowski err = spl_load_image_ext_os(&mmc->block_dev, 18791199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 18891199f4aSPaul Kocialkowski if (!err) 18991199f4aSPaul Kocialkowski return; 19091199f4aSPaul Kocialkowski } 191ade8a1a6SYing Zhang #endif 1923ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 193592f9222SGuillaume GARDET err = spl_load_image_ext(&mmc->block_dev, 194e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 195592f9222SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 19691199f4aSPaul Kocialkowski if (!err) 19791199f4aSPaul Kocialkowski return; 19891199f4aSPaul Kocialkowski #endif 19991199f4aSPaul Kocialkowski #endif 2003ae8f4c8SPaul Kocialkowski #endif 2017dbe63bcSTom Rini #ifdef CONFIG_SUPPORT_EMMC_BOOT 20291199f4aSPaul Kocialkowski case MMCSD_MODE_EMMCBOOT: 2037dbe63bcSTom Rini /* 2047dbe63bcSTom Rini * We need to check what the partition is configured to. 2057dbe63bcSTom Rini * 1 and 2 match up to boot0 / boot1 and 7 is user data 2067dbe63bcSTom Rini * which is the first physical partition (0). 2077dbe63bcSTom Rini */ 20891199f4aSPaul Kocialkowski part = (mmc->part_config >> 3) & PART_ACCESS_MASK; 2097dbe63bcSTom Rini 2107dbe63bcSTom Rini if (part == 7) 2117dbe63bcSTom Rini part = 0; 2127dbe63bcSTom Rini 2137dbe63bcSTom Rini if (mmc_switch_part(0, part)) { 2147dbe63bcSTom Rini #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 21591199f4aSPaul Kocialkowski puts("spl: mmc partition switch failed\n"); 2167dbe63bcSTom Rini #endif 2177dbe63bcSTom Rini hang(); 2187dbe63bcSTom Rini } 21991199f4aSPaul Kocialkowski 2207dbe63bcSTom Rini #ifdef CONFIG_SPL_OS_BOOT 22191199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 22291199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 22391199f4aSPaul Kocialkowski if (!err) 22491199f4aSPaul Kocialkowski return; 22591199f4aSPaul Kocialkowski } 2267dbe63bcSTom Rini #endif 2273ae8f4c8SPaul Kocialkowski #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) 228ecb30139SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 229ecb30139SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 23091199f4aSPaul Kocialkowski if (!err) 23191199f4aSPaul Kocialkowski return; 2323ae8f4c8SPaul Kocialkowski #elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 2333ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 2343ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 2353ae8f4c8SPaul Kocialkowski if (!err) 2363ae8f4c8SPaul Kocialkowski return; 2373ae8f4c8SPaul Kocialkowski #endif 2387dbe63bcSTom Rini #endif 2392c84c9a4SGuillaume GARDET case MMCSD_MODE_UNDEFINED: 2402c84c9a4SGuillaume GARDET default: 2418112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 24291199f4aSPaul Kocialkowski if (err) 24391199f4aSPaul Kocialkowski puts("spl: mmc: no boot mode left to try\n"); 24491199f4aSPaul Kocialkowski else 24591199f4aSPaul Kocialkowski puts("spl: mmc: wrong boot mode\n"); 2468112f5faSPaul Burton #endif 247ade8a1a6SYing Zhang hang(); 248ade8a1a6SYing Zhang } 249ade8a1a6SYing Zhang } 250