/**

  **********************************************************************************
  * @file    sdcard_hal.c
  * @author  Product application department
  * @version V1.0
  * @date    2020.06.01
  * @brief   SDCARD模块HAL层驱动.
  *
  @verbatim
  ===================================================================================
                                  ##### 更新 #####
  ===================================================================================
  [..] 更新时间:
  [..] 更新人:
  [..] 更新内容:
        1. nothing.
  @endverbatim
*/
#include "sdcard_hal.h"
//#include "cpm_hal.h"

/*** 全局变量定义 ***************************************************************/
/** @
  * @{volatile
  */
 
  SD_CardInfo SDCardInfo;

 /* g_sdmmc statement */
  uint32_t g_sdmmc[SDK_SIZEALIGN(SDMMC_GLOBAL_BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)];

/** @ 
  * @}
  */
/** @ 
  * @{static
  */

static uint32_t CSD_Tab[4], CID_Tab[4], RCA = 0;
static uint32_t SCR[2], Switch_Func[16];
static uint32_t CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0;
static uint8_t start_write_block = 0;

/** @ 
  * @}
  */
/*** 常量定义 *******************************************************************/
/** @
  * @{const
  */

/** @ 
  * @}
  */

/*** 函数定义 *******************************************************************/

/**
  *@brief 枚举SD卡
  *-
  *@param[in] NONE
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef HAL_SD_EnumCard(void)
{
	HAL_SDCARD_StateTypeDef errorstatus = SD_OK;

	errorstatus = HAL_SD_Init();  //SD卡接口初始化
	if(errorstatus != SD_OK)
	{
		printf("HAL_SD_Init FAILED \r\n");
		return(errorstatus);
	}
	else
	{
		printf("HAL_SD_Init OK \r\n");
	}

  errorstatus = HAL_SD_GetCardInfo(&SDCardInfo); //获取SD卡信息
	
	printf("ManufacturerID:%x\r\n",SDCardInfo.SD_cid.ManufacturerID);
	printf("OEM_AppliID:%x\r\n",SDCardInfo.SD_cid.OEM_AppliID);
	
	
	errorstatus = HAL_SD_SelectDeselect(SDCardInfo.RCA);
	if(errorstatus != SD_OK)
	{
		printf("HAL_SD_SelectDeselect FAILED\r\n");
		return(errorstatus);
	}
	errorstatus = HAL_SD_EnWideBus();
	if(errorstatus != SD_OK)
	{
		printf("HAL_SD_EnWideBus FAILED\r\n");
		return(errorstatus);
	}
	errorstatus = HAL_SD_SendSCR(SCR);
	if(errorstatus != SD_OK)
	{
		printf("HAL_SD_SendSCR FAILED\r\n");
		return(errorstatus);
	}
		
   if(CardType == SDIO_HIGH_CAPACITY_SD_CARD_V3_0)
   {
   	errorstatus = SD_SwitchFunc_V3_0(Switch_Func);
   }
   else //if(CardType == SDIO_STD_CAPACITY_SD_CARD_V2_0)
    {
    	errorstatus = SD_SwitchFunc_V2_0(Switch_Func);
    }
		
	return(errorstatus);
}



/**
  *@brief SD初始化
  *-
  *@param[in] NONE
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef HAL_SD_Init(void)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;

  /* SD_EMMC_HOST FPGA V1.0, test item select by gpios */
  //GPIO_Configuration(0);//配置SDIO接口使用的FPGA GPIO管脚


  /* Assert Reset - active-low */
  if(SDIO_Reset())
  {
		/* Reset TimeOut (wait for hw rest flag) */
		errorstatus = SD_ERROR;
		printf("SDIO_Reset FAILED \r\n");
		return(errorstatus);
  }

  //SDIO_Init();
	SDIO_Init_NOINT();
	
  //while(SDIO_CardDetect());

  //DRV_CPM_SetSDHostClkDiv(15);//400MHZ/16 == 25MHZ
  //DRV_CPM_SetSDHostClkDiv(7);
  SDIO_SetClk(1<<SD_SLOT1, SDIO_CLKOUT_400kHz_DIV);

  errorstatus = HAL_SD_PowerON();
  if (errorstatus != SD_OK)
  {
    /* CMD Response TimeOut (wait for CMDSENT flag) */
		printf("HAL_SD_PowerON FAILED \r\n");
    return(errorstatus);
  }

  errorstatus = HAL_SD_InitializeCards();
  if (errorstatus != SD_OK)
  {
    /* CMD Response TimeOut (wait for CMDSENT flag) */
		printf("HAL_SD_InitializeCards FAILED \r\n");
    return(errorstatus);
  }
  
  printf("CardType:%d \r\n",SDCardInfo.CardType);

  return(errorstatus);
}

/**
  *@brief SD上电
  *-
  *@param[in] NONE
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef HAL_SD_PowerON(void)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t status, response, count = 0;

  /* CMD0: GO_IDLE_STATE -------------------------------------------------------*/
  /* No CMD response required */
		//printf("1 \r\n");
  CMD0_SD_tsk( CMD0ARG_GO_IDLE_STATE);

  //delay_f(1000);
	//delay(0x10000);
	//delay(0xf0000);
  DelayMS(5);
	//	printf("2 \r\n");
  /* CMD8: SEND_IF_COND --------------------------------------------------------*/
  /* Send CMD8 to verify SD card interface operating condition */
  /* Argument: - [31:12]: Reserved (shall be set to '0')
               - [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
               - [7:0]: Check Pattern (recommended 0xAA) */
  /* CMD Response: R7 */
	//while(1)
	{
		CMD8_SD_tsk(0x000001AA);
		response = R32(SDMMC_RESP0);
  }
	if(response != 0x000001AA)
  {
		//printf("22 response = 0x%08x\r\n",response);
	  //__asm("bkpt 0");
  }
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
    //printf(">>>>>>>>>>>>>>>>>1\r\n");
    W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
    return SD_ERROR;
  }
  else
  {
    //printf(">>>>>>>>>>>>>>>>>2\r\n");
	  CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /* SD Card 2.0 */
  }
	//printf("3 \r\n");
  /* If errorstatus is Command TimeOut, it is a MMC card */
  /* If errorstatus is SD_OK it is a SD card: SD card 2.0 (voltage range mismatch)
     or SD card 1.x */
  /* SD CARD */
  /* Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */
  while(count < SD_MAX_VOLT_TRIAL)
  {
	  //host support High Capacity SD + host support 2.7V-3.V
	  //bit24: S18R --Supports voltage switching for 1.8V
	  //ACMD41_SD_tsk(0x403c0000);
	  ACMD41_SD_tsk(0x513c0000);
	  status = R32(SDMMC_RINTSTS);
	  if(status & DWC_MSH_CMD_ERROR_FLAGS)
	  {
		  W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
		  return SD_ERROR;
	  }
	  status = R32(SDMMC_RESP0);
	  count++;
	  if((status & OCR_BUSY_Bit31) != OCR_POWER_BUSY)
	  {
		  break;
	  }
  }
  if(count >= SD_MAX_VOLT_TRIAL)
  {
      errorstatus = SD_INVALID_VOLTRANGE;
      return(errorstatus);
  }
  //printf(">>>>>>>>>>>>>>>>>3\r\n");
	//printf("4 \r\n");
  if((status & SD_HIGH_CAPACITY) == SD_HIGH_CAPACITY)
  {
      CardType = SDIO_HIGH_CAPACITY_SD_CARD;
      //CardType = SDIO_HIGH_CAPACITY_SD_CARD_V3_0;
  }

