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> 144188ba32SNikita Kiryanov #include <errno.h> 15ade8a1a6SYing Zhang #include <mmc.h> 16e4c444b3STom Rini #include <image.h> 17ade8a1a6SYing Zhang 18ade8a1a6SYing Zhang DECLARE_GLOBAL_DATA_PTR; 19ade8a1a6SYing Zhang 20b97300b6SPaul Kocialkowski static int mmc_load_image_raw_sector(struct mmc *mmc, unsigned long sector) 21ade8a1a6SYing Zhang { 223bc37b6dSPaul Kocialkowski unsigned long count; 23ade8a1a6SYing Zhang u32 image_size_sectors; 24ade8a1a6SYing Zhang struct image_header *header; 25ade8a1a6SYing Zhang 26ade8a1a6SYing Zhang header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - 27ade8a1a6SYing Zhang sizeof(struct image_header)); 28ade8a1a6SYing Zhang 29ade8a1a6SYing Zhang /* read image header to find the image size & load address */ 303bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, sector, 1, header); 31fdfa39d3SSimon Glass debug("read sector %lx, count=%lu\n", sector, count); 323bc37b6dSPaul Kocialkowski if (count == 0) 33ade8a1a6SYing Zhang goto end; 34ade8a1a6SYing Zhang 35fdfa39d3SSimon Glass if (image_get_magic(header) != IH_MAGIC) { 36fdfa39d3SSimon Glass puts("bad magic\n"); 37e4c444b3STom Rini return -1; 38fdfa39d3SSimon Glass } 39e4c444b3STom Rini 40ade8a1a6SYing Zhang spl_parse_image_header(header); 41ade8a1a6SYing Zhang 42ade8a1a6SYing Zhang /* convert size to sectors - round up */ 43ade8a1a6SYing Zhang image_size_sectors = (spl_image.size + mmc->read_bl_len - 1) / 44ade8a1a6SYing Zhang mmc->read_bl_len; 45ade8a1a6SYing Zhang 46ade8a1a6SYing Zhang /* Read the header too to avoid extra memcpy */ 473bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, sector, image_size_sectors, 487ef4c45cSGong Qianyu (void *)(ulong)spl_image.load_addr); 49fdfa39d3SSimon Glass debug("read %x sectors to %x\n", image_size_sectors, 50fdfa39d3SSimon Glass spl_image.load_addr); 51ade8a1a6SYing Zhang 52ade8a1a6SYing Zhang end: 531ec26469SPaul Kocialkowski if (count == 0) { 548112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 551ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 568112f5faSPaul Burton #endif 573bc37b6dSPaul Kocialkowski return -1; 581ec26469SPaul Kocialkowski } 593bc37b6dSPaul Kocialkowski 603bc37b6dSPaul Kocialkowski return 0; 61ade8a1a6SYing Zhang } 62ade8a1a6SYing Zhang 634188ba32SNikita Kiryanov #ifdef CONFIG_DM_MMC 644188ba32SNikita Kiryanov static int spl_mmc_find_device(struct mmc **mmc) 654188ba32SNikita Kiryanov { 664188ba32SNikita Kiryanov struct udevice *dev; 674188ba32SNikita Kiryanov int err; 684188ba32SNikita Kiryanov 694188ba32SNikita Kiryanov err = mmc_initialize(NULL); 704188ba32SNikita Kiryanov if (err) { 714188ba32SNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 724188ba32SNikita Kiryanov printf("spl: could not initialize mmc. error: %d\n", err); 734188ba32SNikita Kiryanov #endif 744188ba32SNikita Kiryanov return err; 754188ba32SNikita Kiryanov } 764188ba32SNikita Kiryanov 774188ba32SNikita Kiryanov err = uclass_get_device(UCLASS_MMC, 0, &dev); 784188ba32SNikita Kiryanov if (err) { 794188ba32SNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 804188ba32SNikita Kiryanov printf("spl: could not find mmc device. error: %d\n", err); 814188ba32SNikita Kiryanov #endif 824188ba32SNikita Kiryanov return err; 834188ba32SNikita Kiryanov } 844188ba32SNikita Kiryanov 854188ba32SNikita Kiryanov *mmc = NULL; 864188ba32SNikita Kiryanov *mmc = mmc_get_mmc_dev(dev); 874188ba32SNikita Kiryanov return *mmc != NULL ? 0 : -ENODEV; 884188ba32SNikita Kiryanov } 894188ba32SNikita Kiryanov #else 904188ba32SNikita Kiryanov static int spl_mmc_find_device(struct mmc **mmc) 914188ba32SNikita Kiryanov { 924188ba32SNikita Kiryanov int err; 934188ba32SNikita Kiryanov 944188ba32SNikita Kiryanov err = mmc_initialize(gd->bd); 954188ba32SNikita Kiryanov if (err) { 964188ba32SNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 974188ba32SNikita Kiryanov printf("spl: could not initialize mmc. error: %d\n", err); 984188ba32SNikita Kiryanov #endif 994188ba32SNikita Kiryanov return err; 1004188ba32SNikita Kiryanov } 1014188ba32SNikita Kiryanov 1024188ba32SNikita Kiryanov /* We register only one device. So, the dev id is always 0 */ 1034188ba32SNikita Kiryanov *mmc = find_mmc_device(0); 1044188ba32SNikita Kiryanov if (!*mmc) { 1054188ba32SNikita Kiryanov #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 1064188ba32SNikita Kiryanov puts("spl: mmc device not found\n"); 1074188ba32SNikita Kiryanov #endif 1084188ba32SNikita Kiryanov return -ENODEV; 1094188ba32SNikita Kiryanov } 1104188ba32SNikita Kiryanov 1114188ba32SNikita Kiryanov return 0; 1124188ba32SNikita Kiryanov } 1134188ba32SNikita Kiryanov #endif 1144188ba32SNikita Kiryanov 115b97300b6SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 116b97300b6SPaul Kocialkowski static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) 117b97300b6SPaul Kocialkowski { 118b97300b6SPaul Kocialkowski disk_partition_t info; 1193bc37b6dSPaul Kocialkowski int err; 120b97300b6SPaul Kocialkowski 1213bc37b6dSPaul Kocialkowski err = get_partition_info(&mmc->block_dev, partition, &info); 1223bc37b6dSPaul Kocialkowski if (err) { 123b97300b6SPaul Kocialkowski #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 1241ec26469SPaul Kocialkowski puts("spl: partition error\n"); 125b97300b6SPaul Kocialkowski #endif 126b97300b6SPaul Kocialkowski return -1; 127b97300b6SPaul Kocialkowski } 128b97300b6SPaul Kocialkowski 1294bfcc54cSStefan Roese #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 1304bfcc54cSStefan Roese return mmc_load_image_raw_sector(mmc, info.start + 1314bfcc54cSStefan Roese CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 1324bfcc54cSStefan Roese #else 133b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, info.start); 1344bfcc54cSStefan Roese #endif 135b97300b6SPaul Kocialkowski } 136b97300b6SPaul Kocialkowski #endif 137b97300b6SPaul Kocialkowski 1382b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 1392b75b0adSPeter Korsgaard static int mmc_load_image_raw_os(struct mmc *mmc) 1402b75b0adSPeter Korsgaard { 1413bc37b6dSPaul Kocialkowski unsigned long count; 14291199f4aSPaul Kocialkowski 1433bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, 1442b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, 1452b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, 14691199f4aSPaul Kocialkowski (void *) CONFIG_SYS_SPL_ARGS_ADDR); 1473bc37b6dSPaul Kocialkowski if (count == 0) { 1488112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 1491ec26469SPaul Kocialkowski puts("spl: mmc block read error\n"); 1508112f5faSPaul Burton #endif 1512b75b0adSPeter Korsgaard return -1; 1522b75b0adSPeter Korsgaard } 1532b75b0adSPeter Korsgaard 154b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, 155b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); 1562b75b0adSPeter Korsgaard } 157*339245b7SNikita Kiryanov #else 158*339245b7SNikita Kiryanov int spl_start_uboot(void) 159*339245b7SNikita Kiryanov { 160*339245b7SNikita Kiryanov return 1; 161*339245b7SNikita Kiryanov } 162*339245b7SNikita Kiryanov static int mmc_load_image_raw_os(struct mmc *mmc) 163*339245b7SNikita Kiryanov { 164*339245b7SNikita Kiryanov return -ENOSYS; 165*339245b7SNikita Kiryanov } 1662b75b0adSPeter Korsgaard #endif 1672b75b0adSPeter Korsgaard 168ade8a1a6SYing Zhang void spl_mmc_load_image(void) 169ade8a1a6SYing Zhang { 170ade8a1a6SYing Zhang struct mmc *mmc; 171ade8a1a6SYing Zhang u32 boot_mode; 172dc3dedfeSSimon Glass int err = 0; 17391199f4aSPaul Kocialkowski __maybe_unused int part; 174ade8a1a6SYing Zhang 1754188ba32SNikita Kiryanov if (spl_mmc_find_device(&mmc)) 176ade8a1a6SYing Zhang hang(); 177ade8a1a6SYing Zhang 178ade8a1a6SYing Zhang err = mmc_init(mmc); 179ade8a1a6SYing Zhang if (err) { 1808112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 18191199f4aSPaul Kocialkowski printf("spl: mmc init failed with error: %d\n", err); 1828112f5faSPaul Burton #endif 183ade8a1a6SYing Zhang hang(); 184ade8a1a6SYing Zhang } 18579adb7a2SPeter Korsgaard 186ade8a1a6SYing Zhang boot_mode = spl_boot_mode(); 18791199f4aSPaul Kocialkowski switch (boot_mode) { 18891199f4aSPaul Kocialkowski case MMCSD_MODE_RAW: 18991199f4aSPaul Kocialkowski debug("spl: mmc boot mode: raw\n"); 19091199f4aSPaul Kocialkowski 19191199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 19291199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 19391199f4aSPaul Kocialkowski if (!err) 19491199f4aSPaul Kocialkowski return; 19591199f4aSPaul Kocialkowski } 1963ae8f4c8SPaul Kocialkowski #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) 197b97300b6SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 198b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 19991199f4aSPaul Kocialkowski if (!err) 20091199f4aSPaul Kocialkowski return; 2013ae8f4c8SPaul Kocialkowski #elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 2023ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 2033ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 2043ae8f4c8SPaul Kocialkowski if (!err) 2053ae8f4c8SPaul Kocialkowski return; 2063ae8f4c8SPaul Kocialkowski #endif 207fd61d399SNikita Kiryanov break; 20891199f4aSPaul Kocialkowski case MMCSD_MODE_FS: 20991199f4aSPaul Kocialkowski debug("spl: mmc boot mode: fs\n"); 21091199f4aSPaul Kocialkowski 2113ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 212592f9222SGuillaume GARDET #ifdef CONFIG_SPL_FAT_SUPPORT 21391199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 21491199f4aSPaul Kocialkowski err = spl_load_image_fat_os(&mmc->block_dev, 21591199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 21691199f4aSPaul Kocialkowski if (!err) 21791199f4aSPaul Kocialkowski return; 21891199f4aSPaul Kocialkowski } 2193ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 220773b5940SDan Murphy err = spl_load_image_fat(&mmc->block_dev, 221e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 222205b4f33SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 22391199f4aSPaul Kocialkowski if (!err) 22491199f4aSPaul Kocialkowski return; 22591199f4aSPaul Kocialkowski #endif 2263ae8f4c8SPaul Kocialkowski #endif 227592f9222SGuillaume GARDET #ifdef CONFIG_SPL_EXT_SUPPORT 22891199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 22991199f4aSPaul Kocialkowski err = spl_load_image_ext_os(&mmc->block_dev, 23091199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 23191199f4aSPaul Kocialkowski if (!err) 23291199f4aSPaul Kocialkowski return; 23391199f4aSPaul Kocialkowski } 2343ae8f4c8SPaul Kocialkowski #ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME 235592f9222SGuillaume GARDET err = spl_load_image_ext(&mmc->block_dev, 236e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 237592f9222SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 23891199f4aSPaul Kocialkowski if (!err) 23991199f4aSPaul Kocialkowski return; 24091199f4aSPaul Kocialkowski #endif 24191199f4aSPaul Kocialkowski #endif 2423ae8f4c8SPaul Kocialkowski #endif 243fd61d399SNikita Kiryanov break; 2447dbe63bcSTom Rini #ifdef CONFIG_SUPPORT_EMMC_BOOT 24591199f4aSPaul Kocialkowski case MMCSD_MODE_EMMCBOOT: 2467dbe63bcSTom Rini /* 2477dbe63bcSTom Rini * We need to check what the partition is configured to. 2487dbe63bcSTom Rini * 1 and 2 match up to boot0 / boot1 and 7 is user data 2497dbe63bcSTom Rini * which is the first physical partition (0). 2507dbe63bcSTom Rini */ 25191199f4aSPaul Kocialkowski part = (mmc->part_config >> 3) & PART_ACCESS_MASK; 2527dbe63bcSTom Rini 2537dbe63bcSTom Rini if (part == 7) 2547dbe63bcSTom Rini part = 0; 2557dbe63bcSTom Rini 2567dbe63bcSTom Rini if (mmc_switch_part(0, part)) { 2577dbe63bcSTom Rini #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 25891199f4aSPaul Kocialkowski puts("spl: mmc partition switch failed\n"); 2597dbe63bcSTom Rini #endif 2607dbe63bcSTom Rini hang(); 2617dbe63bcSTom Rini } 26291199f4aSPaul Kocialkowski 26391199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 26491199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 26591199f4aSPaul Kocialkowski if (!err) 26691199f4aSPaul Kocialkowski return; 26791199f4aSPaul Kocialkowski } 2683ae8f4c8SPaul Kocialkowski #if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) 269ecb30139SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 270ecb30139SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 27191199f4aSPaul Kocialkowski if (!err) 27291199f4aSPaul Kocialkowski return; 2733ae8f4c8SPaul Kocialkowski #elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR) 2743ae8f4c8SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 2753ae8f4c8SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 2763ae8f4c8SPaul Kocialkowski if (!err) 2773ae8f4c8SPaul Kocialkowski return; 2783ae8f4c8SPaul Kocialkowski #endif 279fd61d399SNikita Kiryanov break; 2807dbe63bcSTom Rini #endif 2812c84c9a4SGuillaume GARDET case MMCSD_MODE_UNDEFINED: 2828112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 283fd61d399SNikita Kiryanov default: 28491199f4aSPaul Kocialkowski puts("spl: mmc: wrong boot mode\n"); 2858112f5faSPaul Burton #endif 286ade8a1a6SYing Zhang } 287fd61d399SNikita Kiryanov 288fd61d399SNikita Kiryanov hang(); 289ade8a1a6SYing Zhang } 290