
#include "sdio_drv.h"

unsigned int sddesbuf[1024];

HCON_Reg_t hcon_reg;
void SDIO_HCON(void)
{
	*(u32*)&hcon_reg = R32(SDMMC_HCON);
	if(hcon_reg.card_type != 1)
	{
		__asm("bkpt 0");
	}
}

u8 SDIO_PollStatus(u32 flag_s)
{
	u32 status = 0;
	u32 poll_cnt = 0;

	status = R32(SDMMC_RINTSTS);
	while((status & flag_s)!= flag_s)
	{
		status = R32(SDMMC_RINTSTS);
		if (flag_s == SDMMC_INT_CMD_DONE) //only CMDDONE is expected
		{
			poll_cnt++;
			if (poll_cnt == RESP_TIMEOUT){ //software detect Response timeout
				__asm("bkpt 0");
				return 1;
			}
		}
	}
	//clear
	W32(SDMMC_RINTSTS, flag_s);
	return 0;
}

void SDIO_Start_CMD(void)
{
	u32 status = 0;

	status = R32(SDMMC_CMD);
	while ( status & SDMMC_CMD_START ){
		status = R32(SDMMC_CMD);  //Hardware
	}	
}

void SDIO_SetClk(u32 slot_num, u32 div_val)
{
	/*  P213
	 * Before disabling the clocks, ensure that the card is not busy due to any previous data command.
	 * To determine this, check for 0 in bit 9 of the STATUS register.
	 */
	while(R32(SDMMC_STATUS)&BIT_X(9));

	/* disable clock to CIU */
	W32(SDMMC_CLKENA, 0);
	/* inform CIU: P220 */
	W32(SDMMC_CMD, SDMMC_CMD_START |SDMMC_CMD_UPD_CLK |SDMMC_CMD_PRV_DAT_WAIT);
	SDIO_Start_CMD();

	/* set clock to desired speed */
	W32(SDMMC_CLKSRC, 0);
	W32(SDMMC_CLKDIV, (div_val <<0));
	/* inform CIU */
	W32(SDMMC_CMD, SDMMC_CMD_START |SDMMC_CMD_UPD_CLK |SDMMC_CMD_PRV_DAT_WAIT);
	SDIO_Start_CMD();

	/* enable clock */
	W32(SDMMC_CLKENA, (0x0000<<SDMMC_CLKEN_LOW_PWR) | (slot_num <<SDMMC_CLKEN_ENABLE));
	/* inform CIU */  //P219+P162
	W32(SDMMC_CMD, SDMMC_CMD_START |SDMMC_CMD_UPD_CLK |SDMMC_CMD_PRV_DAT_WAIT);//do not use:(EMMC_SLOT0 <<16)/(SD_SLOT1 <<16)
	SDIO_Start_CMD();
}

void SDIO_SwitchClk(u8 flag)
{
	if(flag == 0) //stop clock
	{
		/* disable clock to CIU */
		W32(SDMMC_CLKENA, 0);
		/* inform CIU: P220 */
		W32(SDMMC_CMD, SDMMC_CMD_START |SDMMC_CMD_UPD_CLK |SDMMC_CMD_PRV_DAT_WAIT|SDMMC_CMD_VOLT_SWITCH);
		SDIO_Start_CMD();
	}
	else
	{
		/* enable clock */
		W32(SDMMC_CLKENA, (1<<SD_SLOT1) <<SDMMC_CLKEN_ENABLE);
		/* inform CIU */  //P219+P162
		W32(SDMMC_CMD, SDMMC_CMD_START |SDMMC_CMD_UPD_CLK |SDMMC_CMD_PRV_DAT_WAIT|SDMMC_CMD_VOLT_SWITCH);//do not use:(EMMC_SLOT0 <<16)/(SD_SLOT1 <<16)
		SDIO_Start_CMD();
	}
}