//  if((status & OCR_S18A_Bit24) == OCR_S18A_Bit24) //voltage switch
//  {
//	  CMD11_SD_tsk();
//	  status = R32(SDMMC_RINTSTS);
//	  if(status & DWC_MSH_CMD_ERROR_FLAGS)
//	  {
//	  	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
//	  	return SD_ERROR;
//	  }
//	  SDIO_SwitchClk(0);
//	  SDIO_Card_Volt(1<<SD_SLOT1, 1); //1.8Vdd
//	  status = R32(SDMMC_UHS_EXT);
//	  status |= 0xffff;
//	  W32(SDMMC_UHS_EXT, status);
//	  delay_f(0x3000); //min >=7ms
//	  GPIO_Configuration(1);//配置SDIO接口使用的FPGA GPIO管脚
//	  SDIO_SwitchClk(1);
//	  SDIO_PollStatus(SDMMC_INT_CMD_DONE|SDMMC_INT_VOLT_SWITCH);
//  }
  return(errorstatus);
}

/**
  *@brief SD初始化卡
  *-
  *@param[in] NONE
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef HAL_SD_InitializeCards(void)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t status;
  uint16_t rca = 0x0001;

//  if(SDIO_GetPowerState(1<<SD_SLOT1) == SDIO_PowerState_OFF)
//  {
//    errorstatus = SD_REQUEST_NOT_APPLICABLE;
//    return(errorstatus);
//  }

  /* Send CMD2 ALL_SEND_CID */
  CMD2_SD_tsk();
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	  W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
		printf("CMD2_SD_tsk FAILED \r\n");
	  return SD_ERROR;
  }
  CID_Tab[3] = R32(SDMMC_RESP0);
  CID_Tab[2] = R32(SDMMC_RESP1);
  CID_Tab[1] = R32(SDMMC_RESP2);
  CID_Tab[0] = R32(SDMMC_RESP3);
	
//	printf("just for delay................... \r\n");
//	printf("just for delay................... \r\n");
//	printf("just for delay................... \r\n");
	//delay(0xf0000);
  DelayMS(100);
	
  /* Send CMD3 SET_REL_ADDR with argument 0 */
  /* SD Card publishes its RCA. */
  CMD3_SD_tsk(0x0000);
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
    W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
    printf("CMD3_SD_tsk FAILED \r\n");
    return SD_ERROR;
  }
  status = R32(SDMMC_RESP0);
  if(0 == (status & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED)))
  {
	  rca = (uint16_t) (status >> 16);
  }
  else
  {
	  if (status & SD_R6_GENERAL_UNKNOWN_ERROR)
	  {
			printf("SD_R6_GENERAL_UNKNOWN_ERROR FAILED \r\n");
		  return(SD_GENERAL_UNKNOWN_ERROR);
	  }
	  if (status & SD_R6_ILLEGAL_CMD)
	  {
			printf("SD_R6_ILLEGAL_CMD FAILED \r\n");
		  return(SD_ILLEGAL_CMD);
	  }
	  if (status & SD_R6_COM_CRC_FAILED)
	  {
			printf("SD_R6_COM_CRC_FAILED FAILED \r\n");
		  return(SD_COM_CRC_FAILED);
	  }
  }

  RCA = rca;
  /* Send CMD9 SEND_CSD with argument as card's RCA */
  CMD9_SD_tsk(RCA);
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
    W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
    printf("CMD9_SD_tsk FAILED \r\n");
    return SD_ERROR;
  }
  CSD_Tab[3] = R32(SDMMC_RESP0);
  CSD_Tab[2] = R32(SDMMC_RESP1);
  CSD_Tab[1] = R32(SDMMC_RESP2);
  CSD_Tab[0] = R32(SDMMC_RESP3);

  errorstatus = SD_OK; /* All cards get intialized */

  return(errorstatus);
}

