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> 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, 477ef4c45cSGong Qianyu (void *)(ulong)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 764bfcc54cSStefan Roese #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 774bfcc54cSStefan Roese return mmc_load_image_raw_sector(mmc, info.start + 784bfcc54cSStefan Roese CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 794bfcc54cSStefan Roese #else 80b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, info.start); 814bfcc54cSStefan Roese #endif 82b97300b6SPaul Kocialkowski } 83b97300b6SPaul Kocialkowski #endif 84b97300b6SPaul Kocialkowski 852b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 862b75b0adSPeter Korsgaard static int mmc_load_image_raw_os(struct mmc *mmc) 872b75b0adSPeter Korsgaard { 883bc37b6dSPaul Kocialkowski unsigned long count; 8991199f4aSPaul Kocialkowski 903bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, 912b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, 922b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, 9391199f4aSPaul Kocialkowski (void *) CONFIG_SYS_SPL_ARGS_ADDR); 943bc37b6dSPaul Kocialkowski if (count == 0) { 958112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 961ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 978112f5faSPaul Burton #endif 982b75b0adSPeter Korsgaard return -1; 992b75b0adSPeter Korsgaard } 1002b75b0adSPeter Korsgaard 101b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, 102b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); 1032b75b0adSPeter Korsgaard } 1042b75b0adSPeter Korsgaard #endif 1052b75b0adSPeter Korsgaard 106ade8a1a6SYing Zhang void spl_mmc_load_image(void) 107ade8a1a6SYing Zhang { 108ade8a1a6SYing Zhang struct mmc *mmc; 109ade8a1a6SYing Zhang u32 boot_mode; 110dc3dedfeSSimon Glass int err = 0; 11191199f4aSPaul Kocialkowski __maybe_unused int part; 112ade8a1a6SYing Zhang 113dc3dedfeSSimon Glass #ifdef CONFIG_DM_MMC 114dc3dedfeSSimon Glass struct udevice *dev; 115dc3dedfeSSimon Glass 116dc3dedfeSSimon Glass mmc_initialize(NULL); 117dc3dedfeSSimon Glass err = uclass_get_device(UCLASS_MMC, 0, &dev); 118dc3dedfeSSimon Glass mmc = NULL; 119dc3dedfeSSimon Glass if (!err) 120dc3dedfeSSimon Glass mmc = mmc_get_mmc_dev(dev); 121dc3dedfeSSimon Glass #else 122ade8a1a6SYing Zhang mmc_initialize(gd->bd); 12391199f4aSPaul Kocialkowski 124ade8a1a6SYing Zhang /* We register only one device. So, the dev id is always 0 */ 125ade8a1a6SYing Zhang mmc = find_mmc_device(0); 126ade8a1a6SYing Zhang if (!mmc) { 1278112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 12891199f4aSPaul Kocialkowski puts("spl: mmc device not found\n"); 1298112f5faSPaul Burton #endif 130ade8a1a6SYing Zhang hang(); 131ade8a1a6SYing Zhang } 132dc3dedfeSSimon Glass #endif 133ade8a1a6SYing Zhang 134dc3dedfeSSimon Glass if (!err) 135ade8a1a6SYing Zhang err = mmc_init(mmc); 136dc3dedfeSSimon Glass 137ade8a1a6SYing Zhang if (err) { 1388112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 13991199f4aSPaul Kocialkowski printf("spl: mmc init failed with error: %d\n", err); 1408112f5faSPaul Burton #endif 141ade8a1a6SYing Zhang hang(); 142ade8a1a6SYing Zhang } 14379adb7a2SPeter Korsgaard 144ade8a1a6SYing Zhang boot_mode = spl_boot_mode(); 14591199f4aSPaul Kocialkowski switch (boot_mode) { 14691199f4aSPaul Kocialkowski case MMCSD_MODE_RAW: 14791199f4aSPaul Kocialkowski debug("spl: mmc boot mode: raw\n"); 14891199f4aSPaul Kocialkowski 1492b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 15091199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 15191199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 15291199f4aSPaul Kocialkowski if (!err) 15391199f4aSPaul Kocialkowski return; 15491199f4aSPaul Kocialkowski } 1552b75b0adSPeter Korsgaard #endif 1563ae8f4c8SPaul Kocialkowski #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) 157b97300b6SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 158b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 15991199f4aSPaul Kocialkowski if (!err) 16091199f4aSPaul Kocialkowski return; 1613ae8f4c8SPaul Kocialkowski #elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 1623ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 1633ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 1643ae8f4c8SPaul Kocialkowski if (!err) 1653ae8f4c8SPaul Kocialkowski return; 1663ae8f4c8SPaul Kocialkowski #endif 167*fd61d399SNikita Kiryanov break; 16891199f4aSPaul Kocialkowski case MMCSD_MODE_FS: 16991199f4aSPaul Kocialkowski debug("spl: mmc boot mode: fs\n"); 17091199f4aSPaul Kocialkowski 1713ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 172592f9222SGuillaume GARDET #ifdef CONFIG_SPL_FAT_SUPPORT 1737ad2cc79SPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 17491199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 17591199f4aSPaul Kocialkowski err = spl_load_image_fat_os(&mmc->block_dev, 17691199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 17791199f4aSPaul Kocialkowski if (!err) 17891199f4aSPaul Kocialkowski return; 17991199f4aSPaul Kocialkowski } 1807ad2cc79SPeter Korsgaard #endif 1813ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 182773b5940SDan Murphy err = spl_load_image_fat(&mmc->block_dev, 183e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 184205b4f33SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 18591199f4aSPaul Kocialkowski if (!err) 18691199f4aSPaul Kocialkowski return; 18791199f4aSPaul Kocialkowski #endif 1883ae8f4c8SPaul Kocialkowski #endif 189592f9222SGuillaume GARDET #ifdef CONFIG_SPL_EXT_SUPPORT 190592f9222SGuillaume GARDET #ifdef CONFIG_SPL_OS_BOOT 19191199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 19291199f4aSPaul Kocialkowski err = spl_load_image_ext_os(&mmc->block_dev, 19391199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 19491199f4aSPaul Kocialkowski if (!err) 19591199f4aSPaul Kocialkowski return; 19691199f4aSPaul Kocialkowski } 197ade8a1a6SYing Zhang #endif 1983ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 199592f9222SGuillaume GARDET err = spl_load_image_ext(&mmc->block_dev, 200e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 201592f9222SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 20291199f4aSPaul Kocialkowski if (!err) 20391199f4aSPaul Kocialkowski return; 20491199f4aSPaul Kocialkowski #endif 20591199f4aSPaul Kocialkowski #endif 2063ae8f4c8SPaul Kocialkowski #endif 207*fd61d399SNikita Kiryanov break; 2087dbe63bcSTom Rini #ifdef CONFIG_SUPPORT_EMMC_BOOT 20991199f4aSPaul Kocialkowski case MMCSD_MODE_EMMCBOOT: 2107dbe63bcSTom Rini /* 2117dbe63bcSTom Rini * We need to check what the partition is configured to. 2127dbe63bcSTom Rini * 1 and 2 match up to boot0 / boot1 and 7 is user data 2137dbe63bcSTom Rini * which is the first physical partition (0). 2147dbe63bcSTom Rini */ 21591199f4aSPaul Kocialkowski part = (mmc->part_config >> 3) & PART_ACCESS_MASK; 2167dbe63bcSTom Rini 2177dbe63bcSTom Rini if (part == 7) 2187dbe63bcSTom Rini part = 0; 2197dbe63bcSTom Rini 2207dbe63bcSTom Rini if (mmc_switch_part(0, part)) { 2217dbe63bcSTom Rini #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 22291199f4aSPaul Kocialkowski puts("spl: mmc partition switch failed\n"); 2237dbe63bcSTom Rini #endif 2247dbe63bcSTom Rini hang(); 2257dbe63bcSTom Rini } 22691199f4aSPaul Kocialkowski 2277dbe63bcSTom Rini #ifdef CONFIG_SPL_OS_BOOT 22891199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 22991199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 23091199f4aSPaul Kocialkowski if (!err) 23191199f4aSPaul Kocialkowski return; 23291199f4aSPaul Kocialkowski } 2337dbe63bcSTom Rini #endif 2343ae8f4c8SPaul Kocialkowski #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) 235ecb30139SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 236ecb30139SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 23791199f4aSPaul Kocialkowski if (!err) 23891199f4aSPaul Kocialkowski return; 2393ae8f4c8SPaul Kocialkowski #elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 2403ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 2413ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 2423ae8f4c8SPaul Kocialkowski if (!err) 2433ae8f4c8SPaul Kocialkowski return; 2443ae8f4c8SPaul Kocialkowski #endif 245*fd61d399SNikita Kiryanov break; 2467dbe63bcSTom Rini #endif 2472c84c9a4SGuillaume GARDET case MMCSD_MODE_UNDEFINED: 2488112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 249*fd61d399SNikita Kiryanov default: 25091199f4aSPaul Kocialkowski puts("spl: mmc: wrong boot mode\n"); 2518112f5faSPaul Burton #endif 252ade8a1a6SYing Zhang } 253*fd61d399SNikita Kiryanov 254*fd61d399SNikita Kiryanov hang(); 255ade8a1a6SYing Zhang } 256