u8 SDIO_Reset(void)
{
	u32 ctrl,timeout = 1000;

	W32(SDMMC_CTRL, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET);
	/* wait till resets clear */
	do{
		ctrl = R32(SDMMC_CTRL);
		if(!(ctrl & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)))
			return 0;
	}while(timeout--);

	return 1;
}
#if 0
void SDIO_Init(void)
{
	u32 fifo_size;
	

	/* Clear(Wr 1) the interrupts for the host controller */
	W32(SDMMC_RINTSTS, 0xFFFFFFFF);
	/* 0=disable all mmc interrupt first */
	W32(SDMMC_INTMASK, 0);
	/* Put in max timeout */
	W32(SDMMC_TMOUT, 0xFFFFFFFF);
	/* .py:  0:1-bit mode */
	W32(SDMMC_CTYPE, SDMMC_CTYPE_1BIT);
	W32(SDMMC_DEBNCE, 0xffffff);
	//drive(write timing), //sample(read timing)  -->0,1,2,3
	W32(SDMMC_UHS_EXT, 1<<23|2<<16);

#if 0
	fifo_size = R32(SDMMC_FIFOTH);
	fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
#else
	fifo_size = FIFO_DEPTH; //Recommended: MSize = 8, TX_WMark = 8, RX_WMark = 7
#endif
	W32(SDMMC_FIFOTH, ((0x2 << 28)|((fifo_size/2 - 1) << 16)|((fifo_size/2) << 0)));
	
	R32(SDMMC_CTRL) |= SDMMC_CTRL_INT_ENABLE;
	NVIC_Init(3, 3, 193, 4);
}
#endif


void SDIO_Init_NOINT(void)
{
	u32 fifo_size;
	

	/* Clear(Wr 1) the interrupts for the host controller */
	W32(SDMMC_RINTSTS, 0xFFFFFFFF);
	/* 0=disable all mmc interrupt first */
	W32(SDMMC_INTMASK, 0);
	/* Put in max timeout */
	W32(SDMMC_TMOUT, 0xFFFFFFFF);
	/* .py:  0:1-bit mode */
	W32(SDMMC_CTYPE, SDMMC_CTYPE_1BIT);
	W32(SDMMC_DEBNCE, 0xffffff);
	//drive(write timing), //sample(read timing)  -->0,1,2,3
	W32(SDMMC_UHS_EXT, 1<<23|2<<16);

#if 0
	fifo_size = R32(SDMMC_FIFOTH);
	fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
#else
	fifo_size = FIFO_DEPTH; //Recommended: MSize = 8, TX_WMark = 8, RX_WMark = 7
#endif
	W32(SDMMC_FIFOTH, ((0x2 << 28)|((fifo_size/2 - 1) << 16)|((fifo_size/2) << 0)));
	
}


u8 SDIO_CardDetect(void)
{
	u32 card_det;

	card_det = R32(SDMMC_CDETECT);
	if((card_det & (1 <<SD_SLOT1)) == SDMMC_CDETECT_CARD_PRESENT) //pin7=DETECT_N[0]=GND
	{
		SDIO_PowerUp(1<<SD_SLOT1, 1); //pin086=CARD_POWER_EN[0]/#EN1---eMMC  (VDDQ)
	   	//delay_f(0x1000);
			//HAL_Delay_ms(3);
			delay(0x10000);
	   	SDIO_Card_Volt(1<<SD_SLOT1, 0); //3.3Vdd
	  	//return SDIO_PollStatus(SDMMC_INT_CD);
	   	return 0;

	}
	return 1;
}

//-----------------------power--------------------------------------------------
/*
 * FPGA: U10=>FPGA_gpio4=>OE   /J10.008=CARD_BIU_VOLT[1]= #FPGA_GPIO4
 *   P207/Output Decoded Voltage
 */
void SDIO_Card_Volt(u32 slot_num, u8 flag)
{
	u32 uhs_1_reg;

	uhs_1_reg = R32(SDMMC_UHS_REG);
	if(flag == 0) //3.3 vdd
	{
		uhs_1_reg &= ~slot_num;
	}
	else //1.8Vdd
	{
		uhs_1_reg |= slot_num;
	}
	W32(SDMMC_UHS_REG, uhs_1_reg);  //P185: 1 ¨C Buffers supplied with 1.8V Vdd
}