/**
  *@brief 获取SD卡信息
  *-
  *@param[in] -cardinfo SD卡信息指针
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef HAL_SD_GetCardInfo(SD_CardInfo *cardinfo)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint8_t tmp = 0;

  cardinfo->CardType = (uint8_t)CardType;
  cardinfo->RCA = (uint16_t)RCA;

  /* Byte 0 */
  tmp = (uint8_t)((CSD_Tab[0] & 0xFF000000) >> 24);
  cardinfo->SD_csd.CSDStruct = (tmp & 0xC0) >> 6;
  cardinfo->SD_csd.SysSpecVersion = (tmp & 0x3C) >> 2;
  cardinfo->SD_csd.Reserved1 = tmp & 0x03;

  /* Byte 1 */
  tmp = (uint8_t)((CSD_Tab[0] & 0x00FF0000) >> 16);
  cardinfo->SD_csd.TAAC = tmp;

  /* Byte 2 */
  tmp = (uint8_t)((CSD_Tab[0] & 0x0000FF00) >> 8);
  cardinfo->SD_csd.NSAC = tmp;

  /* Byte 3 */
  tmp = (uint8_t)(CSD_Tab[0] & 0x000000FF);
  cardinfo->SD_csd.MaxBusClkFrec = tmp;

  /* Byte 4 */
  tmp = (uint8_t)((CSD_Tab[1] & 0xFF000000) >> 24);
  cardinfo->SD_csd.CardComdClasses = tmp << 4;

  /* Byte 5 */
  tmp = (uint8_t)((CSD_Tab[1] & 0x00FF0000) >> 16);
  cardinfo->SD_csd.CardComdClasses |= (tmp & 0xF0) >> 4;
  cardinfo->SD_csd.RdBlockLen = tmp & 0x0F;

  /* Byte 6 */
  tmp = (uint8_t)((CSD_Tab[1] & 0x0000FF00) >> 8);
  cardinfo->SD_csd.PartBlockRead = (tmp & 0x80) >> 7;
  cardinfo->SD_csd.WrBlockMisalign = (tmp & 0x40) >> 6;
  cardinfo->SD_csd.RdBlockMisalign = (tmp & 0x20) >> 5;
  cardinfo->SD_csd.DSRImpl = (tmp & 0x10) >> 4;
  cardinfo->SD_csd.Reserved2 = 0; /* Reserved */

  if(CardType == SDIO_STD_CAPACITY_SD_CARD_V2_0)
  {
    cardinfo->SD_csd.DeviceSize = (tmp & 0x03) << 10;

    /* Byte 7 */
    tmp = (uint8_t)(CSD_Tab[1] & 0x000000FF);
    cardinfo->SD_csd.DeviceSize |= (tmp) << 2;

    /* Byte 8 */
    tmp = (uint8_t)((CSD_Tab[2] & 0xFF000000) >> 24);
    cardinfo->SD_csd.DeviceSize |= (tmp & 0xC0) >> 6;

    cardinfo->SD_csd.MaxRdCurrentVDDMin = (tmp & 0x38) >> 3;
    cardinfo->SD_csd.MaxRdCurrentVDDMax = (tmp & 0x07);

    /* Byte 9 */
    tmp = (uint8_t)((CSD_Tab[2] & 0x00FF0000) >> 16);
    cardinfo->SD_csd.MaxWrCurrentVDDMin = (tmp & 0xE0) >> 5;
    cardinfo->SD_csd.MaxWrCurrentVDDMax = (tmp & 0x1C) >> 2;
    cardinfo->SD_csd.DeviceSizeMul = (tmp & 0x03) << 1;
    /* Byte 10 */
    tmp = (uint8_t)((CSD_Tab[2] & 0x0000FF00) >> 8);
    cardinfo->SD_csd.DeviceSizeMul |= (tmp & 0x80) >> 7;

    cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) ;
    cardinfo->CardCapacity *= (1 << (cardinfo->SD_csd.DeviceSizeMul + 2));
    cardinfo->CardBlockSize = 1 << (cardinfo->SD_csd.RdBlockLen);
    cardinfo->CardCapacity *= cardinfo->CardBlockSize;
  }
  else if(CardType == SDIO_HIGH_CAPACITY_SD_CARD)
  {
    /* Byte 7 */
    tmp = (uint8_t)(CSD_Tab[1] & 0x000000FF);
    cardinfo->SD_csd.DeviceSize = (tmp & 0x3F) << 16;

    /* Byte 8 */
    tmp = (uint8_t)((CSD_Tab[2] & 0xFF000000) >> 24);

    cardinfo->SD_csd.DeviceSize |= (tmp << 8);

    /* Byte 9 */
    tmp = (uint8_t)((CSD_Tab[2] & 0x00FF0000) >> 16);

    cardinfo->SD_csd.DeviceSize |= (tmp);

    /* Byte 10 */
    tmp = (uint8_t)((CSD_Tab[2] & 0x0000FF00) >> 8);

    cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) * 512 * 1024;
    cardinfo->CardBlockSize = 512;
  }


  cardinfo->SD_csd.EraseGrSize = (tmp & 0x40) >> 6;
  cardinfo->SD_csd.EraseGrMul = (tmp & 0x3F) << 1;

  /* Byte 11 */
  tmp = (uint8_t)(CSD_Tab[2] & 0x000000FF);
  cardinfo->SD_csd.EraseGrMul |= (tmp & 0x80) >> 7;
  cardinfo->SD_csd.WrProtectGrSize = (tmp & 0x7F);

  /* Byte 12 */
  tmp = (uint8_t)((CSD_Tab[3] & 0xFF000000) >> 24);
  cardinfo->SD_csd.WrProtectGrEnable = (tmp & 0x80) >> 7;
  cardinfo->SD_csd.ManDeflECC = (tmp & 0x60) >> 5;
  cardinfo->SD_csd.WrSpeedFact = (tmp & 0x1C) >> 2;
  cardinfo->SD_csd.MaxWrBlockLen = (tmp & 0x03) << 2;

  /* Byte 13 */
  tmp = (uint8_t)((CSD_Tab[3] & 0x00FF0000) >> 16);
  cardinfo->SD_csd.MaxWrBlockLen |= (tmp & 0xC0) >> 6;
  cardinfo->SD_csd.WriteBlockPaPartial = (tmp & 0x20) >> 5;
  cardinfo->SD_csd.Reserved3 = 0;
  cardinfo->SD_csd.ContentProtectAppli = (tmp & 0x01);

  /* Byte 14 */
  tmp = (uint8_t)((CSD_Tab[3] & 0x0000FF00) >> 8);
  cardinfo->SD_csd.FileFormatGrouop = (tmp & 0x80) >> 7;
  cardinfo->SD_csd.CopyFlag = (tmp & 0x40) >> 6;
  cardinfo->SD_csd.PermWrProtect = (tmp & 0x20) >> 5;
  cardinfo->SD_csd.TempWrProtect = (tmp & 0x10) >> 4;
  cardinfo->SD_csd.FileFormat = (tmp & 0x0C) >> 2;
  cardinfo->SD_csd.ECC = (tmp & 0x03);

  /* Byte 15 */
  tmp = (uint8_t)(CSD_Tab[3] & 0x000000FF);
  cardinfo->SD_csd.CSD_CRC = (tmp & 0xFE) >> 1;
  cardinfo->SD_csd.Reserved4 = 1;


  /* Byte 0 */
  tmp = (uint8_t)((CID_Tab[0] & 0xFF000000) >> 24);
  cardinfo->SD_cid.ManufacturerID = tmp;

  /* Byte 1 */
  tmp = (uint8_t)((CID_Tab[0] & 0x00FF0000) >> 16);
  cardinfo->SD_cid.OEM_AppliID = tmp << 8;

  /* Byte 2 */
  tmp = (uint8_t)((CID_Tab[0] & 0x000000FF00) >> 8);
  cardinfo->SD_cid.OEM_AppliID |= tmp;

  /* Byte 3 */
  tmp = (uint8_t)(CID_Tab[0] & 0x000000FF);
  cardinfo->SD_cid.ProdName1 = tmp << 24;

  /* Byte 4 */
  tmp = (uint8_t)((CID_Tab[1] & 0xFF000000) >> 24);
  cardinfo->SD_cid.ProdName1 |= tmp << 16;

  /* Byte 5 */
  tmp = (uint8_t)((CID_Tab[1] & 0x00FF0000) >> 16);
  cardinfo->SD_cid.ProdName1 |= tmp << 8;

  /* Byte 6 */
  tmp = (uint8_t)((CID_Tab[1] & 0x0000FF00) >> 8);
  cardinfo->SD_cid.ProdName1 |= tmp;

  /* Byte 7 */
  tmp = (uint8_t)(CID_Tab[1] & 0x000000FF);
  cardinfo->SD_cid.ProdName2 = tmp;

  /* Byte 8 */
  tmp = (uint8_t)((CID_Tab[2] & 0xFF000000) >> 24);
  cardinfo->SD_cid.ProdRev = tmp;

  /* Byte 9 */
  tmp = (uint8_t)((CID_Tab[2] & 0x00FF0000) >> 16);
  cardinfo->SD_cid.ProdSN = tmp << 24;

  /* Byte 10 */
  tmp = (uint8_t)((CID_Tab[2] & 0x0000FF00) >> 8);
  cardinfo->SD_cid.ProdSN |= tmp << 16;

  /* Byte 11 */
  tmp = (uint8_t)(CID_Tab[2] & 0x000000FF);
  cardinfo->SD_cid.ProdSN |= tmp << 8;

  /* Byte 12 */
  tmp = (uint8_t)((CID_Tab[3] & 0xFF000000) >> 24);
  cardinfo->SD_cid.ProdSN |= tmp;

  /* Byte 13 */
  tmp = (uint8_t)((CID_Tab[3] & 0x00FF0000) >> 16);
  cardinfo->SD_cid.Reserved1 |= (tmp & 0xF0) >> 4;
  cardinfo->SD_cid.ManufactDate = (tmp & 0x0F) << 8;

  /* Byte 14 */
  tmp = (uint8_t)((CID_Tab[3] & 0x0000FF00) >> 8);
  cardinfo->SD_cid.ManufactDate |= tmp;

  /* Byte 15 */
  tmp = (uint8_t)(CID_Tab[3] & 0x000000FF);
  cardinfo->SD_cid.CID_CRC = (tmp & 0xFE) >> 1;
  cardinfo->SD_cid.Reserved2 = 1;

  return(errorstatus);
}

/**
  *@brief SD Select or Deselect
  *-
  *@param[in] addr: Address of the Card to be selected.
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef HAL_SD_SelectDeselect(uint32_t addr)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t status;

  /* Send CMD7 SDIO_SEL_DESEL_CARD */
  //CMD7_SD_tsk(addr);
	CMD7_SD_tsk(addr<<16);
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  if(errorstatus != SD_OK)
  {
	  return errorstatus;
  }

  ACMD42_SD_tsk(addr, 0);
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }

  return(errorstatus);
}

/**
  *@brief SD 使能WideBus
  *-
  *@param[in] NONE
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */

