rcar_gen3: drivers: emmc

Signed-off-by: ldts <jramirez@baylibre.com>
diff --git a/drivers/renesas/rcar/emmc/emmc_mount.c b/drivers/renesas/rcar/emmc/emmc_mount.c
new file mode 100644
index 0000000..9a7d2ca
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_mount.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <mmio.h>
+#include "emmc_config.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+#include "emmc_registers.h"
+#include "emmc_def.h"
+#include "micro_delay.h"
+#include "rcar_def.h"
+
+static EMMC_ERROR_CODE emmc_clock_ctrl(uint8_t mode);
+static EMMC_ERROR_CODE emmc_card_init(void);
+static EMMC_ERROR_CODE emmc_high_speed(void);
+static EMMC_ERROR_CODE emmc_bus_width(uint32_t width);
+static uint32_t emmc_set_timeout_register_value(uint32_t freq);
+static void set_sd_clk(uint32_t clkDiv);
+static uint32_t emmc_calc_tran_speed(uint32_t *freq);
+static void emmc_get_partition_access(void);
+static void emmc_set_bootpartition(void);
+
+static void emmc_set_bootpartition(void)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(RCAR_PRR) & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+	if (reg == RCAR_PRODUCT_M3_CUT10) {
+		mmc_drv_obj.boot_partition_en =
+		    (EMMC_PARTITION_ID) ((mmc_drv_obj.ext_csd_data[179] &
+					  EMMC_BOOT_PARTITION_EN_MASK) >>
+					 EMMC_BOOT_PARTITION_EN_SHIFT);
+	} else if ((reg == RCAR_PRODUCT_H3_CUT20)
+		   || (reg == RCAR_PRODUCT_M3_CUT11)) {
+		mmc_drv_obj.boot_partition_en = mmc_drv_obj.partition_access;
+	} else {
+		if ((mmio_read_32(MFISBTSTSR) & MFISBTSTSR_BOOT_PARTITION) !=
+		    0U) {
+			mmc_drv_obj.boot_partition_en = PARTITION_ID_BOOT_2;
+		} else {
+			mmc_drv_obj.boot_partition_en = PARTITION_ID_BOOT_1;
+		}
+	}
+}
+
+static EMMC_ERROR_CODE emmc_card_init(void)
+{
+	int32_t retry;
+	uint32_t freq = MMC_400KHZ;	/* 390KHz */
+	EMMC_ERROR_CODE result;
+	uint32_t resultCalc;
+
+	/* state check */
+	if ((mmc_drv_obj.initialize != TRUE)
+	    || (mmc_drv_obj.card_power_enable != TRUE)
+	    || ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0)
+	    ) {
+		emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* clock on (force change) */
+	mmc_drv_obj.current_freq = 0;
+	mmc_drv_obj.max_freq = MMC_20MHZ;
+	result = emmc_set_request_mmc_clock(&freq);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return EMMC_ERR;
+	}
+
+	rcar_micro_delay(1000U);	/* wait 1ms */
+
+	/* Get current access partition */
+	emmc_get_partition_access();
+
+	/* CMD0, arg=0x00000000 */
+	result = emmc_send_idle_cmd(0x00000000);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	rcar_micro_delay(200U);	/* wait 74clock 390kHz(189.74us) */
+
+	/* CMD1 */
+	emmc_make_nontrans_cmd(CMD1_SEND_OP_COND, EMMC_HOST_OCR_VALUE);
+	for (retry = 300; retry > 0; retry--) {
+		result =
+		    emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+		if (result != EMMC_SUCCESS) {
+			emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+			return result;
+		}
+
+		if ((mmc_drv_obj.r3_ocr & EMMC_OCR_STATUS_BIT) != 0) {
+			break;	/* card is ready. exit loop */
+		}
+		rcar_micro_delay(1000U);	/* wait 1ms */
+	}
+
+	if (retry == 0) {
+		emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR_TIMEOUT);
+		return EMMC_ERR_TIMEOUT;
+	}
+
+	switch (mmc_drv_obj.r3_ocr & EMMC_OCR_ACCESS_MODE_MASK) {
+	case EMMC_OCR_ACCESS_MODE_SECT:
+		mmc_drv_obj.access_mode = TRUE;	/* sector mode */
+		break;
+	default:
+		/* unknown value */
+		emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR);
+		return EMMC_ERR;
+	}
+
+	/* CMD2 */
+	emmc_make_nontrans_cmd(CMD2_ALL_SEND_CID_MMC, 0x00000000);
+	mmc_drv_obj.response = (uint32_t *) (&mmc_drv_obj.cid_data[0]);	/* use CID special buffer */
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	/* CMD3 */
+	emmc_make_nontrans_cmd(CMD3_SET_RELATIVE_ADDR, EMMC_RCA << 16);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	/* CMD9 (CSD) */
+	emmc_make_nontrans_cmd(CMD9_SEND_CSD, EMMC_RCA << 16);
+	mmc_drv_obj.response = (uint32_t *) (&mmc_drv_obj.csd_data[0]);	/* use CSD special buffer */
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	/* card version check */
+	if (EMMC_CSD_SPEC_VARS() < 4) {
+		emmc_write_error_info(EMMC_FUNCNO_CARD_INIT,
+				      EMMC_ERR_ILLEGAL_CARD);
+		return EMMC_ERR_ILLEGAL_CARD;
+	}
+
+	/* CMD7 (select card) */
+	emmc_make_nontrans_cmd(CMD7_SELECT_CARD, EMMC_RCA << 16);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	mmc_drv_obj.selected = TRUE;
+
+	/* card speed check */
+	resultCalc = emmc_calc_tran_speed(&freq);	/* Card spec is calculated from TRAN_SPEED(CSD).  */
+	if (resultCalc == 0) {
+		emmc_write_error_info(EMMC_FUNCNO_CARD_INIT,
+				      EMMC_ERR_ILLEGAL_CARD);
+		return EMMC_ERR_ILLEGAL_CARD;
+	}
+	mmc_drv_obj.max_freq = freq;	/* max frequency (card spec) */
+
+	result = emmc_set_request_mmc_clock(&freq);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return EMMC_ERR;
+	}
+
+	/* set read/write timeout */
+	mmc_drv_obj.data_timeout = emmc_set_timeout_register_value(freq);
+	SETR_32(SD_OPTION,
+		((GETR_32(SD_OPTION) & ~(SD_OPTION_TIMEOUT_CNT_MASK)) |
+		 mmc_drv_obj.data_timeout));
+
+	/* SET_BLOCKLEN(512byte) */
+	/* CMD16 */
+	emmc_make_nontrans_cmd(CMD16_SET_BLOCKLEN, EMMC_BLOCK_LENGTH);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	/* Transfer Data Length */
+	SETR_32(SD_SIZE, EMMC_BLOCK_LENGTH);
+
+	/* CMD8 (EXT_CSD) */
+	emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000,
+			    (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
+			    EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ,
+			    HAL_MEMCARD_NOT_DMA);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		/* CMD12 is not send.
+		 * If BUS initialization is failed, user must be execute Bus initialization again.
+		 * Bus initialization is start CMD0(soft reset command).
+		 */
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	/* Set boot partition */
+	emmc_set_bootpartition();
+
+	return EMMC_SUCCESS;
+}
+
+static EMMC_ERROR_CODE emmc_high_speed(void)
+{
+	uint32_t freq;	      /**< High speed mode clock frequency */
+	EMMC_ERROR_CODE result;
+	uint8_t cardType;
+
+	/* state check */
+	if (mmc_drv_obj.selected != TRUE) {
+		emmc_write_error_info(EMMC_FUNCNO_HIGH_SPEED, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* max frequency */
+	cardType = (uint8_t) mmc_drv_obj.ext_csd_data[EMMC_EXT_CSD_CARD_TYPE];
+	if ((cardType & EMMC_EXT_CSD_CARD_TYPE_52MHZ) != 0)
+		freq = MMC_52MHZ;
+	else if ((cardType & EMMC_EXT_CSD_CARD_TYPE_26MHZ) != 0)
+		freq = MMC_26MHZ;
+	else
+		freq = MMC_20MHZ;
+
+	/* Hi-Speed-mode selction */
+	if ((MMC_52MHZ == freq) || (MMC_26MHZ == freq)) {
+		/* CMD6 */
+		emmc_make_nontrans_cmd(CMD6_SWITCH, EMMC_SWITCH_HS_TIMING);
+		result =
+		    emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+		if (result != EMMC_SUCCESS) {
+			emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
+			return result;
+		}
+
+		mmc_drv_obj.hs_timing = TIMING_HIGH_SPEED;	/* High-Speed */
+	}
+
+	/* set mmc clock */
+	mmc_drv_obj.max_freq = freq;
+	result = emmc_set_request_mmc_clock(&freq);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
+		return EMMC_ERR;
+	}
+
+	/* set read/write timeout */
+	mmc_drv_obj.data_timeout = emmc_set_timeout_register_value(freq);
+	SETR_32(SD_OPTION,
+		((GETR_32(SD_OPTION) & ~(SD_OPTION_TIMEOUT_CNT_MASK)) |
+		 mmc_drv_obj.data_timeout));
+
+	/* CMD13 */
+	emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16);
+	result =
+	    emmc_exec_cmd(EMMC_R1_ERROR_MASK_WITHOUT_CRC, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
+		return result;
+	}
+
+	return EMMC_SUCCESS;
+}
+
+static EMMC_ERROR_CODE emmc_clock_ctrl(uint8_t mode)
+{
+	uint32_t value;
+
+	/* busy check */
+	if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0) {
+		emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK,
+				      EMMC_ERR_CARD_BUSY);
+		return EMMC_ERR;
+	}
+
+	if (mode == TRUE) {
+		/* clock ON */
+		value =
+		    ((GETR_32(SD_CLK_CTRL) | MMC_SD_CLK_START) &
+		     SD_CLK_WRITE_MASK);
+		SETR_32(SD_CLK_CTRL, value);	/* on  */
+		mmc_drv_obj.clock_enable = TRUE;
+	} else {
+		/* clock OFF */
+		value =
+		    ((GETR_32(SD_CLK_CTRL) & MMC_SD_CLK_STOP) &
+		     SD_CLK_WRITE_MASK);
+		SETR_32(SD_CLK_CTRL, value);	/* off */
+		mmc_drv_obj.clock_enable = FALSE;
+	}
+
+	return EMMC_SUCCESS;
+}
+
+static EMMC_ERROR_CODE emmc_bus_width(uint32_t width)
+{
+	EMMC_ERROR_CODE result = EMMC_ERR;
+
+	/* parameter check */
+	if ((width != 8) && (width != 4) && (width != 1)) {
+		emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, EMMC_ERR_PARAM);
+		return EMMC_ERR_PARAM;
+	}
+
+	/* state check */
+	if (mmc_drv_obj.selected != TRUE) {
+		emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	mmc_drv_obj.bus_width = (HAL_MEMCARD_DATA_WIDTH) (width >> 2);	/* 2 = 8bit, 1 = 4bit, 0 =1bit */
+
+	/* CMD6 */
+	emmc_make_nontrans_cmd(CMD6_SWITCH,
+			       (EMMC_SWITCH_BUS_WIDTH_1 |
+				(mmc_drv_obj.bus_width << 8)));
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		/* occurred error */
+		mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT;
+		goto EXIT;
+	}
+
+	switch (mmc_drv_obj.bus_width) {
+	case HAL_MEMCARD_DATA_WIDTH_1_BIT:
+		SETR_32(SD_OPTION,
+			((GETR_32(SD_OPTION) & ~(BIT15 | BIT13)) | BIT15));
+		break;
+	case HAL_MEMCARD_DATA_WIDTH_4_BIT:
+		SETR_32(SD_OPTION, (GETR_32(SD_OPTION) & ~(BIT15 | BIT13)));
+		break;
+	case HAL_MEMCARD_DATA_WIDTH_8_BIT:
+		SETR_32(SD_OPTION,
+			((GETR_32(SD_OPTION) & ~(BIT15 | BIT13)) | BIT13));
+		break;
+	default:
+		goto EXIT;
+	}
+
+	/* 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) {
+		goto EXIT;
+	}
+
+	/* CMD8 (EXT_CSD) */
+	emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000,
+			    (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
+			    EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ,
+			    HAL_MEMCARD_NOT_DMA);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		goto EXIT;
+	}
+
+	return EMMC_SUCCESS;
+
+EXIT:
+
+	emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, result);
+	ERROR("BL2: emmc bus_width error end\n");
+	return result;
+}
+
+EMMC_ERROR_CODE emmc_select_partition(EMMC_PARTITION_ID id)
+{
+	EMMC_ERROR_CODE result;
+	uint32_t arg;
+	uint32_t partition_config;
+
+	/* state check */
+	if (mmc_drv_obj.mount != TRUE) {
+		emmc_write_error_info(EMMC_FUNCNO_NONE, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* id = PARTITION_ACCESS(Bit[2:0]) */
+	if ((id & ~PARTITION_ID_MASK) != 0) {
+		emmc_write_error_info(EMMC_FUNCNO_NONE, EMMC_ERR_PARAM);
+		return EMMC_ERR_PARAM;
+	}
+
+	/* EXT_CSD[179] value */
+	partition_config =
+	    (uint32_t) mmc_drv_obj.ext_csd_data[EMMC_EXT_CSD_PARTITION_CONFIG];
+	if ((partition_config & PARTITION_ID_MASK) == id) {
+		result = EMMC_SUCCESS;
+	} else {
+
+		partition_config =
+		    (uint32_t) ((partition_config & ~PARTITION_ID_MASK) | id);
+		arg = EMMC_SWITCH_PARTITION_CONFIG | (partition_config << 8);
+
+		result = emmc_set_ext_csd(arg);
+	}
+
+	return result;
+}
+
+static void set_sd_clk(uint32_t clkDiv)
+{
+	uint32_t dataL;
+
+	dataL = (GETR_32(SD_CLK_CTRL) & (~SD_CLK_CTRL_CLKDIV_MASK));
+
+	switch (clkDiv) {
+	case 1:
+		dataL |= 0x000000FFU;
+		break;		/* 1/1   */
+	case 2:
+		dataL |= 0x00000000U;
+		break;		/* 1/2   */
+	case 4:
+		dataL |= 0x00000001U;
+		break;		/* 1/4   */
+	case 8:
+		dataL |= 0x00000002U;
+		break;		/* 1/8   */
+	case 16:
+		dataL |= 0x00000004U;
+		break;		/* 1/16  */
+	case 32:
+		dataL |= 0x00000008U;
+		break;		/* 1/32  */
+	case 64:
+		dataL |= 0x00000010U;
+		break;		/* 1/64  */
+	case 128:
+		dataL |= 0x00000020U;
+		break;		/* 1/128 */
+	case 256:
+		dataL |= 0x00000040U;
+		break;		/* 1/256 */
+	case 512:
+		dataL |= 0x00000080U;
+		break;		/* 1/512 */
+	}
+
+	SETR_32(SD_CLK_CTRL, dataL);
+	mmc_drv_obj.current_freq = (uint32_t) clkDiv;
+}
+
+static void emmc_get_partition_access(void)
+{
+	uint32_t reg;
+	EMMC_ERROR_CODE result;
+
+	reg = mmio_read_32(RCAR_PRR) & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+	if ((reg == RCAR_PRODUCT_H3_CUT20) || (reg == RCAR_PRODUCT_M3_CUT11)) {
+		SETR_32(SD_OPTION, 0x000060EEU);	/* 8 bits width */
+		/* CMD8 (EXT_CSD) */
+		emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000U,
+				    (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
+				    EMMC_MAX_EXT_CSD_LENGTH,
+				    HAL_MEMCARD_READ, HAL_MEMCARD_NOT_DMA);
+		mmc_drv_obj.get_partition_access_flag = TRUE;
+		result =
+		    emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+		mmc_drv_obj.get_partition_access_flag = FALSE;
+		if (result == EMMC_SUCCESS) {
+			mmc_drv_obj.partition_access =
+			    (EMMC_PARTITION_ID) (mmc_drv_obj.ext_csd_data[179]
+						 & PARTITION_ID_MASK);
+		} else if (result == EMMC_ERR_CMD_TIMEOUT) {
+			mmc_drv_obj.partition_access = PARTITION_ID_BOOT_1;
+		} else {
+			emmc_write_error_info(EMMC_FUNCNO_GET_PERTITION_ACCESS,
+					      result);
+			panic();
+		}
+		SETR_32(SD_OPTION, 0x0000C0EEU);	/* Initialize */
+	}
+}
+
+static uint32_t emmc_calc_tran_speed(uint32_t *freq)
+{
+	const uint32_t unit[8] = { 10000, 100000, 1000000, 10000000,
+				0, 0, 0, 0 };   /**< frequency unit (1/10) */
+	const uint32_t mult[16] = { 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45,
+				52, 55, 60, 70, 80 };
+
+	uint32_t maxFreq;
+	uint32_t result;
+	uint32_t tran_speed = EMMC_CSD_TRAN_SPEED();
+
+	/* tran_speed = 0x32
+	 * unit[tran_speed&0x7] = uint[0x2] = 1000000
+	 * mult[(tran_speed&0x78)>>3] = mult[0x30>>3] = mult[6] = 26
+	 * 1000000 * 26 = 26000000 (26MHz)
+	 */
+
+	result = 1;
+	maxFreq =
+	    unit[tran_speed & EMMC_TRANSPEED_FREQ_UNIT_MASK] *
+	    mult[(tran_speed & EMMC_TRANSPEED_MULT_MASK) >>
+		 EMMC_TRANSPEED_MULT_SHIFT];
+
+	if (maxFreq == 0) {
+		result = 0;
+	} else if (MMC_FREQ_52MHZ <= maxFreq)
+		*freq = MMC_52MHZ;
+	else if (MMC_FREQ_26MHZ <= maxFreq)
+		*freq = MMC_26MHZ;
+	else if (MMC_FREQ_20MHZ <= maxFreq)
+		*freq = MMC_20MHZ;
+	else
+		*freq = MMC_400KHZ;
+
+	return result;
+}
+
+static uint32_t emmc_set_timeout_register_value(uint32_t freq)
+{
+	uint32_t timeoutCnt;	/* SD_OPTION   - Timeout Counter  */
+
+	switch (freq) {
+	case 1U:
+		timeoutCnt = 0xE0U;
+		break;		/* SDCLK * 2^27 */
+	case 2U:
+		timeoutCnt = 0xE0U;
+		break;		/* SDCLK * 2^27 */
+	case 4U:
+		timeoutCnt = 0xD0U;
+		break;		/* SDCLK * 2^26 */
+	case 8U:
+		timeoutCnt = 0xC0U;
+		break;		/* SDCLK * 2^25 */
+	case 16U:
+		timeoutCnt = 0xB0U;
+		break;		/* SDCLK * 2^24 */
+	case 32U:
+		timeoutCnt = 0xA0U;
+		break;		/* SDCLK * 2^23 */
+	case 64U:
+		timeoutCnt = 0x90U;
+		break;		/* SDCLK * 2^22 */
+	case 128U:
+		timeoutCnt = 0x80U;
+		break;		/* SDCLK * 2^21 */
+	case 256U:
+		timeoutCnt = 0x70U;
+		break;		/* SDCLK * 2^20 */
+	case 512U:
+		timeoutCnt = 0x70U;
+		break;		/* SDCLK * 2^20 */
+	default:
+		timeoutCnt = 0xE0U;
+		break;		/* SDCLK * 2^27 */
+	}
+
+	return timeoutCnt;
+}
+
+EMMC_ERROR_CODE emmc_set_ext_csd(uint32_t arg)
+{
+	EMMC_ERROR_CODE result;
+
+	/* CMD6 */
+	emmc_make_nontrans_cmd(CMD6_SWITCH, arg);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		return result;
+	}
+
+	/* 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;
+	}
+
+	/* CMD8 (EXT_CSD) */
+	emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000,
+			    (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
+			    EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ,
+			    HAL_MEMCARD_NOT_DMA);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		return result;
+	}
+	return EMMC_SUCCESS;
+}
+
+EMMC_ERROR_CODE emmc_set_request_mmc_clock(uint32_t *freq)
+{
+	/* parameter check */
+	if (freq == NULL) {
+		emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK, EMMC_ERR_PARAM);
+		return EMMC_ERR_PARAM;
+	}
+
+	/* state check */
+	if ((mmc_drv_obj.initialize != TRUE)
+	    || (mmc_drv_obj.card_power_enable != TRUE)) {
+		emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* clock is already running in the desired frequency. */
+	if ((mmc_drv_obj.clock_enable == TRUE)
+	    && (mmc_drv_obj.current_freq == *freq)) {
+		return EMMC_SUCCESS;
+	}
+
+	/* busy check */
+	if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0) {
+		emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK,
+				      EMMC_ERR_CARD_BUSY);
+		return EMMC_ERR;
+	}
+
+	set_sd_clk(*freq);
+	mmc_drv_obj.clock_enable = FALSE;
+
+	return emmc_clock_ctrl(TRUE);	/* clock on */
+}
+
+EMMC_ERROR_CODE rcar_emmc_mount(void)
+{
+	EMMC_ERROR_CODE result;
+
+	/* state check */
+	if ((mmc_drv_obj.initialize != TRUE)
+	    || (mmc_drv_obj.card_power_enable != TRUE)
+	    || ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0)
+	    ) {
+		emmc_write_error_info(EMMC_FUNCNO_MOUNT, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* initialize card (IDLE state --> Transfer state) */
+	result = emmc_card_init();
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) {
+			/* nothing to do. */
+		}
+		return result;
+	}
+
+	/* Switching high speed mode */
+	result = emmc_high_speed();
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
+		if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) {
+			/* nothing to do. */
+		}
+		return result;
+	}
+
+	/* Changing the data bus width */
+	result = emmc_bus_width(8);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_BUS_WIDTH);
+		if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) {
+			/* nothing to do. */
+		}
+		return result;
+	}
+
+	/* mount complete */
+	mmc_drv_obj.mount = TRUE;
+
+	return EMMC_SUCCESS;
+}