void SDIO_PowerUp(u32 slot_num, u8 flag)
{
	u32 power;

	power = R32(SDMMC_PWREN);
	if(flag == 0) //off
	{
		power &= ~slot_num;
	}
	else //on
	{
		power |= slot_num;
	}
	W32(SDMMC_PWREN, power);
}

u8 SDIO_GetPowerState(u32 slot_num)
{
	u32 power;

	power = R32(SDMMC_PWREN)&slot_num;
	return (power == 0) ? 0 : 1;
}

void SDIO_Internal_Dmac_Ctrl(u8 flag)
{
	u32 data;

	data = R32(SDMMC_CTRL);
	if(flag == 1) //enable
	{
		data |= SDMMC_CTRL_USE_IDMAC;
		W32(SDMMC_CTRL, data);
		W32(SDMMC_BMOD, (1<<7)|(1<<1));
	}
	else //disable
	{
		data &= ~SDMMC_CTRL_USE_IDMAC;
		W32(SDMMC_CTRL, data);
		data = SDMMC_BMOD;
		data &= ~(1<<7);
		W32(SDMMC_BMOD, data);
	}
}

void SDIO_ConfigDesc(u32 dbaddr, u32 baddr, u16 dscnt, u32 blk_size)
{
	u16 idx;
	u32 temp_baddr, start_addr = dbaddr;

	for(idx = 0; idx < dscnt * 8; idx++)
	{
		W32(start_addr + idx * 4, 0);
	}
	for(idx = 0; idx < dscnt; idx++)
	{
		temp_baddr = start_addr + idx * 32; //16bytes for 32-bit dma haddr, 32bytes for 64-bit dma haddr
	    if (idx == (dscnt - 1))
	    	W32(temp_baddr, (OWN | FS | CH | LD));
	    else
	        W32(temp_baddr, (OWN | FS | CH));
	    temp_baddr = start_addr + idx * 32 + 8;
	    W32(temp_baddr, blk_size);
	    temp_baddr = start_addr + idx * 32 + 16;
	    W32(temp_baddr, baddr);
	    W32(temp_baddr+4, dbaddr+0x50);//high 32bit, no used in this version
	    temp_baddr = start_addr + idx * 32 + 24;
	    W32(temp_baddr, (start_addr + 32 * (idx + 1)));
	    W32(temp_baddr+4, dbaddr+0x50); //high 32bit, no used in this version
	    baddr += blk_size;
	}
}

void CMD0_SD_tsk(u32 arg)
{
	W32(SDMMC_CMDARG, arg);
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD|SDMMC_CMD_INIT|(SD_SLOT1 <<16)|SDMMC_CMD_INDX(0));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* SEND_OP_COND (CMD1) :OCR */
void CMD1_SD_tsk(u32 arg)
{
	W32(SDMMC_CMDARG, arg);
	//4.5-P120: R3 has no CRC. +Res index=111111'b
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
			|(SD_SLOT1 <<16)|SDMMC_CMD_INDX(1));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

void CMD8_SD_tsk(u32 arg)
{
	W32(SDMMC_CMDARG, arg);
	//R7 +Res index=001000'b
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT			//|BIT(29)
		 | SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(8));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

void CMD11_SD_tsk(void)
{
	W32(SDMMC_CMDARG, 0);
	//R1.+Res CMD index.
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD|SDMMC_CMD_VOLT_SWITCH| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
			| SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(11));
	SDIO_PollStatus(SDMMC_INT_VOLT_SWITCH);
}

void CMD55_SD_tsk(u32 rca)
{
	W32(SDMMC_CMDARG, (rca <<16));
	//R1.+Res CMD index.
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
			| SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(55));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* SD_SEND_OP_COND(ACMD41) :OCR */
void ACMD41_SD_tsk(u32 arg)
{
	CMD55_SD_tsk(0x0000);  	 //CMD55 in idle_state shall be the cardĄ¯s default RCA=0x0000.

	W32(SDMMC_CMDARG, arg);	 //the host should set HCS to 0 if the card returns no response to CMD8.
	//R3 has no CRC. +Res index=111111'b
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
			|(SD_SLOT1 <<16)|SDMMC_CMD_INDX(41));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* CMD02:ALL_SEND_CID */