HAL_SDCARD_StateTypeDef HAL_SD_EnWideBus(void)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t status;

  ACMD6_SD_tsk(RCA);
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  W32(SDMMC_CTYPE, SDMMC_CTYPE_4BIT); //Data Bus Width = 4bit

  CMD16_SD_tsk(512);
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();

  return(errorstatus);
}

/**
  *@brief SD 发送SCR
  *-
  *@param[in] scr: 数据指针
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef HAL_SD_SendSCR(uint32_t *scr)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t status;

  /* ACMD51:SEND_SCR */
  ACMD51_SD_tsk(RCA, 8);
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  scr[0] = R32(SDMMC_FIFO_DATA);
  scr[1] = R32(SDMMC_FIFO_DATA);
  if((scr[0]&0x800000) == 0x800000) //SD_SPEC3: Version 3.0
  {
	  CardType = SDIO_HIGH_CAPACITY_SD_CARD_V3_0;
  }

  return(errorstatus);
}

/**
  *@brief SD切换SD2.0
  *-
  *@param[in] switch_func: 数据指针
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef SD_SwitchFunc_V2_0(uint32_t *switch_func)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t status;
  uint8_t i;

  CMD6_SD_tsk(0x00fffff1, 64);
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  for(i=0; i<16; i++)
  {
	  switch_func[i] = R32(SDMMC_FIFO_DATA);
  }

  CMD6_SD_tsk(0x80fffff1, 64);
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  for(i=0; i<16; i++)
  {
	  switch_func[i] = R32(SDMMC_FIFO_DATA);
  }

//  readl(CPM_BASE + 0x24) |= BIT(2);		//bit2 reverse the drv clk, bit3 reverse the sample clk.
//  readl(CPM_BASE + 0x24) |= BIT(3);		//bit2 reverse the drv clk, bit3 reverse the sample clk.
  SDIO_SetClk(1<<SD_SLOT1,SDIO_CLKOUT_25MHz_DIV);

  return(errorstatus);
}

/**
  *@brief SD切换SD3.0
  *-
  *@param[in] switch_func: 数据指针
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef SD_SwitchFunc_V3_0(uint32_t *switch_func)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t status;
  uint8_t i;

  CMD6_SD_tsk(0x00ffffff, 64); //bit31: 0:check function 1:switch function; group 1&2&3&4
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  for(i=0; i<16; i++)
  {
	  switch_func[i] = R32(SDMMC_FIFO_DATA);
  }

  CMD6_SD_tsk(0x00fffff3, 64); //bit31: 0:check function 1:switch function; group 1&2&3&4
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  for(i=0; i<16; i++)
  {
	  switch_func[i] = R32(SDMMC_FIFO_DATA);
  }

  CMD6_SD_tsk(0x80fffff3, 64); //bit31: 0:check function 1:switch function; group 1&2&3&4
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  for(i=0; i<16; i++)
  {
	  switch_func[i] = R32(SDMMC_FIFO_DATA);
  }

  CMD6_SD_tsk(0x00ff3fff, 64); //bit31: 0:check function 1:switch function; group 1&2&3&4
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  for(i=0; i<16; i++)
  {
	  switch_func[i] = R32(SDMMC_FIFO_DATA);
  }

  CMD6_SD_tsk(0x80ff3fff, 64); //bit31: 0:check function 1:switch function; group 1&2&3&4
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  for(i=0; i<16; i++)
  {
	  switch_func[i] = R32(SDMMC_FIFO_DATA);
  }

  SDIO_SetClk(1<<SD_SLOT1,SDIO_CLKOUT_25MHz_DIV);

  return(errorstatus);
}

/**
  *@brief SD_CmdResp1Error
  *-
  *@param[in] NONE
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef SD_CmdResp1Error(void)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t response_r1;

  /* We have received response, retrieve it for analysis  */
  response_r1 = R32(SDMMC_RESP0);

  if ((response_r1 & SD_OCR_ERRORBITS) == 0)
  {
    return(errorstatus);
  }

  if (response_r1 & SD_OCR_ADDR_OUT_OF_RANGE)
  {
    return(SD_ADDR_OUT_OF_RANGE);
  }

  if (response_r1 & SD_OCR_ADDR_MISALIGNED)
  {
    return(SD_ADDR_MISALIGNED);
  }

  if (response_r1 & SD_OCR_BLOCK_LEN_ERR)
  {
    return(SD_BLOCK_LEN_ERR);
  }

  if (response_r1 & SD_OCR_ERASE_SEQ_ERR)
  {
    return(SD_ERASE_SEQ_ERR);
  }

  if (response_r1 & SD_OCR_BAD_ERASE_PARAM)
  {
    return(SD_BAD_ERASE_PARAM);
  }

  if (response_r1 & SD_OCR_WRITE_PROT_VIOLATION)
  {
    return(SD_WRITE_PROT_VIOLATION);
  }

  if (response_r1 & SD_OCR_LOCK_UNLOCK_FAILED)
  {
    return(SD_LOCK_UNLOCK_FAILED);
  }

  if (response_r1 & SD_OCR_COM_CRC_FAILED)
  {
    return(SD_COM_CRC_FAILED);
  }

  if (response_r1 & SD_OCR_ILLEGAL_CMD)
  {
    return(SD_ILLEGAL_CMD);
  }

  if (response_r1 & SD_OCR_CARD_ECC_FAILED)
  {
    return(SD_CARD_ECC_FAILED);
  }

  if (response_r1 & SD_OCR_CC_ERROR)
  {
    return(SD_CC_ERROR);
  }

  if (response_r1 & SD_OCR_GENERAL_UNKNOWN_ERROR)
  {
    return(SD_GENERAL_UNKNOWN_ERROR);
  }

  if (response_r1 & SD_OCR_STREAM_READ_UNDERRUN)
  {
    return(SD_STREAM_READ_UNDERRUN);
  }

  if (response_r1 & SD_OCR_STREAM_WRITE_OVERRUN)
  {
    return(SD_STREAM_WRITE_OVERRUN);
  }

  if (response_r1 & SD_OCR_CID_CSD_OVERWRIETE)
  {
    return(SD_CID_CSD_OVERWRITE);
  }

  if (response_r1 & SD_OCR_WP_ERASE_SKIP)
  {
    return(SD_WP_ERASE_SKIP);
  }

  if (response_r1 & SD_OCR_CARD_ECC_DISABLED)
  {
    return(SD_CARD_ECC_DISABLED);
  }

  if (response_r1 & SD_OCR_ERASE_RESET)
  {
    return(SD_ERASE_RESET);
  }

  if (response_r1 & SD_OCR_AKE_SEQ_ERROR)
  {
    return(SD_AKE_SEQ_ERROR);
  }
  return(errorstatus);
}

