/* 
 | 
 * Copyright 2013 Freescale Semiconductor, Inc. 
 | 
 * 
 | 
 * SPDX-License-Identifier:    GPL-2.0+ 
 | 
 */ 
 | 
  
 | 
#include <common.h> 
 | 
#include <mmc.h> 
 | 
#include <malloc.h> 
 | 
  
 | 
/* 
 | 
 * The environment variables are written to just after the u-boot image 
 | 
 * on SDCard, so we must read the MBR to get the start address and code 
 | 
 * length of the u-boot image, then calculate the address of the env. 
 | 
 */ 
 | 
#define ESDHC_BOOT_IMAGE_SIZE    0x48 
 | 
#define ESDHC_BOOT_IMAGE_ADDR    0x50 
 | 
#define MBRDBR_BOOT_SIG_55    0x1fe 
 | 
#define MBRDBR_BOOT_SIG_AA    0x1ff 
 | 
#define CONFIG_CFG_DATA_SECTOR    0 
 | 
  
 | 
  
 | 
void mmc_spl_load_image(uint32_t offs, unsigned int size, void *vdst) 
 | 
{ 
 | 
    uint blk_start, blk_cnt, err; 
 | 
  
 | 
    struct mmc *mmc = find_mmc_device(0); 
 | 
    if (!mmc) { 
 | 
        puts("spl: mmc device not found!!\n"); 
 | 
        hang(); 
 | 
    } 
 | 
  
 | 
    if (mmc_init(mmc)) { 
 | 
        puts("MMC init failed\n"); 
 | 
        return; 
 | 
    } 
 | 
  
 | 
    blk_start = ALIGN(offs, mmc->read_bl_len) / mmc->read_bl_len; 
 | 
    blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len; 
 | 
  
 | 
    err = mmc->block_dev.block_read(&mmc->block_dev, blk_start, blk_cnt, 
 | 
                    vdst); 
 | 
    if (err != blk_cnt) { 
 | 
        puts("spl: mmc read failed!!\n"); 
 | 
        hang(); 
 | 
    } 
 | 
} 
 | 
  
 | 
/* 
 | 
 * The main entry for mmc booting. It's necessary that SDRAM is already 
 | 
 * configured and available since this code loads the main U-Boot image 
 | 
 * from mmc into SDRAM and starts it from there. 
 | 
 */ 
 | 
  
 | 
void __noreturn mmc_boot(void) 
 | 
{ 
 | 
    __attribute__((noreturn)) void (*uboot)(void); 
 | 
    uint blk_start, blk_cnt, err; 
 | 
#ifndef CONFIG_FSL_CORENET 
 | 
    uchar *tmp_buf; 
 | 
    u32 blklen; 
 | 
    uchar val; 
 | 
    uint i, byte_num; 
 | 
#endif 
 | 
    u32 offset, code_len; 
 | 
    struct mmc *mmc; 
 | 
  
 | 
    mmc = find_mmc_device(0); 
 | 
    if (!mmc) { 
 | 
        puts("spl: mmc device not found!!\n"); 
 | 
        hang(); 
 | 
    } 
 | 
  
 | 
#ifdef CONFIG_FSL_CORENET 
 | 
    offset = CONFIG_SYS_MMC_U_BOOT_OFFS; 
 | 
    code_len = CONFIG_SYS_MMC_U_BOOT_SIZE; 
 | 
#else 
 | 
    blklen = mmc->read_bl_len; 
 | 
    tmp_buf = malloc(blklen); 
 | 
    if (!tmp_buf) { 
 | 
        puts("spl: malloc memory failed!!\n"); 
 | 
        hang(); 
 | 
    } 
 | 
    memset(tmp_buf, 0, blklen); 
 | 
  
 | 
    /* 
 | 
    * Read source addr from sd card 
 | 
    */ 
 | 
    err = mmc->block_dev.block_read(&mmc->block_dev, 
 | 
                    CONFIG_CFG_DATA_SECTOR, 1, tmp_buf); 
 | 
    if (err != 1) { 
 | 
        puts("spl: mmc read failed!!\n"); 
 | 
        free(tmp_buf); 
 | 
        hang(); 
 | 
    } 
 | 
  
 | 
    val = *(tmp_buf + MBRDBR_BOOT_SIG_55); 
 | 
    if (0x55 != val) { 
 | 
        puts("spl: mmc signature is not valid!!\n"); 
 | 
        free(tmp_buf); 
 | 
        hang(); 
 | 
    } 
 | 
    val = *(tmp_buf + MBRDBR_BOOT_SIG_AA); 
 | 
    if (0xAA != val) { 
 | 
        puts("spl: mmc signature is not valid!!\n"); 
 | 
        free(tmp_buf); 
 | 
        hang(); 
 | 
    } 
 | 
  
 | 
    byte_num = 4; 
 | 
    offset = 0; 
 | 
    for (i = 0; i < byte_num; i++) { 
 | 
        val = *(tmp_buf + ESDHC_BOOT_IMAGE_ADDR + i); 
 | 
        offset = (offset << 8) + val; 
 | 
    } 
 | 
    offset += CONFIG_SYS_MMC_U_BOOT_OFFS; 
 | 
    /* Get the code size from offset 0x48 */ 
 | 
    byte_num = 4; 
 | 
    code_len = 0; 
 | 
    for (i = 0; i < byte_num; i++) { 
 | 
        val = *(tmp_buf + ESDHC_BOOT_IMAGE_SIZE + i); 
 | 
        code_len = (code_len << 8) + val; 
 | 
    } 
 | 
    code_len -= CONFIG_SYS_MMC_U_BOOT_OFFS; 
 | 
    /* 
 | 
    * Load U-Boot image from mmc into RAM 
 | 
    */ 
 | 
#endif 
 | 
    blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len; 
 | 
    blk_cnt = ALIGN(code_len, mmc->read_bl_len) / mmc->read_bl_len; 
 | 
    err = mmc->block_dev.block_read(&mmc->block_dev, blk_start, blk_cnt, 
 | 
                    (uchar *)CONFIG_SYS_MMC_U_BOOT_DST); 
 | 
    if (err != blk_cnt) { 
 | 
        puts("spl: mmc read failed!!\n"); 
 | 
#ifndef CONFIG_FSL_CORENET 
 | 
        free(tmp_buf); 
 | 
#endif 
 | 
        hang(); 
 | 
    } 
 | 
  
 | 
    /* 
 | 
    * Clean d-cache and invalidate i-cache, to 
 | 
    * make sure that no stale data is executed. 
 | 
    */ 
 | 
    flush_cache(CONFIG_SYS_MMC_U_BOOT_DST, CONFIG_SYS_MMC_U_BOOT_SIZE); 
 | 
  
 | 
    /* 
 | 
    * Jump to U-Boot image 
 | 
    */ 
 | 
    uboot = (void *)CONFIG_SYS_MMC_U_BOOT_START; 
 | 
    (*uboot)(); 
 | 
} 
 |