void CMD2_SD_tsk(void)
{
	W32(SDMMC_CMDARG, 0);
	//136 bits R2 has CRC. + Res index=111111'b
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
			|SDMMC_CMD_RESP_LONG | SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(2));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* CMD03:SEND_RELATIVE_ADDR */
void CMD3_SD_tsk(u32 rca)
{
	W32(SDMMC_CMDARG, (rca <<16));
	//eMMC: R1.+Res CMD index.
	//SD: R6.+Res CMD index. + new RCA+ status:
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
			| SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(3));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* CMD09:SEND_CSD */
void CMD9_SD_tsk(u32 rca)
{
	W32(SDMMC_CMDARG, (rca <<16));
	//136 bits R2 has CRC. + Res index=111111'b
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
				|SDMMC_CMD_RESP_LONG| SDMMC_CMD_RESP_CRC
				|(SD_SLOT1 <<16)|SDMMC_CMD_INDX(9));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* CMD07:SELECT/DESELECT_CARD */
void CMD7_SD_tsk(u32 rca)
{
	W32(SDMMC_CMDARG, rca);
	//R1/R1b.
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
				| SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(7));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* CMD13:SEND_STATUS */
void CMD13_SD_tsk(u32 rca)
{
	W32(SDMMC_CMDARG, (rca <<16));
	//R1.
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
				| SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(13));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* ACMD51:SET_CLR_CARD_DETECT, arg: bit0, 0:disconnect 1:connect */
void ACMD42_SD_tsk(u32 rca, u32 set_cd)
{
	CMD55_SD_tsk(rca);

	W32(SDMMC_CMDARG, set_cd);
	//R1.
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
				| SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(42));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* ACMD51:SEND_SCR
 * Reads the SD Configuration Register(64bits) */
void ACMD51_SD_tsk(u32 rca, u32 byte_num)
{
	CMD55_SD_tsk(rca);

	W32(SDMMC_CMDARG, 0);
	W32(SDMMC_BLKSIZ, byte_num);
	W32(SDMMC_BYTCNT, byte_num);
	//R1.+data.
	W32(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(51));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE| SDMMC_INT_DATA_OVER);
}

/* SD_SET_BUS_WIDTH(ACMD6) */
void ACMD6_SD_tsk(u32 rca)
{
	CMD55_SD_tsk(rca);  	 //CMD55 in idle_state shall be the cardĄ¯s default RCA=0x0000.

	W32(SDMMC_CMDARG, 0x02);	 //the host should set HCS to 0 if the card returns no response to CMD8.
	//R3 has no CRC. +Res index=111111'b
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
			| SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(6));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* SD_SET_BLOCKLEN(CMD16) */
void CMD16_SD_tsk(u16 blocklen)
{
	W32(SDMMC_CMDARG, blocklen);	 //the host should set HCS to 0 if the card returns no response to CMD8.
	//R3 has no CRC. +Res index=111111'b
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
			| SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(16));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* CMD6:Switch Func
 * HS Switch */
void CMD6_SD_tsk(u32 arg, u32 byte_num)
{
	W32(SDMMC_CMDARG, arg);
	W32(SDMMC_BLKSIZ, byte_num);
	W32(SDMMC_BYTCNT, byte_num);
	//R1.+data.
	W32(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(6));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE| SDMMC_INT_DATA_OVER);
}