/**
  *@brief HAL_SD_ReadBlock
  *-
  *@param[in] addr: Address from where data are to be read.
  *@param[in] readbuff: pointer to the buffer that will contain the received data.
  *@param[in] BlockSize: the SD card Data block size.
  *@param[in] NumberOfBlocks: number of blocks to be read.
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef HAL_SD_ReadBlock(uint32_t addr, uint32_t *readbuff, uint16_t BlockSize, uint32_t NumberOfBlocks)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t TotalNumberOfBytes = 0, *tempbuff = readbuff, status;
#ifndef USE_INTERNAL_DMAC
  uint32_t i,len;
#endif

	 //status = R32(SDMMC_RINTSTS);
	//printf("1:0x%08x\r\n",status);
  if (0 == readbuff)
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }

#ifdef USE_INTERNAL_DMAC
  SDIO_Internal_Dmac_Ctrl(1);
  SDIO_ConfigDesc(DESCRIPTION_ADDR, (uint32_t)tempbuff, NumberOfBlocks, BLOCK_SIZE);
#endif
	
	//status = R32(SDMMC_RINTSTS);
	//printf("2:0x%08x\r\n",status);
	
  TotalNumberOfBytes = NumberOfBlocks * BlockSize;
  if(NumberOfBlocks > 1)
  {
	  CMD18_SD_tsk(addr, TotalNumberOfBytes);
  }
  else
  {
	  CMD17_SD_tsk(addr, TotalNumberOfBytes);
  }
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  if(status & DWC_MSH_DATA_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_DATA_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }
	
	//status = R32(SDMMC_RINTSTS);
	//printf("3:0x%08x\r\n",status);
	
#ifdef USE_INTERNAL_DMAC
  while (!(status & SDMMC_INT_DATA_OVER))
  {
	  status = R32(SDMMC_RINTSTS);
	//	printf("0x%08x\r\n",status);
//	  if(sd_read_complete())
//	  {
//		  W32(0x63F00000+0x14, R32(0x63F00000+0x14)|0x10000000);
//	  }
	  /*if(sd_read_stop())
	  {
		  W32(SDMMC_CTRL, SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET);
		  delay_f(100);
		  break;
	  }*/
  }
#else
  len = (TotalNumberOfBytes > (FIFO_DEPTH<<2)) ? FIFO_DEPTH : (TotalNumberOfBytes>>2);
  while (!(status & SDMMC_INT_DATA_OVER))
  {
	  if (status & SDMMC_INT_RXDR)
	  {
		  for(i=0; i<len; i++)
		  {
			*tempbuff = R32(SDMMC_FIFO_DATA);
			tempbuff++;
		  }
	  }
	  status = R32(SDMMC_RINTSTS);
  }
  while(!(R32(SDMMC_STATUS) & 0x4)) //fifo not empty
  {
	  *tempbuff = R32(SDMMC_FIFO_DATA);
	  tempbuff++;
  }
#endif
  if(NumberOfBlocks > 1)
  {
#ifdef SEND_AUTO_STOP
	  while (!(status & SDMMC_INT_ACD))
	  {
		  status = R32(SDMMC_RINTSTS);
	  }
#else
	  errorstatus = HAL_SD_StopTransfer();
	  if (errorstatus != SD_OK)
	  {
		return(errorstatus);
	  }
#endif
  }

  /* Clear all the static flags */
  W32(SDMMC_RINTSTS, 0xFFFFFFFF);

  return(errorstatus);
}


/**
  *@brief HAL_SD_WriteBlock
  *-
  *@param[in] addr: Address from where data are to be read.
  *@param[in] writebuff: pointer to the buffer that contain the data to be transferred.
  *@param[in] BlockSize: the SD card Data block size.
  *@param[in] NumberOfBlocks: number of blocks to be written.
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef HAL_SD_WriteBlock(uint32_t addr, uint32_t *writebuff, uint16_t BlockSize, uint32_t NumberOfBlocks)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t cardstate = 0, TotalNumberOfBytes, status;
  uint32_t *tempbuff = writebuff;
#ifndef USE_INTERNAL_DMAC
  uint16_t i;
#endif

  if (writebuff == 0)
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }

  TotalNumberOfBytes = NumberOfBlocks * BlockSize;

#ifdef USE_INTERNAL_DMAC
  SDIO_Internal_Dmac_Ctrl(1);
  SDIO_ConfigDesc(DESCRIPTION_ADDR, (uint32_t)tempbuff, NumberOfBlocks, BLOCK_SIZE);
#else
  for(i=0; i<TotalNumberOfBytes>>2; i++) //数据长度不能超过FIFO_DEPTH
  {
	W32(SDMMC_FIFO_DATA, *tempbuff);
	tempbuff++;
  }
#endif

  if(NumberOfBlocks > 1)
  {
	  CMD25_SD_tsk(addr, TotalNumberOfBytes);
  }
  else
  {
	  CMD24_SD_tsk(addr, TotalNumberOfBytes);
  }
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  if(status & DWC_MSH_DATA_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_DATA_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }

  while((status & (SDMMC_INT_DATA_OVER|SDMMC_INT_TXDR)) != (SDMMC_INT_DATA_OVER|SDMMC_INT_TXDR))
  {
	  status = R32(SDMMC_RINTSTS);
	  ///TODO
		//if(sd_write_complete())
	  {
		//  W32(0x63F00000+0x14, R32(0x63F00000+0x14)|0x02000000);
	  }
  }
  //W32(0x63F00000+0x14, R32(0x63F00000+0x14)&~0x02000000);

  if(NumberOfBlocks > 1)
  {
	  errorstatus = HAL_SD_StopTransfer();
	  if (errorstatus != SD_OK)
	  {
		return(errorstatus);
	  }
  }

  /* Clear all the static flags */
  W32(SDMMC_RINTSTS, 0xFFFFFFFF);

  /* Wait till the card is in programming state */
  do
  {
	  while(R32(SDMMC_STATUS) & BIT_X(9)); //1: card data busy
	  CMD13_SD_tsk(RCA);
	  status = R32(SDMMC_RINTSTS);
	  if(status & DWC_MSH_CMD_ERROR_FLAGS)
	  {
		W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
		return SD_ERROR;
	  }
	  errorstatus = SD_CmdResp1Error();
	  if (errorstatus != SD_OK)
	  {
		return(errorstatus);
	  }
	  cardstate = (R32(SDMMC_RESP0)>>9) & 0xf;
  }while((errorstatus == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING)));


#ifdef USE_INTERNAL_DMAC
  	  SDIO_Internal_Dmac_Ctrl(0);
#endif
  /* Clear all the static flags */
  W32(SDMMC_RINTSTS, 0xFFFFFFFF);

  return(errorstatus);
}

HAL_SDCARD_StateTypeDef SDIO_CMD53_Xfer(uint32_t arg, uint32_t *buff, uint16_t BlockSize, uint32_t NumberOfBlocks, uint8_t is_write)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t TotalNumberOfBytes, status;
  uint32_t *tempbuff = buff;
#ifndef USE_INTERNAL_DMAC
  uint16_t i;
#endif

  if (buff == 0)
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }

  TotalNumberOfBytes = NumberOfBlocks * BlockSize;

#ifdef USE_INTERNAL_DMAC
  SDIO_Internal_Dmac_Ctrl(1);
  SDIO_ConfigDesc(DESCRIPTION_ADDR, (uint32_t)tempbuff, NumberOfBlocks, BlockSize);
#else
  for(i=0; i<TotalNumberOfBytes>>2; i++) //数据长度不能超过FIFO_DEPTH
  {
	W32(SDMMC_FIFO_DATA, *tempbuff);
	tempbuff++;
  }
#endif

//    printf("blk size: 0x%x, blk num: 0x%x\r\n", BlockSize, NumberOfBlocks);
//    printf("buff addr: 0x%08x, is_write: %d\r\n", tempbuff, is_write);

//@@@@@@@@@@@
    W32(SDMMC_BYTCNT, TotalNumberOfBytes);
    W32(SDMMC_BLKSIZ, BlockSize);
    W32(SDMMC_CARDTHRCTL, (CARD_THRESHOLD<<16)|0x04);
