| /***************************************************************************** |
| * Copyright Statement: |
| * -------------------- |
| * This software is protected by Copyright and the information contained |
| * herein is confidential. The software may not be copied and the information |
| * contained herein may not be used or disclosed except with the written |
| * permission of MediaTek Inc. (C) 2005 |
| * |
| * BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
| * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
| * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON |
| * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. |
| * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE |
| * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR |
| * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH |
| * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO |
| * NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S |
| * SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. |
| * |
| * BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE |
| * LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, |
| * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, |
| * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO |
| * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
| * |
| * THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE |
| * WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF |
| * LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND |
| * RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER |
| * THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC). |
| * |
| *****************************************************************************/ |
| |
| /***************************************************************************** |
| * |
| * Filename: |
| * --------- |
| * sd.c |
| * |
| * Project: |
| * -------- |
| * Maui_Software |
| * |
| * Description: |
| * ------------ |
| * driver functons for SD/MMC |
| * |
| * |
| * Author: |
| * ------- |
| * ------- |
| * |
| *============================================================================ |
| * HISTORY |
| * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!! |
| *------------------------------------------------------------------------------ |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * removed! |
| * |
| * removed! |
| * removed! |
| * removed! |
| * |
| *------------------------------------------------------------------------------ |
| * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!! |
| *============================================================================ |
| ****************************************************************************/ |
| #include "drv_features.h" |
| #ifndef DRV_MSDC_OFF |
| #include "kal_public_api.h" //MSBB change #include "kal_release.h" |
| |
| #include "kal_general_types.h" |
| //#include "btif_sw.h" |
| //#include "kal_public_api.h" |
| #include "kal_public_defs.h" |
| #include "kal_debug.h" |
| #include "init.h" |
| |
| #include "kal_trace.h" |
| #include "dcl.h" |
| #include "drv_comm.h" |
| #include "drv_features.h" |
| #include "kal_public_defs.h" //MSBB change #include "stack_config.h" |
| #include "qmu_bm.h" |
| #include "qmu_bm_util.h" |
| |
| #if !defined(__UBL__) || defined(__CARD_DOWNLOAD__) || defined(__EMMC_BOOTING__) |
| #include "us_timer.h" |
| #include "msdc_reg_adap.h" |
| #include "reg_base.h" |
| #include "msdc_api.h" |
| #include "msdc_def.h" |
| #include "sd_def.h" |
| #include "upll_ctrl.h" |
| #include "drv_trc.h" |
| #if defined(__AUDIO_DSP_LOWPOWER__) |
| #include "audlp_exp.h" |
| #endif |
| |
| #if defined(__EMMC_BOOTING__) |
| #include "FTL.h" |
| #endif |
| |
| #ifdef DRV_LSD |
| #include "msdc_lsd.h" |
| |
| |
| |
| extern void LSD_Host74TCMDHigh(void); |
| extern kal_bool LSD_HostDetectBusy(void); |
| #endif |
| |
| #if defined(__MSDC_SD_MMC__) |
| //global variables |
| T_SDC_HANDLE gSD_blk[SD_NUM]; |
| T_SDC_HANDLE *gSD = gSD_blk; |
| |
| /*global veriable ,operation by DMA ,alloc in uncached memory*/ |
| #ifdef MSDC_GPD_BD_BUF_CACHED |
| msdc_gpd_t MSDC_gpd[SD_NUM]; |
| msdc_gpd_t MSDC_gpd_end[SD_NUM]; |
| |
| msdc_bd_t MSDC_bd[SD_NUM][MSDC_BD_MAX]; |
| #else |
| __attribute__ ( (section ("NONCACHEDRW")))msdc_gpd_t MSDC_gpd[SD_NUM]; |
| __attribute__ ( (section ("NONCACHEDRW")))msdc_gpd_t MSDC_gpd_end[SD_NUM]; |
| |
| __attribute__ ( (section ("NONCACHEDRW")))msdc_bd_t MSDC_bd[SD_NUM][MSDC_BD_MAX]; |
| #endif |
| |
| //static SDC_CMD_STATUS gblSDsta; |
| |
| extern MSDC_Custom_Handle msdc_custom_handle; |
| void SD_Sleep4Wait(kal_int32 sleep_tick); |
| void SD_Use13M_Clock(void); |
| extern kal_uint8 MSDC_GetIOCtrlParam(void); |
| extern kal_bool INT_USBBoot(void); |
| #if defined(DRV_MSDC_LATCH_MT6276_SERIES) |
| extern void MSDC_SetLatchTuning(void); |
| #else |
| extern void MSDC_SetIOCONRegDLT(void); |
| #endif//#if defined(DRV_MSDC_LATCH_MT6276_SERIES) |
| //kal_uint32 sd_writeFailReason; // fix Lint warning |
| #if !defined(DRV_MSDC_LATCH_MT6276_SERIES) |
| void SD_SetRedDlt(kal_uint32 redDlt); |
| #endif//#if !defined(DRV_MSDC_LATCH_MT6276_SERIES) |
| extern void SLA_CustomLogging(kal_char *customJob, kal_int32 saAction); |
| |
| /*#ifdef DRV_MSDC_SDC_V3 |
| static kal_uint32 sd_cmd_extra = ((64) << 24); // CTOC = 64 |
| #else |
| static kal_uint32 sd_cmd_extra = 0; |
| #endif*/ |
| |
| #if defined(__SIM_PLUS__) |
| #if !defined(__CUST_NEW__) |
| kal_char MSDC_GetClockWithoutSIMPlus(void); |
| #endif |
| #endif |
| |
| |
| |
| #ifdef DCL_MSDC_INTERFACE |
| #include "dcl.h" |
| |
| SDC_CMD_STATUS SD_SetCallBack(MSDC_CALLBACK callback1, MSDC_CALLBACK callback2, MSDC_CALLBACK callback3, MSDC_CALLBACK callback4, MSDC_CALLBACK callback5, MSDC_CALLBACK callback6); |
| SDC_CMD_STATUS SD_SetReadTestFlag(kal_uint32 readTestFlag); |
| SDC_CMD_STATUS SD_readTest(void); |
| SDC_CMD_STATUS SD_SetUpllClock(void); |
| |
| #ifdef __MEUT__ |
| SDDriver_t sd_driver_MTK1 = |
| { |
| (DCL_SINGLE_BLK_RD)SD_ReadSingleBlock, |
| (DCL_MUL_BLK_RD)SD_ReadMultiBlock, |
| (DCL_SINGLE_BLK_WR)SD_WriteSingleBlock, |
| (DCL_MUL_BLK_WR)SD_WriteMultiBlock, |
| (DCL_SD_INITITALIZE)SD_Initialize, |
| (DCL_SET_PRE_ERASE_CNT)SD_SetPreEraseBlk, |
| (DCL_SD_SET_CALLBACK)SD_SetCallBack, |
| (DCL_SET_READ_TEST_FLAG)SD_SetReadTestFlag, |
| (DCL_SD_READ_TEST)SD_readTest, |
| (DCL_SD_SET_UPLL_CLOCK_TEST)SD_SetUpllClock, |
| (DCL_SD_ERASE_BLK)SD_FlushSectors, |
| }; |
| #else |
| SDDriver_t sd_driver_MTK1 = |
| { |
| (DCL_SINGLE_BLK_RD)SD_ReadSingleBlock, |
| (DCL_MUL_BLK_RD)SD_ReadMultiBlock, |
| (DCL_SINGLE_BLK_WR)SD_WriteSingleBlock, |
| (DCL_MUL_BLK_WR)SD_WriteMultiBlock, |
| (DCL_SD_INITITALIZE)SD_Initialize, |
| (DCL_SET_PRE_ERASE_CNT)SD_SetPreEraseBlk, |
| (DCL_SD_SET_CALLBACK)NULL, |
| (DCL_SET_READ_TEST_FLAG)NULL, |
| (DCL_SD_READ_TEST)NULL, |
| (DCL_SD_SET_UPLL_CLOCK_TEST)NULL, |
| (DCL_SD_ERASE_BLK)SD_FlushSectors, |
| (DCL_GPD_MUL_BLK_RD)SD_GpdReadMultiBlock, |
| (DCL_GPD_MUL_BLK_WR)SD_GpdWriteMultiBlock, |
| }; |
| #endif |
| |
| #endif |
| |
| #if defined( __MSDC_BASIC_LOAD__) || defined( __MEUT__) |
| #define MSDC_TESTBUFFER_SIZE 512 |
| kal_uint32 msdc_testBuffer[(MSDC_TESTBUFFER_SIZE / 4)]; |
| kal_uint32 msdc_writeBuffer[(MSDC_TESTBUFFER_SIZE / 4)]; |
| |
| #define CMD_DVT_TEST_STATUS 7 |
| kal_uint32 msdc_ReadTestFlag; |
| MSDC_CALLBACK msdc_TestCallBack1; |
| MSDC_CALLBACK msdc_TestCallBack2; |
| MSDC_CALLBACK msdc_TestCallBack3; |
| MSDC_CALLBACK msdc_TestCallBack4; |
| MSDC_CALLBACK msdc_TestCallBack5; |
| MSDC_CALLBACK msdc_TestCallBack6; |
| static kal_uint32 sendCmdTimes = 0; |
| #endif |
| |
| #ifdef __CARD_DOWNLOAD__ |
| extern kal_bool MSDC_QueryIsPowerControllable(void); |
| extern void MSDC_SetPower(kal_bool enable); |
| #endif |
| |
| |
| |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_Acmd42 |
| * |
| * DESCRIPTION |
| * connect/disconnect the 50K Ohm pull-up resistor on CD/DAT3 |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| * NOTE |
| * |
| * |
| *************************************************************************/ |
| |
| // Get CID(CMD2) |
| SDC_CMD_STATUS SD_Acmd42(kal_bool connect) |
| { |
| SDC_CMD_STATUS status; |
| MSDC_DEBUG("[SD][%s %d]send cmd55\r\n",__FUNCTION__,__LINE__); |
| |
| // send APP_CMD |
| if ((status = SD_Cmd55(gSD->mRCA)) != NO_ERROR) |
| return status; |
| |
| MSDC_DEBUG("[SD][%s %d]send acmd42\r\n",__FUNCTION__,__LINE__); |
| |
| // send cmd6 |
| if ((status = SD_SendCmd(SDC_CMD_ACMD42, connect,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| gSD->mCD_DAT3 = KAL_FALSE; // pull-up resistor is disconnected for data trnasfer |
| return NO_ERROR; |
| } |
| |
| |
| #if defined(MSDC_MMC441_SUPPORT) |
| |
| kal_bool SD_eMMC_ECSD_setValue(kal_uint8 addr, kal_uint8 value) |
| { |
| //kal_uint32 r0; // [TODO]: eMMC |
| //kal_bool status = KAL_FALSE; |
| kal_uint8 *pData; |
| |
| if (192 <= addr) //addr above 192 is information registers, we can't write these registers |
| ASSERT(0); |
| |
| MSDC_PDNControl(KAL_FALSE); |
| |
| if (NO_ERROR != SD_Switch_MMC40(SET_BYTE, addr, value, 0)) |
| ASSERT(0); |
| |
| //if(NO_ERROR != SD_GetStatus(gSD->mRCA,(kal_uint32*)&r0)) |
| // ASSERT(0); |
| if (NO_ERROR != SD_SendEXTCSD_MMC40(MSDC_Sector)) |
| ASSERT(0); |
| |
| pData = (kal_uint8 *)MSDC_Sector; |
| |
| if (value != *(pData + addr)) |
| ASSERT(0); |
| |
| //status = KAL_TRUE; |
| MSDC_PDNControl(KAL_TRUE); |
| return KAL_TRUE; |
| } |
| |
| /* |
| This API is to ask eMMC to start the partition. |
| That is, this API should be called after configuring partition settings. |
| */ |
| kal_bool SD_eMMC_ECSD_StartPartition() |
| { |
| kal_bool status; |
| |
| /*if this is not eMMC 4.4, assert it */ |
| //EMMC44_CHECK_AND_ASSERT; |
| |
| /*the device has been partitioned*/ |
| if (EMMC_MASK_PARTITION_SETTING & gSD->mCSD.ext_csd->partition_settig) |
| { |
| ASSERT(0); |
| } |
| |
| status = SD_eMMC_ECSD_setValue(EXT_CSD_PARTITION_CONFIG_INDEX, 1); |
| |
| return status; |
| } |
| |
| // unit: 512-byte |
| kal_uint32 SD_eMMC_getWpgSize() |
| { |
| if ((1 & gSD->mCSD.ext_csd->erase_grp_def) && (gSD->mCSD.ext_csd->hc_wp_grp_size > 0)) |
| return 1024 * gSD->mCSD.ext_csd->hc_erase_grp_size * gSD->mCSD.ext_csd->hc_wp_grp_size; |
| else |
| return (gSD->mCSD.wp_grp_size_mmc >> 9); |
| } |
| |
| /* |
| This API is called to configure partition settings. Size unit is 512-byte. |
| */ |
| kal_bool SD_eMMC_ECSD_configPartition(eMMC_partitions partition, kal_uint32 startAddr, kal_uint32 size, kal_bool isEnhanced) |
| { |
| |
| kal_bool status; |
| kal_uint32 maxEnhSizeMult; |
| kal_uint32 wpgSize; |
| kal_uint32 wpgNum; |
| kal_uint32 partitionSize[5]; |
| kal_uint8 regIndex; |
| kal_uint8 value[3]; |
| |
| if (eMMC_GP_partition1 > partition || eMMC_user_Area < partition) |
| ASSERT(0); |
| |
| /*if this is not eMMC 4.4, assert it */ |
| //EMMC44_CHECK_AND_ASSERT; |
| |
| /*1st, if this card does not support enhanced feature or does not support partition feature, we can not do this function*/ |
| |
| /* 2nd, there is a limitation for the total size of enhanced memory area. |
| we have to know the total size of other existed enhanced area and check whether the setting violet the limitation. |
| */ |
| maxEnhSizeMult = gSD->mCSD.ext_csd->max_enh_size_mult[0] | ( gSD->mCSD.ext_csd->max_enh_size_mult[1] << 8) | ( gSD->mCSD.ext_csd->max_enh_size_mult[2] << 16); |
| |
| /*get current all partition size*/ |
| partitionSize[eMMC_GP_partition1 - eMMC_GP_partition1] = gSD->mCSD.ext_csd->gp_size_mult[0] | ( gSD->mCSD.ext_csd->gp_size_mult[1] << 8) | ( gSD->mCSD.ext_csd->gp_size_mult[2] << 16); |
| partitionSize[eMMC_GP_partition2 - eMMC_GP_partition1] = gSD->mCSD.ext_csd->gp_size_mult[3] | ( gSD->mCSD.ext_csd->gp_size_mult[4] << 8) | ( gSD->mCSD.ext_csd->gp_size_mult[5] << 16); |
| partitionSize[eMMC_GP_partition3 - eMMC_GP_partition1] = gSD->mCSD.ext_csd->gp_size_mult[6] | ( gSD->mCSD.ext_csd->gp_size_mult[7] << 8) | ( gSD->mCSD.ext_csd->gp_size_mult[8] << 16); |
| partitionSize[eMMC_GP_partition4 - eMMC_GP_partition1] = gSD->mCSD.ext_csd->gp_size_mult[9] | ( gSD->mCSD.ext_csd->gp_size_mult[10] << 8) | ( gSD->mCSD.ext_csd->gp_size_mult[11] << 16); |
| partitionSize[eMMC_user_Area - eMMC_GP_partition1] = gSD->mCSD.ext_csd->enh_size_mult[0] | ( gSD->mCSD.ext_csd->enh_size_mult[1] << 8) | ( gSD->mCSD.ext_csd->enh_size_mult[2] << 16); |
| |
| /*calculate how many wpg we need to set*/ |
| wpgSize = SD_eMMC_getWpgSize(); |
| wpgNum = (size / wpgSize) + ((size % wpgSize) > 0 ? 1 : 0); |
| |
| /*replace old size with the new size we want to set*/ |
| partitionSize [partition - eMMC_GP_partition1] = wpgNum; |
| |
| if ((partitionSize[0] + partitionSize[1] + partitionSize[2] + partitionSize[3] + partitionSize[4]) > maxEnhSizeMult) |
| return KAL_FALSE; |
| |
| /*everything check passed, now we can set the value*/ |
| if (eMMC_user_Area > partition) |
| regIndex = EXT_CSD_GP_SIZE_MULT_GP0_INDEX + 3 * (partition - eMMC_GP_partition1); |
| else |
| regIndex = EXT_CSD_ENH_SIZE_MULT_INDEX; |
| |
| value[2] = wpgNum / 64; |
| value[1] = (wpgNum - (value[2] * 64)) / 8; |
| value[0] = wpgNum - (value[2] * 64) - (value[1] * 8); |
| status = SD_eMMC_ECSD_setValue(regIndex, value[0]); |
| |
| if (KAL_TRUE != status) |
| goto err_exit; |
| |
| status = SD_eMMC_ECSD_setValue(regIndex + 1, value[1]); |
| |
| if (KAL_TRUE != status) |
| goto err_exit; |
| |
| status = SD_eMMC_ECSD_setValue(regIndex + 2, value[2]); |
| |
| if (KAL_TRUE != status) |
| goto err_exit; |
| |
| err_exit: |
| return status; |
| |
| } |
| |
| /* |
| This API is to configure to boot from specified partition. |
| By this API, DA can decide from wich partition, will card output the boot code in boot mode. |
| */ |
| kal_bool SD_eMMC_ECSD_setCurrentPart(eMMC_partitions partition) |
| { |
| kal_uint8 regValue; |
| kal_bool status; |
| eMMC_partitions pt; |
| |
| if (0 == partition || eMMC_user_Area < partition) |
| ASSERT(0); |
| |
| /*if this is not eMMC 4.4, assert it */ |
| //EMMC44_CHECK_AND_ASSERT; |
| |
| pt = (partition == eMMC_user_Area) ? 0 : partition; |
| |
| regValue = gSD->mCSD.ext_csd->partition_config; |
| |
| /*currently it uses the setting DA want, no need to change*/ |
| if (pt == (EMMC_MASK_PARTITION_CONFIG & regValue)) |
| return KAL_TRUE; |
| |
| regValue &= ~EMMC_MASK_PARTITION_CONFIG; |
| regValue |= pt; |
| status = SD_eMMC_ECSD_setValue(EXT_CSD_PARTITION_CONFIG_INDEX, regValue); |
| |
| #if 0 |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| #if defined(__EMMC_BOOTING__) |
| /* under construction !*/ |
| #endif |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| #endif |
| |
| return status; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_IsEMMC |
| * |
| * DESCRIPTION |
| * Check inserted card is e-MMC 4.4 |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| *************************************************************************/ |
| void SD_IsEmmcV44() |
| { |
| /* from eMMC 4.3, EXT_CSD_REV has maximum value 3, and from eMMC 4.4, EXT_CSD_REV new value 4, 5 |
| */ |
| if (3 < gSD->mCSD.ext_csd->ext_csd_rev) |
| { |
| if (0 != gSD->mCSD.ext_csd->boot_size_mul) //has boot partition, this is eMMC |
| { |
| gSD->emmc_info.isEmmcV44 = (kal_bool)KAL_TRUE; |
| gSD->emmc_info.bootPartitionSize = 2 * 128 * gSD->mCSD.ext_csd->boot_size_mul; |
| gSD->emmc_info.gp1PartitionSize = SD_eMMC_getWpgSize() * |
| (gSD->mCSD.ext_csd->gp_size_mult[0] |
| + ( gSD->mCSD.ext_csd->gp_size_mult[1] * 256) |
| + ( gSD->mCSD.ext_csd->gp_size_mult[2] * 65536)); |
| |
| /*from spec, alternated boot method is mandatory for eMMC4.4*/ |
| if ( 0 == (0x1 & gSD->mCSD.ext_csd->boot_info)) |
| ASSERT(0); |
| |
| /*we can't use the card that don't have RST signal support*/ |
| if ( 0x2 == (0x3 & gSD->mCSD.ext_csd->rst_function)) |
| ASSERT(0); |
| |
| if ( 0x1 == (0x1 & gSD->mCSD.ext_csd->partition_support)) |
| gSD->emmc_info.supportPartition = (kal_bool)KAL_TRUE; |
| else |
| gSD->emmc_info.supportPartition = (kal_bool)KAL_FALSE; |
| |
| if ( 0x2 == (0x2 & gSD->mCSD.ext_csd->partition_support)) |
| gSD->emmc_info.supportEnhancedPart = (kal_bool)KAL_TRUE; |
| else |
| gSD->emmc_info.supportEnhancedPart = (kal_bool)KAL_FALSE; |
| } |
| else //normal mmc card without boot support |
| { |
| gSD->emmc_info.isEmmcV44 = (kal_bool)KAL_FALSE; |
| } |
| } |
| else //spec version below or equals to eMMC 4.3 |
| { |
| gSD->emmc_info.isEmmcV44 = (kal_bool)KAL_FALSE; |
| } |
| } |
| |
| #endif//defined(MSDC_MMC441_SUPPORT) |
| |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_SetMMC40_4bit_high_speed |
| * |
| * DESCRIPTION |
| * Check inserted card is SD or MMC |
| * |
| * PARAMETERS |
| * |
| * |
| * RETURNS |
| * SD_CARD or MMC_CARD |
| * |
| * GLOBALS AFFECTED |
| * gMSDC_Handle |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_SetMMC40_bus_high_speed(void) |
| { |
| kal_uint32 clock, hs; |
| // kal_uint8 *pData; |
| |
| #if !defined(__EMMC_BOOTING__) |
| |
| if (SD_SetBlength(512) != NO_ERROR) |
| goto err; |
| |
| #endif |
| |
| #ifndef MSDC_SPECIAL_MMC_41_CARD |
| |
| // read the EXT_CSD |
| if (SD_SendEXTCSD_MMC40(MSDC_Sector) != NO_ERROR) |
| goto err; |
| |
| #endif |
| |
| /*calculate size*/ |
| if (MMC42_CARD == gMSDC_Handle->mMSDC_type) |
| { |
| gSD->mCSD.capacity = (kal_uint64)gSD->mCSD.ext_csd->sec_count * 512; |
| } |
| |
| #if defined(MSDC_MMC441_SUPPORT) |
| SD_IsEmmcV44(); |
| #endif |
| |
| // set high speed |
| #ifndef MSDC_SPECIAL_MMC_41_CARD |
| |
| if (gSD->mCSD.ext_csd->card_type & HS_52M) |
| #endif |
| { |
| // should be 52000 |
| clock = 52000000; |
| //clock = gMSDC_Handle->msdc_clock / 2; |
| |
| //if (52000000 < clock) |
| // clock = clock / 2; |
| |
| hs = 1; |
| //MSDC_LSD_WriteReg32(MSDC_IOCON,0x010002FF) |
| |
| MSDC_DEBUG("[MSDC][%s %d]1.Set clock to %d \r\n",__FUNCTION__,__LINE__,clock); |
| } |
| |
| #ifndef MSDC_SPECIAL_MMC_41_CARD |
| else if (gSD->mCSD.ext_csd->card_type & HS_26M) |
| { |
| // should be 26000 |
| clock = 26000000; |
| hs = 1; |
| } |
| else |
| { |
| clock = 13000000; |
| hs = 0; |
| } |
| |
| #endif |
| |
| if (hs) |
| { |
| //! [TODO]: eMMC |
| /* select proper power class |
| if(SD_Switch_MMC40(SET_BYTE,EXT_CSD_POW_CLASS_INDEX, |
| (gSD->mCSD.ext_csd->pwr_52_360&0xf) ,0) != NO_ERROR) |
| goto err; |
| */ |
| |
| |
| |
| /* enable high speed (26M or 52M)*/ |
| if(SD_Switch_MMC40(SET_BYTE,EXT_CSD_HIGH_SPPED_INDEX,EXT_CSD_ENABLE_HIGH_SPEED,0) != NO_ERROR) |
| goto err; |
| |
| |
| // latch data at falling edge to cover the card driving capability |
| // MSDC_LSD_SetBits32(MSDC_CFG,MSDC_CFG_RED); |
| } |
| |
| #ifndef DRV_LSD |
| |
| //#ifndef DRV_MSDC_CLK_SEARCH |
| //gMSDC_Handle->msdc_clock = MSDC_CLOCK; |
| MSDC_SetClock(clock,KAL_FALSE); |
| //#endif |
| #else |
| LSD_HostSetClock(LSD_SPEED_52M); |
| #endif |
| |
| |
| |
| if (NO_SINGLE_LINE == gMSDC_Handle->trySingleLine) |
| { |
| // select bus width |
| #if defined(MMC40_USE_4BIT_BUS) |
| // enable 4-bit bus width |
| if (SD_Switch_MMC40(SET_BYTE, EXT_CSD_BUS_WIDTH_INDEX, BIT_4_MMC40, 0) != NO_ERROR) |
| goto err; |
| |
| #ifdef MSDC_SPECIAL_MMC_41_CARD |
| |
| if (KAL_TRUE == kal_query_systemInit() |
| || KAL_TRUE == FTL_isPollingMode() |
| ) |
| { |
| MSDC_GPTI_BusyWait(2); |
| } |
| else |
| { |
| kal_sleep_task(4); |
| } |
| |
| #endif |
| |
| MSDC_SetBusWidth(BIT_4W); |
| gSD->bus_width = 4; |
| #elif defined(MMC40_USE_8BIT_BUS) |
| |
| // enable 8-bit bus width |
| if (SD_Switch_MMC40(SET_BYTE, EXT_CSD_BUS_WIDTH_INDEX, BIT_8_MMC40, 0) != NO_ERROR) |
| goto err; |
| MSDC_SetBusWidth(BIT_8W); |
| gSD->bus_width = 8; |
| #endif |
| } |
| else |
| { |
| gMSDC_Handle->trySingleLine&=(~TEMP_SINGLE_LINE); |
| } |
| |
| #ifndef MSDC_SPECIAL_MMC_41_CARD |
| |
| if (SD_SendEXTCSD_MMC40(MSDC_Sector) != NO_ERROR) |
| goto err;; |
| |
| #endif |
| |
| return NO_ERROR; |
| err: |
| |
| return ERR_MMC_BUS_HS_ERROR; |
| } |
| /************************************************************************* |
| * FUNCTION |
| * SD_CheckSDorMMC |
| * |
| * DESCRIPTION |
| * Check inserted card is SD or MMC |
| * |
| * PARAMETERS |
| * |
| * |
| * RETURNS |
| * SD_CARD or MMC_CARD |
| * |
| * GLOBALS AFFECTED |
| * gMSDC_Handle |
| * |
| *************************************************************************/ |
| T_MSDC_CARD SD_CheckSDorMMC() |
| { |
| SDC_CMD_STATUS status; |
| |
| #if defined(SD_MMC_HIGH_DENSITY_SUPPORT) |
| SD_Cmd8(); |
| #endif |
| status = SD_Acmd41_SD(); |
| |
| if (status == NO_ERROR) |
| return gMSDC_Handle->mMSDC_type; // SD_CARD |
| else |
| MSDC_ERR("[SD]SD_Acmd41_SD returns error code: %d\r\n", status); |
| |
| status = SD_Cmd1_MMC(); |
| |
| if (status == NO_ERROR) |
| return gMSDC_Handle->mMSDC_type; // MMC_CARD |
| else |
| MSDC_ERR("[SD]SD_Cmd1_MMC returns error code: %d\r\n", status); |
| |
| return UNKNOWN_CARD; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_SetDefault |
| * |
| * DESCRIPTION |
| * set default values to gSD |
| * |
| * PARAMETERS |
| * |
| * |
| * RETURNS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| *************************************************************************/ |
| void SD_SetDefault(void) |
| { |
| MSDC_LOCK_TAG tempLock; |
| kal_mem_cpy(&tempLock, &gSD->mSDdrv_lock, sizeof(MSDC_LOCK_TAG)); |
| kal_mem_set(gSD, 0, sizeof(T_SDC_HANDLE)); |
| |
| gSD->mBKLength = 0; |
| gSD->mRCA = 0; |
| gSD->mInactive = KAL_FALSE; |
| gSD->mState = IDLE_STA; |
| gSD->bus_width = 1; |
| //gSD->mCD_DAT3 = KAL_TRUE; |
| |
| kal_mem_cpy(&gSD->mSDdrv_lock, &tempLock, sizeof(MSDC_LOCK_TAG)); |
| } |
| |
| void SD_Use24M_Clock(void) |
| { |
| |
| } |
| |
| void SD_Use13M_Clock(void) |
| { |
| |
| } |
| |
| #ifdef DRV_MSDC_CLK_MT6268_SERIES |
| void SD_Use30M_Clock(void) |
| { |
| |
| } |
| |
| void SD_Use45M_Clock(void) |
| { |
| |
| } |
| #endif |
| |
| #ifdef DRV_MSDC_CLK_SEARCH |
| |
| kal_uint32 whenToStop; |
| kal_uint32 stopTimeout = 300; |
| |
| #if !defined(DRV_MSDC_LATCH_MT6276_SERIES) |
| |
| void SD_SetRedDlt(kal_uint32 redDlt) |
| { |
| |
| } |
| #endif//#if !defined(DRV_MSDC_LATCH_MT6276_SERIES) |
| |
| kal_bool sd_DltTestWithClkStopped(kal_uint32 data_adrs) |
| { |
| return 0; |
| |
| } |
| |
| #if !defined(DRV_MSDC_LATCH_MT6276_SERIES) |
| |
| kal_bool SD_setCLKAndTest(kal_uint32 targetCLK) |
| { |
| return 0; |
| } |
| |
| |
| kal_uint32 SD_tuneCLK2() |
| { |
| return 0; |
| } |
| |
| #else//!defined(DRV_MSDC_LATCH_MT6276_SERIES) |
| |
| kal_bool SD_IsClkInRange(kal_uint32 clk) |
| { |
| return 0; |
| } |
| |
| kal_bool SD_CanCmdBeLatched(void) |
| { |
| return 0; |
| } |
| |
| /*kal_bool SD_CanDataBeLatched(msdc_clk_setting cs) |
| { |
| |
| }*/ |
| |
| /*SDC_CMD_STATUS MSDC_AutoCalibrate( |
| msdc_acb_mode mode, |
| msdc_acb_scan_mode scanMode, |
| msdc_acb_tun_scheme tunScheme, |
| kal_uint8 tunBlockNum |
| ) |
| { |
| |
| }*/ |
| |
| /*kal_uint32 MSDC_ManuCalibrate( |
| msdc_clk_setting cs, |
| msdc_acb_mode mode |
| ) |
| { |
| |
| }*/ |
| |
| #define MAX_NUM_MULTI_PHASE 32 |
| SDC_CMD_STATUS FindMostConsecutiveBits( |
| kal_uint32 word, |
| kal_uint8 wordLen, |
| kal_uint8 threshold, |
| kal_uint8 *pos |
| ) |
| { |
| return 0; |
| } |
| |
| /*SDC_CMD_STATUS MSDC_AutoCalibrate_FindBestLatchWindow( |
| msdc_acb_scan_mode scanMode, |
| kal_uint8 *pos |
| ) |
| { |
| |
| }*/ |
| |
| /*SDC_CMD_STATUS MSDC_ManuCali_FindBestLatchWindow( |
| msdc_clk_setting cs, |
| kal_uint32 phaseArraySeamless, |
| kal_uint8 *pos |
| ) |
| { |
| |
| }*/ |
| |
| /*kal_uint32 SD_ClkTuning_AutoCalibrate(msdc_clk_setting cs) |
| { |
| |
| }*/ |
| |
| /*kal_uint32 SD_ClkTuning_ManualCalibrate(msdc_clk_setting cs) |
| { |
| |
| }*/ |
| |
| /*kal_uint32 SD_ClkTuning_FeedbackClk(msdc_clk_setting cs) |
| { |
| |
| }*/ |
| |
| kal_uint32 SD_tuneCLK2() |
| { |
| return 0; |
| } |
| |
| #endif//!defined(DRV_MSDC_LATCH_MT6276_SERIES) |
| |
| #endif//#ifdef DRV_MSDC_CLK_SEARCH |
| |
| #ifdef __MEUT__ |
| kal_bool msdcOddNumberSizeTestByDMA; |
| kal_bool msdcDoNotRST; |
| SDC_CMD_STATUS msdcReadTest(kal_uint32 size, kal_uint8 *compareBuffer, kal_uint32 data_adrs) |
| { |
| |
| return 0; |
| } |
| |
| #endif |
| |
| |
| #ifdef __MSDC_BASIC_LOAD__ |
| |
| kal_bool msdcOddNumberSizeTestByDMA; |
| kal_bool msdcDoNotRST; |
| SDC_CMD_STATUS msdcTransferLengthTest(kal_uint32 size, kal_uint8 *compareBuffer, kal_uint32 data_adrs) |
| { |
| return 0; |
| } |
| |
| SDC_CMD_STATUS msdcWriteLengthTest(kal_uint32 size, kal_uint8 *compareBuffer, kal_uint32 data_adrs, kal_bool notChange) |
| { |
| return 0; |
| |
| } |
| #endif |
| |
| #if defined(MSDC_QMU_ENABLE) |
| #define MSDC_QBM_BPS_NUM 1 |
| #define MSDC_QBM_BPS_BUF_SZ QBM_QUEUE_GET_MEM_SIZE(QBM_SIZE_TGPD_BPS, MSDC_QBM_BPS_NUM) |
| kal_uint8 msdc_bps_buf[MSDC_QBM_BPS_BUF_SZ]; |
| void *g_p_msdc_bps[MSDC_QBM_BPS_NUM]; |
| |
| /* Initialize the QUM buffer for MSDC queue transfer */ |
| kal_bool SD_QMU_Init(void) |
| { |
| kal_bool ret = KAL_TRUE; |
| unsigned char idx = 0; |
| bm_queue_config conf; |
| qbm_gpd *p_cur_gpd = NULL ,*p_head_gpd = NULL , *p_tail_gpd = NULL; |
| |
| /* Init the BPS pointer */ |
| for (idx = 0; idx < MSDC_QBM_BPS_NUM; idx++) |
| g_p_msdc_bps[idx] = NULL; |
| |
| /*initial non-free bypass GPD buffer pool*/ |
| qbm_init_q_config(&conf); |
| conf.buff_num = MSDC_QBM_BPS_NUM; |
| conf.p_mem_pool_str = msdc_bps_buf; |
| conf.p_mem_pool_end = msdc_bps_buf + MSDC_QBM_BPS_BUF_SZ; |
| |
| /*user must flush the GPD after this non-free init queue*/ |
| if (QBM_ERROR_OK != qbm_init_queue_non_free(QBM_TYPE_TGPD_BPS, &conf , (void **)&p_head_gpd, (void **)&p_tail_gpd)) { |
| return KAL_FALSE; |
| } |
| |
| idx = 0; |
| p_cur_gpd = p_head_gpd; |
| |
| do { |
| qbm_set_non_free(p_cur_gpd); |
| qbm_set_used(p_cur_gpd); |
| QBM_DES_CLR_HWO(p_cur_gpd); |
| QBM_DES_SET_NEXT(p_cur_gpd, NULL); |
| |
| g_p_msdc_bps[idx] = p_cur_gpd; |
| |
| /*flush GPD here because qbm_init_queue_non_free don't flush GPD*/ |
| QBM_CACHE_FLUSH(p_cur_gpd, sizeof(qbm_gpd)); |
| idx ++; |
| |
| /*should consider the bps_ptr array count*/ |
| if ((p_cur_gpd == p_tail_gpd) || (idx >= MSDC_QBM_BPS_NUM)) { |
| break; |
| } |
| |
| p_cur_gpd = p_cur_gpd->p_next; |
| } while(1); |
| |
| return ret; |
| } |
| #endif |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_Initialize |
| * |
| * DESCRIPTION |
| * Initial SD controller and card |
| * |
| * PARAMETERS |
| * |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_Initialize(void) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 cid[4], csd[4], scr[4]; |
| kal_uint32 sd_status[16]; |
| kal_uint16 rca; |
| |
| /*check if init or not*/ |
| if (gMSDC_Handle->mIsInitialized==KAL_TRUE) |
| { |
| return NO_ERROR; |
| } |
| |
| #if defined(MSDC_MMC441_SUPPORT) |
| gSD->emmc_info.isEmmcV44 = KAL_FALSE; |
| #endif |
| |
| /* Re-Init gSD */ |
| kal_mem_set(&gSD->mSCR, 0, sizeof(T_SCR)); |
| |
| /*reset event*/ |
| kal_set_eg_events(gMSDC_Handle->MSDC_Events,0,KAL_AND); |
| |
| /*reset MSDC*/ |
| MSDC_RESET(); |
| |
| /*may switch to 1.8 last time,we should set signal volt to 3.3v and power cycle*/ |
| gMSDC_Handle->signal_volt=3300; |
| MSDC_SetSignalPower(KAL_TRUE, gMSDC_Handle->signal_volt); |
| power_cycle(20); |
| |
| /* Set INIT clock */ |
| MSDC_SetClock(MSDC_INIT_CLOCK,KAL_FALSE); |
| /*set to 1 bit data line*/ |
| MSDC_SetBusWidth(BIT_1W); |
| /*SD_SetDefault*/ |
| SD_SetDefault(); //need check the function !!!!!! |
| /*set latch tuning*/ |
| |
| /*set IOCON1 */ |
| /*set CARD_CK_PWDN=0 */ |
| MSDC_ClearBits32(MSDC_CFG,MSDC_CFG_CKPDN); |
| /*enable bus clk*/ |
| MSDC_SetBits32(MSDC_CFG,MSDC_CFG_CKDRV_EN); |
| |
| /*reset cmd0*/ |
| status=SD_Reset(); |
| SD_INITIALIZE_STATUS_CHECK(); /*need check this function !!!!!!!!!!!!*/ |
| /*checkSDorMMC cmd8 acmd41 cmd1*/ |
| if (SD_CheckSDorMMC() == UNKNOWN_CARD) |
| { |
| MSDC_ERR("[SD][%s %d]unknow card\r\n",__FUNCTION__,__LINE__); |
| SD_TRACE2(TRACE_GROUP_5, MSDC_GENERAL_FAIL, MSDC_DRV_TRC_FILE_SD, __LINE__); |
| status = ERR_STATUS; |
| goto err; |
| } |
| /*getCID cmd2*/ |
| status = SD_GetCID(cid); |
| SD_INITIALIZE_STATUS_CHECK(); |
| /*validateRCA cmd3*/ |
| status = SD_ValidateRCA(&rca); |
| SD_INITIALIZE_STATUS_CHECK(); |
| /*GetCSD cmd9*/ |
| status = SD_GetCSD(gSD->mRCA, csd); |
| SD_INITIALIZE_STATUS_CHECK(); |
| MSDC_DEBUG("[SD][%s %d]send cmd4\r\n",__FUNCTION__,__LINE__); |
| /*setSDR cmd4*/ |
| if (gSD->mCSD.dsr_imp){ |
| if ((status = SD_SetDSR()) != NO_ERROR) |
| { |
| //dbg_print("6\r\n"); |
| SD_TRACE2(TRACE_GROUP_5, MSDC_GENERAL_FAIL, MSDC_DRV_TRC_FILE_SD, __LINE__); |
| goto err; |
| } |
| } |
| /*check Write Protected*/ |
| #if defined(MSDC_WR_PROT_EN) |
| #if defined(_MSDC_INTERNAL_CD_INT_PIN_) |
| if(!(MSDC_Reg32(MSDC_PS)&MSDC_PS_WP)) |
| { |
| //gSD->mWPEnabled=KAL_TRUE; |
| if (gSD->mWPEnabled!=KAL_TRUE) |
| gSD->mWPEnabled=KAL_FALSE; |
| } |
| else |
| { |
| //gSD->mWPEnabled=KAL_FALSE; |
| gSD->mWPEnabled=KAL_TRUE; |
| } |
| #else |
| { |
| DCL_HANDLE handle; |
| |
| GPIO_CTRL_READ_T data; |
| |
| /* when use EINT for card detect,get the status */ |
| handle = DclGPIO_Open(DCL_GPIO, MSDC_WP_GPIO); |
| DclGPIO_Control(handle, GPIO_CMD_READ, (DCL_CTRL_DATA_T *)&data); |
| |
| if (data.u1IOData) |
| gSD->mWPEnabled = KAL_TRUE; |
| else |
| gSD->mWPEnabled = KAL_FALSE; |
| |
| DclGPIO_Close(handle); |
| } |
| #endif |
| #else /* MSDC_WR_PROT_EN */ |
| gSD->mWPEnabled = KAL_FALSE; |
| #endif |
| |
| MSDC_CRIT("[SD][%s %d]Card is %s\r\n",__FUNCTION__,__LINE__, |
| gSD->mWPEnabled ? "WP-ed" : "Not WP-ed"); |
| |
| /*select Card cmd7*/ |
| status = SD_SelectCard(gSD->mRCA); |
| if (status == CARD_IS_LOCKED) |
| gSD->mIsLocked = KAL_TRUE; |
| SD_INITIALIZE_STATUS_CHECK(); |
| |
| |
| /*read SCR cmd16 acmd51*/ |
| if (gMSDC_Handle->mMSDC_type==SD_CARD\ |
| ||gMSDC_Handle->mMSDC_type==SD20_HCS_CARD ||gMSDC_Handle->mMSDC_type==SD20_LCS_CARD\ |
| ||gMSDC_Handle->mMSDC_type==SD30_CARD) |
| { |
| status = SD_ReadSCR(scr); |
| SD_INITIALIZE_STATUS_CHECK(); |
| |
| status = SD_ReadSDStatus(sd_status); |
| SD_INITIALIZE_STATUS_CHECK(); |
| |
| /*set bus width acmd6*/ |
| if (NO_SINGLE_LINE == gMSDC_Handle->trySingleLine) |
| { |
| status = SD_SetBusWidth(BIT_4W); |
| SD_INITIALIZE_STATUS_CHECK(); |
| } |
| else |
| { |
| gMSDC_Handle->trySingleLine&=~(TEMP_SINGLE_LINE); |
| } |
| |
| /*acmd42*/ |
| #if !defined(__MSDC_TFLASH_DAT3_1BIT_HOT_PLUG__) |
| status = SD_Acmd42(KAL_FALSE); |
| SD_INITIALIZE_STATUS_CHECK(); |
| #endif |
| |
| status=SD_SwitchSpeedMode(); |
| SD_INITIALIZE_STATUS_CHECK(); |
| |
| #if defined(MSDC_CONFIG_SD30_SUPPORT) |
| if (gMSDC_Handle->mMSDC_type==SD30_CARD) |
| { |
| |
| switch (gSD->function_set.function1) |
| { |
| case FUN1_SET_SDR104: |
| MSDC_SetClock(208000000,KAL_FALSE); |
| gMSDC_Handle->msdc_clkTuneUpperBund = 100000000; |
| break; |
| case FUN1_SET_SDR50: |
| MSDC_SetClock(100000000,KAL_FALSE); |
| gMSDC_Handle->msdc_clkTuneUpperBund = 50000000; |
| break; |
| case FUN1_SET_SDR25_HS: |
| MSDC_SetClock(50000000,KAL_FALSE); |
| gMSDC_Handle->msdc_clkTuneUpperBund = 25000000; |
| break; |
| case FUN1_SET_SDR12_DS: |
| MSDC_SetClock(25000000,KAL_FALSE); |
| gMSDC_Handle->msdc_clkTuneUpperBund = 12500000; |
| break; |
| case FUN1_SET_DDR50: |
| MSDC_SetClock(50000000,KAL_TRUE); |
| gMSDC_Handle->msdc_clkTuneUpperBund = 25000000; |
| break; |
| } |
| } |
| else |
| #endif |
| { |
| if (gSD->function_set.function1==1) |
| { |
| MSDC_CRIT("[SD][%s %d]set Bus Clock to 50M(HS)\r\n",__FUNCTION__,__LINE__); |
| MSDC_SetClock(50000000,KAL_FALSE); |
| gMSDC_Handle->msdc_clkTuneUpperBund = 25000000; |
| } |
| else |
| { |
| MSDC_CRIT("[SD][%s %d]set Bus Clock to 25M(DS)\r\n",__FUNCTION__,__LINE__); |
| MSDC_SetClock(25000000,KAL_FALSE); |
| gMSDC_Handle->msdc_clkTuneUpperBund = 12500000; |
| } |
| } |
| |
| /* For SDA compliance test */ |
| if (((gSD->mSCR.spec_ver==SD_SPEC_101)||(gSD->mSCR.spec_ver==SD_SPEC_110)||(gSD->mCSD.csd_ver==CSD_VER_1_0))&& |
| ((kal_uint32)(gSD->mCSD.capacity / (1024 * 1024)) > 2048)&&(status==NO_ERROR)) { |
| status = ERR_STATUS; |
| MSDC_ERR("[SD] We would not mount >2G Card which is compliant to SD1.x\r\n"); |
| goto err; |
| } |
| if (((gSD->mSCR.spec_ver<=SD_SPEC_200))&& |
| ((kal_uint32)(gSD->mCSD.capacity / (1024 * 1024)) > 32768)&&(status==NO_ERROR)) { |
| status = ERR_STATUS; |
| MSDC_ERR("[SD] We would not mount >32GB Card which is compliant to SD2.0\r\n"); |
| goto err; |
| } |
| } |
| else |
| { |
| MSDC_CRIT("[SD][%s %d]init mmc \r\n",__FUNCTION__,__LINE__); |
| //mmc card |
| if ((gMSDC_Handle->mMSDC_type == MMC_CARD || gMSDC_Handle->mMSDC_type == MMC42_CARD) && gSD->mCSD.spec_ver >= 4) |
| { |
| if (gMSDC_Handle->mMSDC_type == MMC_CARD) /*we don't need to change MMC42_CARD to MMC40_CARD*/ |
| gMSDC_Handle->mMSDC_type = MMC40_CARD; |
| status = SD_SetMMC40_bus_high_speed(); |
| SD_INITIALIZE_STATUS_CHECK(); |
| #if defined(MSDC_MMC441_SUPPORT) |
| if ( gSD->mCSD.ext_csd->ext_csd_rev >= 5 ) |
| { |
| // set ERASE_GROUP_DEF[175] before issuing read, write, erase, write protect |
| status = SD_Switch_MMC40(SET_BYTE, EXT_CSD_ERASE_GRP_DEF, 1 , 0); |
| SD_INITIALIZE_STATUS_CHECK(); |
| } |
| #endif |
| } |
| else |
| { |
| MSDC_SetClock(13000000,KAL_FALSE); |
| } |
| |
| } |
| |
| /* Set block length cmd16 */ |
| status = SD_SetBlength(512); |
| SD_INITIALIZE_STATUS_CHECK(); |
| |
| err: |
| |
| if (status != NO_ERROR) |
| { |
| MSDC_ERR("[SD][%s %d]mount fail %x\r\n",__FUNCTION__,__LINE__,status); |
| SD_SetDefault(); |
| gMSDC_Handle->mIsInitialized = KAL_FALSE; |
| gMSDC_Handle->mIsPresent = KAL_FALSE; |
| MSDC_turnOnVMC(gMSDC_Handle->mIsPresent); |
| MSDC_SetVddPower(KAL_FALSE, gMSDC_Handle->vdd_volt); |
| MSDC_PDNControl(KAL_TRUE); |
| } |
| else |
| { |
| MSDC_CRIT("[SD][%s %d]mount ok %x\r\n",__FUNCTION__,__LINE__,status); |
| gMSDC_Handle->mIsInitialized = KAL_TRUE; |
| } |
| |
| /*reset event*/ |
| kal_set_eg_events(gMSDC_Handle->MSDC_Events, 0, KAL_AND); |
| return status; |
| |
| } |
| |
| #ifdef __MEUT__ |
| SDC_CMD_STATUS SD_SetCallBack(MSDC_CALLBACK callback1, MSDC_CALLBACK callback2, MSDC_CALLBACK callback3, MSDC_CALLBACK callback4, MSDC_CALLBACK callback5, MSDC_CALLBACK callback6) |
| { |
| return 0; |
| } |
| SDC_CMD_STATUS SD_SetReadTestFlag(kal_uint32 readTestFlag) |
| { |
| return 0; |
| } |
| SDC_CMD_STATUS SD_readTest(void) |
| { |
| |
| return 0; |
| } |
| |
| SDC_CMD_STATUS SD_SetUpllClock(void) |
| { |
| |
| return 0; |
| } |
| #endif |
| |
| |
| void SD_InvertN(kal_uint8 *dest, kal_uint8 *src, kal_uint8 len) |
| { |
| int i; |
| |
| for (i = 0; i < len; i++) |
| *(dest + len - 1 - i) = *(src + i); |
| |
| } |
| /************************************************************************* |
| * FUNCTION |
| * power2 |
| * |
| * DESCRIPTION |
| * Calculate the power of 2 |
| * |
| * PARAMETERS |
| * num: |
| * |
| * RETURNS |
| * 2^num |
| * |
| * GLOBALS AFFECTED |
| * |
| *************************************************************************/ |
| static kal_uint32 power2(kal_uint32 num) |
| { |
| return 1 << num; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_AnalysisCSD |
| * |
| * DESCRIPTION |
| * Analysis Card Specific Data and store in the member of gSD |
| * |
| * PARAMETERS |
| * csd: input csd for analysis |
| * RETURNS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| *************************************************************************/ |
| void SD_AnalysisCSD(kal_uint32* csd) |
| { |
| kal_uint8 *ptr; |
| kal_uint32 c_mult, c_size; |
| |
| ptr = (kal_uint8*)csd; |
| c_mult = c_size = 0; |
| // these offsets refer to the spec. of SD and MMC |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.csd_ver, ptr, 126, 2); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.tacc, ptr, 112, 8); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.nsac, ptr, 104, 8); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.tran_speed, ptr, 96, 8); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.ccc, ptr, 84, 12); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.r_blk_len, ptr, 80, 4); |
| gSD->mCSD.r_blk_len = power2(gSD->mCSD.r_blk_len); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.r_blk_part, ptr, 79, 1); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.w_blk_misali, ptr, 78, 1); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.r_blk_misali, ptr, 77, 1); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.dsr_imp, ptr, 76, 1); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.w_blk_part, ptr, 21, 1); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.w_blk_len, ptr, 22, 4); |
| gSD->mCSD.w_blk_len = power2(gSD->mCSD.w_blk_len); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.wp_grp_enable, ptr, 31, 1); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.temp_wp,ptr,12,1); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.perm_wp,ptr,13,1); |
| if (gSD->mCSD.temp_wp || gSD->mCSD.perm_wp) |
| gSD->mWPEnabled = KAL_TRUE; |
| |
| // there are some difference of CSD between SD and MMC |
| if (gMSDC_Handle->mMSDC_type == MMC_CARD || gMSDC_Handle->mMSDC_type == MMC42_CARD) |
| { |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.spec_ver, ptr, 122, 4); |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.erase_sec_size_mmc, ptr, 42, 5); |
| gSD->mCSD.erase_sec_size_mmc = (gSD->mCSD.erase_sec_size_mmc + 1) * gSD->mCSD.w_blk_len; |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.erase_grp_size_mmc, ptr, 37, 5); |
| gSD->mCSD.erase_grp_size_mmc = (gSD->mCSD.erase_grp_size_mmc + 1) * gSD->mCSD.erase_sec_size_mmc; |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.wp_grp_size_mmc, ptr, 32, 5); |
| gSD->mCSD.wp_grp_size_mmc = (gSD->mCSD.wp_grp_size_mmc + 1) * gSD->mCSD.erase_grp_size_mmc; |
| } |
| else // SD_CARD |
| { |
| if (gSD->mCSD.csd_ver == CSD_VER_2_0) |
| gSD->mIsBlkAddr = 1; |
| else |
| gSD->mIsBlkAddr = 0; |
| |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.erase_sec_size_sd, ptr, 39, 7); |
| gSD->mCSD.erase_sec_size_sd += 1; |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.wp_prg_size_sd, ptr, 32, 7); |
| gSD->mCSD.wp_prg_size_sd = (gSD->mCSD.wp_prg_size_sd + 1) * gSD->mCSD.erase_sec_size_sd; |
| GetBitFieldN((kal_uint8*)&gSD->mCSD.erase_blk_en_sd, ptr, 46, 1); |
| } |
| |
| #if defined(SD_MMC_HIGH_DENSITY_SUPPORT) |
| |
| if ((gMSDC_Handle->mMSDC_type == SD20_HCS_CARD||\ |
| gMSDC_Handle->mMSDC_type == SD30_CARD) && gSD->mCSD.csd_ver >= SD_CSD_VER_20) |
| { |
| GetBitFieldN((kal_uint8*)&c_size, ptr, 48, 22); |
| gSD->mBKNum = (c_size + 1); |
| gSD->mCSD.capacity = (kal_uint64)gSD->mBKNum * 512 * 1024; |
| } |
| else |
| #endif |
| { |
| GetBitFieldN((kal_uint8*)&c_mult, ptr, 47, 3); |
| c_mult = power2(c_mult + 2); |
| GetBitFieldN((kal_uint8*)&c_size, ptr, 62, 12); |
| gSD->mBKNum = (c_size + 1) * c_mult; |
| gSD->mCSD.capacity = (kal_uint64)(c_size + 1) * (kal_uint64)c_mult * (kal_uint64)gSD->mCSD.r_blk_len; |
| } |
| if (!(gSD->mCSD.ccc &CCC_BLOCK_WRITE)) |
| gSD->mWPEnabled = KAL_TRUE; //unsupport write command |
| |
| MSDC_CRIT("[SD][%s %d]The capacity is %d MB, BLK_ADDR(%d)\r\n", __FUNCTION__, __LINE__, |
| (kal_uint32)(gSD->mCSD.capacity / (1024 * 1024)), gSD->mIsBlkAddr); |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_AnalysisCID |
| * |
| * DESCRIPTION |
| * Analysis Card Identificaton and store in the member of gSD |
| * |
| * PARAMETERS |
| * cid: input of card ID for analysis |
| * RETURNS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| *************************************************************************/ |
| void SD_AnalysisCID(kal_uint32* cid) |
| { |
| kal_uint8 i; |
| kal_uint8* pcid; |
| pcid = (kal_uint8*)cid; |
| |
| if (gMSDC_Handle->mMSDC_type == MMC_CARD || MMC42_CARD == gMSDC_Handle->mMSDC_type) |
| { |
| GetBitFieldN((kal_uint8*)&gSD->mCID.year, pcid, 8, 4); |
| gSD->mCID.year += 1997; |
| GetBitFieldN((kal_uint8*)&gSD->mCID.month, pcid, 12, 4); |
| GetBitFieldN((kal_uint8*)&gSD->mCID.psn, pcid, 16, 32); |
| GetBitFieldN((kal_uint8*)&gSD->mCID.prv, pcid, 48, 8); |
| |
| for (i = 0; i < 6; i++) |
| gSD->mCID.pnm[i] = *(pcid + 7 + i); |
| |
| GetBitFieldN((kal_uint8*)&gSD->mCID.oid, pcid, 104, 16); |
| GetBitFieldN((kal_uint8*)&gSD->mCID.mid, pcid, 120, 8); |
| |
| // special case handling |
| { |
| kal_uint8 pnm[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x36, 0x31}; |
| |
| if (gSD->mCID.mid == 6 && gSD->mCID.oid == 0 && |
| !kal_mem_cmp(gSD->mCID.pnm, pnm, 6)) |
| { |
| gSD->flags |= SD_FLAG_MMC_MRSW_FAIL; |
| } |
| } |
| #ifdef __CMMB_CAS_FULL_CARD_SUPPORT__ |
| { |
| kal_uint8 fullCardPnm[] = {0x55, 0x59, 0x4E, 0x41, 0x49, 0x54}; |
| |
| if (!kal_mem_cmp(gSD->mCID.pnm, fullCardPnm, 6)) /*Tianyu does not provide MID and OID*/ |
| { |
| SD_setFullCard(KAL_TRUE); |
| gMSDC_Handle->msdc_clkTuneUpperBund = 15000; |
| } |
| else |
| SD_setFullCard(KAL_FALSE); |
| } |
| #endif |
| |
| } |
| else // SD_CARD |
| { |
| gSD->mCID.mid = *(pcid + 15); |
| gSD->mCID.oid = *(pcid + 13) + 256 * (*(pcid + 14)); |
| |
| for (i = 0; i < 5; i++) |
| gSD->mCID.pnm[i] = *(pcid + 8 + i); |
| |
| gSD->mCID.prv = *(pcid + 7); |
| //gSD->mCID.psn = *(kal_uint32*)(pcid+3); |
| gSD->mCID.psn = (*(kal_uint32*)(pcid + 4) << 8) | *(pcid + 3); |
| gSD->mCID.month = (kal_uint8)GET_BIT(*(pcid + 1), 0, BIT_MASK_4); |
| gSD->mCID.year = GET_BIT(*(pcid + 1), 4, BIT_MASK_4) + 16 * GET_BIT(*(pcid + 2), 0, BIT_MASK_4) + 2000; |
| } |
| |
| #ifdef MSDC_TRACE_LEVEL1 |
| MD_TRC_MSDC_INFORM_CID(gSD->mCID.mid, gSD->mCID.oid); |
| #endif |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_AnalysisSCR |
| * |
| * DESCRIPTION |
| * Analysis SD Card Configuration Register and store in the member of gSD |
| * |
| * PARAMETERS |
| * scr: input of scr for analysis |
| * RETURNS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| * NOTE |
| * Only for SD card. |
| * |
| *************************************************************************/ |
| void SD_AnalysisSCR(kal_uint32* scr) |
| { |
| kal_uint8 *pscr; |
| |
| pscr = (kal_uint8*)scr; |
| gSD->mSCR.spec_ver = (SD_SPEC)((kal_uint8)GET_BIT(*(pscr), 0, BIT_MASK_4)); |
| |
| if (gSD->mSCR.spec_ver > SD_SPEC_101) |
| gSD->flags |= SD_FLAG_CMD6_SUPPORT; |
| |
| gSD->mSCR.dat_after_erase = (kal_uint8)GET_BIT(*(pscr + 1), 7, BIT_MASK_1); |
| gSD->mSCR.security = (kal_uint8)GET_BIT(*(pscr + 1), 4, BIT_MASK_3); |
| gSD->mSCR.bus_width = (kal_uint8)GET_BIT(*(pscr + 1), 0, BIT_MASK_4); |
| gSD->mSCR.cmd_support = (kal_uint8)GET_BIT(*(pscr + 3), 0, BIT_MASK_2); |
| |
| gSD->mSCR.sd_spec3 = (kal_uint8)GET_BIT(*(pscr + 2), 7, BIT_MASK_1); |
| if ((gSD->mSCR.spec_ver == SD_SPEC_200) && (gSD->mSCR.sd_spec3)) |
| gSD->mSCR.spec_ver = SD_SPEC_30X; |
| else |
| gSD->mSCR.spec_ver = SD_SPEC_200; |
| |
| MSDC_CRIT("[SD] SD_SPEC(%d) SD_SPEC3(%d) SD_BUS_WIDTH=%d\r\n", |
| gSD->mSCR.spec_ver, gSD->mSCR.sd_spec3, gSD->mSCR.bus_width); |
| MSDC_CRIT("[SD] SD_SECU(%d) CMD_SUPP(%d): CMD23(%d), CMD20(%d)\r\n", |
| gSD->mSCR.security, gSD->mSCR.cmd_support, |
| (gSD->mSCR.cmd_support >> 1) & 0x1, gSD->mSCR.cmd_support & 0x1); |
| } |
| |
| kal_uint32 SD_CmdPollResp(kal_uint32 * error,kal_uint32 pollTime_ms) |
| { |
| kal_uint32 status; |
| |
| if (!MSDC_TIMEOUT_WAIT(MSDC_Reg32(MSDC_INT)&MSDC_CMD_INTS,pollTime_ms)) |
| { |
| status=MSDC_Reg32(MSDC_INT); |
| MSDC_WriteReg32(MSDC_INT,(status&MSDC_CMD_INTS)); |
| if (status & MSDC_INT_CMDTMO) |
| { |
| MSDC_ERR("[SD][%s %d]CMDTMO(%d)\r\n",__FUNCTION__, |
| __LINE__, gMSDC_Handle->cmd); |
| *error=ERR_CMD_TIMEOUT; |
| } |
| else if (status & MSDC_INT_RSPCRCERR) |
| { |
| MSDC_ERR("[SD][%s %d]CMDCRC(%d)\r\n",__FUNCTION__, |
| __LINE__, gMSDC_Handle->cmd); |
| *error=ERR_CMD_RSPCRCERR; |
| } |
| else if (status & MSDC_INT_CMDRDY) |
| { |
| *error=NO_ERROR; |
| } |
| /*we get the interrupt information*/ |
| return 0; |
| } |
| /*polling timeout ,so we need sleep and try wait interrupt*/ |
| return 1; //tiemeout |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_WaitCmdRdyOrTo |
| * |
| * DESCRIPTION |
| * Wait until command ready or timeout |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * Interrupt driven and polling are both implemented |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_WaitCmdRdyOrTo(void) |
| { |
| kal_uint32 ret; |
| kal_uint32 status; |
| kal_uint32 flag; |
| /*poll 5 ms first to check response*/ |
| ret=SD_CmdPollResp(&(gMSDC_Handle->error),5); |
| if (ret) |
| { |
| MSDC_START_TIMER(MSDC_CMD_TIMEOUT/10); |
| /*enable interrupt*/ |
| MSDC_SetBits32(MSDC_INTEN,MSDC_CMD_INTS|MSDC_INT_CDSC); |
| /*use interrupt handler*/ |
| kal_retrieve_eg_events(gMSDC_Handle->MSDC_Events,EVENT_CMD_DONE,KAL_OR_CONSUME,&flag,KAL_SUSPEND); |
| /*disable interrupt*/ |
| MSDC_ClearBits32(MSDC_INTEN, MSDC_CMD_INTS); |
| MSDC_STOP_TIMER(); |
| if (gMSDC_Handle->is_timeout) |
| { |
| gMSDC_Handle->error=MSDC_GPT_TIMEOUT_ERR; |
| } |
| else |
| { |
| status=gMSDC_Handle->msdc_int&MSDC_CMD_INTS; |
| |
| if (status &MSDC_INT_CMDRDY) |
| { |
| gMSDC_Handle->error=NO_ERROR; |
| } |
| else if (status& MSDC_INT_CMDTMO) |
| { |
| MSDC_ERR("[SD][%s %d]CMDTMO(%d), MSDC_CMD_INTS:%x\r\n",__FUNCTION__, |
| __LINE__, gMSDC_Handle->cmd, status); |
| gMSDC_Handle->error=ERR_CMD_TIMEOUT; |
| } |
| else if (status & MSDC_INT_RSPCRCERR) |
| { |
| MSDC_ERR("[SD][%s %d]CMDCRC(%d), MSDC_CMD_INTS:%x\r\n",__FUNCTION__, |
| __LINE__, gMSDC_Handle->cmd, status); |
| gMSDC_Handle->error=ERR_CMD_RSPCRCERR; |
| } |
| else |
| { |
| MSDC_ERR("[SD][%s %d]ERR(%d), MSDC_CMD_INTS:%x\r\n",__FUNCTION__, |
| __LINE__, gMSDC_Handle->cmd, status); |
| gMSDC_Handle->error=ERR_CMD_TIMEOUT; |
| } |
| ret=status; |
| } |
| } |
| return gMSDC_Handle->error; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_WaitDatRdyOrTo |
| * |
| * DESCRIPTION |
| * Wait until data ready or timeout ,just for pio read and write |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * just polling |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_WaitDatRdyOrTo(kal_uint32 *buffer,kal_uint32 byte_len,kal_bool isWrite) |
| { |
| kal_uint32 intsts; |
| kal_uint8 * u8ptr; |
| kal_uint32 * ptr; |
| ptr=buffer; |
| |
| gMSDC_Handle->abort=0; |
| MSDC_SetBits32(MSDC_INTEN,MSDC_INTEN_DATTMO|MSDC_INTEN_DATCRCERR); |
| if(!isWrite) |
| { |
| /*poll to read data from FIFO*/ |
| while(byte_len) |
| { |
| |
| if ((byte_len>=MSDC_FIFO_THD)&&(MSDC_RXFIFOCNT()>=MSDC_FIFO_THD)){ |
| int count =MSDC_FIFO_THD>>2; |
| do{ |
| *ptr++=MSDC_FIFO_READ32(); |
| }while(--count); |
| byte_len-=MSDC_FIFO_THD; |
| |
| } |
| else if ((byte_len<MSDC_FIFO_THD)&&(MSDC_RXFIFOCNT()>=byte_len)) |
| { |
| while(byte_len>3){ |
| *ptr++=MSDC_FIFO_READ32(); |
| byte_len-=4; |
| } |
| u8ptr=(kal_uint8 *)ptr; |
| while(byte_len){ |
| *u8ptr++=MSDC_FIFO_READ8(); |
| byte_len--; |
| } |
| } |
| if (gMSDC_Handle->abort){ |
| gMSDC_Handle->abort=0; |
| MSDC_ERR("[SD][%s %d]pio read abort ,byte_len=%d \r\n",__FUNCTION__,__LINE__,byte_len); |
| break; |
| } |
| } |
| } |
| else |
| { |
| /*poll to write data into FIFO*/ |
| while(byte_len){ |
| if (byte_len >= MSDC_FIFO_SZ){ |
| if (MSDC_TXFIFOCNT()==0){ |
| int count =MSDC_FIFO_SZ>>2; |
| do { |
| MSDC_FIFO_WRITE32(*ptr); |
| ptr++; |
| }while(--count); |
| byte_len-=MSDC_FIFO_SZ; |
| } |
| } |
| else if ((byte_len<MSDC_FIFO_SZ)&&(MSDC_TXFIFOCNT()==0)){ |
| while(byte_len){ |
| while(byte_len>3){ |
| MSDC_FIFO_WRITE32(*ptr); |
| ptr++; |
| byte_len-=4; |
| } |
| u8ptr=(kal_uint8 *)ptr; |
| while(byte_len){ |
| MSDC_FIFO_WRITE8(*u8ptr); |
| u8ptr++; |
| byte_len--; |
| } |
| } |
| } |
| if (gMSDC_Handle->abort) |
| { |
| gMSDC_Handle->abort=0; |
| MSDC_ERR("[SD][%s %d]pio write abort ,byte_len=%d \r\n",__FUNCTION__,__LINE__,byte_len); |
| break; |
| } |
| } |
| |
| } |
| |
| MSDC_ClearBits32(MSDC_INTEN, MSDC_INTEN_DATTMO|MSDC_INTEN_DATCRCERR); |
| if (byte_len) |
| goto end; |
| intsts =MSDC_PollInts(MSDC_INT_XFER_COMPL|MSDC_INT_DATTMO|MSDC_INT_DATCRCERR,100); |
| MSDC_DEBUG("[SD][%s %d]intsts =%x \r\n",__FUNCTION__,__LINE__,intsts); |
| MSDC_CLR_FIFO(); |
| if (intsts&MSDC_INT_XFER_COMPL) |
| { |
| gMSDC_Handle->error=NO_ERROR; |
| } |
| else if (intsts&MSDC_INT_DATCRCERR){ |
| gMSDC_Handle->error=ERR_DAT_CRCERR; |
| } |
| else if (intsts&MSDC_INT_DATTMO) |
| { |
| gMSDC_Handle->error=ERR_DAT_TIMEOUT; |
| } |
| end: |
| if (gMSDC_Handle->error) |
| { |
| MSDC_FatalErrorHandle(); |
| } |
| |
| /*wait busy for write operation*/ |
| if (isWrite) |
| { |
| dbg_print("isWrite=%x ,go to MSDC_CheckCardBusy",isWrite); |
| MSDC_CheckCardBusy(KAL_FALSE,30*1000); |
| } |
| return gMSDC_Handle->error; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_WaitCardNotBusy |
| * |
| * DESCRIPTION |
| * Wait until card is not busy (R1b) |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * void |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * Interrupt driven and polling are both implemented |
| * |
| *************************************************************************/ |
| extern kal_bool FTL_isPollingMode(); |
| kal_uint32 direct_msdc_entry = 0; |
| |
| SDC_CMD_STATUS SD_WaitCardNotBusy(kal_uint32 timeout_ms) |
| { |
| if(MSDC_TIMEOUT_WAIT((!SD_IS_R1B_BUSY())&&MSDC_Check_Card_Present(),timeout_ms)) |
| { |
| gMSDC_Handle->error=ERR_CMD_TIMEOUT; |
| MSDC_ERR("[SD][%s %d]R1B busy timeout ,wait %d ms\r\n",__FUNCTION__,__LINE__,timeout_ms); |
| return ERR_CMD_TIMEOUT; |
| } |
| return NO_ERROR; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_CheckStatus |
| * |
| * DESCRIPTION |
| * Check command status |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_CheckStatus(void) |
| { |
| kal_uint32 status; |
| |
| status= MSDC_Reg32(SDC_RESP0); |
| if ((status & SDC_CSTA_MASK) == 0 ) |
| return NO_ERROR; |
| |
| MSDC_ERR("[SD][%s %d]check status<%x>\r\n",__FUNCTION__,__LINE__,status); |
| if (status & SDC_CARD_IS_LOCKED) |
| { |
| |
| return CARD_IS_LOCKED; |
| } |
| return ERR_STATUS; |
| |
| } |
| |
| |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_Send_Cmd |
| * |
| * DESCRIPTION |
| * to launch the command packet to the card |
| * |
| * PARAMETERS |
| * 1. cmd: the content of SDC_CMD register |
| * 2. arg: the argument(if the command need no argument, fill it with 0) |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * 1. Check if controller is available before launch any commands |
| * 2. Maybe add check if card is busy (R1b) |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_SendCmdOnly( kal_uint32 cmd, kal_uint32 arg,kal_uint32 timeout_ms) |
| { |
| kal_uint32 retry_count=0; |
| check_busy: |
| /*wait CMD busy and SDC busy*/ |
| if (cmd == SDC_CMD_CMD12||cmd==SDC_CMD_CMD13) |
| { |
| if (MSDC_TIMEOUT_WAIT((!SD_IS_CMD_BUSY()),timeout_ms)) |
| { |
| gMSDC_Handle->error=ERR_CMD_TIMEOUT; |
| MSDC_FatalErrorHandle(); |
| MSDC_ERR("[SD][%s %d]wait cmd busy timeout !!,retry %d times\r\n",__FUNCTION__,__LINE__,retry_count); |
| } |
| } |
| else |
| { |
| if (MSDC_TIMEOUT_WAIT((!SD_IS_SDC_BUSY()), timeout_ms)) |
| { |
| gMSDC_Handle->error=ERR_CMD_TIMEOUT; |
| MSDC_FatalErrorHandle(); |
| MSDC_ERR("[SD][%s %d]wait SDC busy %d ms timeout!!,retry %d times\r\n",__FUNCTION__,__LINE__,timeout_ms,retry_count); |
| goto retry; |
| } |
| } |
| if (gSD->mBKLength&&(gSD->mBKLength <= 0xfff)) |
| { |
| cmd|=(gSD->mBKLength<<16); |
| } |
| |
| /* If the card supports CMD23, enable AUTOCMD23 function of MSDC */ |
| if (((cmd & 0x3F) == 18) || ((cmd & 0x3F) == 25)) { |
| if ((gSD->mSCR.cmd_support >> 1) & 0x1) |
| cmd |= (2 << 28); |
| } |
| |
| MSDC_DEBUG("[SD]CMD=%d, arg=%X\r\n", cmd & 0x3F, arg); |
| |
| /*set argument*/ |
| MSDC_WriteReg32(SDC_ARG,arg); |
| /*set command*/ |
| MSDC_WriteReg32(SDC_CMD,cmd); |
| gMSDC_Handle->cmd = (kal_uint8)(cmd & 0x3F); |
| gMSDC_Handle->error=NO_ERROR; |
| return gMSDC_Handle->error; |
| |
| retry: |
| if ((!SD_IS_SDC_BUSY())&&(retry_count<3)){ |
| retry_count++; |
| goto check_busy; |
| } |
| return gMSDC_Handle->error; |
| |
| } |
| |
| #define MSDC_TUNE_CMD_RESP_TA_MAX (8) |
| #define MSDC_TUNE_INT_DAT_LATCH_CK_MAX (8) |
| #define MSDC_TUNE_WCRC_TA_MAX (8) |
| |
| static kal_uint8 fgCMDTuneLargeScale = 1; |
| static kal_uint32 times_large = 0; |
| static kal_uint32 times_small = 0; |
| |
| static kal_uint8 fgWrTuneLargeScale = 1; |
| static kal_uint32 times_large_w = 0; |
| static kal_uint32 times_small_w = 0; |
| |
| static kal_uint8 fgReadTuneLargeScale = 1; |
| static kal_uint32 times_large_r = 0; |
| static kal_uint32 times_small_r = 0; |
| |
| static kal_uint32 msdc_tune_cmd_retry(kal_uint32 cmd, kal_uint32 arg, kal_uint32 timeout_ms) |
| { |
| kal_uint32 result = ERR_CMD_RSPCRCERR; |
| |
| /* CMD12 CRCERR should not tune */ |
| if ((cmd & 0x3F) == 12) { |
| result = NO_ERROR; |
| goto done; |
| } |
| |
| /* Send 'STOP' command to complete 'TRANS' state */ |
| if (MSDC_Reg32(SDC_CMD)&0x1800) |
| { |
| /*check if has data phase*/ |
| result=SD_SendCmdOnly(SDC_CMD_CMD12,SDC_NO_ARG,1000); |
| result=SD_WaitCmdRdyOrTo(); |
| if (result!=NO_ERROR) |
| goto err; |
| } |
| |
| if (gMSDC_Handle->app_cmd) |
| { |
| /*for acmd ,we should send cmd55 again*/ |
| result=SD_SendCmdOnly(SDC_CMD_CMD55,gSD->mRCA,1000); |
| if (result!=NO_ERROR) |
| goto err; |
| result=SD_WaitCmdRdyOrTo(); |
| if (result!=NO_ERROR) |
| goto err; |
| } |
| |
| result=SD_SendCmdOnly(cmd,arg,timeout_ms); |
| |
| if (result!=NO_ERROR) |
| goto err; |
| |
| result=SD_WaitCmdRdyOrTo(); |
| if (result==NO_ERROR) |
| goto done; |
| if (result != ERR_CMD_RSPCRCERR) |
| goto err; |
| |
| err: |
| MSDC_FatalErrorHandle(); |
| done: |
| return result; |
| } |
| |
| kal_uint32 msdc_tune_cmd_large_scale() |
| { |
| kal_uint32 ret = 0; |
| kal_uint32 clk_mode, cmd_resp_ta_cntr, r_smpl; |
| |
| times_large++; |
| |
| MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, clk_mode); |
| MSDC_GET_FIELD(MSDC_PATCH_BIT1, MSDC_CMD_RSP_TA_CNTR, cmd_resp_ta_cntr); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, r_smpl); |
| |
| /* |
| * If MSDC_CFG.CLK_MODE = 1 && Bus_Speed > 100MHz |
| * that is ultra high speed mode, tune CMD_RESP_TA first |
| */ |
| if ((clk_mode == 1) || (clk_mode == 2) || |
| (gMSDC_Handle->op_clock >= MSDC_TUNE_UHS_SCLK)) { |
| cmd_resp_ta_cntr++; |
| MSDC_SET_FIELD(MSDC_PATCH_BIT1, MSDC_CMD_RSP_TA_CNTR, |
| cmd_resp_ta_cntr & (MSDC_TUNE_CMD_RESP_TA_MAX - 1)); |
| |
| if (cmd_resp_ta_cntr >= MSDC_TUNE_CMD_RESP_TA_MAX) { |
| r_smpl++; |
| MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, r_smpl % 2); |
| } |
| } |
| else { |
| /* |
| * In low speed mode, just tune R_SMPL |
| * and set MSDC_CMD_RSP_TA_CNTR back to 0 |
| */ |
| r_smpl++; |
| cmd_resp_ta_cntr = 0; |
| MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, r_smpl % 2); |
| MSDC_SET_FIELD(MSDC_PATCH_BIT1, MSDC_CMD_RSP_TA_CNTR, cmd_resp_ta_cntr & |
| (MSDC_TUNE_CMD_RESP_TA_MAX - 1)); |
| } |
| |
| /* Now all the parameters are set to 0 */ |
| if (r_smpl >= 2) |
| ret = 1; |
| |
| MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, clk_mode); |
| MSDC_GET_FIELD(MSDC_PATCH_BIT1, MSDC_CMD_RSP_TA_CNTR, cmd_resp_ta_cntr); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, r_smpl); |
| |
| MSDC_NOTICE("[SD] <TUNE_CMD_LS><%d> CKMOD=%d, CMD_RSP_TA=%d, R_SMPL=%d\r\n", |
| times_large, clk_mode, cmd_resp_ta_cntr, r_smpl); |
| |
| if (ret) |
| times_large = 0; |
| |
| return ret; |
| } |
| |
| kal_uint32 msdc_tune_cmd_small_scale() |
| { |
| kal_uint32 ret = 0; |
| kal_uint32 cmd_rxdly, clk_mode, cmd_resp_ta_cntr, r_smpl; |
| |
| times_small++; |
| MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, clk_mode); |
| MSDC_GET_FIELD(MSDC_PATCH_BIT1, MSDC_CMD_RSP_TA_CNTR, cmd_resp_ta_cntr); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, r_smpl); |
| MSDC_GET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY, cmd_rxdly); |
| |
| /* Adjust CMD_RXDLY in PAD macro */ |
| cmd_rxdly++; |
| MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY, cmd_rxdly & 0x1F); |
| |
| /* Adjust R_SMPL */ |
| if (cmd_rxdly >= 32) { |
| r_smpl++; |
| MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, r_smpl % 2); |
| } |
| |
| /* |
| * Adjust CMD_RSP_TA_CNTR |
| * if MSDC_CFG.CLK_MODE = 1 && Bus_Speed > 100MHz |
| */ |
| if (r_smpl >= 2) { |
| if ((clk_mode == 1) || (clk_mode == 2) || (gMSDC_Handle->op_clock >= MSDC_TUNE_UHS_SCLK)) { |
| cmd_resp_ta_cntr++; |
| MSDC_SET_FIELD(MSDC_PATCH_BIT1, MSDC_CMD_RSP_TA_CNTR, |
| cmd_resp_ta_cntr & (MSDC_TUNE_CMD_RESP_TA_MAX - 1)); |
| |
| if (cmd_resp_ta_cntr >= MSDC_TUNE_CMD_RESP_TA_MAX) |
| ret = 1; |
| } |
| else |
| ret= 1; |
| } |
| |
| MSDC_GET_FIELD(MSDC_PATCH_BIT1, MSDC_CMD_RSP_TA_CNTR, cmd_resp_ta_cntr); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, r_smpl); |
| MSDC_GET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY, cmd_rxdly); |
| |
| MSDC_NOTICE("[SD] <TUNE_CMD_SS><%d> CMD_RXDLY=%d, R_SMPL=%d, CMD_RSP_TA=%d\r\n", |
| times_small, cmd_rxdly, r_smpl, cmd_resp_ta_cntr); |
| |
| /* Now all the parameters are set to 0 */ |
| if (ret) |
| times_small = 0; |
| |
| return ret; |
| } |
| |
| SDC_CMD_STATUS SD_CmdTuneResp(kal_uint32 cmd,kal_uint32 arg,kal_uint32 timeout_ms) |
| { |
| kal_uint32 result = ERR_CMD_RSPCRCERR; |
| |
| do { |
| /* Retry the CMD with error handling */ |
| result = msdc_tune_cmd_retry(cmd, arg, timeout_ms); |
| |
| if ((result == ERR_CMD_TIMEOUT) || |
| (result == NO_ERROR)) { |
| if (result == NO_ERROR) { |
| if (times_large) |
| fgCMDTuneLargeScale = 0; |
| |
| times_small = 0; |
| } |
| goto done; |
| } |
| |
| /* Large scale timing tuning */ |
| if (fgCMDTuneLargeScale) { |
| if (msdc_tune_cmd_large_scale()) |
| fgCMDTuneLargeScale = 0; |
| } |
| /* Small scale timing tuning */ |
| else { |
| if (msdc_tune_cmd_small_scale()) |
| goto done; |
| } |
| |
| } while (1); |
| |
| done: |
| MSDC_CRIT("[SD] <TUNE_CMD%d_DONE>", cmd & 0x3F); |
| if (result == NO_ERROR) |
| MSDC_CRIT(" %s\r\n", "PASS"); |
| else if (result == ERR_CMD_RSPCRCERR) |
| MSDC_CRIT(" %s\r\n", "CRCERR"); |
| else if (result == ERR_CMD_TIMEOUT) |
| MSDC_CRIT(" %s\r\n", "TIMEOUT"); |
| |
| return result; |
| } |
| |
| SDC_CMD_STATUS SD_SendCmd(kal_uint32 cmd,kal_uint32 arg,kal_uint32 timeout_ms) |
| { |
| kal_uint32 status; |
| /*send command */ |
| status = SD_SendCmdOnly(cmd,arg,timeout_ms); |
| if (status!=NO_ERROR) |
| { |
| MSDC_ERR("[SD][%s %d]send cmd %d error \r\n",__FUNCTION__,__LINE__,cmd); |
| return status; |
| } |
| /*wait command complete*/ |
| status=SD_WaitCmdRdyOrTo(); |
| if (status != NO_ERROR) |
| { |
| MSDC_FatalErrorHandle(); |
| if (status == ERR_CMD_RSPCRCERR) |
| { |
| SD_CmdTuneResp(cmd, arg,timeout_ms); |
| } |
| status = gMSDC_Handle->error; |
| |
| return status; |
| } |
| if (cmd== SDC_CMD_CMD55 ) |
| { |
| gMSDC_Handle->app_cmd=1; |
| } |
| else |
| { |
| gMSDC_Handle->app_cmd=0; |
| |
| } |
| return status; |
| } |
| kal_uint32 SD_PioRead(kal_uint32 * buffer,kal_uint32 num) |
| { |
| kal_uint32 *ptr=buffer; |
| kal_uint8 *u8ptr; |
| kal_uint32 left; |
| ptr =buffer; |
| left=num; |
| while(left) |
| { |
| if ((left>=MSDC_FIFO_THD)&&(MSDC_RXFIFOCNT()>=MSDC_FIFO_THD)){ |
| int count =MSDC_FIFO_THD>>2; |
| do{ |
| *ptr++=MSDC_FIFO_READ32(); |
| }while(--count); |
| left-=MSDC_FIFO_THD; |
| |
| } |
| else if ((left<MSDC_FIFO_THD)&&(MSDC_RXFIFOCNT()>=left)) |
| { |
| while(left>3){ |
| *ptr++=MSDC_FIFO_READ32(); |
| left-=4; |
| } |
| u8ptr=(kal_uint8 *)ptr; |
| while(left){ |
| *u8ptr++=MSDC_FIFO_READ8(); |
| left--; |
| } |
| |
| if (gMSDC_Handle->abort){ |
| gMSDC_Handle->abort=0; |
| MSDC_ERR("[SD][%s %d]pio read abort!!, num= %d \r\n",__FUNCTION__,__LINE__,num); |
| goto end; |
| } |
| } |
| } |
| end: |
| return left; |
| } |
| |
| kal_uint32 SD_PioWrite(kal_uint32 * buffer,kal_uint32 num) |
| { |
| kal_uint32 * ptr=buffer; |
| kal_uint8 *u8ptr; |
| kal_uint32 left; |
| ptr=buffer; |
| left=num; |
| while(left){ |
| if (left >= MSDC_FIFO_SZ){ |
| if (MSDC_TXFIFOCNT()==0){ |
| int count =MSDC_FIFO_SZ>>2; |
| do { |
| MSDC_FIFO_WRITE32(*ptr); |
| ptr++; |
| }while(--count); |
| left-=MSDC_FIFO_SZ; |
| } |
| } |
| else if ((left<MSDC_FIFO_SZ)&&(MSDC_TXFIFOCNT()==0)){ |
| while(left){ |
| while(left>3){ |
| MSDC_FIFO_WRITE32(*ptr); |
| ptr++; |
| left-=4; |
| } |
| u8ptr=(kal_uint8 *)ptr; |
| while(left){ |
| MSDC_FIFO_WRITE8(*u8ptr); |
| u8ptr++; |
| left--; |
| } |
| } |
| } |
| if (gMSDC_Handle->abort) |
| { |
| gMSDC_Handle->abort=0; |
| MSDC_ERR("[SD][%s %d]pio write abort %d \r\n",__FUNCTION__,__LINE__,num); |
| goto done; |
| } |
| } |
| |
| done: |
| return left; |
| } |
| |
| #if !defined(MSDC_QMU_ENABLE) |
| static kal_uint8 msdc_cal_checksum(const void *buf,kal_uint32 len) |
| { |
| kal_uint32 i,sum=0; |
| kal_char *data=(char*)buf; |
| for(i=0;i<len;i++) |
| { |
| sum+=*data++; |
| } |
| return 0xFF-(kal_uint8)sum; |
| } |
| #endif |
| |
| static DCL_STATUS SD_ConfigGpdList(kal_uint32 size) |
| { |
| #if !defined(MSDC_QMU_ENABLE) |
| kal_uint32 i,buflen,data_count; |
| kal_uint32 * data_ptr; |
| kal_uint32 t1; |
| qbm_gpd* cur_gpd=NULL,*cur_bd=NULL; |
| msdc_gpd_t *gpd; |
| msdc_gpd_t *gpd_end; |
| qbm_gpd *head; |
| qbm_gpd *tail; |
| kal_uint8 sel = 0; |
| |
| #define CONFIG_GPDLIST_TIMEOUT 10000 |
| |
| head = MSDC_Blk[sel].head; |
| tail = MSDC_Blk[sel].tail; |
| gpd = MSDC_Blk[sel].gpd; |
| gpd_end = MSDC_Blk[sel].gpd_end; |
| |
| gpd->intr =1; /*don't generate DMA_done interrupt*/ |
| gpd->extlen =0; /*ignore cmd,arg etc*/ |
| gpd->hwo =1; /*config hardware owner*/ |
| gpd->bdp =1; /*use buffer descriptor list*/ |
| gpd->ptr =(void*)(&MSDC_bd[sel][0]); |
| gpd->next =(void*)gpd_end; |
| |
| #ifdef MSDC_DMA_CHKSUM_EN |
| gpd->chksum =0; |
| gpd->chksum =msdc_cal_checksum(gpd,16); |
| #endif |
| |
| gpd_end->intr =0; /*don't generate DMA_done interrupt*/ |
| gpd_end->extlen =0; /*ignore cmd,arg etc*/ |
| gpd_end->hwo =0; /*config hardware owner*/ |
| gpd_end->bdp =0; /*use buffer descriptor list*/ |
| gpd_end->ptr =0; |
| gpd_end->next =NULL; |
| |
| #ifdef MSDC_DMA_CHKSUM_EN |
| gpd_end->chksum =0; |
| gpd_end->chksum =msdc_cal_checksum(gpd_end,16); |
| #endif |
| |
| data_count = 0; |
| t1 = drv_get_current_time(); |
| |
| for (i=0,cur_gpd=head;;cur_gpd=QBM_DES_GET_NEXT(cur_gpd)) { |
| if (i > MSDC_BD_MAX) |
| { |
| MSDC_ERR("[%s %d]qbm_gpd list is to long,only supprot %d object \r\n",__FUNCTION__,__LINE__,MSDC_BD_MAX); |
| return STATUS_INVALID_ARGUMENT; |
| } |
| |
| /* NULL pointer check */ |
| if (cur_gpd == NULL) { |
| MSDC_ERR("[%s %d]cur_gpd is NULL pointer!\r\n",__FUNCTION__,__LINE__); |
| return STATUS_INVALID_ARGUMENT; |
| } |
| |
| if (QBM_DES_GET_BDP(cur_gpd)) |
| { |
| // if GPD with BD with data buffer |
| cur_bd=QBM_DES_GET_DATAPTR(cur_gpd); |
| while(1) |
| { |
| buflen=QBM_DES_GET_DATALEN(cur_bd); |
| data_ptr=(kal_uint32 *)QBM_DES_GET_DATAPTR(cur_bd); |
| if ((data_count+buflen)>size) |
| { //if buffer length is large the secotors we want to transfer |
| buflen=size-data_count; |
| data_count=size; |
| } |
| else |
| { |
| data_count+=buflen; |
| } |
| if (buflen) |
| { // if point to a buffer adress on this BD |
| |
| if (((cur_gpd==tail)&&(QBM_DES_GET_EOL(cur_bd)))||(data_count==size)) |
| MSDC_bd[sel][i].eol =1; |
| else |
| MSDC_bd[sel][i].eol =0; |
| MSDC_bd[sel][i].next =&MSDC_bd[sel][i+1]; |
| MSDC_bd[sel][i].ptr =data_ptr; |
| MSDC_bd[sel][i].buflen =buflen; |
| clean_and_invalidate_dcache(CPU_CACHE_LINE_ALIGN_ADDR((kal_uint32)data_ptr),CPU_CACHE_LINE_ALIGN_LEN((kal_uint32)data_ptr,buflen)); |
| MSDC_bd[sel][i].blkpad =0; |
| MSDC_bd[sel][i].dwpad =0; |
| MSDC_bd[sel][i].chksum=0; |
| MSDC_bd[sel][i].chksum=msdc_cal_checksum(&MSDC_bd[sel][i],16); |
| i++; |
| } |
| if(QBM_DES_GET_EOL(cur_bd)) |
| { |
| break; |
| } |
| cur_bd=QBM_DES_GET_NEXT(cur_bd); |
| } |
| } |
| else |
| { |
| // if GPD with data buffer |
| buflen=QBM_DES_GET_DATALEN(cur_gpd); |
| //dbg_print("%d buflen=%d\r\n",i,buflen); |
| data_ptr=(kal_uint32 *)QBM_DES_GET_DATAPTR(cur_gpd); |
| if ((data_count+buflen)>size) |
| { |
| buflen=size-data_count; |
| data_count=size; |
| //dbg_print("entry last data_count %d,buflen %d size %d\r\n",data_count,buflen,size); |
| } |
| else |
| { |
| data_count+=buflen; |
| } |
| if (buflen) |
| { |
| if (cur_gpd==tail||data_count==size) |
| MSDC_bd[sel][i].eol =1; |
| else |
| MSDC_bd[sel][i].eol =0; |
| MSDC_bd[sel][i].next =&MSDC_bd[sel][i+1]; |
| MSDC_bd[sel][i].ptr =data_ptr; |
| MSDC_bd[sel][i].buflen =buflen; |
| |
| /* |
| * There is NO need to clean the data cache, which is transfered |
| * from MSD and USB, because the buffer is directly read or write |
| * by DMA, CPU are not involved in. |
| */ |
| #if defined(MSDC_SCAT_BUF_FLUSH) || defined(ATEST_DRV_MSDC) |
| clean_and_invalidate_dcache(CPU_CACHE_LINE_ALIGN_ADDR((kal_uint32)data_ptr),CPU_CACHE_LINE_ALIGN_LEN((kal_uint32)data_ptr,buflen)); |
| #endif |
| |
| MSDC_bd[sel][i].blkpad =0; |
| MSDC_bd[sel][i].dwpad =0; |
| |
| #ifdef MSDC_DMA_CHKSUM_EN |
| MSDC_bd[sel][i].chksum=0; |
| MSDC_bd[sel][i].chksum=msdc_cal_checksum(&MSDC_bd[sel][i], 16); |
| #endif |
| |
| i++; |
| } |
| } |
| if (cur_gpd==tail) |
| break; |
| |
| } |
| |
| if (drv_get_duration_ms(t1)>CONFIG_GPDLIST_TIMEOUT) |
| { |
| MSDC_INFO("[%s %d]config gpd list timeout\r\n",__FUNCTION__,__LINE__,MSDC_BD_MAX); |
| return STATUS_INVALID_ARGUMENT; |
| } |
| |
| //if data buffer is not enough |
| if (data_count!=size) |
| { |
| MSDC_INFO("[%s %d]data_count %d,size %d\r\n",__FUNCTION__,__LINE__,data_count,size); |
| return STATUS_INVALID_ARGUMENT; |
| } |
| |
| /* Flush the GPD and BD from cache to memory */ |
| #ifdef MSDC_GPD_BD_BUF_CACHED |
| clean_and_invalidate_dcache(CPU_CACHE_LINE_ALIGN_ADDR((kal_uint32)gpd), |
| CPU_CACHE_LINE_ALIGN_LEN((kal_uint32)gpd, sizeof(msdc_gpd_t))); |
| clean_and_invalidate_dcache(CPU_CACHE_LINE_ALIGN_ADDR((kal_uint32)gpd_end), |
| CPU_CACHE_LINE_ALIGN_LEN((kal_uint32)gpd_end, sizeof(msdc_gpd_t))); |
| clean_and_invalidate_dcache(CPU_CACHE_LINE_ALIGN_ADDR((kal_uint32)&MSDC_bd[sel][0]), |
| CPU_CACHE_LINE_ALIGN_LEN((kal_uint32)&MSDC_bd[sel][0], i * sizeof(msdc_bd_t))); |
| #endif |
| |
| return STATUS_OK; |
| |
| #else |
| |
| qbm_gpd *head, *tail, *tail_bak, *p_bps_gpd, *p_cur_gpd; |
| kal_uint8 sel = 0; |
| |
| head = MSDC_Blk[sel].head; |
| tail = MSDC_Blk[sel].tail; |
| tail_bak = tail; |
| |
| /* In case of normal transfer */ |
| if (!gMSDC_Handle->f_tuning) { |
| p_bps_gpd = g_p_msdc_bps[sel]; |
| if (!p_bps_gpd) { |
| MSDC_ERR("[%s %d]Invalid loacal bypass GPD buffer!\r\n",__FUNCTION__,__LINE__); |
| return STATUS_FAIL; |
| } |
| |
| /* Link the bypass GPD to tail */ |
| qbmt_common_en_q_rx(p_bps_gpd, p_bps_gpd, (void **)&head, (void **)&tail); |
| |
| /* Set HWO = 1, cause it is cleared by USB QMU */ |
| p_cur_gpd = head; |
| do { |
| if (p_cur_gpd == tail_bak) |
| break; |
| |
| QBM_DES_SET_HWO(p_cur_gpd); |
| QBM_CACHE_FLUSH(p_cur_gpd, 2); |
| |
| p_cur_gpd = p_cur_gpd->p_next; |
| } while(1); |
| } |
| /* In case of re-try on tuning */ |
| else { |
| p_cur_gpd = head; |
| |
| /* Re-Set HWO = 1, and flush cache */ |
| do { |
| QBM_DES_SET_HWO(p_cur_gpd); |
| QBM_CACHE_FLUSH(p_cur_gpd, sizeof(qbm_gpd)); |
| |
| if ((p_cur_gpd == tail)) |
| break; |
| |
| p_cur_gpd = p_cur_gpd->p_next; |
| |
| } while(1); |
| } |
| |
| /* Set the QMU start address */ |
| gMSDC_Handle->buf_addr = (void *)MSDC_Blk[sel].head; |
| |
| return STATUS_OK; |
| |
| #endif |
| } |
| |
| SDC_CMD_STATUS SD_ReqHandleData(kal_uint32 data_adrs, void* buffer, kal_uint32 num,kal_bool isWrite,kal_bool isLinkListBuf) |
| { |
| kal_uint32 status ; |
| kal_bool dma; |
| kal_uint32 intsts; |
| kal_uint8 cmd23_sup = 0; |
| |
| MSDC_INFO("[SD]SD_Req: CMD%s Addr=%x BlkNum=%d Buf=%x\r\n", |
| isWrite ? "25(24)" : "18(17)", data_adrs, num, buffer); |
| |
| /*Set block size and block num*/ |
| if (gSD->mBKLength!=512) |
| { |
| status =SD_SetBlength(512); |
| if (status != NO_ERROR) |
| { |
| return status; |
| } |
| |
| } |
| MSDC_WriteReg32(SDC_BLK_NUM,num); |
| /*set read timeout*/ |
| /*check we use dma or pio*/ |
| if(gSD->mBKLength*num <512) |
| { |
| /*use pio*/ |
| dma=0; |
| //set to PIO mode |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 1, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=0; |
| } |
| else |
| { |
| /*use dma*/ |
| dma=1; |
| //set to DMA mode |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 0, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=1; |
| } |
| |
| dma=1; /*driver unsupport PIO now*/ |
| gMSDC_Handle->dma_xfer=1; |
| if (dma) |
| { |
| kal_set_eg_events(gMSDC_Handle->MSDC_Events, 0,KAL_AND); |
| /*enable DMA*/ |
| MSDC_ClearBits32(MSDC_CFG,MSDC_CFG_PIO); |
| /*start command*/ |
| if (!isWrite) |
| { |
| if (num==1) |
| { |
| status=SD_SendCmdOnly(SDC_CMD_CMD17,data_adrs,MSDC_CMD_TIMEOUT); |
| } |
| else |
| { |
| status=SD_SendCmdOnly(SDC_CMD_CMD18,data_adrs,MSDC_CMD_TIMEOUT); |
| } |
| } |
| else |
| { |
| if (num==1) |
| { |
| status=SD_SendCmdOnly(SDC_CMD_CMD24,data_adrs,MSDC_CMD_TIMEOUT); |
| } |
| else |
| { |
| status=SD_SendCmdOnly(SDC_CMD_CMD25,data_adrs,MSDC_CMD_TIMEOUT); |
| } |
| } |
| if (status !=NO_ERROR) |
| { |
| goto done; |
| } |
| /*map dma data*/ |
| |
| /*config dma*/ |
| gMSDC_Handle->total_count=num*gSD->mBKLength; |
| gMSDC_Handle->buf_addr=buffer; |
| |
| if (isLinkListBuf) { |
| status = SD_ConfigGpdList(gMSDC_Handle->total_count); |
| if (status != STATUS_OK) { |
| MSDC_ERR("[%s %d]Config GPD list fail!\r\n",__FUNCTION__,__LINE__); |
| return status; |
| } |
| } |
| |
| MSDC_DMATransferFirst(isWrite,isLinkListBuf); |
| |
| /*wait cmd rsp*/ |
| status=SD_WaitCmdRdyOrTo(); |
| if (status != NO_ERROR) |
| { |
| MSDC_FatalErrorHandle(); |
| if (status == ERR_CMD_RSPCRCERR) |
| { |
| if (!isWrite) |
| { if (num==1) |
| status=SD_CmdTuneResp(SDC_CMD_CMD17, data_adrs,MSDC_CMD_TIMEOUT); |
| else |
| status=SD_CmdTuneResp(SDC_CMD_CMD18, data_adrs,MSDC_CMD_TIMEOUT); |
| } |
| else |
| { |
| if(num==1) |
| status=SD_CmdTuneResp(SDC_CMD_CMD24, data_adrs,MSDC_CMD_TIMEOUT); |
| else |
| status=SD_CmdTuneResp(SDC_CMD_CMD25, data_adrs,MSDC_CMD_TIMEOUT); |
| } |
| } |
| if(status != NO_ERROR) |
| goto done; |
| } |
| /*start dma and wait data complete*/ |
| status = MSDC_DMATransferFinal(isWrite,isLinkListBuf); |
| } |
| else |
| { |
| /*pio mode*/ |
| if (SD_SendCmd(((isWrite==KAL_TRUE) ?SDC_CMD_CMD25:SDC_CMD_CMD18),data_adrs,MSDC_CMD_TIMEOUT)) |
| { |
| goto done; |
| } |
| MSDC_SetBits32(MSDC_INTEN,MSDC_INTEN_DATTMO|MSDC_INTEN_DATCRCERR); |
| if(!isWrite) |
| { |
| /*poll to read data from FIFO*/ |
| status =SD_PioRead(buffer,num*gSD->mBKLength); |
| } |
| else |
| { |
| /*poll to write data to FIFO*/ |
| status =SD_PioWrite(buffer,num*gSD->mBKLength); |
| } |
| |
| MSDC_ClearBits32(MSDC_INTEN, MSDC_INTEN_DATTMO|MSDC_INTEN_DATCRCERR); |
| if (status) |
| { |
| goto done; |
| } |
| intsts =MSDC_PollInts(MSDC_INT_XFER_COMPL|MSDC_INT_DATTMO|MSDC_INT_DATCRCERR,100); |
| if (intsts&MSDC_INT_XFER_COMPL) |
| { |
| status=gMSDC_Handle->error=NO_ERROR; |
| } |
| else if (intsts&MSDC_INT_DATCRCERR){ |
| status=gMSDC_Handle->error=ERR_DAT_CRCERR; |
| } |
| else if (intsts&MSDC_INT_DATTMO) |
| { |
| status=gMSDC_Handle->error=ERR_DAT_TIMEOUT; |
| } |
| else |
| MSDC_ERR("[SD][%s %d]SW timeout in wait PIO data done\r\n",__FUNCTION__,__LINE__); |
| } |
| done: |
| if (status) |
| { |
| MSDC_FatalErrorHandle(); |
| } |
| |
| /*cmd12 to stop data*/ |
| cmd23_sup = (gSD->mSCR.cmd_support >> 1) & 0x1; |
| if (((num>1) && !cmd23_sup) || ((num>1) && cmd23_sup && status)) |
| SD_SendCmd(SDC_CMD_CMD12, SDC_NO_ARG, MSDC_CMD_TIMEOUT); |
| |
| /* Check card status after each operation */ |
| MSDC_CheckCardBusy(KAL_FALSE, 10*1000); |
| |
| return status; |
| } |
| |
| kal_uint32 msdc_tune_write_large_scale() |
| { |
| kal_uint32 ret = 0; |
| kal_uint32 ultra_hs = 0; |
| kal_uint32 clk_mode, wr_datcrc_ta, w_d_smpl; |
| |
| times_large_w++; |
| |
| MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, clk_mode); |
| MSDC_GET_FIELD(MSDC_PATCH_BIT1, MSDC_WRDAT_CRCS_TA_CNTR, wr_datcrc_ta); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_WDSPL, w_d_smpl); |
| |
| /* |
| * If MSDC_CFG.CLK_MODE = 1 && Bus_Speed > 100MHz |
| * that is ultra high speed mode, tune WRDAT_CRCS_TA_CNTR first |
| */ |
| if ((clk_mode == 1) || (clk_mode == 2) || (gMSDC_Handle->op_clock > MSDC_TUNE_UHS_SCLK)) |
| ultra_hs = 1; |
| |
| if (ultra_hs) { |
| wr_datcrc_ta++; |
| MSDC_SET_FIELD(MSDC_PATCH_BIT1, MSDC_WRDAT_CRCS_TA_CNTR, |
| wr_datcrc_ta & (MSDC_TUNE_WCRC_TA_MAX - 1)); |
| |
| if (wr_datcrc_ta >= MSDC_TUNE_WCRC_TA_MAX) { |
| w_d_smpl++; |
| MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_WDSPL, w_d_smpl % 2); |
| } |
| } |
| else { |
| w_d_smpl++; |
| wr_datcrc_ta = 0; |
| MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_WDSPL, w_d_smpl % 2); |
| MSDC_SET_FIELD(MSDC_PATCH_BIT1, MSDC_WRDAT_CRCS_TA_CNTR, |
| wr_datcrc_ta & (MSDC_TUNE_WCRC_TA_MAX - 1)); |
| } |
| |
| if (w_d_smpl >= 2) { |
| ret = 1; |
| } |
| |
| MSDC_GET_FIELD(MSDC_PATCH_BIT1, MSDC_WRDAT_CRCS_TA_CNTR, wr_datcrc_ta); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_WDSPL, w_d_smpl); |
| |
| MSDC_NOTICE("[SD] <TUNE_WR_LS><%d> %s=%d, %s=%d, %s=%d\r\n", |
| times_large_w, "CKMOD", clk_mode, |
| "WR_DATCRC_TA", wr_datcrc_ta, "W_D_SMPL", w_d_smpl); |
| |
| if (ret) |
| times_large_w = 0; |
| |
| return ret; |
| } |
| |
| kal_uint32 msdc_tune_write_small_scale() |
| { |
| kal_uint32 ret = 0; |
| kal_uint32 ultra_hs = 0; |
| kal_uint32 clk_mode, wr_datcrc_ta, w_d_smpl, dat0_rd_dly, dat_wr_rxdly; |
| |
| times_small_w++; |
| |
| /* |
| * When re-enter the tuning flow, |
| * Clear the pad macro then tune from the beginning |
| */ |
| if (times_small_w == 1) { |
| MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, 0); |
| } |
| |
| MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, clk_mode); |
| MSDC_GET_FIELD(MSDC_PATCH_BIT1, MSDC_WRDAT_CRCS_TA_CNTR, wr_datcrc_ta); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_WDSPL, w_d_smpl); |
| MSDC_GET_FIELD(MSDC_DAT_RDDLY0, MSDC_DAT_RDDLY0_D0, dat0_rd_dly); |
| MSDC_GET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, dat_wr_rxdly); |
| |
| /* |
| * If MSDC_CFG.CLK_MODE = 1 && Bus_Speed > 100MHz |
| * that is ultra high speed mode, tune WRDAT_CRCS_TA_CNTR |
| * and PAT_DAT_WR_RXDLY at last |
| */ |
| if ((clk_mode == 1) || (clk_mode == 2) || (gMSDC_Handle->op_clock > MSDC_TUNE_UHS_SCLK)) |
| ultra_hs = 1; |
| |
| dat_wr_rxdly++; |
| MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, dat_wr_rxdly & 0x1F); |
| |
| if (dat_wr_rxdly >= 32) { |
| w_d_smpl++; |
| MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_WDSPL, w_d_smpl % 2); |
| } |
| |
| if (ultra_hs) { |
| if (w_d_smpl >= 2) { |
| wr_datcrc_ta++; |
| MSDC_SET_FIELD(MSDC_PATCH_BIT1, MSDC_WRDAT_CRCS_TA_CNTR, |
| wr_datcrc_ta & (MSDC_TUNE_WCRC_TA_MAX - 1)); |
| } |
| |
| if (wr_datcrc_ta >= MSDC_TUNE_WCRC_TA_MAX) |
| ret = 1; |
| } |
| |
| if (w_d_smpl >= 2) |
| ret = 1; |
| |
| MSDC_GET_FIELD(MSDC_PATCH_BIT1, MSDC_WRDAT_CRCS_TA_CNTR, wr_datcrc_ta); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_WDSPL, w_d_smpl); |
| MSDC_GET_FIELD(MSDC_DAT_RDDLY0, MSDC_DAT_RDDLY0_D0, dat0_rd_dly); |
| MSDC_GET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, dat_wr_rxdly); |
| |
| MSDC_NOTICE("[SD] <TUNE_WR_SS><%d> %s=%d, %s=%d, %s=%d\r\n", |
| times_small_w, "CKMOD", clk_mode, |
| "WR_DATCRC_TA", wr_datcrc_ta, "W_D_SMPL", w_d_smpl); |
| MSDC_NOTICE(" %s=%d, %s=%d\r\n", |
| "DAT0_RD_DLY", dat0_rd_dly, "DAT_WR_RXDLY", dat_wr_rxdly); |
| |
| if (ret) |
| times_small_w = 0; |
| |
| return ret; |
| } |
| |
| kal_uint32 SD_TuneWrite(kal_uint32 address,void * txbuffer,kal_uint32 num,kal_bool isLinkListBuf) |
| { |
| kal_uint32 result = ERR_DAT_CRCERR; |
| |
| do { |
| /* Retry the Write with error handling */ |
| result = SD_ReqHandleData(address,txbuffer,num,KAL_TRUE,isLinkListBuf); |
| |
| if (/*(result == ERR_DAT_TIMEOUT) ||*/ |
| (result == NO_ERROR)) { |
| if (times_large_w) |
| fgWrTuneLargeScale = 0; |
| |
| times_small_w = 0; |
| |
| goto done; |
| } |
| |
| /* Large scale timing tuning */ |
| if (fgWrTuneLargeScale) { |
| if (msdc_tune_write_large_scale()) |
| fgWrTuneLargeScale = 0; |
| } |
| /* Small scale timing tuning */ |
| else { |
| if (msdc_tune_write_small_scale()) |
| goto done; |
| } |
| |
| } while (1); |
| |
| done: |
| MSDC_CRIT("[SD] <TUNE_WRITE_DONE>"); |
| if (result == NO_ERROR) |
| MSDC_CRIT(" %s\r\n", "PASS"); |
| else if (result == ERR_DAT_CRCERR) |
| MSDC_CRIT(" %s\r\n", "CRCERR"); |
| else if (result == ERR_DAT_TIMEOUT) |
| MSDC_CRIT(" %s\r\n", "TIMEOUT"); |
| |
| return result; |
| } |
| |
| |
| kal_uint32 msdc_tune_read_large_scale() |
| { |
| kal_uint32 ret = 0; |
| kal_uint32 ultra_hs = 0; |
| kal_uint32 clk_mode, int_dat_latch, ckgen_dly, r_d_smpl; |
| |
| times_large_r++; |
| |
| MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, clk_mode); |
| MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, int_dat_latch); |
| MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, ckgen_dly); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RDSPL, r_d_smpl); |
| |
| /* |
| * If MSDC_CFG.CLK_MODE = 1 && Bus_Speed > 100MHz |
| * that is ultra high speed mode, tune INT_DAT_LATCH_CK_SEL |
| * and CKGEN_MSDC_DLY_SEL first |
| */ |
| if ((clk_mode == 1) || (clk_mode == 2) || (gMSDC_Handle->op_clock > MSDC_TUNE_UHS_SCLK)) |
| ultra_hs = 1; |
| |
| if (ultra_hs) { |
| /* Sampling edge is fixed by default setting - rising edge */ |
| int_dat_latch++; |
| MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, |
| int_dat_latch & (MSDC_TUNE_INT_DAT_LATCH_CK_MAX - 1)); |
| |
| if (int_dat_latch >= MSDC_TUNE_INT_DAT_LATCH_CK_MAX) { |
| ckgen_dly++; |
| MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, ckgen_dly & 0x1F); |
| |
| if (ckgen_dly >= 32) |
| ret = 1; |
| } |
| } |
| else { |
| /* |
| * In low speed mode, just tune R_D_SMPL |
| * and set other parameters back to 0 |
| */ |
| r_d_smpl++; |
| int_dat_latch = 0; |
| ckgen_dly = 0; |
| MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RDSPL, r_d_smpl % 2); |
| MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, |
| int_dat_latch & (MSDC_TUNE_INT_DAT_LATCH_CK_MAX - 1)); |
| MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, ckgen_dly & 0x1F); |
| |
| } |
| |
| if (r_d_smpl >= 2) |
| ret = 1; |
| |
| MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, int_dat_latch); |
| MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, ckgen_dly); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RDSPL, r_d_smpl); |
| |
| MSDC_NOTICE("[SD] <TUNE_RD_LS><%d> %s=%d, %s=%d, %s=%d, %s=%d\r\n", |
| times_large_r, "CKMOD", clk_mode, |
| "INT_DAT_L", int_dat_latch, "CKGEN_DLY", ckgen_dly, |
| "R_D_SMPL", r_d_smpl); |
| |
| if (ret) |
| times_large_r = 0; |
| |
| return ret; |
| |
| } |
| |
| kal_uint32 msdc_tune_read_small_scale() |
| { |
| kal_uint32 ret = 0; |
| kal_uint32 ultra_hs = 0; |
| kal_uint32 clk_mode, int_dat_latch, ckgen_dly, r_d_smpl, dat_rddly0, dat_rddly1; |
| kal_uint32 dat0_rd_dly, dat1_rd_dly, dat2_rd_dly, dat3_rd_dly; |
| kal_uint32 dat4_rd_dly, dat5_rd_dly, dat6_rd_dly, dat7_rd_dly; |
| |
| kal_uint32 ddr = 0, dcrc_sts; |
| |
| times_small_r++; |
| |
| MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, clk_mode); |
| |
| /* |
| * If MSDC_CFG.CLK_MODE = 1 && Bus_Speed > 100MHz |
| * that is ultra high speed mode, tune INT_DAT_LATCH_CK_SEL |
| * and CKGEN_MSDC_DLY_SEL at last |
| */ |
| if ((clk_mode == 1) || (clk_mode == 2) || (gMSDC_Handle->op_clock > MSDC_TUNE_UHS_SCLK)) |
| ultra_hs = 1; |
| |
| /* |
| * When re-enter the tune in Non-UHS mode, |
| * Clear the pad macro then tune from the beginning |
| */ |
| if ((times_small_r == 1) && (ultra_hs == 0)) { |
| MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RDSPL, 0); |
| MSDC_WriteReg32(MSDC_DAT_RDDLY0, 0); |
| MSDC_WriteReg32(MSDC_DAT_RDDLY1, 0); |
| } |
| |
| MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, int_dat_latch); |
| MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, ckgen_dly); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RDSPL, r_d_smpl); |
| dat_rddly0 = MSDC_Reg32(MSDC_DAT_RDDLY0); |
| dat_rddly1 = MSDC_Reg32(MSDC_DAT_RDDLY1); |
| |
| /* Get data CRC status */ |
| MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_NEG | SDC_DCRC_STS_POS, dcrc_sts); |
| |
| /* Check output clock is SDR mode or DDR mode */ |
| ddr = (clk_mode == 2) ? 1 : 0; |
| if (!ddr) |
| dcrc_sts &= ~SDC_DCRC_STS_NEG; |
| |
| /* Tune PAD macro first */ |
| MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1); |
| |
| dat0_rd_dly = (dat_rddly0 >> 24) & 0x1F; |
| dat1_rd_dly = (dat_rddly0 >> 16) & 0x1F; |
| dat2_rd_dly = (dat_rddly0 >> 8) & 0x1F; |
| dat3_rd_dly = (dat_rddly0 >> 0) & 0x1F; |
| dat4_rd_dly = (dat_rddly1 >> 24) & 0x1F; |
| dat5_rd_dly = (dat_rddly1 >> 16) & 0x1F; |
| dat6_rd_dly = (dat_rddly1 >> 8) & 0x1F; |
| dat7_rd_dly = (dat_rddly1 >> 0) & 0x1F; |
| |
| if (ddr) { |
| dat0_rd_dly = (dcrc_sts & (1 << 0) || dcrc_sts & (1 << 8)) ? (dat0_rd_dly + 1) : dat0_rd_dly; |
| dat1_rd_dly = (dcrc_sts & (1 << 1) || dcrc_sts & (1 << 9)) ? (dat1_rd_dly + 1) : dat1_rd_dly; |
| dat2_rd_dly = (dcrc_sts & (1 << 2) || dcrc_sts & (1 << 10)) ? (dat2_rd_dly + 1) : dat2_rd_dly; |
| dat3_rd_dly = (dcrc_sts & (1 << 3) || dcrc_sts & (1 << 11)) ? (dat3_rd_dly + 1) : dat3_rd_dly; |
| dat4_rd_dly = (dcrc_sts & (1 << 4) || dcrc_sts & (1 << 12)) ? (dat4_rd_dly + 1) : dat4_rd_dly; |
| dat5_rd_dly = (dcrc_sts & (1 << 5) || dcrc_sts & (1 << 13)) ? (dat5_rd_dly + 1) : dat5_rd_dly; |
| dat6_rd_dly = (dcrc_sts & (1 << 6) || dcrc_sts & (1 << 14)) ? (dat6_rd_dly + 1) : dat6_rd_dly; |
| dat7_rd_dly = (dcrc_sts & (1 << 7) || dcrc_sts & (1 << 15)) ? (dat7_rd_dly + 1) : dat7_rd_dly; |
| } else { |
| dat0_rd_dly = (dcrc_sts & (1 << 0)) ? (dat0_rd_dly + 1) : dat0_rd_dly; |
| dat1_rd_dly = (dcrc_sts & (1 << 1)) ? (dat1_rd_dly + 1) : dat1_rd_dly; |
| dat2_rd_dly = (dcrc_sts & (1 << 2)) ? (dat2_rd_dly + 1) : dat2_rd_dly; |
| dat3_rd_dly = (dcrc_sts & (1 << 3)) ? (dat3_rd_dly + 1) : dat3_rd_dly; |
| dat4_rd_dly = (dcrc_sts & (1 << 4)) ? (dat4_rd_dly + 1) : dat4_rd_dly; |
| dat5_rd_dly = (dcrc_sts & (1 << 5)) ? (dat5_rd_dly + 1) : dat5_rd_dly; |
| dat6_rd_dly = (dcrc_sts & (1 << 6)) ? (dat6_rd_dly + 1) : dat6_rd_dly; |
| dat7_rd_dly = (dcrc_sts & (1 << 7)) ? (dat7_rd_dly + 1) : dat7_rd_dly; |
| } |
| |
| dat_rddly0 = ((dat0_rd_dly & 0x1F) << 24) | ((dat1_rd_dly & 0x1F) << 16) | |
| ((dat2_rd_dly & 0x1F) << 8) | ((dat3_rd_dly & 0x1F) << 0); |
| dat_rddly1 = ((dat4_rd_dly & 0x1F) << 24) | ((dat5_rd_dly & 0x1F) << 16) | |
| ((dat6_rd_dly & 0x1F) << 8) | ((dat7_rd_dly & 0x1F) << 0); |
| |
| MSDC_WriteReg32(MSDC_DAT_RDDLY0, dat_rddly0); |
| MSDC_WriteReg32(MSDC_DAT_RDDLY1, dat_rddly1); |
| |
| /* Then R_D_SMPL */ |
| if( (dat0_rd_dly >= 32) || (dat1_rd_dly >= 32) || (dat2_rd_dly >= 32) || (dat3_rd_dly >= 32)|| |
| (dat4_rd_dly >= 32) || (dat5_rd_dly >= 32) || (dat6_rd_dly >= 32) || (dat7_rd_dly >= 32)){ |
| |
| /* |
| * On ultra-hs mode, do NOT tune sampling edge, |
| * because of the 'internal boundary' issue of the current IP |
| */ |
| if (!ultra_hs) { |
| r_d_smpl++; |
| MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RDSPL, r_d_smpl % 2); |
| } |
| |
| /* Re-tune the data pad macro */ |
| MSDC_WriteReg32(MSDC_DAT_RDDLY0, 0); |
| MSDC_WriteReg32(MSDC_DAT_RDDLY1, 0); |
| |
| /* Then CKGEN_MSDC_DLY_SEL if it is SDR104 mode */ |
| if (ultra_hs) { |
| ckgen_dly++; |
| MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, ckgen_dly & 0x1F); |
| |
| if (ckgen_dly >= 32) |
| ret = 1; |
| } |
| else { |
| if (r_d_smpl >= 2) |
| ret = 1; |
| } |
| |
| } |
| |
| MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, int_dat_latch); |
| MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, ckgen_dly); |
| MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RDSPL, r_d_smpl); |
| dat_rddly0 = MSDC_Reg32(MSDC_DAT_RDDLY0); |
| dat_rddly1 = MSDC_Reg32(MSDC_DAT_RDDLY1); |
| |
| MSDC_NOTICE("[SD] <TUNE_RD_SS><%d> %s=%d, %s=%d, %s=%d, %s=%d\r\n", |
| times_small_r, "CKMOD", clk_mode, |
| "INT_DAT_L", int_dat_latch, "CKGEN_DLY", ckgen_dly, |
| "R_D_SMPL", r_d_smpl); |
| MSDC_NOTICE(" %s=0x%x, %s=0x%x\r\n", |
| "DAT_RDDLY0", dat_rddly0, "DAT_RDDLY1", dat_rddly1); |
| |
| if (ret) |
| times_small_r = 0; |
| |
| return ret; |
| |
| } |
| |
| SDC_CMD_STATUS SD_TuneRead(kal_uint32 data_adrs,void *rxbuffer,kal_uint32 num,kal_bool isLinkListBuf) |
| { |
| kal_uint32 result = ERR_DAT_CRCERR; |
| |
| do { |
| /* Retry the Read with error handling */ |
| result = SD_ReqHandleData(data_adrs,rxbuffer,num,KAL_FALSE,isLinkListBuf); |
| |
| if ((result == ERR_DAT_TIMEOUT) || |
| (result == NO_ERROR)) { |
| if (result == NO_ERROR) { |
| if (times_large_r) |
| fgReadTuneLargeScale = 0; |
| |
| times_small_r = 0; |
| } |
| |
| goto done; |
| } |
| |
| /* Large scale timing tuning */ |
| if (fgReadTuneLargeScale) { |
| if (msdc_tune_read_large_scale()) |
| fgReadTuneLargeScale = 0; |
| } |
| /* Small scale timing tuning */ |
| else { |
| if (msdc_tune_read_small_scale()) |
| goto done; |
| } |
| |
| } while (1); |
| |
| done: |
| MSDC_CRIT("[SD] <TUNE_READ_DONE>"); |
| if (result == NO_ERROR) |
| MSDC_CRIT(" %s\r\n", "PASS"); |
| else if (result == ERR_DAT_CRCERR) |
| MSDC_CRIT(" %s\r\n", "CRCERR"); |
| else if (result == ERR_DAT_TIMEOUT) |
| MSDC_CRIT(" %s\r\n", "TIMEOUT"); |
| |
| return result; |
| } |
| |
| void msdc_tune_init(void) |
| { |
| /* Initialize the tuning releated parameters and registers */ |
| fgCMDTuneLargeScale = 1; |
| times_large = 0; |
| times_small = 0; |
| MSDC_SET_FIELD_NPW(MSDC_PATCH_BIT1, MSDC_CMD_RSP_TA_CNTR, 0); |
| MSDC_SET_FIELD_NPW(MSDC_IOCON, MSDC_IOCON_RSPL, 0); |
| MSDC_SET_FIELD_NPW(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY, 0); |
| |
| fgWrTuneLargeScale = 1; |
| times_large_w = 0; |
| times_small_w = 0; |
| MSDC_SET_FIELD_NPW(MSDC_PATCH_BIT1, MSDC_WRDAT_CRCS_TA_CNTR, 0); |
| MSDC_SET_FIELD_NPW(MSDC_IOCON, MSDC_IOCON_WDSPL, 0); |
| MSDC_SET_FIELD_NPW(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, 0); |
| |
| fgReadTuneLargeScale = 1; |
| times_large_r = 0; |
| times_small_r = 0; |
| MSDC_WriteReg32_NPW(MSDC_DAT_RDDLY0, 0); |
| MSDC_WriteReg32_NPW(MSDC_DAT_RDDLY1, 0); |
| MSDC_SET_FIELD_NPW(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, 0); |
| MSDC_SET_FIELD_NPW(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, 0); |
| MSDC_SET_FIELD_NPW(MSDC_IOCON, MSDC_IOCON_RDSPL, 0); |
| } |
| |
| SDC_CMD_STATUS SD_HandleWriteTMO(kal_uint32 address,void *txbuffer,kal_uint32 num,kal_bool isLinkListBuf) |
| { |
| kal_uint32 cur_wrta,orig_wr_crcta; |
| kal_uint32 status,i,ret; |
| |
| ret=SD_GetStatus(gSD->mRCA,&status); |
| if (ret){ |
| return ERR_DAT_TIMEOUT; |
| } |
| if (status&(R1_OUT_OF_RANGE_31|R1_ADDRESS_ERROR_30)){ |
| return ERR_DAT_TIMEOUT; |
| } |
| orig_wr_crcta=(MSDC_Reg32(MSDC_PATCH_BIT1)&MSDC_PATCH_BIT1_WRDAT_CRCS)>>(uffs(MSDC_PATCH_BIT1_WRDAT_CRCS)-1); |
| /*Ncrc may cause Write data timeout*/ |
| for (i=0;i<8;i++){ |
| cur_wrta=(orig_wr_crcta+i)%8; |
| MSDC_SetData32(MSDC_PATCH_BIT1,MSDC_PATCH_BIT1_WRDAT_CRCS,cur_wrta<<(uffs(MSDC_PATCH_BIT1_WRDAT_CRCS)-1)); |
| ret=SD_ReqHandleData(address,txbuffer,num,KAL_TRUE,isLinkListBuf); |
| if (ret==0) |
| return 0; |
| if (ret==ERR_DAT_CRCERR||ret==ERR_CMD_RSPCRCERR) |
| { |
| return ret; |
| } |
| } |
| if (ret) |
| { |
| return ret; |
| } |
| ret=SD_TuneWrite( address,txbuffer,num,isLinkListBuf); |
| return ret; |
| } |
| /************************************************************************* |
| * FUNCTION |
| * SD_Reset |
| * |
| * DESCRIPTION |
| * reset all cards to idle state |
| * |
| * PARAMETERS |
| * 1. cmd: the content of SDC_CMD register |
| * 2. arg: the argument(if the command need no argument, fill it with 0) |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_Reset(void) |
| { |
| SDC_CMD_STATUS status; |
| status=SD_SendCmd(SDC_CMD_CMD0,SDC_NO_ARG,MSDC_CMD_TIMEOUT); |
| gSD->mState=IDLE_STA; |
| return status; |
| |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_Cmd55 |
| * |
| * DESCRIPTION |
| * APP_CMD: inidicate to the card that the next command is an application specified command |
| * rather than a standard command |
| * |
| * PARAMETERS |
| * rca: relative card address |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_Cmd55(kal_uint16 rca) |
| { |
| SDC_CMD_STATUS status; |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD55, ((kal_uint32)rca << 16),MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| //check APP_CMD bit in status register |
| status=MSDC_Reg32(SDC_RESP0); |
| |
| if (!(status & R1_APP_CMD_5)) |
| return ERR_APPCMD_FAILED; |
| |
| return NO_ERROR; |
| |
| } |
| /************************************************************************* |
| * FUNCTION |
| * SD_Cmd8 |
| * |
| * DESCRIPTION |
| * 1. Sends SD Memory Card interface conditions for support larger than 2G cards |
| * 2. check if the card is compliant to SD2.0 or higher |
| * 3. only performed while at IDLE state. |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * |
| * GLOBALS AFFECTED |
| * gSD->mIsCMD8 |
| * |
| *************************************************************************/ |
| void SD_Cmd8(void) |
| { |
| kal_uint32 resp; |
| kal_uint32 retry = 4; |
| MSDC_DEBUG("[SD][%s %d]Cmd8 arg=%x\r\n",__FUNCTION__,__LINE__,SDC_CMD8_ARG); |
| |
| cmd8_retry: |
| if (SD_SendCmd(SDC_CMD_CMD8, SDC_CMD8_ARG,MSDC_CMD_TIMEOUT) != NO_ERROR) |
| { |
| MSDC_ERR("[SD][%s %d]SDC_Cmd8 fail\r\n",__FUNCTION__,__LINE__); |
| SD_Reset(); |
| gSD->mCMD8Resp = SD_CMD8_RESP_NORESP; |
| return; |
| } |
| |
| resp= MSDC_Reg32(SDC_RESP0); |
| MSDC_DEBUG("[SD][%s %d]Cmd8 resp=%x\r\n",__FUNCTION__,__LINE__,resp); |
| |
| if (resp == SDC_CMD8_ARG) |
| gSD->mCMD8Resp = SD_CMD8_RESP_VALID; |
| else { |
| MSDC_ERR("[SD]CMD8 check pattern error, %X(%X)\r\n",SDC_CMD8_ARG,resp); |
| |
| if (retry--) |
| goto cmd8_retry; |
| |
| gSD->mCMD8Resp = SD_CMD8_RESP_INVALID; |
| } |
| |
| return; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_Cmd1_MMC |
| * |
| * DESCRIPTION |
| * asks all cards in idle state to send their OCR in the response on the CMD line |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| * NOTE |
| * only works for MMC |
| * |
| *************************************************************************/ |
| extern kal_bool FTL_isPollingMode(); |
| |
| SDC_CMD_STATUS SD_Cmd1_MMC(void) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 _ocr, ocr_i, t2; |
| |
| #if defined(SD_MMC_HIGH_DENSITY_SUPPORT) |
| |
| if (gSD->mCMD8Resp == SD_CMD8_RESP_INVALID) |
| return ERR_CMD8_INVALID; |
| |
| ocr_i = (SDC_OCR_DEFAULT | MMC_HIGH_DESITY_CHECK_BIT); |
| #else |
| ocr_i = SDC_OCR_DEFAULT; |
| #endif |
| |
| if (gMSDC_Handle->is_init_timeout == KAL_TRUE) |
| return ERR_R3_OCR_BUSY; |
| |
| t2 = drv_get_current_time(); |
| |
| do |
| { |
| /*send cmd1*/ |
| if ((status=SD_SendCmd(SDC_CMD_CMD1,ocr_i,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| _ocr=MSDC_Reg32(SDC_RESP0); |
| MSDC_NOTICE("[SD]OCR = %x\r\n", _ocr); |
| |
| if ((_ocr & SDC_OCR_DEFAULT) == 0) |
| return ERR_OCR_NOT_SUPPORT; |
| |
| if (!gMSDC_Handle->mIsPresent) |
| return MSDC_CARD_NOT_PRESENT; |
| |
| if (!(_ocr & SDC_OCR_BUSY)) |
| { |
| if (drv_get_duration_ms(t2) > MSDC_TIMEOUT_PERIOD_INI) |
| { |
| gMSDC_Handle->is_init_timeout = KAL_TRUE; |
| break; |
| } |
| |
| msdc_sleep(2); |
| } |
| else { |
| MSDC_CRIT("[SD]OCR = %x\r\n", _ocr); |
| break; |
| } |
| } |
| while (1); |
| |
| if (gMSDC_Handle->is_init_timeout) |
| return ERR_CMD_TIMEOUT; |
| |
| #if defined(SD_MMC_HIGH_DENSITY_SUPPORT) |
| |
| if ((_ocr & MMC_HIGH_DESITY_CHECK_MSK) == MMC_HIGH_DESITY_CHECK_BIT) |
| { |
| gSD->flags |= SD_FLAG_HCS_SUPPORT; |
| gMSDC_Handle->mMSDC_type = MMC42_CARD; |
| gSD->mIsBlkAddr = 1; |
| } |
| else |
| #endif |
| gMSDC_Handle->mMSDC_type = MMC_CARD; |
| |
| gSD->mInactive = KAL_FALSE; |
| gSD->mSDC_ocr = _ocr; |
| gSD->mState = READY_STA; |
| |
| return NO_ERROR; |
| } |
| SDC_CMD_STATUS SD_Cmd11(void) |
| { |
| SDC_CMD_STATUS status; |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD11, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| { |
| return status; |
| } |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| return NO_ERROR; |
| |
| } |
| kal_int32 SD_SwitchVolt18() |
| { |
| kal_uint32 status,t2; |
| status=SD_Cmd11(); |
| if (status !=NO_ERROR) |
| return status; |
| /*make sure SDC is not BUSY*/ |
| if (MSDC_TIMEOUT_WAIT((!SD_IS_SDC_BUSY())&&MSDC_Check_Card_Present(),MSDC_CMD_TIMEOUT)) |
| { |
| MSDC_ERR("[SD][%s %d]wait SDC busy timeout\r\n",__FUNCTION__,__LINE__); |
| return ERR_STATUS; |
| } |
| /*check data[3:0] and cmd is lower by card*/ |
| if(MSDC_Reg32(MSDC_PS)&((1<<24)|(0xf<<16))) |
| return CHECK_DATA_CMD_LOW_FAIL; |
| /*pull up disabled in CMD and DAT[3:0]*/ |
| MSDC_ConfigPin(MSDC_PIN_PULL_NONE); |
| /*switch signal voltage to 1.8v*/ |
| gMSDC_Handle->signal_volt=1800; |
| MSDC_SetSignalPower(1,gMSDC_Handle->signal_volt); |
| /*wait 5ms*/ |
| msdc_sleep(2); |
| /*PULL UP enable in CMD and DAT[3:0]*/ |
| MSDC_ConfigPin(MSDC_PIN_PULL_UP); |
| msdc_sleep(1); |
| /*start to detect volt change */ |
| MSDC_SetBits32(MSDC_CFG,MSDC_CFG_BV18SDT); |
| msdc_sleep(20); |
| t2=drv_get_current_time(); |
| do{ |
| if(((status=MSDC_Reg32(MSDC_CFG))& MSDC_CFG_BV18SDT)==0); |
| { |
| if (status&MSDC_CFG_BV18PSS) |
| { |
| //pass to switch volt to 1.8v |
| return NO_ERROR; |
| } |
| else |
| { |
| //fail to switch volt to 1.8v |
| MSDC_ERR("[SD][%s %d]1.8v fail ,MSDC_CFG %x\r\n",__FUNCTION__,__LINE__,status); |
| break; |
| } |
| } |
| if (drv_get_duration_ms(t2) > MSDC_TIMEOUT_PERIOD_INI) |
| { |
| //detect volt change timeout |
| MSDC_ERR("[SD][%s %d]detect volt change timeout\r\n",__FUNCTION__,__LINE__); |
| break; |
| } |
| }while(1); |
| |
| //come to here ,mean timeout or switch 1.8v fail |
| |
| return ERR_STATUS; |
| } |
| /************************************************************************* |
| * FUNCTION |
| * SD_Acmd41_SD |
| * |
| * DESCRIPTION |
| * asks all cards in idle state to send their OCR in the response on the CMD line |
| * OCR: Operation Condition Register |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| * NOTE |
| * only works for SD |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_Acmd41_SD(void) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 _ocr = 0, ocr_i = 0, t2; |
| |
| #if defined(SD_MMC_HIGH_DENSITY_SUPPORT) |
| |
| if (gSD->mCMD8Resp == SD_CMD8_RESP_NORESP) |
| ocr_i = SDC_OCR_DEFAULT; |
| else if (gSD->mCMD8Resp == SD_CMD8_RESP_VALID) { |
| #if defined(MSDC_CONFIG_SD30_SUPPORT) |
| if (TEMP_SINGLE_LINE == gMSDC_Handle->trySingleLine) |
| ocr_i = (SDC_OCR_DEFAULT | SD_ACMD41_HCS); |
| else |
| ocr_i = (SDC_OCR_DEFAULT | SD_ACMD41_HCS |SD_ACMD41_S18R | SD_ACMD41_XPC); |
| |
| #else |
| ocr_i = (SDC_OCR_DEFAULT | SD_ACMD41_HCS); |
| #endif |
| } |
| else if (gSD->mCMD8Resp == SD_CMD8_RESP_INVALID) |
| return ERR_CMD8_INVALID; |
| |
| #else |
| ocr_i = SDC_OCR_DEFAULT; |
| #endif |
| MSDC_CRIT("[SD][%s %d]Host OCR = %x\r\n",__FUNCTION__,__LINE__,ocr_i); |
| retry: |
| gMSDC_Handle->is_init_timeout = KAL_FALSE; |
| t2 = drv_get_current_time(); |
| |
| do |
| { |
| /*send ACMD41*/ |
| status = SD_Cmd55(SDC_RCA_DEFAULT); |
| |
| if (status != NO_ERROR) |
| { |
| return status; |
| } |
| |
| status=SD_SendCmd(SDC_CMD_ACMD41, ocr_i, MSDC_CMD_TIMEOUT); |
| if (status != NO_ERROR) |
| { |
| return status; |
| } |
| |
| /*check response*/ |
| _ocr = MSDC_Reg32(SDC_RESP0); |
| MSDC_NOTICE("[SD]ACMD41 resp = %x\r\n", _ocr); |
| |
| if ((_ocr & SDC_OCR_DEFAULT) == 0) |
| return ERR_OCR_NOT_SUPPORT; |
| |
| if (!gMSDC_Handle->mIsPresent) |
| return ERR_CARD_NOT_PRESENT; |
| |
| if (!(_ocr & SDC_OCR_BUSY)) |
| { |
| /*if return busy ,we check timeout or not*/ |
| if (drv_get_duration_ms(t2) > MSDC_TIMEOUT_PERIOD_INI) |
| { |
| gMSDC_Handle->is_init_timeout = KAL_TRUE; |
| MSDC_ERR("[SD]ACMD41 Polling BUSY timeout!\r\n"); |
| break; |
| } |
| |
| msdc_sleep(5); |
| } |
| else |
| { |
| /*not busy */ |
| MSDC_CRIT("[SD]OCR = %x\r\n", _ocr); |
| break; |
| } |
| } |
| while (1); |
| |
| if (gMSDC_Handle->is_init_timeout) |
| return ERR_R3_OCR_BUSY; |
| |
| gSD->mInactive = KAL_FALSE; |
| gSD->mSDC_ocr = _ocr; |
| #if defined(SD_MMC_HIGH_DENSITY_SUPPORT) |
| gSD->flags |= SD_FLAG_SD_TYPE_CARD; |
| |
| if (_ocr & SD_ACMD41_HCS) |
| { |
| #if defined(MSDC_CONFIG_SD30_SUPPORT) |
| if (_ocr & SD_ACMD41_S18R ) |
| { |
| status=SD_SwitchVolt18(); |
| if (status != NO_ERROR) |
| { |
| return status; //need delete |
| //fail to switch to 1.8v ,so set signal voltage back to 3.3.v |
| gMSDC_Handle->signal_volt=3300; |
| MSDC_SetSignalPower(1,gMSDC_Handle->signal_volt); |
| power_cycle(1); |
| SD_Reset(); |
| SD_Cmd8(); |
| ocr_i = (SDC_OCR_DEFAULT | SD_ACMD41_HCS); |
| goto retry; |
| } |
| |
| gSD->flags|=SD_FLAG_UHS_SUPPORT; |
| gMSDC_Handle->mMSDC_type=SD30_CARD; |
| MSDC_CRIT("[SD][%s %d]SD3.0 UHS Card\r\n",__FUNCTION__,__LINE__); |
| } |
| else |
| #endif |
| { |
| gSD->flags |= SD_FLAG_HCS_SUPPORT; |
| gMSDC_Handle->mMSDC_type = SD20_HCS_CARD; |
| MSDC_CRIT("[SD][%s %d]SD2.0 High Capacity Card\r\n",__FUNCTION__,__LINE__); |
| |
| } |
| |
| |
| } |
| else if (gSD->mCMD8Resp == SD_CMD8_RESP_VALID) |
| gMSDC_Handle->mMSDC_type = SD20_LCS_CARD; |
| else |
| #endif |
| gMSDC_Handle->mMSDC_type = SD_CARD; |
| |
| gSD->mState = READY_STA; |
| |
| return NO_ERROR; |
| |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_GetCID |
| * |
| * DESCRIPTION |
| * Read Card Identification. |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| * NOTE |
| * |
| * |
| *************************************************************************/ |
| |
| // Get CID(CMD2) |
| SDC_CMD_STATUS SD_GetCID(kal_uint32 *Cid) |
| { |
| int i; |
| SDC_CMD_STATUS status; |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD2, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| { |
| return status; |
| } |
| |
| //read R2 |
| for (i = 0; i < 4; i++) |
| { |
| Cid[i]=MSDC_Reg32((SDC_RESP0 + i * sizeof(kal_uint32))); |
| } |
| |
| SD_AnalysisCID(Cid); |
| gSD->mState = IDENT_STA; |
| |
| return NO_ERROR; |
| |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_ValidateRCA |
| * |
| * DESCRIPTION |
| * assing or read RCA |
| * |
| * PARAMETERS |
| * pRca: used for input or output RCA |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * gSD |
| * |
| * NOTE |
| * RCA is assinged to MMC card fixed to SDC_RCA_MMC(1) |
| * |
| *************************************************************************/ |
| |
| // assign or read RCA |
| SDC_CMD_STATUS SD_ValidateRCA(kal_uint16* pRca) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 resp; |
| kal_uint8 state; |
| kal_uint32 retry; |
| |
| #if defined(SD_MMC_HIGH_DENSITY_SUPPORT) |
| |
| if (gSD->flags & SD_FLAG_SD_TYPE_CARD ) |
| #else |
| if (gMSDC_Handle->mMSDC_type == SD_CARD) |
| #endif |
| { |
| //read RCA form card |
| retry=10; |
| /*if card return RCA=0 we will retry,*/ |
| while(retry--) |
| { |
| MSDC_DEBUG("[SD][%s %d]send cmd3\r\n",__FUNCTION__,__LINE__); |
| if ((status = SD_SendCmd(SDC_CMD_CMD3, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R6 |
| resp=MSDC_Reg32(SDC_RESP0); |
| MSDC_DEBUG("[SD][%s %d]cmd3 reps=%x\r\n",__FUNCTION__,__LINE__,resp); |
| #ifdef MSDC_TRACE_LEVEL1 |
| MD_TRC_MSDC_INFORM_R0(resp, __LINE__); |
| #endif |
| if ((resp>>16)!=0) |
| { |
| *pRca = resp >> 16; |
| gSD->mRCA = *pRca; |
| break; |
| } |
| MSDC_DEBUG("[SD][%s %d]gSD->mRCA=%x\r\n",__FUNCTION__,__LINE__,gSD->mRCA); |
| } |
| if (retry==0) |
| { |
| /*always return RCA=0*/ |
| return ERR_RCA_FAIL; |
| } |
| |
| } |
| else |
| { |
| //assign RCA to card |
| if ((status = SD_SendCmd(SDC_CMD_CMD3_MMC, ((kal_uint32)SDC_RCA_MMC << 16),MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R1 |
| resp=MSDC_Reg32(SDC_RESP0); |
| #ifdef MSDC_TRACE_LEVEL1 |
| MD_TRC_MSDC_INFORM_R0(resp, __LINE__); |
| #endif |
| SD_GetStatus(SDC_RCA_MMC, &resp); |
| state = 0; |
| GetBitFieldN((kal_uint8*)&state, (kal_uint8*)&resp, 9, 4); |
| |
| if (STBY_STA != state) |
| return ERR_RCA_FAIL; |
| |
| *pRca = gSD->mRCA = SDC_RCA_MMC; |
| } |
| |
| gSD->mState = STBY_STA; |
| return NO_ERROR; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_SetDSR |
| * |
| * DESCRIPTION |
| * set default value to the DSR |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * SDC_DSR_DEFAULT(0x404) |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_SetDSR(void) |
| { |
| return SD_SendCmd(SDC_CMD_CMD4, (kal_uint32)SDC_DSR_DEFAULT << 16,MSDC_CMD_TIMEOUT); |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_SelectCard |
| * |
| * DESCRIPTION |
| * select/deselect card |
| * |
| * PARAMETERS |
| * rca: relative card address |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_SelectCard(kal_uint16 rca) |
| { |
| SDC_CMD_STATUS status; |
| MSDC_DEBUG("[SD][%s %d]send cmd7\r\n",__FUNCTION__,__LINE__); |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD7, ((kal_uint32)rca << 16),MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| { |
| return status; |
| } |
| |
| //read R1b |
| if ((status = SD_WaitCardNotBusy(MSDC_DATA_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| return NO_ERROR; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_GetCSD |
| * |
| * DESCRIPTION |
| * Get CSD from addressed card |
| * |
| * PARAMETERS |
| * rca: relative card address |
| * Csd: used for containing read CSD |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_GetCSD(kal_uint16 rca, kal_uint32 Csd[4]) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 i; |
| MSDC_DEBUG("[SD][%s %d]send cmd9\r\n",__FUNCTION__,__LINE__); |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD9, ((kal_uint32)rca << 16),MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| { |
| return status; |
| } |
| |
| |
| // read R2 |
| for (i = 0; i < 4; i++) |
| { |
| Csd[i]=MSDC_Reg32((volatile kal_uint32 *)(SDC_RESP0 + i * 4)); |
| #ifdef MSDC_DEBUG_PRINT |
| MSDC_DEBUG("%x ",Csd[i]); |
| #endif |
| } |
| #ifdef MSDC_DEBUG_PRINT |
| MSDC_DEBUG("\r\n "); |
| #endif |
| // analysis CSD... |
| SD_AnalysisCSD(Csd); |
| |
| return NO_ERROR; |
| } |
| |
| // addressed send CID |
| SDC_CMD_STATUS SD_GetAddressedCID(kal_uint16 rca, kal_uint32 Cid[4]) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 i; |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD10, (kal_uint32)rca << 16,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| // read R2 |
| for (i = 0; i < 4; i++) |
| { |
| #ifndef DRV_LSD |
| Cid[i]=MSDC_Reg32((volatile kal_uint32 *)(SDC_RESP0 + i * 4)); |
| #else |
| Cid[i]=MSDC_Reg32(SDC_RESP0 + i); |
| #endif |
| } |
| |
| return NO_ERROR; |
| } |
| |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_StopTrans |
| * |
| * DESCRIPTION |
| * Stop Muli-Block operation |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * definition of SD_STOP_SLOW is used for some erroneous card |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_StopTrans(void) |
| { |
| SDC_CMD_STATUS status; |
| #define CMD12_TIMEOUT_MS 1000 |
| status = SD_SendCmd(SDC_CMD_CMD12,SDC_NO_ARG,MSDC_CMD_TIMEOUT); |
| MSDC_CLR_FIFO(); |
| return status; |
| |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_GetStatus |
| * |
| * DESCRIPTION |
| * addressed send status |
| * |
| * PARAMETERS |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_GetStatus(kal_uint16 rca, kal_uint32* resp) |
| { |
| SDC_CMD_STATUS status; |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD13, ((kal_uint32)rca << 16),MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| *resp=MSDC_Reg32(SDC_RESP0); |
| |
| return NO_ERROR; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_SetBlength |
| * |
| * DESCRIPTION |
| * set block length |
| * |
| * PARAMETERS |
| * BKLength: block length u want to set |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * gSD->mBKLength |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_SetBlength(kal_uint32 BKLength) |
| { |
| SDC_CMD_STATUS status; |
| |
| // maximal value of block length is 2048 |
| if (BKLength > SDC_MAX_BKLENGTH) |
| return ERR_INVALID_BKLENGTH; |
| |
| if (!gSD->mCSD.r_blk_part && BKLength < gSD->mCSD.max_r_blk_len ) |
| return ERR_INVALID_BKLENGTH; |
| if ((status = SD_SendCmd(SDC_CMD_CMD16, BKLength,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R1 |
| status = SD_CheckStatus(); |
| // 2. configure the controller |
| gSD->mBKLength = BKLength; |
| // BitFieldWrite32((kal_uint32*)SDC_CMD, BKLength, SDC_CMD_BLKLEN); |
| return status; |
| } |
| |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_ReadSingleBlock |
| * |
| * DESCRIPTION |
| * 1. read a single block form data_adrs of card to the rxbuffer |
| * 2. the block length is set by set block length |
| * |
| * PARAMETERS |
| * data_adrs: starting address to read |
| * rxbuffer: as name |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * the size of rxbuffer should be 4*n (n : integer) |
| * |
| *************************************************************************/ |
| #ifdef DRV_MSDC_SLIM |
| SDC_CMD_STATUS SD_ReadSingleBlock(kal_uint32 data_adrs, kal_uint32* rxbuffer) // slim |
| { |
| return SD_ReadMultiBlock(data_adrs, rxbuffer, 1); // slim |
| } |
| #else |
| SDC_CMD_STATUS SD_ReadSingleBlock(kal_uint32 data_adrs, kal_uint32* rxbuffer) |
| { |
| return SD_ReadMultiBlock(data_adrs, rxbuffer, 1); |
| } |
| #endif |
| /************************************************************************* |
| * FUNCTION |
| * SD_ReadMultiBlock |
| * |
| * DESCRIPTION |
| * read num of blocks into rxbuffer |
| * |
| * PARAMETERS |
| * data_adrs: starting address to read |
| * rxbuffer: as name |
| * num: number of blocks to read |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| #ifdef DRV_MSDC_SLIM |
| SDC_CMD_STATUS |
| SD_ReadMultiBlock(kal_uint32 data_adrs, kal_uint32* rxbuffer, kal_uint32 num_blk) // slim |
| { |
| |
| |
| } |
| #else |
| SDC_CMD_STATUS SD_ReadMultiBlock(kal_uint32 data_adrs, kal_uint32* rxbuffer, kal_uint32 num_blk) |
| { |
| kal_uint32 status; |
| |
| status = SD_ReqHandleData(data_adrs, rxbuffer,num_blk, KAL_FALSE,KAL_FALSE); |
| if (status==ERR_DAT_CRCERR) |
| { |
| status=SD_TuneRead(data_adrs,rxbuffer,num_blk,KAL_FALSE); |
| } |
| return status; |
| } |
| #endif |
| |
| |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_WriteSingleBlock |
| * |
| * DESCRIPTION |
| * write a single block |
| * |
| * PARAMETERS |
| * address: starting address to write |
| * txbuffer: as name |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * block length is set by Set_Block_Length |
| * |
| *************************************************************************/ |
| #ifdef DRV_MSDC_SLIM |
| //__attribute__ ((section ("EXT_BOOTLOADER_CODE"))) SDC_CMD_STATUS SD_WriteSingleBlock(kal_uint32 address, kal_uint32* txbuffer) // slim |
| SDC_CMD_STATUS SD_WriteSingleBlock(kal_uint32 address, kal_uint32* txbuffer) |
| { |
| return SD_WriteMultiBlock(address, txbuffer, 1); // slim |
| } |
| #else |
| //__attribute__ ((section ("EXT_BOOTLOADER_CODE"))) SDC_CMD_STATUS SD_WriteSingleBlock(kal_uint32 address, kal_uint32* txbuffer) |
| SDC_CMD_STATUS SD_WriteSingleBlock(kal_uint32 address, kal_uint32* txbuffer) |
| { |
| return SD_WriteMultiBlock(address, txbuffer, 1); |
| } |
| #endif |
| |
| void SD_Sleep4Wait(kal_int32 sleep_tick) |
| { |
| |
| } |
| /************************************************************************* |
| * FUNCTION |
| * SD_WriteMultiBlock |
| * |
| * DESCRIPTION |
| * write num blocks starting at address |
| * |
| * PARAMETERS |
| * address: starting address to write |
| * txbuffer: as name |
| * num: number of blocks to write |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * block length is set by Set_Block_Length |
| * |
| *************************************************************************/ |
| //#ifndef DRV_MSDC_SLIM |
| //__attribute__ ((section ("EXT_BOOTLOADER_CODE"))) SDC_CMD_STATUS SD_WriteMultiBlock(kal_uint32 address, kal_uint32* txbuffer, kal_uint32 num) |
| SDC_CMD_STATUS SD_WriteMultiBlock(kal_uint32 address, kal_uint32* txbuffer, kal_uint32 num_blk) |
| { |
| SDC_CMD_STATUS status; |
| |
| if (gSD->mWPEnabled) |
| return ERR_WRITE_PROTECT; |
| if ((status=SD_ReqHandleData(address, txbuffer, num_blk, KAL_TRUE,KAL_FALSE))!=NO_ERROR) |
| { |
| if (status ==ERR_DAT_CRCERR) |
| { |
| status=SD_TuneWrite(address,txbuffer,num_blk,KAL_FALSE); |
| } |
| else if (status == ERR_DAT_TIMEOUT) |
| { |
| status=SD_HandleWriteTMO(address,txbuffer,num_blk,KAL_FALSE); |
| } |
| } |
| |
| return status; |
| } |
| |
| SDC_CMD_STATUS SD_GpdWriteMultiBlock(kal_uint32 address ,kal_uint32 num_blk,void *gpd_data) |
| { |
| SDC_CMD_STATUS status; |
| |
| gMSDC_Handle->f_tuning = 0; |
| |
| if (gSD->mWPEnabled) |
| return ERR_WRITE_PROTECT; |
| if ((status=SD_ReqHandleData(address, gpd_data, num_blk, KAL_TRUE,KAL_TRUE))!=NO_ERROR) |
| { |
| gMSDC_Handle->f_tuning = 1; |
| |
| if (status ==ERR_DAT_CRCERR) |
| { |
| status=SD_TuneWrite(address,gpd_data,num_blk,KAL_TRUE); |
| } |
| else if (status == ERR_DAT_TIMEOUT) |
| { |
| status=SD_HandleWriteTMO(address,gpd_data,num_blk,KAL_TRUE); |
| } |
| } |
| return status; |
| } |
| |
| SDC_CMD_STATUS SD_GpdReadMultiBlock(kal_uint32 address ,kal_uint32 num_blk,void *gpd_data ) |
| { |
| kal_uint32 status; |
| |
| gMSDC_Handle->f_tuning = 0; |
| status = SD_ReqHandleData(address, gpd_data,num_blk, KAL_FALSE,KAL_TRUE); |
| |
| if (status==ERR_DAT_CRCERR) |
| { |
| gMSDC_Handle->f_tuning = 1; |
| status=SD_TuneRead(address,gpd_data,num_blk,KAL_TRUE); |
| } |
| return status; |
| } |
| |
| |
| //#else |
| //__attribute__ ((section ("EXT_BOOTLOADER_CODE"))) SDC_CMD_STATUS SD_WriteMultiBlock(kal_uint32 address, kal_uint32* txbuffer, kal_uint32 num) // slim |
| //SDC_CMD_STATUS SD_WriteMultiBlock(kal_uint32 address, kal_uint32* txbuffer, kal_uint32 num) // slim |
| //{ |
| |
| |
| //} |
| //#endif |
| |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_SetBusWidth |
| * |
| * DESCRIPTION |
| * ACMD6: set the data width 00 for 1 bit, 10 for 4 bits |
| * |
| * PARAMETERS |
| * width: indicate the bus width |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * Not every card support 4-bits bus |
| * only for SD |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_SetBusWidth(SD_BITWIDTH width) |
| { |
| SDC_CMD_STATUS status; |
| MSDC_DEBUG("[SD][%s %d]send ACMD6 ,change bus width to %d\r\n",__FUNCTION__,__LINE__,width); |
| |
| // check if card support 4 bits bus |
| if ((width == BIT_4W) && !(gSD->mSCR.bus_width & 0x04)) |
| return ERR_NOT_SUPPORT_4BITS; |
| |
| // send APP_CMD |
| if ((status = SD_Cmd55(gSD->mRCA)) != NO_ERROR) |
| return status; |
| |
| // send cmd6 |
| if ((status = SD_SendCmd(SDC_CMD_ACMD6, width,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| |
| // set the controler bus width |
| MSDC_SetBusWidth(width); |
| gSD->bus_width = width; |
| return NO_ERROR; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_ReadSCR |
| * |
| * DESCRIPTION |
| * ACMD51: read the SD Configuration Register(8bytes block read) |
| * |
| * PARAMETERS |
| * scr: used for store SCR |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * Make sure the size of SCR is 8 bytes |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_ReadSCR(kal_uint32* scr) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 blklen; |
| |
| ASSERT((kal_uint32)scr % 4 == 0); |
| |
| MSDC_DEBUG("[SD][%s %d]send cmd55\r\n",__FUNCTION__,__LINE__); |
| |
| // send APP_CMD |
| if ((status = SD_Cmd55(gSD->mRCA)) != NO_ERROR) |
| return status; |
| |
| // set block number |
| blklen=gSD->mBKLength; |
| gSD->mBKLength = 8; |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| MSDC_DEBUG("[SD][%s %d]send acmd51\r\n",__FUNCTION__,__LINE__); |
| |
| // set to pio mode and clear fifo |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 1, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=0; |
| MSDC_CLR_FIFO(); |
| |
| // send command |
| if ((status = SD_SendCmd(SDC_CMD_ACMD51, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| // read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| // read data(8bytes) |
| status=SD_WaitDatRdyOrTo(scr,8,KAL_FALSE); |
| if (status !=NO_ERROR) |
| return status; |
| MSDC_DEBUG("[SD][%s %d]scr=%x %x\r\n",__FUNCTION__,__LINE__,*scr,*(scr+1)); |
| |
| SD_AnalysisSCR(scr); |
| MSDC_CLR_FIFO(); |
| |
| gSD->mBKLength = blklen; |
| |
| return NO_ERROR; |
| |
| } |
| |
| static kal_uint32 unstuff_sd_status(kal_uint32 *raw_sd_status, kal_uint32 start, kal_uint32 size) |
| { |
| kal_uint32 __mask = (1 << (size)) - 1; |
| int __off = 63 - ((start) / 8); |
| int __shft; |
| kal_uint8 *raw = (kal_uint8 *)raw_sd_status; |
| kal_uint32 __res = 0; |
| |
| if ((start & 7) + 1 >= size) |
| { |
| __shft = ((start & 7) + 1) - size; |
| __res = raw[__off] >> __shft; |
| } |
| else if (size <= 32) |
| { |
| size -= ((start & 7) + 1); |
| __shft = size; |
| __res = raw[__off] << __shft; |
| while (size) |
| { |
| __off++; |
| if (size >= 8) |
| { |
| size -= 8; |
| __res |= raw[__off] << size; |
| } |
| else |
| { |
| __mask = (1 << (size)) - 1; |
| __res |= (raw[__off] >> (8 - size)) & __mask; |
| size = 0; |
| } |
| } |
| } |
| return __res & __mask; |
| } |
| #define UNSTUFF_SD_STATUS(r,s,sz) unstuff_sd_status(r,s,sz) |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_ReadSDStatus |
| * |
| * DESCRIPTION |
| * ACMD13: read the SD Status Register(64bytes block read) |
| * |
| * PARAMETERS |
| * sd_status: used for store SD Status |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * Make sure the size of SD Status is 64 bytes |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_ReadSDStatus(kal_uint32* sd_status) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 blklen; |
| |
| ASSERT((kal_uint32)sd_status % 4 == 0); |
| |
| MSDC_DEBUG("[SD][%s %d]send cmd55\r\n",__FUNCTION__,__LINE__); |
| |
| // send APP_CMD |
| if ((status = SD_Cmd55(gSD->mRCA)) != NO_ERROR) |
| return status; |
| |
| // set block number |
| blklen=gSD->mBKLength; |
| gSD->mBKLength = 64; |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| MSDC_DEBUG("[SD][%s %d]send acmd13\r\n",__FUNCTION__,__LINE__); |
| |
| // set to pio mode and clear fifo |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 1, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=0; |
| |
| // send command |
| if ((status = SD_SendCmd(SDC_CMD_ACMD13, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| // read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| // read data(8bytes) |
| status=SD_WaitDatRdyOrTo(sd_status,64,KAL_FALSE); |
| gSD->mBKLength = blklen; |
| |
| if (status !=NO_ERROR) |
| return status; |
| MSDC_DEBUG("[SD][%s %d]sd_status=%x %x\r\n",__FUNCTION__,__LINE__,*sd_status,*(sd_status+1)); |
| |
| gSD->mSDSts.dat_bus_width = UNSTUFF_SD_STATUS(sd_status, 511, 2); |
| gSD->mSDSts.secured_mode = UNSTUFF_SD_STATUS(sd_status, 509, 1); |
| gSD->mSDSts.sd_card_type = UNSTUFF_SD_STATUS(sd_status, 495, 16); |
| gSD->mSDSts.size_of_prot_area = UNSTUFF_SD_STATUS(sd_status, 479, 32); |
| gSD->mSDSts.speed_class = UNSTUFF_SD_STATUS(sd_status, 447, 8); |
| gSD->mSDSts.perf_move = UNSTUFF_SD_STATUS(sd_status, 439, 8); |
| gSD->mSDSts.au_size = UNSTUFF_SD_STATUS(sd_status, 431, 4); |
| gSD->mSDSts.erase_size = UNSTUFF_SD_STATUS(sd_status, 423, 16); |
| gSD->mSDSts.erase_timeout = UNSTUFF_SD_STATUS(sd_status, 407, 6); |
| gSD->mSDSts.erase_offset = UNSTUFF_SD_STATUS(sd_status, 401, 2); |
| gSD->mSDSts.uhs_speed_grade = UNSTUFF_SD_STATUS(sd_status, 399, 4); |
| gSD->mSDSts.uhs_au_size = UNSTUFF_SD_STATUS(sd_status, 395, 4); |
| |
| /* If it is a SD ROM Card, set the WP flag */ |
| if (gSD->mSDSts.sd_card_type == 0x0001) { |
| gSD->mWPEnabled = KAL_TRUE; |
| MSDC_CRIT("[SD]It is a ROM Card!\r\n"); |
| } |
| |
| return NO_ERROR; |
| |
| } |
| |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_SetPreEraseBlk |
| * |
| * DESCRIPTION |
| * ACMD23: set the number of write blocksto be pre-erased before writing |
| * used for faster multiple Block Write |
| * |
| * PARAMETERS |
| * num: used for storing number of blocks during multi-block operation |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_SetPreEraseBlk(kal_uint32 num) |
| { |
| SDC_CMD_STATUS status; |
| |
| //[22:0] number of blocks |
| num &= 0x003FFF; |
| |
| // send APP_CMD |
| if ((status = SD_Cmd55(gSD->mRCA)) != NO_ERROR) |
| return status; |
| |
| // send CMD23 |
| if ((status = SD_SendCmd(SDC_CMD_ACMD23, num,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| return NO_ERROR; |
| |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_EraseCmdClass |
| * |
| * DESCRIPTION |
| * groups of erase commands including CMD32 ~CMD38 |
| * |
| * PARAMETERS |
| * cmd: indicate which command to execute |
| * address: starting address wiht write protection |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * CMD34~CMD37 are only for MMC |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_EraseCmdClass(kal_uint32 cmd , kal_uint32 address) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 sdcard_status; |
| kal_set_eg_events(gMSDC_Handle->MSDC_Events, 0, KAL_AND); |
| |
| if (cmd != SDC_CMD_CMD38) |
| { |
| if ((status = SD_SendCmd(cmd, address,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| } |
| else if ((status = SD_SendCmd(cmd, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| |
| if (cmd == SDC_CMD_CMD38) |
| { |
| |
| if ((status = SD_WaitCardNotBusy(MSDC_DATA_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| do |
| { |
| if ((status = SD_GetStatus(gSD->mRCA, (kal_uint32*)&sdcard_status)) != NO_ERROR) |
| return status; |
| |
| if (gMSDC_Handle->mIsPresent == KAL_FALSE) |
| return ERR_INVALID_CARD; |
| } |
| while (R1_CURRENT_STATE(sdcard_status) != TRAN_STA); |
| } |
| |
| return NO_ERROR; |
| } |
| /************************************************************************* |
| * FUNCTION |
| * SD_Switch_MMC40 |
| * |
| * DESCRIPTION |
| * CMD6: set the command set or write to the EXT_CSD (for MMC4.0) |
| * |
| * PARAMETERS |
| * access: access mode |
| * index: index to EXT_CSD |
| * value: value to write to EXT_CSD |
| * set: selected command set |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_Switch_MMC40(kal_uint8 access, kal_uint8 index, kal_uint8 value, kal_uint8 set) |
| { |
| SDC_CMD_STATUS status = NO_ERROR; |
| kal_uint32 arg = 0; |
| kal_uint32 resp = 0; |
| kal_bool retry = KAL_FALSE; |
| // kal_uint8 *pData = NULL; |
| |
| switch_start: |
| |
| arg = (access << 24) | (index << 16) | (value << 8) | set; |
| |
| // send command |
| if ((status = SD_SendCmd(SDC_CMD_CMD6_MMC, arg,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| { |
| goto ERR_Exit; |
| } |
| |
| #ifndef DRV_LSD |
| |
| //read R1b |
| if ((status = SD_WaitCardNotBusy(MSDC_DATA_TIMEOUT)) != NO_ERROR) |
| goto ERR_Exit; |
| |
| #endif |
| |
| SD_GetStatus(gSD->mRCA, (kal_uint32*)&status); |
| |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| goto ERR_Exit; |
| |
| resp=MSDC_Reg32(SDC_RESP0); |
| |
| if ((resp & MMC_SWITCH_ERROR) != 0) |
| { |
| if (retry == KAL_FALSE) |
| { |
| #ifdef MSDC_TRACE_LEVEL2 |
| MD_TRC_MSDC_INFORM_R0(resp, __LINE__); |
| #endif |
| retry = KAL_TRUE; |
| goto switch_start; |
| } |
| else |
| return ERR_MMC_SWITCH_ERROR; |
| } |
| |
| return NO_ERROR; |
| |
| ERR_Exit: |
| return status; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_SendEXTCSD_MMC40 |
| * |
| * DESCRIPTION |
| * CMD8: read the content of EXT_CSD register |
| * |
| * PARAMETERS |
| * kal: access mode |
| * index: index to EXT_CSD |
| * value: value to write to EXT_CSD |
| * set: selected command set |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| #if 0 |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| #ifdef DRV_LSD |
| /* under construction !*/ |
| #endif |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| /* under construction !*/ |
| #else |
| SDC_CMD_STATUS SD_SendEXTCSD_MMC40(kal_uint32* rxbuffer) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 blklen; |
| // SDC_CMD_STATUS status1; |
| // kal_bool retry = KAL_FALSE; |
| //kal_uint32 idx = 0; |
| |
| //start: |
| blklen=gSD->mBKLength; |
| gSD->mBKLength = 512; |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| //set to pio mode and clear fifo |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 1, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=0; |
| MSDC_CLR_FIFO(); |
| |
| // read the block of 512 bytes (make sure the rxbuffer is 4 byte aligned) |
| if ((status = SD_SendCmd(SDC_CMD_CMD8_MMC40, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| goto ERR_Exit; |
| |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| goto ERR_Exit; |
| |
| //idx = 0; |
| /*move data from FIFO to buffer*/ |
| if ((status = SD_WaitDatRdyOrTo(rxbuffer,512,KAL_FALSE))!=NO_ERROR) |
| { |
| goto ERR_Exit; |
| } |
| |
| kal_mem_cpy(MSDC_eCSD, rxbuffer, 512); |
| gSD->mCSD.ext_csd = (T_EXT_CSD_MMC40 *)MSDC_eCSD;//rxbuffer; |
| gSD->mBKLength=blklen; |
| return NO_ERROR; |
| |
| ERR_Exit: |
| |
| MSDC_FatalErrorHandle(); |
| return status; |
| } |
| #endif |
| /************************************************************************* |
| * FUNCTION |
| * SD_CheckTimeoutWithSleep |
| * |
| * DESCRIPTION |
| * check timeout or not and sleep 1 tick if has been waited more than 10 ms |
| * |
| * PARAMETERS |
| * start_time: the time start to wait, get with drv_get_current_time |
| * duration_ms: the timeout limitation |
| * |
| * RETURNS |
| * kal_bool, timeout:KAL_TRUE; not timeout:KAL_FALSE; |
| * |
| * GLOBALS AFFECTED |
| * gMSDC_Handle->is_timeout |
| * |
| * NOTE: |
| * This function should be called in the wait loop to prevent block other tasks. |
| * |
| *************************************************************************/ |
| kal_bool SD_CheckTimeoutWithSleep(kal_int32 start_time, |
| kal_int32 duration_ms) |
| { |
| kal_int32 elapsed_time = drv_get_duration_ms(start_time); |
| //check timeout or not |
| if(elapsed_time > duration_ms) |
| { |
| gMSDC_Handle->is_timeout = KAL_TRUE; |
| return KAL_TRUE; |
| } |
| gMSDC_Handle->is_timeout = KAL_FALSE; |
| |
| if(elapsed_time < 10) |
| { |
| return KAL_FALSE; |
| } |
| else if ((KAL_FALSE == kal_query_systemInit()) |
| #ifdef __TST_WRITE_TO_FILE__/*error recording: considering error recording additionally*/ |
| && (KAL_FALSE == INT_QueryExceptionStatus()) |
| #endif |
| && (KAL_FALSE == kal_if_hisr()) |
| && (KAL_FALSE == kal_if_lisr())) |
| { |
| kal_sleep_task(1); |
| } |
| return KAL_FALSE; |
| |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_Switch_SD11 |
| * |
| * DESCRIPTION |
| * CMD6: switch command to query and select the specific functions. (SD1.1 or later) |
| * PARAMETERS |
| * arg: argument |
| * resp: buffer to contain the ther 64 bytes status information |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_Switch_SD11(kal_uint32 arg, T_SWITCH_STATUS* info) |
| { |
| SDC_CMD_STATUS status = NO_ERROR; |
| kal_uint32 blklen; |
| gSD->mBKNum=1; |
| blklen=gSD->mBKLength; |
| gSD->mBKLength = SD_CMD6_RESP_LEN; |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| //set to pio mode and clear fifo |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 1, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=0; |
| MSDC_CLR_FIFO(); |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD6_SD11, arg,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| status=SD_WaitDatRdyOrTo((kal_uint32 *)info,SD_CMD6_RESP_LEN,KAL_FALSE); |
| gSD->mBKLength=blklen; |
| return status; |
| } |
| |
| /************************************************************************* |
| * FUNCTION |
| * SD_Switch_SD11 |
| * |
| * DESCRIPTION |
| * Enable the high speed interface to support up to 50M Hz clock |
| * |
| * PARAMETERS |
| * arg: argument |
| * resp: buffer to contain the ther 64 bytes status information |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * |
| * NOTE |
| * |
| *************************************************************************/ |
| |
| #ifndef DRV_MSDC_CORRECT_CMD6 |
| SDC_CMD_STATUS SD_SelectHighSpeed_SD11(void) |
| { |
| SDC_CMD_STATUS status; |
| T_SWITCH_STATUS *p = (T_SWITCH_STATUS*)MSDC_Sector; |
| MSDC_DEBUG("[SD][%s %d]send cmd6 \r\n",__FUNCTION__,__LINE__); |
| |
| if ((status = SD_Switch_SD11(SD_CMD6_QUERY_HIGH_SPEED, p)) != NO_ERROR) |
| return status; |
| |
| if (p->max_current == 0) |
| return ERR_SD_HS_FAIL; |
| |
| if ((p->group1_info & (1 << SD_FUNC_HIGH_SPEED)) && |
| (p->group1_result == SD_FUNC_HIGH_SPEED)) |
| { |
| if ((status = SD_Switch_SD11(SD_CMD6_SELECT_HIGH_SPEED, p)) != NO_ERROR) |
| return status; |
| |
| if (p->max_current == 0) |
| return ERR_SD_HS_FAIL; |
| |
| if (p->group1_result == SD_FUNC_HIGH_SPEED) |
| gSD->flags |= SD_FLAG_HS_SUPPORT; |
| } |
| else |
| return ERR_SD_HS_FAIL; |
| |
| |
| return NO_ERROR; |
| } |
| #else |
| typedef struct |
| { |
| kal_uint16 max_current; |
| kal_uint16 group1_info; |
| kal_uint16 group1_status; |
| kal_uint8 group1_result; |
| kal_uint8 structure_version; |
| }T_Group1SwitchStatus; |
| /************************************************************************* |
| * FUNCTION |
| * SD_ParseGroup1FunctionStatus |
| * |
| * DESCRIPTION |
| * Parse the Group1 functons' information form the data returned by CMD6 |
| * |
| * PARAMETERS |
| * arg: |
| * T_Group1SwitchStatus* sf_status : information of group1 function |
| * kal_uint8* crude_info : crude data returned by CMD6 |
| * resp: |
| * |
| * RETURNS |
| * void |
| * |
| * GLOBALS AFFECTED |
| * None |
| * NOTE |
| * |
| *************************************************************************/ |
| void SD_ParseGroup1FunctionStatus(T_Group1SwitchStatus* sf_status, kal_uint8* crude_info) |
| { |
| sf_status->max_current = (((*(kal_uint8 *)crude_info) << 8) |
| | (*(kal_uint8 *)(crude_info + 1))); |
| sf_status->group1_info = (((*(kal_uint8 *)(crude_info + 12)) << 8) |
| | (*(kal_uint8 *)(crude_info + 13))); |
| sf_status->group1_result = ((*(kal_uint8 *)(crude_info + 16)) & 0xf); |
| sf_status->structure_version = (*(kal_uint8 *)(crude_info + 17)); |
| sf_status->group1_status = (((*(kal_uint8 *)(crude_info + 28)) << 8) |
| | (*(kal_uint8 *)(crude_info + 29))); |
| } |
| /************************************************************************* |
| * FUNCTION |
| * SD_QuerySwithHighSpeed |
| * |
| * DESCRIPTION |
| * Send CMD6 with query or swith and check the response data. |
| * |
| * PARAMETERS |
| * arg: kal_uint32 arg |
| * resp: |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * MSDC_Sector |
| * NOTE |
| * |
| *************************************************************************/ |
| SDC_CMD_STATUS SD_QuerySwithHighSpeed(kal_uint32 arg) |
| { |
| T_Group1SwitchStatus sf_status; |
| SDC_CMD_STATUS cmd_status; |
| if ((cmd_status = SD_Switch_SD11(arg, (T_SWITCH_STATUS*)MSDC_Sector)) != NO_ERROR) |
| return cmd_status; |
| SD_ParseGroup1FunctionStatus(&sf_status,(kal_uint8*)MSDC_Sector); |
| if (0 == sf_status.max_current) |
| return ERR_HIGH_SPEED_CONSUMPTION; |
| if ((SD_FUNC_HIGH_SPEED == sf_status.group1_result)\ |
| && (0==(sf_status.group1_status & (1 << SD_FUNC_HIGH_SPEED)))) |
| return NO_ERROR;//the high speed function can be switched |
| if ((0xF == sf_status.group1_result) || (!(sf_status.group1_info & (1 << SD_FUNC_HIGH_SPEED)))) |
| return ERR_HIGH_SPEED_NOT_SUPPORT;//not support |
| if (sf_status.group1_status & (1 << SD_FUNC_HIGH_SPEED))//busy |
| return ERR_HIGH_SPEED_BUSY; |
| return ERR_HIGH_SPEED_COMMON_ERROR; |
| } |
| /************************************************************************* |
| * FUNCTION |
| * SD_SelectHighSpeed_SD11 |
| * |
| * DESCRIPTION |
| * Select high speed mode for the SD card that supports CMD6 |
| * |
| * PARAMETERS |
| * arg: void |
| * resp: |
| * |
| * RETURNS |
| * SDC_CMD_STATUS |
| * |
| * GLOBALS AFFECTED |
| * gSD->flags |
| * NOTE |
| * |
| *************************************************************************/ |
| |
| SDC_CMD_STATUS SD_SelectHighSpeed_SD11(void) |
| { |
| SDC_CMD_STATUS high_speed_status; |
| kal_int32 t1; |
| t1 = drv_get_current_time(); |
| do |
| { |
| high_speed_status = SD_QuerySwithHighSpeed(SD_CMD6_QUERY_HIGH_SPEED);//query |
| dbg_print("query high_speed_status: %x\r\n",high_speed_status); |
| if (NO_ERROR == high_speed_status) |
| { |
| high_speed_status = SD_QuerySwithHighSpeed(SD_CMD6_SELECT_HIGH_SPEED);//switch |
| dbg_print("switch high_speed_status: %x\r\n",high_speed_status); |
| if (NO_ERROR == high_speed_status) |
| { |
| gSD->flags |= SD_FLAG_HS_SUPPORT; |
| return NO_ERROR; |
| } |
| if (ERR_HIGH_SPEED_BUSY != high_speed_status) |
| break; |
| } |
| if (ERR_HIGH_SPEED_BUSY != high_speed_status) |
| break; |
| if (drv_get_duration_ms(t1)>500) |
| return ERR_HIGH_SPEED_TIMEOUT; |
| //if(SD_CheckTimeoutWithSleep(t1,500)) |
| // return ERR_HIGH_SPEED_TIMEOUT;//timeout |
| }while(1); |
| return high_speed_status; |
| } |
| |
| #endif |
| |
| void parse_Cmd6FunctionStatus(T_SWITCH_STATUS *new_status,kal_uint8 * cur_Status) |
| { |
| new_status->max_current=((*(kal_uint8*)cur_Status)<<8)\ |
| | (*(kal_uint8 *)(cur_Status+1)); |
| new_status->ver=(*(kal_uint8 *)(cur_Status+17)); |
| new_status->group1_info=((*(kal_uint8 *)(cur_Status+12))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+13)); |
| new_status->group1_result=(*(kal_uint8*)(cur_Status+16))&0xf; |
| new_status->group1_busy=((*(kal_uint8*)(cur_Status+28))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+29)); |
| |
| new_status->group2_info=((*(kal_uint8 *)(cur_Status+10))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+11)); |
| new_status->group2_result=((*(kal_uint8*)(cur_Status+16))>>4)&0xf; |
| new_status->group2_busy=((*(kal_uint8*)(cur_Status+26))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+27)); |
| |
| new_status->group3_info=((*(kal_uint8 *)(cur_Status+8))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+9)); |
| new_status->group3_result=(*(kal_uint8*)(cur_Status+15))&0xf; |
| new_status->group3_busy=((*(kal_uint8*)(cur_Status+24))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+25)); |
| |
| new_status->group4_info=((*(kal_uint8 *)(cur_Status+6))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+7)); |
| new_status->group4_result=((*(kal_uint8*)(cur_Status+15))>>4)&0xf; |
| new_status->group4_busy=((*(kal_uint8*)(cur_Status+22))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+23)); |
| |
| new_status->group5_info=((*(kal_uint8 *)(cur_Status+4))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+5)); |
| new_status->group5_result=(*(kal_uint8*)(cur_Status+14))&0xf; |
| new_status->group5_busy=((*(kal_uint8*)(cur_Status+20))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+21)); |
| |
| new_status->group6_info=((*(kal_uint8 *)(cur_Status+2))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+3)); |
| new_status->group6_result=((*(kal_uint8*)(cur_Status+14))>>4)&0xf; |
| new_status->group6_busy=((*(kal_uint8*)(cur_Status+18))<<8)\ |
| | (*(kal_uint8 *)(cur_Status+19)); |
| /* |
| dbg_print("new_status->group1_info :%x\r\n",new_status->group1_info); |
| dbg_print("new_status->group1_result:%x\r\n",new_status->group1_result); |
| dbg_print("new_status->group1_busy:%x\r\n",new_status->group1_busy); |
| |
| dbg_print("new_status->group2_info :%x\r\n",new_status->group2_info); |
| dbg_print("new_status->group2_result:%x\r\n",new_status->group2_result); |
| dbg_print("new_status->group2_busy:%x\r\n",new_status->group2_busy); |
| |
| dbg_print("new_status->group3_info :%x\r\n",new_status->group3_info); |
| dbg_print("new_status->group3_result:%x\r\n",new_status->group3_result); |
| dbg_print("new_status->group3_busy:%x\r\n",new_status->group3_busy); |
| |
| dbg_print("new_status->group4_info :%x\r\n",new_status->group4_info); |
| dbg_print("new_status->group4_result:%x\r\n",new_status->group4_result); |
| dbg_print("new_status->group4_busy:%x\r\n",new_status->group4_busy); |
| |
| dbg_print("new_status->group5_info :%x\r\n",new_status->group5_info); |
| dbg_print("new_status->group5_result:%x\r\n",new_status->group5_result); |
| dbg_print("new_status->group5_busy:%x\r\n",new_status->group5_busy); |
| |
| dbg_print("new_status->group6_info :%x\r\n",new_status->group6_info); |
| dbg_print("new_status->group6_result:%x\r\n",new_status->group6_result); |
| dbg_print("new_status->group6_busy:%x\r\n",new_status->group6_busy); |
| dbg_print("new_status->max_current:%x\r\n",new_status->max_current); |
| dbg_print("new_status->ver:%x\r\n",new_status->ver); |
| */ |
| |
| } |
| |
| SDC_CMD_STATUS SD_CheckSwitch(void) |
| { |
| //read the function support by current card |
| kal_uint32 status; |
| T_SWITCH_STATUS funcStatus; |
| |
| char *uhs_mode[] = {"SDR12", "SDR25", "SDR50", "SDR104", "DDR50"}; |
| char *speed_mode[] = {"DS", "HS"}; |
| char *drv_strength[] = {"TYPE_A", "TYPE_B", "TYPE_C", "TYPE_D"}; |
| char *cur_limit[] = {"200mA", "400mA", "600mA", "800mA"}; |
| |
| if ((status = SD_Switch_SD11(SD_CMD6_QUERY_SUPPORT_FUNCTION, (T_SWITCH_STATUS*)MSDC_Sector)) != NO_ERROR) |
| return status; |
| parse_Cmd6FunctionStatus(&funcStatus,(kal_uint8*)MSDC_Sector); |
| gSD->card_support.function1=funcStatus.group1_info; |
| gSD->card_support.function2=funcStatus.group2_info; |
| gSD->card_support.function3=funcStatus.group3_info; |
| gSD->card_support.function4=funcStatus.group4_info; |
| #if defined(MSDC_CONFIG_SD30_SUPPORT) |
| if (gMSDC_Handle->mMSDC_type==SD30_CARD) |
| { |
| //for SD3.0 |
| /*set bus speed mode*/ |
| if(gSD->card_support.function1&gMSDC_Handle->host_support.function1&FUN1_SDR104) |
| gSD->function_set.function1=FUN1_SET_SDR104; |
| else if(gSD->card_support.function1&gMSDC_Handle->host_support.function1&FUN1_DDR50) |
| gSD->function_set.function1=FUN1_SET_DDR50; |
| else if(gSD->card_support.function1&gMSDC_Handle->host_support.function1&FUN1_SDR50) |
| gSD->function_set.function1=FUN1_SET_SDR50; |
| else if(gSD->card_support.function1&gMSDC_Handle->host_support.function1&FUN1_SDR25_HS) |
| gSD->function_set.function1=FUN1_SET_SDR25_HS; |
| else |
| gSD->function_set.function1=FUN1_SET_SDR12_DS; |
| /*set command system*/ |
| gSD->function_set.function2=FUN2_SET_DEFAULT; |
| /*set driver strength */ |
| if (gSD->card_support.function3&gMSDC_Handle->host_support.function3&FUN3_TYPE_A) |
| gSD->function_set.function3=FUN3_SET_TYPE_A; |
| else if(gSD->card_support.function3&gMSDC_Handle->host_support.function3&FUN3_TYPE_B) |
| gSD->function_set.function3=FUN3_SET_TYPE_B; |
| else if(gSD->card_support.function3&gMSDC_Handle->host_support.function3&FUN3_TYPE_C) |
| gSD->function_set.function3=FUN3_SET_TYPE_C; |
| else if(gSD->card_support.function3&gMSDC_Handle->host_support.function3&FUN3_TYPE_D) |
| gSD->function_set.function3=FUN3_SET_TYPE_D; |
| else |
| gSD->function_set.function3=FUN3_SET_TYPE_A; |
| /*set current limit*/ |
| if (gSD->function_set.function1==FUN1_SET_SDR104||gSD->function_set.function1==FUN1_SET_DDR50 |
| ||gSD->function_set.function1==FUN1_SET_SDR50) |
| { |
| if(gSD->card_support.function4&gMSDC_Handle->host_support.function4&FUN4_800MA) |
| gSD->function_set.function4=FUN4_SET_800MA; |
| else if (gSD->card_support.function4&gMSDC_Handle->host_support.function4&FUN4_600MA) |
| gSD->function_set.function4=FUN4_SET_600MA; |
| else if (gSD->card_support.function4&gMSDC_Handle->host_support.function4&FUN4_400MA) |
| gSD->function_set.function4=FUN4_SET_400MA; |
| else |
| gSD->function_set.function4=FUN4_SET_200MA; |
| } |
| else |
| { |
| gSD->function_set.function4=FUN4_SET_200MA; |
| } |
| |
| MSDC_CRIT("[SD][%s]Switch to %s speed mode! \r\n", __FUNCTION__, |
| uhs_mode[gSD->function_set.function1]); |
| MSDC_CRIT("[SD][%s]Switch to %s drive strength! \r\n", __FUNCTION__, |
| drv_strength[gSD->function_set.function3]); |
| MSDC_CRIT("[SD][%s]Switch to %s current limit! \r\n", __FUNCTION__, |
| cur_limit[gSD->function_set.function4]); |
| } |
| else |
| #endif |
| { |
| //for 2.0 HS DS card |
| if(gSD->card_support.function1&gMSDC_Handle->host_support.function1&FUN1_SDR25_HS) |
| gSD->function_set.function1=FUN1_SET_SDR25_HS; |
| else |
| gSD->function_set.function1=FUN1_SET_SDR12_DS; |
| |
| MSDC_CRIT("[SD][%s]Switch to %s speed mode! \r\n", __FUNCTION__, |
| speed_mode[gSD->function_set.function1]); |
| } |
| return NO_ERROR; |
| |
| } |
| |
| SDC_CMD_STATUS SD_QuerySwith(kal_uint32 cmd6_arg) |
| { |
| |
| SDC_CMD_STATUS cmd_status; |
| T_SWITCH_STATUS card_support; |
| if ((cmd_status = SD_Switch_SD11(cmd6_arg, (T_SWITCH_STATUS*)MSDC_Sector)) != NO_ERROR) |
| return cmd_status; |
| parse_Cmd6FunctionStatus(&card_support,(kal_uint8*)MSDC_Sector); |
| /* |
| dbg_print("card_support.group1_info :%x\r\n",card_support.group1_info); |
| dbg_print("card_support.group1_result:%x\r\n",card_support.group1_result); |
| dbg_print("card_support.group1_busy:%x\r\n",card_support.group1_busy); |
| |
| dbg_print("card_support.group2_info :%x\r\n",card_support.group2_info); |
| dbg_print("card_support.group2_result:%x\r\n",card_support.group2_result); |
| dbg_print("card_support.group2_busy:%x\r\n",card_support.group2_busy); |
| |
| dbg_print("card_support.group3_info :%x\r\n",card_support.group3_info); |
| dbg_print("card_support.group3_result:%x\r\n",card_support.group3_result); |
| dbg_print("card_support.group3_busy:%x\r\n",card_support.group3_busy); |
| |
| dbg_print("card_support.group4_info :%x\r\n",card_support.group4_info); |
| dbg_print("card_support.group4_result:%x\r\n",card_support.group4_result); |
| dbg_print("card_support.group4_busy:%x\r\n",card_support.group4_busy); |
| |
| dbg_print("card_support.group5_info :%x\r\n",card_support.group5_info); |
| dbg_print("card_support.group5_result:%x\r\n",card_support.group5_result); |
| dbg_print("card_support.group5_busy:%x\r\n",card_support.group5_busy); |
| |
| dbg_print("card_support.group6_info :%x\r\n",card_support.group6_info); |
| dbg_print("card_support.group6_result:%x\r\n",card_support.group6_result); |
| dbg_print("card_support.group6_busy:%x\r\n",card_support.group6_busy); |
| dbg_print("card_support.max_current:%x\r\n",card_support.max_current); |
| dbg_print("card_support.ver:%x\r\n",card_support.ver); |
| */ |
| if (0 == card_support.max_current) |
| return ERR_HIGH_SPEED_CONSUMPTION; |
| #if defined(MSDC_CONFIG_SD30_SUPPORT) |
| if (gMSDC_Handle->mMSDC_type==SD30_CARD) |
| { |
| if ((gSD->function_set.function1==card_support.group1_result)\ |
| &&(0==(card_support.group1_busy &(1<<(gSD->function_set.function1))))) |
| { |
| |
| if ((gSD->function_set.function3==card_support.group3_result)\ |
| &&(0==(card_support.group3_busy &(1<<(gSD->function_set.function3))))) |
| { |
| |
| if ((gSD->function_set.function4==card_support.group4_result)\ |
| &&(0==(card_support.group4_busy &(1<<(gSD->function_set.function4))))) |
| { |
| |
| return NO_ERROR; |
| } |
| } |
| } |
| dbg_print("gSD->function_set.function1=%x card_support.group1_result=%x\r\n",gSD->function_set.function1,card_support.group1_result); |
| dbg_print("gSD->function_set.function3=%x card_support.group3_result=%x\r\n",gSD->function_set.function3,card_support.group3_result); |
| dbg_print("gSD->function_set.function4=%x card_support.group4_result=%x\r\n",gSD->function_set.function4,card_support.group4_result); |
| dbg_print("busy1 %x busy3 %x busy4 %x\r\n",(card_support.group1_busy &(1<<(gSD->function_set.function1)))\ |
| ,(card_support.group3_busy &(1<<(gSD->function_set.function3)))\ |
| ,(card_support.group4_busy &(1<<(gSD->function_set.function4)))); |
| if ((0xF == card_support.group1_result)\ |
| || (!(card_support.group1_info & (1<<(gSD->function_set.function1))))) |
| return ERR_SPEED_MODE_UNSUPPORT;//not support |
| if ((0xF == card_support.group3_result)\ |
| || (!(card_support.group3_info & (1<<(gSD->function_set.function3))))) |
| return ERR_DRIVER_TYPE_UNSUPPORT;//not support |
| if ((0xF == card_support.group4_result)\ |
| || (!(card_support.group4_info & (1<<(gSD->function_set.function4))))) |
| return ERR_CURRENT_LIMIT_UNSUPPORT;//not support |
| |
| |
| if (card_support.group1_busy & (1 << (gSD->function_set.function1)))//busy |
| return ERR_SWITCH_BUSY; |
| if (card_support.group3_busy & (1 << (gSD->function_set.function3)))//busy |
| return ERR_SWITCH_BUSY; |
| if (card_support.group4_busy & (1 << (gSD->function_set.function4)))//busy |
| return ERR_SWITCH_BUSY; |
| } |
| else |
| #endif |
| { |
| if ((gSD->function_set.function1==card_support.group1_result)\ |
| &&(0==(card_support.group1_busy &(1<<(gSD->function_set.function1))))) |
| return NO_ERROR; |
| if ((0xF == card_support.group1_result)\ |
| || (!(card_support.group1_info & (1<<(gSD->function_set.function1))))) |
| return ERR_HIGH_SPEED_NOT_SUPPORT;//not support |
| if (card_support.group1_busy & (1 << (gSD->function_set.function1)))//busy |
| return ERR_HIGH_SPEED_BUSY; |
| } |
| |
| return ERR_HIGH_SPEED_COMMON_ERROR; |
| } |
| |
| SDC_CMD_STATUS SD_SwitchSpeedMode(void) |
| { |
| kal_uint32 status,set_function; |
| kal_int32 t1; |
| |
| if (gSD->mSCR.spec_ver<SCR_SEC_VER_1) |
| { |
| gSD->function_set.function1=0; |
| return NO_ERROR; |
| } |
| if (!(gSD->mCSD.ccc&CCC_SWITCH)) |
| { |
| gSD->function_set.function1=0; |
| return NO_ERROR; |
| } |
| |
| t1 = drv_get_current_time(); |
| if ((status =SD_CheckSwitch()) != NO_ERROR) |
| return status; |
| #if defined(MSDC_CONFIG_SD30_SUPPORT) |
| if (gMSDC_Handle->mMSDC_type==SD30_CARD) |
| { |
| set_function=0x00ff0000|gSD->function_set.function1|(gSD->function_set.function3<<8)|(gSD->function_set.function4<<12); |
| } |
| else |
| #endif |
| { |
| set_function=0x00fffff0|gSD->function_set.function1; |
| } |
| do |
| { |
| status = SD_QuerySwith(SD_CMD6_QUERY_SWITCH|set_function);//query |
| if (NO_ERROR == status) |
| { |
| status = SD_QuerySwith(SD_CMD6_SELECT_SWITCH|set_function);//switch |
| if (NO_ERROR == status) |
| { |
| if (gMSDC_Handle->mMSDC_type==SD30_CARD) |
| { |
| gSD->flags |= SD_FLAG_UHS_ENABLED; |
| } |
| else if (gSD->function_set.function1==1) |
| { |
| gSD->flags |= SD_FLAG_HS_ENABLED; |
| } |
| |
| return NO_ERROR; |
| } |
| if (ERR_SWITCH_BUSY != status) |
| break; |
| } |
| if (ERR_SWITCH_BUSY != status) |
| break; |
| if (drv_get_duration_ms(t1)>500) |
| return ERR_SWITCH_TIMEOUT; |
| }while(1); |
| return status; |
| } |
| SDC_CMD_STATUS SD_GoInactive(kal_uint16 rca) |
| { |
| SDC_CMD_STATUS status; |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD15, (kal_uint32)rca << 16,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| return NO_ERROR; |
| } |
| |
| SDC_CMD_STATUS SD_ReadStream_MMC(kal_uint32 address, kal_uint32* rxbuffer, kal_uint32 bytes) |
| { |
| |
| return 0; |
| } |
| |
| |
| // write data stream from card only for MMC |
| SDC_CMD_STATUS SD_WriteStream_MMC(kal_uint32 address, kal_uint32* txbuffer, kal_uint32 bytes) |
| { |
| return 0; |
| } |
| |
| //program CSD, transfer CSD through data line |
| SDC_CMD_STATUS SD_ProgramCSD(kal_uint32 Csd[4]) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 blklen; |
| //set block length to 16 , num to 1 |
| |
| gSD->mBKNum=1; |
| blklen=gSD->mBKLength; |
| gSD->mBKLength = 16; |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| //set to pio mode and clear fifo |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 1, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=0; |
| MSDC_CLR_FIFO(); |
| |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD27, 0,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| { |
| //SD_WaitDatRdyOrTo(); |
| return status; |
| } |
| //send CSD 128 bits |
| status=SD_WaitDatRdyOrTo(Csd,16,KAL_TRUE); |
| //set block length back to 512 |
| BitFieldWrite32((kal_uint32*)SDC_CMD, 512, SDC_CMD_BLKLEN); |
| gSD->mBKLength=blklen; |
| return status; |
| } |
| |
| |
| //set write protect |
| SDC_CMD_STATUS SD_SetWriteProtect(kal_uint32 address) |
| { |
| SDC_CMD_STATUS status; |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD28, address,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| //wait until data line is ready |
| status =SD_WaitCardNotBusy(MSDC_DATA_TIMEOUT); |
| return status; |
| } |
| |
| //clear write protect |
| SDC_CMD_STATUS SD_ClrWriteProtect(kal_uint32 address) |
| { |
| SDC_CMD_STATUS status; |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD29, address,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| status=SD_WaitCardNotBusy(MSDC_DATA_TIMEOUT); |
| return status; |
| } |
| |
| // send write protect(single block read) |
| SDC_CMD_STATUS SD_SendWriteProtect(kal_uint32 address, kal_uint32* WPBits32) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 tmp,blklen; |
| |
| |
| BitFieldWrite32((kal_uint32*)SDC_CMD, 4, SDC_CMD_BLKLEN); |
| blklen=gSD->mBKLength; |
| gSD->mBKLength=4; |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| MSDC_CLR_FIFO(); |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD30, address,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| //read 32 write protection bits |
| tmp=MSDC_FIFO_READ32(); |
| MSDC_InvertN((kal_uint8*)WPBits32, (kal_uint8*)&tmp, 4); |
| // configure the controller to the original block length |
| BitFieldWrite32((kal_uint32*)SDC_CMD, 512, SDC_CMD_BLKLEN); |
| gSD->mBKLength=blklen; |
| |
| return NO_ERROR; |
| } |
| |
| // CMD39: Fast IO-used to write and read 8 bit register |
| SDC_CMD_STATUS SD_FastIO_MMC(kal_uint16 rca, kal_bool isWrite, kal_uint8 reg_adrs, kal_uint8 data) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 arg = 0; |
| |
| arg = rca << 16; |
| arg |= isWrite << 15; |
| arg |= reg_adrs << 8; |
| arg |= data; |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD39_MMC, arg,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| return NO_ERROR; |
| } |
| |
| |
| // Sets the system into interrupt mode (MMC) |
| SDC_CMD_STATUS SD_GoIRQ_MMC(void) |
| { |
| SDC_CMD_STATUS status; |
| |
| if ((status = SD_SendCmd(SDC_CMD_CMD40_MMC, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| status = *(kal_uint32*)SDC_RESP0; |
| #ifdef MSDC_TRACE_LEVEL2 |
| MD_TRC_MSDC_INFORM_R0(status, __LINE__); |
| #endif |
| |
| return NO_ERROR; |
| } |
| |
| // Used to set/reset password ,lock/unlock the card and force erase total card. |
| // similiar to a signle block write structure.(CMD42) |
| // max password length = 16 |
| SDC_CMD_STATUS SD_LockUnlock(SD_LOCK_OP op, kal_char* Oldpwd, kal_char* Newpwd, kal_uint8 Oldlen, kal_uint8 Newlen) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint8 lockbk[SDC_MAX_LOCKBK]; |
| kal_uint32 blklen, *ptr = (kal_uint32*)lockbk, count; |
| |
| if (Oldlen > 16 || Newlen > 16) |
| return ERR_ERRORS; |
| |
| /* save the original block length*/ |
| blklen = gSD->mBKLength; |
| |
| kal_mem_set(lockbk, 0, SDC_MAX_LOCKBK); |
| |
| switch (op) |
| { |
| case SET_PWD: |
| lockbk[0] = 0x01; |
| break; |
| |
| case CLR_PWD: |
| lockbk[0] = 0x02; |
| break; |
| |
| case LOCK_CARD: |
| lockbk[0] = 0x04; |
| break; |
| |
| case UNLOCK_CARD: |
| lockbk[0] = 0x00; |
| break; |
| |
| case ERASE: |
| lockbk[0] = 0x08; |
| break; |
| } |
| |
| lockbk[1] = Oldlen + Newlen; |
| kal_mem_cpy(&lockbk[2], Oldpwd, Oldlen); |
| kal_mem_cpy(&lockbk[2 + Oldlen], Newpwd, Newlen); |
| |
| /* set block length */ |
| if (op != ERASE) |
| { |
| SD_SetBlength(2 + lockbk[1]); |
| count = ((lockbk[1] + 2) % sizeof(kal_uint32)) ? ((lockbk[1] + 2) / sizeof(kal_uint32) + 1) : |
| ((lockbk[1] + 2) / sizeof(kal_uint32)); |
| gSD->mBKNum=1; |
| blklen=gSD->mBKLength; |
| gSD->mBKLength = 2 + lockbk[1]; |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| //set to pio mode and clear fifo |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 1, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=0; |
| MSDC_CLR_FIFO(); |
| } |
| else |
| { |
| SD_SetBlength(1); |
| gSD->mBKNum=1; |
| blklen=gSD->mBKLength; |
| gSD->mBKLength = 1; |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| //set to pio mode and clear fifo |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 1, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=0; |
| MSDC_CLR_FIFO(); |
| count = 1; |
| } |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| /* send command */ |
| if ((status = SD_SendCmd(SDC_CMD_CMD42, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| /* read R1b */ |
| SD_CheckStatus(); |
| /* clear FIFO */ |
| MSDC_CLR_FIFO(); |
| |
| |
| #ifndef DRV_LSD |
| status=SD_WaitDatRdyOrTo(ptr,count,KAL_TRUE); |
| |
| #endif |
| |
| /* wait util card has finished programming */ |
| SD_WaitCardNotBusy(MSDC_DATA_TIMEOUT); |
| // restore the block length back |
| if (status != NO_ERROR) |
| { |
| return gMSDC_Handle->error; |
| } |
| |
| // restore the block length back |
| SD_SetBlength(blklen); |
| gSD->mBKLength=blklen; |
| /* check status*/ |
| SD_GetStatus(gSD->mRCA, &status); |
| |
| if (status & R1_LOCK_UNLOCK_FAILED_24) |
| return ERR_LOCK_UNLOCK_FAILED; |
| |
| if ((op == LOCK_CARD) && !(status & R1_CARD_IS_LOCKED_25)) |
| return ERR_LOCK_UNLOCK_FAILED; |
| |
| if ((op == UNLOCK_CARD) && (status & R1_CARD_IS_LOCKED_25)) |
| return ERR_LOCK_UNLOCK_FAILED; |
| |
| return NO_ERROR; |
| } |
| |
| // ACMD13: read SD status(512bits = 64bytes single block read) |
| SDC_CMD_STATUS SD_GetSDStatus(kal_uint32* sd_status) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 blklen; |
| |
| |
| //if ((status = SD_SetBlength(64)) != NO_ERROR) |
| // return status; |
| |
| // send APP_CMD |
| if ((status = SD_Cmd55(gSD->mRCA)) != NO_ERROR) |
| return status; |
| // save the orignial block length |
| blklen=gSD->mBKLength; |
| gSD->mBKLength = 64; |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| MSDC_DEBUG("[SD][%s %d]send acmd13\r\n",__FUNCTION__,__LINE__); |
| |
| //set to pio mode and clear fifo |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 1, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=0; |
| MSDC_CLR_FIFO(); |
| // send ACMD13 |
| if ((status = SD_SendCmd(SDC_CMD_ACMD13, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| // read sd status(64bytes = 4x16) |
| status=SD_WaitDatRdyOrTo(sd_status,64,KAL_FALSE); |
| if (status !=NO_ERROR) |
| { |
| return status; |
| } |
| gSD->mBKLength=blklen; |
| return NO_ERROR; |
| } |
| //ACMD22: get the number of written write blocks(4bytes single block read) |
| SDC_CMD_STATUS SD_GetNumWrittenBlk(kal_uint32* num) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 blklen, tmp; |
| |
| // send APP_CMD |
| if ((status = SD_Cmd55(gSD->mRCA)) != NO_ERROR) |
| return status; |
| |
| blklen=gSD->mBKLength; |
| gSD->mBKLength = 4; |
| MSDC_WriteReg32(SDC_BLK_NUM,1); |
| MSDC_DEBUG("[SD][%s %d]send acmd13\r\n",__FUNCTION__,__LINE__); |
| |
| //set to pio mode and clear fifo |
| BitFieldWrite32((kal_uint32 *)MSDC_CFG, 1, MSDC_CFG_PIO); |
| gMSDC_Handle->dma_xfer=0; |
| MSDC_CLR_FIFO(); |
| |
| // send CMD22 |
| if ((status = SD_SendCmd(SDC_CMD_ACMD22, SDC_NO_ARG,MSDC_CMD_TIMEOUT)) != NO_ERROR) |
| return status; |
| |
| //read R1 |
| if ((status = SD_CheckStatus()) != NO_ERROR) |
| return status; |
| |
| // read the number of written write blocks(4bytes) |
| |
| if ((status=SD_WaitDatRdyOrTo(&tmp,4,KAL_FALSE))!=NO_ERROR) |
| return status; |
| |
| MSDC_InvertN((kal_uint8*)num, (kal_uint8*)&tmp, 4); |
| |
| // resotre block length |
| gSD->mBKLength=blklen; |
| return NO_ERROR; |
| } |
| |
| #ifdef DRV_MSDC_HW_CONTENTION |
| extern kal_semid dclMsdcArb; |
| #endif |
| |
| void SD_startFastFormat(void) |
| { |
| #if defined(__AUDIO_DSP_LOWPOWER__) |
| AUDMA_LOCK(AUDMA_ID_MSDC); |
| #endif |
| |
| #ifdef DRV_MSDC_HW_CONTENTION |
| kal_uint32 retAddr; |
| |
| #if defined(__RVCT__) |
| /* RVCT doesn't support inline assemlber; bypass temporarily */ |
| retAddr = 0; |
| #else /* __RVCT__ */ |
| /* get the return address */ |
| __asm |
| { |
| MOV retAddr, lr |
| } |
| #endif /* __RVCT__ */ |
| |
| |
| if (NULL == dclMsdcArb) |
| ASSERT(0); |
| |
| if (kal_query_systemInit() == KAL_FALSE) |
| { |
| /*must gain resource here before calling writeSectors*/ |
| kal_take_sem(dclMsdcArb, 1); |
| SD_setArbRetAddr(retAddr); |
| SD_setArbThdId((kal_uint32)kal_get_current_thread_ID()); |
| } |
| |
| #endif |
| |
| |
| #ifdef DRV_LSD |
| LSD_startFastFormat(); |
| #elif defined(__DRV_MSDC_FAST_FORMAT__) |
| gMSDC_Handle->MSDC_fastFormat = KAL_TRUE; |
| #endif |
| } |
| |
| void SD_closeFastFormat(void) |
| { |
| #ifdef DRV_LSD |
| LSD_closeFastFormat(); |
| #elif defined(__DRV_MSDC_FAST_FORMAT__) |
| gMSDC_Handle->MSDC_fastFormat = KAL_FALSE; |
| #endif |
| |
| #ifdef DRV_MSDC_HW_CONTENTION |
| |
| if (kal_query_systemInit() == KAL_FALSE) |
| { |
| /*when the semaphore is returned, we set thdId to zero, but not retAddr, we can know that it is released from here*/ |
| SD_setArbThdId(NULL); |
| kal_give_sem(dclMsdcArb); |
| } |
| |
| #endif |
| |
| #if defined(__AUDIO_DSP_LOWPOWER__) |
| AUDMA_UNLOCK(AUDMA_ID_MSDC); |
| #endif |
| |
| } |
| |
| |
| //__attribute__ ((section ("EXT_BOOTLOADER_CODE")))SDC_CMD_STATUS SD_FlushSectors(kal_uint32 startSector, kal_uint32 sectorNum) |
| SDC_CMD_STATUS SD_FlushSectors(kal_uint32 startSector, kal_uint32 sectorNum) |
| { |
| SDC_CMD_STATUS status; |
| kal_uint32 sectorMult,maxBlk; |
| |
| if (gSD->flags & SD_FLAG_HCS_SUPPORT) |
| sectorMult = 1; |
| else |
| sectorMult = SECTOR_SIZE; |
| maxBlk=gSD->mCSD.capacity /512; |
| if(0 == sectorNum || sectorNum > maxBlk || startSector > maxBlk){ |
| //ASSERT(0); |
| status = STATUS_INVALID_CTRL_DATA; |
| return status; |
| } |
| |
| /*check that ending block should be smaller than maximum block number*/ |
| if((startSector + sectorNum - 1) > maxBlk){ |
| //ASSERT(0); |
| status = STATUS_INVALID_CTRL_DATA; |
| return status; |
| } |
| MSDC_PDNControl(KAL_FALSE); |
| |
| // there are differences between SD and MMC |
| // tag erase start(CMD32) |
| if ((status = SD_EraseCmdClass(SDC_CMD_CMD32, sectorMult * startSector)) != NO_ERROR) |
| { |
| goto ErrorExit; |
| } |
| |
| // tag erase end(CMD33) |
| if ((status = SD_EraseCmdClass(SDC_CMD_CMD33, sectorMult * (startSector + sectorNum - 1))) != NO_ERROR) |
| { |
| goto ErrorExit; |
| } |
| |
| // erase...(CMD38) |
| if ((status = SD_EraseCmdClass(SDC_CMD_CMD38, 0)) != NO_ERROR) |
| { |
| goto ErrorExit; |
| } |
| |
| ErrorExit: |
| MSDC_PDNControl(KAL_TRUE); |
| return status; |
| } |
| |
| #ifdef IC_MODULE_TEST |
| |
| kal_bool MSDC_ModuleTest_Report(void) |
| { |
| |
| SDC_CMD_STATUS status; |
| |
| if (gMSDC_Handle->mIsInitialized == KAL_FALSE) |
| return KAL_FALSE; |
| |
| MSDC_PDNControl(KAL_FALSE); |
| |
| gMSDC_Handle->mIsInitialized = KAL_TRUE; |
| gMSDC_Handle->trySingleLine = KAL_TRUE; |
| |
| status = SD_Initialize(); |
| |
| if (status == NO_ERROR) |
| return KAL_TRUE; |
| else |
| return KAL_FALSE; |
| |
| } |
| #endif |
| |
| #else |
| #ifdef DRV_LSD |
| T_SDC_HANDLE gSD_blk[SD_NUM]; |
| T_SDC_HANDLE *gSD = gSD_blk; |
| #endif |
| #endif // defined(__MSDC_SD_MMC__) |
| |
| #ifdef MSDC_DEBUG |
| |
| #define TST_ADRS 512*12 |
| kal_uint32 SD_MMC_Test(void) |
| { |
| |
| return 0; |
| |
| } |
| #endif // FPGA_DEBUG |
| |
| #endif//!defined(__UBL__) || defined(__CARD_DOWNLOAD__) || defined(__EMMC_BOOTING__) |
| |
| #else //DRV_MSDC_OFF |
| #include "kal_public_api.h" //MSBB change #include "kal_release.h" |
| #include "kal_general_types.h" |
| //#include "btif_sw.h" |
| #include "kal_public_api.h" |
| #include "kal_internal_api.h" |
| #include "kal_public_defs.h" |
| |
| //#include "gpt_sw.h" |
| #include "drv_comm.h" |
| #include "reg_base.h" |
| #include "msdc_def.h" |
| #include "sd_def.h" |
| #include "upll_ctrl.h" |
| //#include "Drv_trc.h" |
| #ifdef DCL_MSDC_INTERFACE |
| #include "dcl.h" |
| void SD_dummyAPI(void) {} |
| SDC_CMD_STATUS SD_SetBlength(kal_uint32 BKLength) {} |
| SDDriver_t sd_driver_MTK1 = |
| { |
| (DCL_SINGLE_BLK_RD)SD_dummyAPI, |
| (DCL_MUL_BLK_RD)SD_dummyAPI, |
| (DCL_SINGLE_BLK_WR)SD_dummyAPI, |
| (DCL_MUL_BLK_WR)SD_dummyAPI, |
| (DCL_SD_INITITALIZE)SD_dummyAPI, |
| (DCL_SET_PRE_ERASE_CNT)SD_dummyAPI, |
| (DCL_SD_SET_CALLBACK)SD_dummyAPI, |
| (DCL_SET_READ_TEST_FLAG)SD_dummyAPI, |
| (DCL_SD_READ_TEST)SD_dummyAPI, |
| (DCL_SD_SET_UPLL_CLOCK_TEST)SD_dummyAPI, |
| (DCL_SD_ERASE_BLK)SD_dummyAPI, |
| (DCL_GPD_MUL_BLK_RD)SD_dummyAPI, |
| (DCL_GPD_MUL_BLK_WR)SD_dummyAPI, |
| }; |
| #endif //DCL_MSDC_INTERFACE |
| |
| void SD_startFastFormat(void) {} |
| void SD_closeFastFormat(void) {} |
| T_SDC_HANDLE gSD_blk[SD_NUM]; |
| T_SDC_HANDLE *gSD = gSD_blk; |
| |
| #if defined( __MSDC_BASIC_LOAD__) || defined( __MEUT__) |
| kal_uint32 msdc_ReadTestFlag; |
| #endif |
| |
| #endif //DRV_MSDC_OFF |
| |
| |