/* CMD17:Read Single Block */
void CMD17_SD_tsk(u32 arg, u32 byte_num)
{
	W32(SDMMC_BYTCNT, byte_num);
	W32(SDMMC_BLKSIZ, BLOCK_SIZE);
	W32(SDMMC_CARDTHRCTL, (CARD_THRESHOLD<<16)|0x01);
#ifdef USE_INTERNAL_DMAC
	W32(SDMMC_DBADDRL, DESCRIPTION_ADDR);
	W32(SDMMC_DBADDRU, DESCRIPTION_ADDR+0x50); //high 32bit, no used in this version
#endif
	W32(SDMMC_CMDARG, arg);
	//R1.+data.
	W32(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(17));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* CMD18:Read Multi Block */
void CMD18_SD_tsk(u32 arg, u32 byte_num)
{
#ifdef UNDEFINED_TRANS_NUM
	W32(SDMMC_BYTCNT, 0);
#else
	W32(SDMMC_BYTCNT, byte_num);
#endif
	W32(SDMMC_BLKSIZ, BLOCK_SIZE);
	W32(SDMMC_CARDTHRCTL, (CARD_THRESHOLD<<16)|0x01);
#ifdef USE_INTERNAL_DMAC
	W32(SDMMC_DBADDRL, DESCRIPTION_ADDR);
	W32(SDMMC_DBADDRU, DESCRIPTION_ADDR+0x50); //high 32bit, no used in this version
#endif
	W32(SDMMC_CMDARG, arg);
	//R1.+data.
#ifdef SEND_AUTO_STOP
	W32(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(18)|SDMMC_CMD_SEND_AUTO_STOP);
#else
	W32(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(18));
#endif
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* STOP_TRANSMISSION(CMD12) */
void CMD12_SD_tsk(void)
{
	W32(SDMMC_CMDARG, 0);	 //the host should set HCS to 0 if the card returns no response to CMD8.
	//R3 has no CRC. +Res index=111111'b
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT | SDMMC_CMD_STOP
			| SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(12));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* CMD24:Write Single Block */
void CMD24_SD_tsk(u32 arg, u32 byte_num)
{
	W32(SDMMC_BYTCNT, byte_num);
	W32(SDMMC_BLKSIZ, BLOCK_SIZE);
	W32(SDMMC_CARDTHRCTL, (CARD_THRESHOLD<<16)|0x04);
#ifdef USE_INTERNAL_DMAC
	W32(SDMMC_DBADDRL, DESCRIPTION_ADDR);
	W32(SDMMC_DBADDRU, DESCRIPTION_ADDR+0x50); //high 32bit, no used in this version
#endif
	W32(SDMMC_CMDARG, arg);
	//R1.+data.
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT | SDMMC_CMD_DAT_WR
				| SDMMC_CMD_RESP_CRC | SDMMC_CMD_DAT_EXP |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(24));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}

/* CMD25:Write Multi Block */
void CMD25_SD_tsk(u32 arg, u32 byte_num)
{
#ifdef UNDEFINED_TRANS_NUM
	W32(SDMMC_BYTCNT, 0);
#else
	W32(SDMMC_BYTCNT, byte_num);
#endif
	W32(SDMMC_BLKSIZ, BLOCK_SIZE);
	W32(SDMMC_CARDTHRCTL, (CARD_THRESHOLD<<16)|0x04);
#ifdef USE_INTERNAL_DMAC
	W32(SDMMC_DBADDRL, DESCRIPTION_ADDR);
	W32(SDMMC_DBADDRU, DESCRIPTION_ADDR+0x50); //high 32bit, no used in this version
#endif
	W32(SDMMC_CMDARG, arg);
	//R1.+data.
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT | SDMMC_CMD_DAT_WR
				| SDMMC_CMD_RESP_CRC | SDMMC_CMD_DAT_EXP |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(25));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}


/* SD_SEND_OP_COND(ACMD41) :OCR */
void CMD5_SD_tsk(u32 arg)
{
	W32(SDMMC_CMDARG, arg);
	//R3 has no CRC. +Res index=111111'b
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
			|(SD_SLOT1 <<16)|SDMMC_CMD_INDX(5));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
	R32(SDMMC_CMD) &= ~SDMMC_CMD_USE_HOLD;
}

void CMD52_SD_tsk(u32 arg)
{
	W32(SDMMC_CMDARG, arg);
	//R1/R1b.
	W32(SDMMC_CMD, SDMMC_CMD_START|SDMMC_CMD_USE_HOLD| SDMMC_CMD_RESP_EXP| SDMMC_CMD_PRV_DAT_WAIT
				| SDMMC_CMD_RESP_CRC |(SD_SLOT1 <<16)|SDMMC_CMD_INDX(52));
	SDIO_PollStatus(SDMMC_INT_CMD_DONE);
}
