/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #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; }