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 { 20*3bc37b6dSPaul 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 */ 28*3bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, sector, 1, header); 29*3bc37b6dSPaul 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 */ 42*3bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, sector, image_size_sectors, 43721931f8SPeter Korsgaard (void *) spl_image.load_addr); 44ade8a1a6SYing Zhang 45ade8a1a6SYing Zhang end: 468112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 47*3bc37b6dSPaul Kocialkowski if (count == 0) 4891199f4aSPaul Kocialkowski printf("spl: mmc block read error\n"); 498112f5faSPaul Burton #endif 5079adb7a2SPeter Korsgaard 51*3bc37b6dSPaul Kocialkowski if (count == 0) 52*3bc37b6dSPaul Kocialkowski return -1; 53*3bc37b6dSPaul Kocialkowski 54*3bc37b6dSPaul Kocialkowski return 0; 55ade8a1a6SYing Zhang } 56ade8a1a6SYing Zhang 57b97300b6SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 58b97300b6SPaul Kocialkowski static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) 59b97300b6SPaul Kocialkowski { 60b97300b6SPaul Kocialkowski disk_partition_t info; 61*3bc37b6dSPaul Kocialkowski int err; 62b97300b6SPaul Kocialkowski 63*3bc37b6dSPaul Kocialkowski err = get_partition_info(&mmc->block_dev, partition, &info); 64*3bc37b6dSPaul Kocialkowski if (err) { 65b97300b6SPaul Kocialkowski #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 66b97300b6SPaul Kocialkowski printf("spl: partition error\n"); 67b97300b6SPaul Kocialkowski #endif 68b97300b6SPaul Kocialkowski return -1; 69b97300b6SPaul Kocialkowski } 70b97300b6SPaul Kocialkowski 71b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, info.start); 72b97300b6SPaul Kocialkowski } 73b97300b6SPaul Kocialkowski #endif 74b97300b6SPaul Kocialkowski 752b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 762b75b0adSPeter Korsgaard static int mmc_load_image_raw_os(struct mmc *mmc) 772b75b0adSPeter Korsgaard { 78*3bc37b6dSPaul Kocialkowski unsigned long count; 7991199f4aSPaul Kocialkowski 80*3bc37b6dSPaul Kocialkowski count = mmc->block_dev.block_read(0, 812b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, 822b75b0adSPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, 8391199f4aSPaul Kocialkowski (void *) CONFIG_SYS_SPL_ARGS_ADDR); 84*3bc37b6dSPaul Kocialkowski if (count == 0) { 858112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 8691199f4aSPaul Kocialkowski printf("spl: mmc block read error\n"); 878112f5faSPaul Burton #endif 882b75b0adSPeter Korsgaard return -1; 892b75b0adSPeter Korsgaard } 902b75b0adSPeter Korsgaard 91b97300b6SPaul Kocialkowski return mmc_load_image_raw_sector(mmc, 92b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); 932b75b0adSPeter Korsgaard } 942b75b0adSPeter Korsgaard #endif 952b75b0adSPeter Korsgaard 96ade8a1a6SYing Zhang void spl_mmc_load_image(void) 97ade8a1a6SYing Zhang { 98ade8a1a6SYing Zhang struct mmc *mmc; 99ade8a1a6SYing Zhang u32 boot_mode; 10091199f4aSPaul Kocialkowski int err; 10191199f4aSPaul Kocialkowski __maybe_unused int part; 102ade8a1a6SYing Zhang 103ade8a1a6SYing Zhang mmc_initialize(gd->bd); 10491199f4aSPaul Kocialkowski 105ade8a1a6SYing Zhang /* We register only one device. So, the dev id is always 0 */ 106ade8a1a6SYing Zhang mmc = find_mmc_device(0); 107ade8a1a6SYing Zhang if (!mmc) { 1088112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 10991199f4aSPaul Kocialkowski puts("spl: mmc device not found\n"); 1108112f5faSPaul Burton #endif 111ade8a1a6SYing Zhang hang(); 112ade8a1a6SYing Zhang } 113ade8a1a6SYing Zhang 114ade8a1a6SYing Zhang err = mmc_init(mmc); 115ade8a1a6SYing Zhang if (err) { 1168112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 11791199f4aSPaul Kocialkowski printf("spl: mmc init failed with error: %d\n", err); 1188112f5faSPaul Burton #endif 119ade8a1a6SYing Zhang hang(); 120ade8a1a6SYing Zhang } 12179adb7a2SPeter Korsgaard 122ade8a1a6SYing Zhang boot_mode = spl_boot_mode(); 12391199f4aSPaul Kocialkowski switch (boot_mode) { 12491199f4aSPaul Kocialkowski case MMCSD_MODE_RAW: 12591199f4aSPaul Kocialkowski debug("spl: mmc boot mode: raw\n"); 12691199f4aSPaul Kocialkowski 1272b75b0adSPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 12891199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 12991199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 13091199f4aSPaul Kocialkowski if (!err) 13191199f4aSPaul Kocialkowski return; 13291199f4aSPaul Kocialkowski } 1332b75b0adSPeter Korsgaard #endif 134b97300b6SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 135b97300b6SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 136b97300b6SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 137b97300b6SPaul Kocialkowski #else 138b97300b6SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 139721931f8SPeter Korsgaard CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 140b97300b6SPaul Kocialkowski #endif 14191199f4aSPaul Kocialkowski if (!err) 14291199f4aSPaul Kocialkowski return; 143592f9222SGuillaume GARDET #if defined(CONFIG_SPL_FAT_SUPPORT) || defined(CONFIG_SPL_EXT_SUPPORT) 14491199f4aSPaul Kocialkowski case MMCSD_MODE_FS: 14591199f4aSPaul Kocialkowski debug("spl: mmc boot mode: fs\n"); 14691199f4aSPaul Kocialkowski 147592f9222SGuillaume GARDET #ifdef CONFIG_SPL_FAT_SUPPORT 1487ad2cc79SPeter Korsgaard #ifdef CONFIG_SPL_OS_BOOT 14991199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 15091199f4aSPaul Kocialkowski err = spl_load_image_fat_os(&mmc->block_dev, 15191199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 15291199f4aSPaul Kocialkowski if (!err) 15391199f4aSPaul Kocialkowski return; 15491199f4aSPaul Kocialkowski } 1557ad2cc79SPeter Korsgaard #endif 156773b5940SDan Murphy err = spl_load_image_fat(&mmc->block_dev, 157e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 158205b4f33SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 15991199f4aSPaul Kocialkowski if (!err) 16091199f4aSPaul Kocialkowski return; 16191199f4aSPaul Kocialkowski #endif 162592f9222SGuillaume GARDET #ifdef CONFIG_SPL_EXT_SUPPORT 163592f9222SGuillaume GARDET #ifdef CONFIG_SPL_OS_BOOT 16491199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 16591199f4aSPaul Kocialkowski err = spl_load_image_ext_os(&mmc->block_dev, 16691199f4aSPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION); 16791199f4aSPaul Kocialkowski if (!err) 16891199f4aSPaul Kocialkowski return; 16991199f4aSPaul Kocialkowski } 170ade8a1a6SYing Zhang #endif 171592f9222SGuillaume GARDET err = spl_load_image_ext(&mmc->block_dev, 172e2ccdf89SPaul Kocialkowski CONFIG_SYS_MMCSD_FS_BOOT_PARTITION, 173592f9222SGuillaume GARDET CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); 17491199f4aSPaul Kocialkowski if (!err) 17591199f4aSPaul Kocialkowski return; 17691199f4aSPaul Kocialkowski #endif 17791199f4aSPaul Kocialkowski #endif 1787dbe63bcSTom Rini #ifdef CONFIG_SUPPORT_EMMC_BOOT 17991199f4aSPaul Kocialkowski case MMCSD_MODE_EMMCBOOT: 1807dbe63bcSTom Rini /* 1817dbe63bcSTom Rini * We need to check what the partition is configured to. 1827dbe63bcSTom Rini * 1 and 2 match up to boot0 / boot1 and 7 is user data 1837dbe63bcSTom Rini * which is the first physical partition (0). 1847dbe63bcSTom Rini */ 18591199f4aSPaul Kocialkowski part = (mmc->part_config >> 3) & PART_ACCESS_MASK; 1867dbe63bcSTom Rini 1877dbe63bcSTom Rini if (part == 7) 1887dbe63bcSTom Rini part = 0; 1897dbe63bcSTom Rini 1907dbe63bcSTom Rini if (mmc_switch_part(0, part)) { 1917dbe63bcSTom Rini #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 19291199f4aSPaul Kocialkowski puts("spl: mmc partition switch failed\n"); 1937dbe63bcSTom Rini #endif 1947dbe63bcSTom Rini hang(); 1957dbe63bcSTom Rini } 19691199f4aSPaul Kocialkowski 1977dbe63bcSTom Rini #ifdef CONFIG_SPL_OS_BOOT 19891199f4aSPaul Kocialkowski if (!spl_start_uboot()) { 19991199f4aSPaul Kocialkowski err = mmc_load_image_raw_os(mmc); 20091199f4aSPaul Kocialkowski if (!err) 20191199f4aSPaul Kocialkowski return; 20291199f4aSPaul Kocialkowski } 2037dbe63bcSTom Rini #endif 204ecb30139SPaul Kocialkowski #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 205ecb30139SPaul Kocialkowski err = mmc_load_image_raw_partition(mmc, 206ecb30139SPaul Kocialkowski CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION); 207ecb30139SPaul Kocialkowski #else 208b97300b6SPaul Kocialkowski err = mmc_load_image_raw_sector(mmc, 2097dbe63bcSTom Rini CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); 210ecb30139SPaul Kocialkowski #endif 21191199f4aSPaul Kocialkowski if (!err) 21291199f4aSPaul Kocialkowski return; 2137dbe63bcSTom Rini #endif 2142c84c9a4SGuillaume GARDET case MMCSD_MODE_UNDEFINED: 2152c84c9a4SGuillaume GARDET default: 2168112f5faSPaul Burton #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 21791199f4aSPaul Kocialkowski if (err) 21891199f4aSPaul Kocialkowski puts("spl: mmc: no boot mode left to try\n"); 21991199f4aSPaul Kocialkowski else 22091199f4aSPaul Kocialkowski puts("spl: mmc: wrong boot mode\n"); 2218112f5faSPaul Burton #endif 222ade8a1a6SYing Zhang hang(); 223ade8a1a6SYing Zhang } 224ade8a1a6SYing Zhang } 225