/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "emmc_config.h" #include "emmc_hal.h" #include "emmc_std.h" #include "emmc_registers.h" #include "emmc_def.h" #define MIN_EMMC(a, b) (((a) < (b)) ? (a) : (b)) #define EMMC_RW_SECTOR_COUNT_MAX 0x0000ffffU static EMMC_ERROR_CODE emmc_multiple_block_read (uint32_t *buff_address_virtual, uint32_t sector_number, uint32_t count, HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode) { EMMC_ERROR_CODE result; /* parameter check */ if ((count > EMMC_RW_SECTOR_COUNT_MAX) || (count == 0) || ((transfer_mode != HAL_MEMCARD_DMA) && (transfer_mode != HAL_MEMCARD_NOT_DMA)) ) { emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_PARAM); return EMMC_ERR_PARAM; } /* CMD23 */ emmc_make_nontrans_cmd(CMD23_SET_BLOCK_COUNT, count); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { return result; } SETR_32(SD_SECCNT, count); SETR_32(SD_STOP, 0x00000100); SETR_32(CC_EXT_MODE, (CC_EXT_MODE_CLEAR | CC_EXT_MODE_DMASDRW_ENABLE)); /* SD_BUF Read/Write DMA Transfer enable */ /* CMD18 */ emmc_make_trans_cmd(CMD18_READ_MULTIPLE_BLOCK, sector_number, buff_address_virtual, count << EMMC_SECTOR_SIZE_SHIFT, HAL_MEMCARD_READ, transfer_mode); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { return result; /* CMD18 error code */ } /* CMD13 */ emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { return result; } #if RCAR_BL2_DCACHE == 1 if (transfer_mode == HAL_MEMCARD_NOT_DMA) { flush_dcache_range((uint64_t) buff_address_virtual, ((size_t) count << EMMC_SECTOR_SIZE_SHIFT)); } #endif /* RCAR_BL2_DCACHE == 1 */ /* ready status check */ if ((mmc_drv_obj.r1_card_status & EMMC_R1_READY) == 0) { emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_CARD_BUSY); return EMMC_ERR_CARD_BUSY; } /* state check */ if (mmc_drv_obj.current_state != EMMC_R1_STATE_TRAN) { emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_CARD_STATE); return EMMC_ERR_CARD_STATE; } return EMMC_SUCCESS; } EMMC_ERROR_CODE emmc_read_sector(uint32_t *buff_address_virtual, uint32_t sector_number, uint32_t count, uint32_t feature_flags) { uint32_t trans_count; uint32_t remain; EMMC_ERROR_CODE result; HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode; /* parameter check */ if (count == 0) { emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_PARAM); return EMMC_ERR_PARAM; } /* state check */ if (mmc_drv_obj.mount != TRUE) { emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_STATE); return EMMC_ERR_STATE; } /* DMA? */ if ((feature_flags & LOADIMAGE_FLAGS_DMA_ENABLE) != 0) { transfer_mode = HAL_MEMCARD_DMA; } else { transfer_mode = HAL_MEMCARD_NOT_DMA; } remain = count; while (remain != 0) { trans_count = MIN_EMMC(remain, EMMC_RW_SECTOR_COUNT_MAX); result = emmc_multiple_block_read(buff_address_virtual, sector_number, trans_count, transfer_mode); if (result != EMMC_SUCCESS) { return result; } buff_address_virtual += (EMMC_BLOCK_LENGTH_DW * trans_count); sector_number += trans_count; remain -= trans_count; } return EMMC_SUCCESS; }