//	  W32(SDMMC_CARDTHRCTL, 0);
    W32(SDMMC_DBADDRL, DESCRIPTION_ADDR);
    W32(SDMMC_DBADDRU, DESCRIPTION_ADDR+0x50); //high 32bit, no used in this version
    W32(SDMMC_CMDARG, arg);

    W32(SDMMC_CMD, 0);

    if(is_write)
        R32(SDMMC_CMD) |= SDMMC_CMD_DAT_WR;

    //R1.+data.
    R32(SDMMC_CMD) |= SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
    			                | SDMMC_CMD_RESP_CRC | SDMMC_CMD_DAT_EXP |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(53);
    
    SDIO_PollStatus(SDMMC_INT_CMD_DONE);

//@@@@@@@@@@@

  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
       __asm("bkpt 0");
	return SD_ERROR;
  }
  if(status & DWC_MSH_DATA_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_DATA_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  if (errorstatus != SD_OK)
  {
    __asm("bkpt 0");
    return(errorstatus);
  }

  while((status & (SDMMC_INT_DATA_OVER)) != (SDMMC_INT_DATA_OVER))
  {
	  status = R32(SDMMC_RINTSTS);
  }

	#define BIT9 (1<<9)
  while(R32(SDMMC_STATUS) & BIT9);  //wait for busy done.

//  printf("TBB = 0x%08x, TCB = 0x%08x, status: 0x%08x\r\n", 
//            R32(SDMMC_TBBCNT), R32(SDMMC_TCBCNT), R32(SDMMC_STATUS));

#ifdef USE_INTERNAL_DMAC
  	  SDIO_Internal_Dmac_Ctrl(0);
#endif
  /* Clear all the static flags */
  W32(SDMMC_RINTSTS, 0xFFFFFFFF);

  return(errorstatus);
}

/**
  *@brief HAL_SD_StopTransfer
  *-
  *@param[in] NONE
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef HAL_SD_StopTransfer(void)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t status;

  CMD12_SD_tsk();
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();

  return(errorstatus);
}

/**
  *@brief SD_ReadBlock_Start
  *-
  *@param[in] addr ：address
  *@param[in] BlockSize :block size
	*@param[in] NumberOfBlocks :block number
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef SD_ReadBlock_Start(uint32_t addr, uint16_t BlockSize, uint32_t NumberOfBlocks)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t TotalNumberOfBytes = 0, status;

  TotalNumberOfBytes = NumberOfBlocks * BlockSize;
  if(NumberOfBlocks > 1)
  {
	  CMD18_SD_tsk(addr, TotalNumberOfBytes);
  }
  else
  {
	  CMD17_SD_tsk(addr, TotalNumberOfBytes);
  }
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  if(status & DWC_MSH_DATA_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_DATA_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }

  while(!(R32(SDMMC_RINTSTS) & SDMMC_INT_RXDR));

  return(errorstatus);
}

HAL_SDCARD_StateTypeDef SD_ReadBlock_Stop(uint8_t multi)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;

  if(multi == MULTI_READ_CMD_START)
  {
#ifdef SEND_AUTO_STOP
	  while (!(status & SDMMC_INT_ACD))
	  {
		  status = R32(SDMMC_RINTSTS);
	  }
#else
	  errorstatus = HAL_SD_StopTransfer();
	  if (errorstatus != SD_OK)
	  {
		return(errorstatus);
	  }
#endif
  }

  W32(SDMMC_CTRL, SDMMC_CTRL_FIFO_RESET);
  while(R32(SDMMC_CTRL)&SDMMC_CTRL_FIFO_RESET);
  while(!(R32(SDMMC_RINTSTS) & SDMMC_INT_DATA_OVER));
  /* Clear all the static flags */
  W32(SDMMC_RINTSTS, 0xFFFFFFFF);

  return(errorstatus);
}


/**
  *@brief SD_WriteBlock_Start
  *-
  *@param[in] addr ：address
  *@param[in] BlockSize :block size
	*@param[in] NumberOfBlocks :block number
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef SD_WriteBlock_Start(uint32_t addr, uint16_t BlockSize, uint32_t NumberOfBlocks)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t TotalNumberOfBytes, status;

  if(start_write_block == 1)
  {
	  return SD_OK;
  }

  TotalNumberOfBytes = NumberOfBlocks * BlockSize;
  if(NumberOfBlocks > 1)
  {
	  CMD25_SD_tsk(addr, TotalNumberOfBytes);
  }
  else
  {
	  CMD24_SD_tsk(addr, TotalNumberOfBytes);
  }
  status = R32(SDMMC_RINTSTS);
  if(status & DWC_MSH_CMD_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
	return SD_ERROR;
  }
  if(status & DWC_MSH_DATA_ERROR_FLAGS)
  {
	W32(SDMMC_RINTSTS, DWC_MSH_DATA_ERROR_FLAGS);
	return SD_ERROR;
  }
  errorstatus = SD_CmdResp1Error();
  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }
  start_write_block = 1;

  return(errorstatus);
}


/**
  *@brief SD_WriteBlock_Stop
  *-
  *@param[in] multi
  *@retval @ref HAL_SDCARD_StateTypeDef,SD Card Error code.
  */
HAL_SDCARD_StateTypeDef SD_WriteBlock_Stop(uint8_t multi)
{
  HAL_SDCARD_StateTypeDef errorstatus = SD_OK;
  uint32_t cardstate = 0, status;

  while(!(R32(SDMMC_RINTSTS)&SDMMC_INT_TXDR));

  if(multi == MULTI_WRITE_CMD_START)
  {
	  errorstatus = HAL_SD_StopTransfer();
	  if (errorstatus != SD_OK)
	  {
		return(errorstatus);
	  }
  }

  while(!(R32(SDMMC_RINTSTS) & SDMMC_INT_DATA_OVER));
  W32(SDMMC_CTRL, SDMMC_CTRL_FIFO_RESET);
  while(R32(SDMMC_CTRL)&SDMMC_CTRL_FIFO_RESET);
  /* Clear all the static flags */
  W32(SDMMC_RINTSTS, 0xFFFFFFFF);

  /* Wait till the card is in programming state */
  do
  {
	  while(R32(SDMMC_STATUS) & BIT_X(9)); //1: card data busy
	  CMD13_SD_tsk(RCA);
	  status = R32(SDMMC_RINTSTS);
	  if(status & DWC_MSH_CMD_ERROR_FLAGS)
	  {
		W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
		return SD_ERROR;
	  }
	  errorstatus = SD_CmdResp1Error();
	  if (errorstatus != SD_OK)
	  {
		return(errorstatus);
	  }
	  cardstate = (R32(SDMMC_RESP0)>>9) & 0xf;
  }while((errorstatus == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING)));

  start_write_block = 0;
  /* Clear all the static flags */
  W32(SDMMC_RINTSTS, 0xFFFFFFFF);

  return(errorstatus);
}

/**
  *@brief core_sdio_xfer
  *-
  *@param[in] content
  *@retval uint32_t.
  */
uint32_t core_sdio_xfer(SDMMCHOST_TRANSFER  *content)
{
//    usdhc_transfer_t content;
    uint32_t status;
    uint32_t count;
    uint32_t response;

   /// printf("cmd idx: %d, argu: 0x%08x\r\n", content->command->index, content->command->argument);
    
    switch(content->command->index)
    {
        case 0:
              /* CMD0: GO_IDLE_STATE -------------------------------------------------------*/
              /* No CMD response required */
              CMD0_SD_tsk( CMD0ARG_GO_IDLE_STATE);
            break;
        case 3:
              CMD3_SD_tsk(0x0000);
              status = R32(SDMMC_RINTSTS);
              if(status & DWC_MSH_CMD_ERROR_FLAGS)
              {
                W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
                return SD_ERROR;
              }
              status = R32(SDMMC_RESP0);
              if(0 == (status & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED)))
              {
                  //g_sdio.relativeAddress = (uint16_t) (status >> 16);
                  //content->command->response[0] = status;
              }
            content->command->response[0] = status;

            break;
        case 5:
            {
//                EPORT_EPDDR = 0x03;
//                EPORT_EPDR = 0x00;

                CMD5_SD_tsk(content->command->argument);
                status = R32(SDMMC_RINTSTS);
                if(status & DWC_MSH_CMD_ERROR_FLAGS)
                {
                    W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
                    return SD_ERROR;
                }
                response = R32(SDMMC_RESP0);
#if 1
		count = 0;
                while(count < SD_MAX_VOLT_TRIAL)
                {
                    //host support High Capacity SD + host support 2.7V-3.V
                    //bit24: S18R --Supports voltage switching for 1.8V
                    //ACMD41_SD_tsk(0x403c0000);
                    //ACMD41_SD_tsk(0x513c0000);
                    CMD5_SD_tsk(0x00320000);
                    status = R32(SDMMC_RINTSTS);
                    if(status & DWC_MSH_CMD_ERROR_FLAGS)
                    {
                        W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
                        return SD_ERROR;
                    }
                    response = R32(SDMMC_RESP0);
//			printf("CMD5 resp = 0x%08x\r\n", response);
                    count++;
                    delay(0x1000);
                    if((response & OCR_BUSY_Bit31) != OCR_POWER_BUSY)
                    {
                        break;
                    }
                }
                if(count >= SD_MAX_VOLT_TRIAL)
                {
                    __asm("bkpt 0");
                }
                if((status & SD_HIGH_CAPACITY) == SD_HIGH_CAPACITY)
                {
                    CardType = SDIO_HIGH_CAPACITY_SD_CARD;
                }
#endif
                content->command->response[0] = response;
//                printf("resp = %08x\r\n", response);
            }
            break;
        case 7:
            
            /* Send CMD7 SDIO_SEL_DESEL_CARD */
            CMD7_SD_tsk(content->command->argument);
            status = R32(SDMMC_RINTSTS);
            if(status & DWC_MSH_CMD_ERROR_FLAGS)
            {
              W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
              __asm("bkpt 0");
            }
            status = SD_CmdResp1Error();
            if(status != SD_OK)
            {
                __asm("bkpt 0");
                return status;
            }
            content->command->response[0] = R32(SDMMC_RESP0);
            break;
        case 52:
            CMD52_SD_tsk(content->command->argument);

            status = R32(SDMMC_RINTSTS);
            if(status & DWC_MSH_CMD_ERROR_FLAGS)
            {
                W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
//                __asm("bkpt 0");
            }

            response= R32(SDMMC_RESP0);
            
            content->command->response[0] = response;
//            printf("resp = %08x\r\n", response);

            /* read data from response */
            break;
        case 53:
            
            if(content->data->rxData)
            {
                //read.
                SDIO_CMD53_Xfer(content->command->argument,
                                                content->data->rxData,
                                                content->data->blockSize,
                                                content->data->blockCount,
                                                0);
            }
            else if(content->data->txData)
            {
                //write.
                SDIO_CMD53_Xfer(content->command->argument,
                                (uint32_t *)content->data->txData,
                                content->data->blockSize,
                                content->data->blockCount,
                                1);
            }
            else
            {
                __asm("bkpt 0");
            }

            break;
    }

    return kStatus_Success;
}

/**
  *@brief SDIO_GetCardCapability
  *
  *@param[in] card
  *@param[in] func
  *@retval status_t.
  */
status_t SDIO_GetCardCapability(sdio_card_t *card, sdio_func_num_t func)
{
    uint8_t *tempBuffer = (uint8_t *)g_sdmmc;
    uint32_t i          = 0U;

    memset(g_sdmmc, 0U, sizeof(g_sdmmc));

    for (i = 0U; i <= SDIO_CCCR_REG_NUMBER; i++)
    {
        if (kStatus_Success !=
            SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, SDIO_FBR_BASE(func) + i, 0U, &tempBuffer[i]))
        {
            return kStatus_SDMMC_TransferFailed;
        }
    }

    switch (func)
    {
        case kSDIO_FunctionNum0:

            card->sdVersion    = tempBuffer[kSDIO_RegSDVersion];
            card->sdioVersion  = tempBuffer[kSDIO_RegCCCRSdioVer] >> 4U;
            card->cccrVersioin = tempBuffer[kSDIO_RegCCCRSdioVer] & 0xFU;
            /* continuous SPI interrupt */
            if (tempBuffer[kSDIO_RegBusInterface] & 0x40U)
            {
                card->cccrflags |= kSDIO_CCCRSupportContinuousSPIInt;
            }
            /* 8bit data bus */
            if (tempBuffer[kSDIO_RegBusInterface] & 0x4U)
            {
                card->cccrflags |= SDIO_CCCR_SUPPORT_8BIT_BUS;
            }

            /* card capability register */
            card->cccrflags |= (tempBuffer[kSDIO_RegCardCapability] & 0xDFU);
            /* master power control */
            if (tempBuffer[kSDIO_RegPowerControl] & 0x01U)
            {
                card->cccrflags |= kSDIO_CCCRSupportMasterPowerControl;
            }
            /* high speed flag */
            if (tempBuffer[kSDIO_RegBusSpeed] & 0x01U)
            {
                card->cccrflags |= SDIO_CCCR_SUPPORT_HIGHSPEED;
            }
            /* uhs mode flag */
            card->cccrflags |= (tempBuffer[kSDIO_RegUHSITimingSupport] & 7U) << 11U;
            /* driver type flag */
            card->cccrflags |= (tempBuffer[kSDIO_RegDriverStrength] & 7U) << 14U;
            /* low speed 4bit */
            if (tempBuffer[kSDIO_RegCardCapability] & 0x80U)
            {
                card->cccrflags |= kSDIO_CCCRSupportLowSpeed4Bit;
            }
            /* common CIS pointer */
            card->commonCISPointer = tempBuffer[kSDIO_RegCommonCISPointer] |
                                     (tempBuffer[kSDIO_RegCommonCISPointer + 1U] << 8U) |
                                     (tempBuffer[kSDIO_RegCommonCISPointer + 2U] << 16U);

            /* check card capability of support async interrupt */
            if ((tempBuffer[kSDIO_RegInterruptExtension] & SDIO_CCCR_ASYNC_INT_MASK) == SDIO_CCCR_ASYNC_INT_MASK)
            {
                card->cccrflags |= SDIO_CCCR_SUPPORT_ASYNC_INT;
            }

            break;

        case kSDIO_FunctionNum1:
        case kSDIO_FunctionNum2:
        case kSDIO_FunctionNum3:
        case kSDIO_FunctionNum4:
        case kSDIO_FunctionNum5:
        case kSDIO_FunctionNum6:
        case kSDIO_FunctionNum7:
            card->ioFBR[func - 1U].ioStdFunctionCode = tempBuffer[0U] & 0x0FU;
            card->ioFBR[func - 1U].ioExtFunctionCode = tempBuffer[1U];
            card->ioFBR[func - 1U].ioPointerToCIS = tempBuffer[9U] | (tempBuffer[10U] << 8U) | (tempBuffer[11U] << 16U);
            card->ioFBR[func - 1U].ioPointerToCSA =
                tempBuffer[12U] | (tempBuffer[13U] << 8U) | (tempBuffer[14U] << 16U);
            if (tempBuffer[2U] & 0x01U)
            {
                card->ioFBR[func - 1U].flags |= kSDIO_FBRSupportPowerSelection;
            }
            if (tempBuffer[0U] & 0x40U)
            {
                card->ioFBR[func - 1U].flags |= kSDIO_FBRSupportCSA;
            }

            break;

        default:
            break;
    }

    return kStatus_Success;
}

/**
  *@brief SDIO_EnableAsyncInterrupt
  *
  *@param[in] card
  *@param[in] enable
  *@retval status_t.
  */
status_t SDIO_EnableAsyncInterrupt(sdio_card_t *card, bool enable)
{
    uint8_t eai = 0U;

    if ((card->cccrflags & SDIO_CCCR_SUPPORT_ASYNC_INT) == 0U)
    {
        return kStatus_SDMMC_NotSupportYet;
    }

    /* load interrupt enable register */
    if (kStatus_Success !=
        SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegInterruptExtension, 0U, &eai))
    {
        return kStatus_SDMMC_TransferFailed;
    }
    /* if already enable/disable , do not need enable/disable again */
    if (((eai)&SDIO_CCCR_ENABLE_AYNC_INT) == (enable ? SDIO_CCCR_ENABLE_AYNC_INT : 0U))
    {
        return kStatus_Success;
    }

    /* enable the eai */
    if (enable)
    {
        eai |= SDIO_CCCR_ENABLE_AYNC_INT;
    }
    else
    {
        eai &= ~(SDIO_CCCR_ENABLE_AYNC_INT);
    }

    /* write to register */
    if (kStatus_Success !=
        SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegInterruptExtension, eai, &eai))
    {
        return kStatus_SDMMC_TransferFailed;
    }

    return kStatus_Success;
}

/**
  *@brief SDIO_SetDriverStrength
  *
  *@param[in] driverStrength
  *@retval status_t.
  */
status_t SDIO_SetDriverStrength(sd_driver_strength_t driverStrength)
{
    uint8_t strength = 0U, temp = 0U;

    switch (driverStrength)
    {
        case kSD_DriverStrengthTypeA:
            strength = SDIO_CCCR_ENABLE_DRIVER_TYPE_A;
            break;
        case kSD_DriverStrengthTypeC:
            strength = SDIO_CCCR_ENABLE_DRIVER_TYPE_C;
            break;
        case kSD_DriverStrengthTypeD:
            strength = SDIO_CCCR_ENABLE_DRIVER_TYPE_D;
            break;
        default:
            strength = SDIO_CCCR_ENABLE_DRIVER_TYPE_B;
            break;
    }

    if (kStatus_Success !=
        SDIO_IO_RW_Direct(NULL, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegDriverStrength, 0U, &temp))
    {
        return kStatus_SDMMC_TransferFailed;
    }

    temp &= ~SDIO_CCCR_DRIVER_TYPE_MASK;
    temp |= strength;

    return SDIO_IO_RW_Direct(NULL, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegDriverStrength, temp, &temp);
}

/**
  *@brief SDIO_SwitchToHighSpeed
  *
  *@param[in] card
  *@retval status_t.
  */
status_t SDIO_SwitchToHighSpeed(sdio_card_t *card)
{
    uint8_t temp        = 0U;
    uint32_t retryTimes = SDIO_RETRY_TIMES;
    status_t status     = kStatus_SDMMC_SDIO_SwitchHighSpeedFail;

    //SDIO_SetClk(1<<SD_SLOT1, 11); 
    //@@@@@@@@@@@@@@

//    EPORT_EPDDR = 0x03;
//    EPORT_EPDR = 0x00;

//    return kStatus_Success;

    if (card->cccrflags & SDIO_CCCR_SUPPORT_HIGHSPEED)
    {
        if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegBusSpeed, 0U, &temp))
        {
            return kStatus_SDMMC_TransferFailed;
        }

        temp &= ~SDIO_CCCR_BUS_SPEED_MASK;
        temp |= SDIO_CCCR_ENABLE_HIGHSPEED_MODE;

        do
        {
            retryTimes--;
            /* enable high speed mode */

            if (kStatus_Success !=
                SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegBusSpeed, temp, &temp))
            {
                continue;
            }
            /* either EHS=0 and SHS=0 ,the card is still in default mode  */
            if ((temp & 0x03U) == 0x03U)
            {
                /* high speed mode , set freq to 50MHZ */
//                card->busClock_Hz =
//                    SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SD_CLOCK_50MHZ);

                //@@@@@@@@@@@@@@@@
//                  readl(0x40004000 + 0x24) |= (1 << 2);		//bit2 reverse the drv clk, bit3 reverse the sample clk.
//                  readl(0x40004000 + 0x24) |= (1 << 3);		//bit2 reverse the drv clk, bit3 reverse the sample clk.
									SDIO_SetClk(1<<SD_SLOT1, SDIO_CLKOUT_25MHz_DIV); 
                //@@@@@@@@@@@@@@

//                EPORT_EPDDR = 0x03;
//                EPORT_EPDR = 0x00;


                status = kStatus_Success;
                break;
            }
            else
            {
                continue;
            }

        } while (retryTimes);
    }
    else
    {
        /* default mode 25MHZ */
        //card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SD_CLOCK_25MHZ);

        //@@@@@@@@@@@@@@@@
//          readl(0x40004000 + 0x24) |= (1 << 2);		//bit2 reverse the drv clk, bit3 reverse the sample clk.
//          readl(0x40004000 + 0x24) |= (1 << 3);		//bit2 reverse the drv clk, bit3 reverse the sample clk.
        SDIO_SetClk(1<<SD_SLOT1, SDIO_CLKOUT_25MHz_DIV);
        //@@@@@@@@@@@@@@

 //           EPORT_EPDDR = 0x03;
 //           EPORT_EPDR = 0x00;

        status            = kStatus_Success;
    }

    SDIO_SetDriverStrength(kSD_DriverStrengthTypeA);

    return status;
}


/**
  *@brief SDIO_IO_RW_Direct
  *
  *@param[in] card
  *@param[in] direction
  *@param[in] func
  *@param[in] regAddr
  *@param[in] dataIn
  *@param[out] dataOut
  *@retval uint32_t.
  */
uint32_t SDIO_IO_RW_Direct(sdio_card_t *card,
                           sdio_io_direction_t direction,
                           sdio_func_num_t func,
                           uint32_t regAddr,
                           uint8_t dataIn,
                           uint8_t *dataOut)
{

    uint32_t argument;
    uint32_t status;

    argument = (func << SDIO_CMD_ARGUMENT_FUNC_NUM_POS) |
                       ((regAddr & SDIO_CMD_ARGUMENT_REG_ADDR_MASK) << SDIO_CMD_ARGUMENT_REG_ADDR_POS);

    if ((dataOut != NULL) && (direction == kSDIO_IOWrite))
    {
        argument |= (1U << SDIO_CMD_ARGUMENT_RW_POS) | (1U << SDIO_DIRECT_CMD_ARGUMENT_RAW_POS);
    }

    if (direction == kSDIO_IOWrite)
    {
        argument |= dataIn & SDIO_DIRECT_CMD_DATA_MASK;
    }

    CMD52_SD_tsk(argument);

    status = R32(SDMMC_RINTSTS);
    if(status & DWC_MSH_CMD_ERROR_FLAGS)
    {
        W32(SDMMC_RINTSTS, DWC_MSH_CMD_ERROR_FLAGS);
        return kStatus_Fail;
    }
    
    status = R32(SDMMC_RESP0);

    if (dataOut != NULL)
    {
        /* read data from response */
        *dataOut = status & SDIO_DIRECT_CMD_DATA_MASK;
    }

    return kStatus_Success;
}

