/*
*****************************************************************************************
* This driver refers to SD Specifications Part A2, SD Host Controller Simplified Spec.
* Version 2.00, Feb 8, 2007. Web presence at http://www.sdcard.org/home
* Another important document is SD Specifications Part 1, Physical Layer Simplified
* Specification Vesion 2.00 which is also available for download from the same sdcard
* web site.
*****************************************************************************************
*/

#include "ssd1928_sdhc.h"
//debug
#include "comm.h"
#include "monitor.h"

/*
*****************************************************************************************
* There are dependencies between operation modes and card states.
* Each state in the SD memory card state is associated with one
* operation mode. More details on page 12,
* Physical Layer Simplified Specification Version 2.00
* web site.
*****************************************************************************************
*/
CARD_STATE _card_state[] = 
{
	{0, "idle(0)"},		// idle state			:card id mode
	{1, "ready(1)"},	// ready state			:card id mode
	{2, "ident(2)"},	// identification state	:card id mode
	{3, "stby(3)"},		// stand-by state		:data transfer mode
	{4, "tran(4)"},		// transfer state		:data transfer mode
	{5, "data(5)"},		// sending-data state	:data transfer mode
	{6, "rcv(6)"},		// receive-data state	:data transfer mode
	{7, "prg(7)"},		// programming state	:data transfer mode
	{8, "dis(8)"},		// disconnect state		:data transfer mode
	{9, "reserved(9)"},
	{10, "reserved(10)"},
	{11, "reserved(11)"},
	{12, "reserved(12)"},
	{13, "reserved(13)"},
	{14, "reserved(14)"},
	{15, "reserved(15)"},
	{0, ""}
};

INT32 	g_card_capacity;
CSD_T	g_csd;			// card specific data structure (more details in ssd1928_sdhc.h file)
CID_T	g_cid;			// card identification(more details in ssd1928_sdhc.h file)
SCR_T	g_scr;			// card configuration(more details in ssd1928_sdhc.h file)
UINT16  g_rca;			// RCA register is a 16-bit register that stores the card address
						// published by the card id process (default value is 0x0000)
UINT32  g_ocr;			// OCR register is a 32-bit register that stores the VDD voltage
						// profile of the card (Section 5.1 on Physical Layer Spec. Version 2.00)
UINT32	g_cardtype = 0;	// SDMEM, SDHC, MMC. SDIO is not supported yet.
/*
*****************************************************************************************
* 									Local Function Prototype
*****************************************************************************************
*/
SHORT ssd1928_SDSendCmd(BYTE cmd, DWORD arg);

INT32 send_cmd_SD (		// direct port from Solomon example
		UINT16 idx, 
		UINT16 type, 
		UINT16 rsp, 
		INT32 data_prsnt,
		INT32 crc_check, 
		INT32 idx_check, 
		UINT32 arg[4]);

INT32 send_app_cmd (	// direct port from Solomon example for application specific command send
		UINT16 idx, 
		UINT16 type, 
		UINT16 rsp, 
		INT32 crc_check, 
		INT32 idx_check, 
		UINT32 arg[4]);

/*
*****************************************************************************************
*									SD CLK GENERATION
*
* Description :	This function initializes the SD clk with a divisor for MCLK (fixed 72MHz)
*
* Argument :	BYTE 	'div'	specifies the divisor for MCLK/2
*						 80h	base clock divided by 256, i.e. 72MHz/2/256
*						 40h	divided by 128
*						 20h	divided by 64
*						 10h	divided by 32
*						 08h	divided by 16
*						 04h	divided by 8
*						 02h	divided by 4
*						 01h	divided by 2
*						 00h	divided by 1 (10MHz ~63MHz)
*						 FFh	Stop SD Clock and ICLK
*
* Return :		-1		 if stabliazation filed
*				 0		 if clock set successful and stable
*****************************************************************************************
*/
SHORT ssd1928_SDSetClk(BYTE div)
{
		SHORT i;

		if (div == 0xFF) 
		{
			SetRegB(REG_u8ClkCntl, 0x00);
			return 0;
		}

		SetRegB(0x1001, 0x01); //make sure SD_CLK divisor bit set to 1, SD_CLK=MCLK/2
		/*
		SetRegB(REG_u8ClkCntl, GetReg(REG_u8ClkCntl)&~(1<<2));	//disable SD clock
		SetRegB(REG_u8ClkCntl, 0x01);			//Internal Clock enable for SD		
		for (i = 0; i < MAX_WAIT; i++)
		{
			if (GetReg(REG_u8ClkCntl) & 0x02)	//wait until PLL stable
				break;
		}	

		if(i == MAX_WAIT)
		{
			xputs("Clock Control: Internal clock oscillation failed to reach stability\n");
			return -1;
		}		

		*/
		SetRegB(REG_u8ClkDiv, div);	//For MCLK=72MHz, this divisor further divides it by divisor 'div'
									//therefore the SD_CLK = 72MHz/2/divisor

		SetRegB(REG_u8ClkCntl, 0x05);	//SD Clock enable
		for (i = 0; i<MAX_WAIT; i++)
		{
			if (GetReg(REG_u8ClkCntl)&0x02)	//wait until clock stable
			break;
		}

		if(i == MAX_WAIT)
		{
			xputs("Clock Control: SD clk failed to stablize after clock divisor set\n");
			return -1;
		}

		return 0;

}

/*
*****************************************************************************************
*									SEND SD CMD
*
* Description :	This function is a direct "translation" from Solomon example
*
* Argument :	UNIT16	'idx'		is the command index CMD0-63
*				UINT16	'type'		indicates 4 command types according to SDHC Spec. 
*									ABORT(3), RESUME(2), SUSPEND(1), NORMAL(0)
*				UINT16	'rsp'		Response type select R0(no response), R136(response length 136)
*									R48(length 48), R48b(length 48 with busy check)
*				INT32 'data_prsnt' 	This bit is set to 1 to indicate that data is present
*									and shall be transferred using the DAT line.
*									It is set to 0 for several command types such as 
*									1) Commands using only CMD line (ex. CMD52)
*									2) Commands with no data transfer but using busy 
*									   signal on DAT0 (CMD38)
*									3) Resume command
*				INT32 'crc_check'	Command CRC check enable (1) or (0)
*				INT32 'idx_check'	Command index check enable (1) or (0)
*				UINT32 'arg[4]'		is the command argument specified in the Physical	
*									Layer Specification
*
*
* Return :		0					if no error
*				-1, -2, -4			if interrupt error, command inhibit error, etc.
* 
* Note :		Everything is direct copy from Solomon example except the condition
*				g_irq is not checked, and an extra xputs for debug at error=4
*****************************************************************************************
*/
INT32 send_cmd_SD (
		UINT16 idx, 
		UINT16 type, 
		UINT16 rsp, 
		INT32 data_prsnt,
		INT32 crc_check, 
		INT32 idx_check, 
		UINT32 arg[4])
{
	UINT32 i;
	INT32 error = 0;
	UINT16 cmd = 0;
	UINT16 u16NrmIntrSignalEn = 0;
	UINT16 u16ErrIntrSignalEn = 0;
	UINT16 u16NrmIntrStatus = 0;

	if (rsp == R48b || data_prsnt)
	{
		SetRegB(REG_u8ToutCntl, 0x0e);	// TMCLK * 2^^27
	}

	// clear previous status
	SetRegW(REG_u16NrmIntrStatus , (INTR_CMD_COMPLETE | (data_prsnt ? INTR_DAT_COMPLETE : 0)));	
	SetRegW(REG_u16NrmIntrStatusEn , GetRegW(REG_u16NrmIntrStatusEn)| (INTR_CMD_COMPLETE | (data_prsnt ? INTR_DAT_COMPLETE : 0)));	
	
	GetRegW(REG_u16ErrIntrStatus, 0xffff);	// clear previous status of err interrupt status
	
	SetRegW(REG_u16ErrIntrStatusEn ,
			//SSD_REGRW(REG_u16ErrIntrStatusEn)| //check if it is need or not
			EINTR_CMD_TOUT | EINTR_CMD_END |
			(crc_check ? EINTR_CMD_CRC : 0) | 
			(idx_check ? EINTR_CMD_IDX : 0) |
		       	(data_prsnt ? (EINTR_DAT_TOUT | EINTR_DAT_CRC | EINTR_DAT_END |
				       EINTR_VS_DAT_CONFLICT | EINTR_VS_BLKSZ_ERR) : 0) |
			((rsp == R48b) ? EINTR_DAT_TOUT : 0) 
			| EINTR_VS_RSP_DIR );

	SetRegL(REG_u32Arg, SWAP32(arg[0]));

	cmd |= 	CMD_IDX (idx) | CMD_TYPE (type) | CMD_RSP (rsp) | 
			(crc_check ? CMDR_CRC_CHECK_EN : 0) | (idx_check ? CMDR_IDX_CHECK_EN : 0) |
			(data_prsnt ? CMDR_DATA_PRESENT : 0);

	arg[0] = 0;
	arg[1] = 0;
	arg[2] = 0;
	arg[3] = 0;

	xprintf("send_cmd_SD: Send cmd %d - %x\r\n",idx,cmd);
	
	SetRegW(REG_u16Cmd , cmd); //REG_u16Cmd = 0x110e

	for (i = 0; i < MAX_WAIT; i++) 
	{
		if ((GetRegL(REG_u32PrsntState) & PSR_INHIBIT_CMD) 
		 || (GetRegW(REG_u16NrmIntrStatus) & INTR_CMD_COMPLETE))
			break;

		//move this error check here becase the loop mostly quit at i=0.
		if (i == MAX_WAIT - 1)	
		{	
			error = 1;
			xputs("send_cmd_SD: error 1\n\r");
			goto l_err;
		}
	}
	
	for (i = 0; i < MAX_WAIT; i++)
	{
		if ((u16NrmIntrStatus=GetRegW(REG_u16NrmIntrStatus)) & (INTR_CMD_COMPLETE | INTR_ERR))	
			break;
			
		if (i == MAX_WAIT-1)
		{
			error = 2;
			xputs("send_cmd_SD: error 2\n\r");
			goto l_err;
		}
	}

	arg[0] = SWAP32 (GetRegL(REG_a32Rsp+0));
	arg[1] = SWAP32 (GetRegL(REG_a32Rsp+4));
	arg[2] = SWAP32 (GetRegL(REG_a32Rsp+8));
	arg[3] = SWAP32 (GetRegL(REG_a32Rsp+12));

	if (u16NrmIntrStatus & INTR_ERR)
	{
		SetRegW(REG_u16ErrIntrStatus , 0xffff);

		SetRegW(REG_u16NrmIntrStatus , INTR_CMD_COMPLETE);
		if (GetRegW(REG_u16NrmIntrStatus))
		{
			SetRegW(REG_u16NrmIntrStatus , 0x00ff);
		}
		error = 4; //Not a error
		xputs("send_cmd_SD: error 4\n\r");
		goto l_err;
	}

	if (u16NrmIntrStatus & INTR_CMD_COMPLETE)
	{
		//clear
		SetRegW(REG_u16NrmIntrStatus , INTR_CMD_COMPLETE);
	}

l_err:
	SetRegW(REG_u16NrmIntrStatusEn, GetRegW(REG_u16NrmIntrStatusEn)& ~INTR_CMD_COMPLETE);
	SetRegW(REG_u16ErrIntrStatusEn, GetRegW(REG_u16ErrIntrStatusEn) & ~(EINTR_CMD_TOUT | EINTR_CMD_CRC | EINTR_CMD_IDX | EINTR_CMD_END | EINTR_VS_RSP_DIR));

	return (error ? -error : 0);
}

/*
*****************************************************************************************
*							SEND APPLICATION SPECIFIC CMD
*
* Description :	This function is a direct "translation" from Solomon example
*
* Argument :	UNIT16	'idx'		is the command index CMD0-63
*				UINT16	'type'		indicates 4 command types according to SDHC Spec. 
*									ABORT(3), RESUME(2), SUSPEND(1), NORMAL(0)
*				UINT16	'rsp'		Response type select R0(no response), R136(response length 136)
*									R48(length 48), R48b(length 48 with busy check)
*				INT32 'crc_check'	Command CRC check enable (1) or (0)
*				INT32 'idx_check'	Command index check enable (1) or (0)
*				UINT32 'arg[4]'		is the command argument specified in the Physical	
*									Layer Specification
*
*
* Return :		0					if no error
* 
* Note :		Everything is direct copy from Solomon example except the condition
*				g_irq is not checked
*****************************************************************************************
*/
INT32 send_app_cmd (
		UINT16 idx, 
		UINT16 type, 
		UINT16 rsp, 
		INT32 crc_check, 
		INT32 idx_check, 
		UINT32 arg[4])
{
	INT32 i;

	INT32 error = 0;
	UINT16 cmd;
	UINT32 arg0 = 0;
	UINT32 arg1 = arg[1]; 	// save it here
	UINT16 u16NrmIntrSignalEn = 0;
	UINT16 u16ErrIntrSignalEn = 0;

	
	xputs("send_app_cmd:\r\n");

	if (type == SUSPEND || type == RESUME)
	{
		xprintf("send_app_cmd(ACMD%u): Suspend/Resume are not supported\n\r", idx);
		return -1;
	}


	if (GetRegL(REG_u32PrsntState) & PSR_INHIBIT_CMD)
	{
		xprintf("send_app_cmd(ACMD%u): Command Inhibit CMD is active\n\r", idx);
		return -1;
	} 

	SetRegW(REG_u16NrmIntrStatus , GetRegW(REG_u16NrmIntrStatus));	// clear previous status

	SetRegW(REG_u16NrmIntrStatusEn, GetRegW(REG_u16NrmIntrStatusEn) | INTR_CMD_COMPLETE);	

	SetRegW(REG_u16ErrIntrStatus, GetRegW(REG_u16ErrIntrStatus)|GetRegW(REG_u16ErrIntrStatus));	// clear previous status
	SetRegW(REG_u16ErrIntrStatusEn, GetRegW(REG_u16ErrIntrStatusEn) |
			( EINTR_CMD_TOUT | EINTR_CMD_END | EINTR_VS_RSP_DIR |
			(crc_check ? EINTR_CMD_CRC : 0) |
			(idx_check ? EINTR_CMD_IDX : 0)));
						 
	SetRegL(REG_u32Arg , SWAP32(arg[0]));

	//Send CMD55
	cmd = CMD_IDX (0x37) | CMD_TYPE (NORMAL) | CMD_RSP (R48);
	cmd |= crc_check ? CMDR_CRC_CHECK_EN : 0;
	cmd |= idx_check ? CMDR_IDX_CHECK_EN : 0;

	xprintf("send_app_cmd: Send CMD55 %x\r\n", cmd);

	SetRegW(REG_u16Cmd , cmd);

	for (i = 0; i < MAX_WAIT; i++)
	{
		if (GetRegL(REG_u32PrsntState) & PSR_INHIBIT_CMD) //If CMD line busy, break loop
			break;
	}

	if (i==MAX_WAIT) return -1;

	// wait for command complete or error
	for (i = 0; i < MAX_WAIT; i++)
	{
		if (GetRegW(REG_u16NrmIntrStatus) & (INTR_CMD_COMPLETE | INTR_ERR))	
			break;
	}

	arg0   = SWAP32 (GetRegL(REG_a32Rsp));	// arg[0] - contains response to CMD55
	arg[0] = arg0;
	arg[1] = SWAP32 (GetRegL(REG_a32Rsp+4));
	arg[2] = SWAP32 (GetRegL(REG_a32Rsp+8));
	arg[3] = SWAP32 (GetRegL(REG_a32Rsp+12));
	
	xprintf("Response from CMD55: %x %x %x %x\r\n",arg[0],arg[1],arg[2],arg[3]);

	if (i == MAX_WAIT)
	{
		error = 1;
		xputs("send_app_cmd: error 1\r\n");
		goto l_err;
	}

	if (GetRegW(REG_u16NrmIntrStatus) & INTR_ERR)
	{
		SetRegW(REG_u16ErrIntrStatus , GetRegW(REG_u16ErrIntrStatus));

		SetRegW(REG_u16NrmIntrStatus , INTR_CMD_COMPLETE);
		if (GetRegW(REG_u16NrmIntrStatus))
		{
			SetRegW(REG_u16NrmIntrStatus , GetRegW(REG_u16NrmIntrStatus));
		}

		ssd1928_SDReset (SW_RESET_CMD);
		error = 1;
		
		xputs("send_app_cmd: error 2\r\n");
		goto l_err;
	}

	if (GetRegW(REG_u16NrmIntrStatus) & INTR_CMD_COMPLETE)
	{
		SetRegW(REG_u16NrmIntrStatus , INTR_CMD_COMPLETE);
	}

	//(idx = ACMD41 during card init)
	SetRegL(REG_u32Arg , SWAP32(arg1));
	
	cmd = CMD_IDX (idx) | CMD_TYPE (NORMAL) | CMD_RSP (R48);
	cmd |= crc_check ? CMDR_CRC_CHECK_EN : 0;
	cmd |= idx_check ? CMDR_IDX_CHECK_EN : 0;
	
	xprintf("send_app_cmd: Send CMD55 %x\r\n",cmd);
	
	xprintf("send_app_cmd: *0x1130 = %x\r\n",GetRegL(0x1130));

	xprintf("send_app_cmd: Send cmd %d\r\n",idx);
	xprintf("send_app_cmd: cmd = %x\r\n",cmd);
	xprintf("send_app_cmd: REG_u16Cmd = %x\r\n",REG_u16Cmd);	

	SetRegW(REG_u16Cmd , cmd);

	//Wait Until Command Complete
	for (i = 0; i < MAX_WAIT; i++)
	{
		if(GetRegW(REG_u16NrmIntrStatus) & (INTR_CMD_COMPLETE | INTR_ERR))
		{	
			xprintf("send_app_cmd: Command %d completed\r\n",idx);
			break;
		}
	}

	//Command Timeout
	if (i == MAX_WAIT)
	{
		error = 1;
		
		xputs("send_app_cmd: error 3\r\n");
		goto l_err;
	}

	arg1 = SWAP32 (GetRegL(REG_a32Rsp+0));	// arg[0] - contains response to ACMD
	arg[0] = arg1;
	arg[1] = SWAP32 (GetRegL(REG_a32Rsp+4) );
	arg[2] = SWAP32 (GetRegL(REG_a32Rsp+8) );
	arg[3] = SWAP32 (GetRegL(REG_a32Rsp+12) );

	xprintf("Response from ACMD41: %x %x %x %x\r\n",arg[0],arg[1],arg[2],arg[3]);

	if (GetRegW(REG_u16NrmIntrStatus) & INTR_ERR)
	{
		SetRegW(REG_u16ErrIntrStatus,  GetRegW(REG_u16ErrIntrStatus));

		if (GetRegW(REG_u16NrmIntrStatus))
		{
			SetRegW(REG_u16NrmIntrStatus , GetRegW(REG_u16NrmIntrStatus));
		}

		ssd1928_SDReset (SW_RESET_CMD);
		error = 1;
		
		xputs("send_app_cmd: error 5\r\n");
		goto l_err;
	}

	if (GetRegW(REG_u16NrmIntrStatus) & INTR_CMD_COMPLETE) 
		SetRegW(REG_u16NrmIntrStatus , INTR_CMD_COMPLETE);
		
	xputs("send_app_cmd: no error\r\n");

l_err:
	SetRegW(REG_u16NrmIntrStatusEn, GetRegW(REG_u16NrmIntrStatusEn) & ~INTR_CMD_COMPLETE);
	SetRegW(REG_u16ErrIntrStatusEn, GetRegW(REG_u16ErrIntrStatusEn) & ~(EINTR_CMD_TOUT | EINTR_CMD_CRC | 
				EINTR_CMD_IDX | EINTR_CMD_END));
	
	arg[0] = arg0;
	arg[1] = arg1;
	

	if (idx == 41 && error)
	{
		xprintf("send_app_cmd (ACMD%u): Result = %s\n\r", idx, (error ? "No response": "Passed"));
			//db ("send_app_cmd (ACMD%u): Result = %s\n\r", idx, (error ? "No response": "Passed"));
	}
	else
	{
	 	xprintf("send_app_cmd (ACMD%u): Result = %s\n\r", idx, (error ? "Failed": "Passed"));
		//db ("send_app_cmd (ACMD%u): Result = %s\n\r", idx, (error ? "Failed": "Passed"));
	}

	return (error ? -1 : 0);

}

/*
*****************************************************************************************
*								Send a command packet to SD
* Description:
*
* Argument:		BYTE 	'cmd'		is the Command Index from CMD0 to CMD63
*				DWORD 	'arg'		is ...
* Return:
*****************************************************************************************
*/
SHORT ssd1928_SDSendCmd(BYTE cmd, DWORD arg)
{

	SHORT i;

	if (GetRegL(REG_u32PrsntState) & 0x01)
	{
		xputs ("SDSendCmd: Command Inhibit CMD is active\n");
		return -1;
	}

	SetRegL(REG_u32Arg, arg);
	SetRegW(REG_u16Cmd, cmd);
	
	for (i = 0; i < MAX_WAIT; i++) {
		if (GetRegL(REG_u32PrsntState) & 0x01) 	//Command Inhibit active
		break;
	}

	if (i == MAX_WAIT)
	{
		xputs ("SDSendCmd: Command Inhibit (CMD) is active\n");
		return -1;
	}

	for(i = 0; i < MAX_WAIT; i++)
	{
		if (GetRegW(REG_u16NrmIntrStatus) & 0x01)
		break;
	}
	if (i == MAX_WAIT)
	{
		xputs ("SDSendCmd: Normal Interrupt Status Timeout Err\n");	//Timeout occur during transfer
		return -1;
	}
	

	return 0;							//return response
}

/*
*****************************************************************************************
* 									LOW LEVEL SD CARD RESET
*
* Description:	This function read/write REG[112Fh] to perform software reset for
*				DATA line, CMD line, and reset for all
*
* Argument : 	BYTE	'reset_type'
*						0b00000001	-	Software reset for all, SD card shall reset
*										itself
*						0b00000010	- 	Only part of command circuit is reset
*										Present State register and Normal Interrupt Status
*										register affected.
*						0b00000100	-	DMA circuit is also reset. Buffer Data Port register,
*										Present State register, Block Gap Control register, etc
*										are affected
* Return :		-1 		if timeout
*				 0		if reset successful
*
* Note :		Please refer to section 2.2.16 of Simplified SD Host Controller Spec A2 for details
*****************************************************************************************
*/
SHORT ssd1928_SDReset (BYTE reset_type)
{
	SHORT i = 0;

	SetRegB(REG_u8SwReset, GetReg(REG_u8SwReset)| reset_type);
	for (i = 0; i < MAX_WAIT; i++)
	{
		if (!(GetReg(REG_u8SwReset) & reset_type))
			break;
	}

	return (i == MAX_WAIT) ? -1 : 0;
}

/*
*****************************************************************************************
*										SD CARD DETECT
*
* Description : This function checks if a card is inserted and stablized; else, report 
*				card missing and return
* 				This function assumes debug window in 19200bps, 8-n-1 with
* 				UART connection to a PC for the current version.
* 				It makes use of the register Present State Register at REG[1124h]
* 				to detect if an SD card has been inserted.
* 				There are more states reflected from this State Register. Please refer
* 				to SD Host Controller Simplified Spec. A2 for details
*
* Argument : 	None
* Return :		-1 		if no card, or card not stablized
*				 0		if card present and stable
*
* Dependency : comm.c and monitor.c
*****************************************************************************************
*/
SHORT ssd1928_SDCardDetect(void)
{
	SHORT i;

	// Bit 18 reflects the inverse value of the SD card socket's CD pin
	// When Card present (SDCD=low), Bit(18)=1; when card absent (SDCD=high), Bit(18)=0
	if(!(GetRegL(REG_u32PrsntState)&PSR_CARD_DET_PIN))
	{
		xputs ("SDCardDetect: SDCD=0\n");
		return -1;
	}

	//Bit test Bit(16) for Card inserted. This bit indicates whether a card has been inserted. 
	if (GetRegL(REG_u32PrsntState) & PSR_CARD_INSERTED)
	{
		for(i=0; i<MAX_WAIT; i++)
		{
			if (GetRegL(REG_u32PrsntState) & PSR_CARD_STABLE) break;
		}
		if(i==MAX_WAIT)
		{
			xputs ("SDCardDetect: Card inserted but not stable\n");
			return -1;
		}
	} 
		else
	{
		xputs ("SDCardDetect: Reset or Debouncing or No card\n");
		return -1;
	}

	return 0;
}

/*
*****************************************************************************************
*									POWER CONTROL FOR SD BUS
*
* Description : This function detects 3.3V Voltage Support capabilities from ssd1928
*				and then switch ON/OFF for SD Bus Power.
*				Somehow, the current version of SDD1928 devaites from SD Spec A2 
*				as 1.8V, and 3.0V are not supported.
*				The reset voltage support level is 3.3V, and it is the default as well.
*				Please refer to SD Host Controller Simplified Spec. A2's 
*				Power Control Register (Offset 029h) & Capabilities Register (Offset 040h)
*				for details
*
* Argument : 	BOOL	'pwr'
*				 1(TRUE)	to power UP
*				 0(FALSE)	to power DOWN
*
* Return :		-1 		if Capabilities Register has no Bus Pwer information
*				 0		if power ON successful
*
* Dependency : comm.c and monitor.c
*****************************************************************************************
*/
SHORT ssd1928_SDPwrCntl(BOOL pwr)
{
	SetRegB(REG_u8PwrCntl ,GetReg(REG_u8PwrCntl)& 0xFE);	//power off SD Bus power first

	if (pwr)	// turn on power
	{
		if (GetRegL(REG_u32Capabilities) & (1UL<<24))
			SetRegB(REG_u8PwrCntl , 0x0E);
		else
		{
			xputs ("Capabilities Register has no Bus Pwer information\n");
			return -1;
		}
		SetRegB(REG_u8PwrCntl,GetReg(REG_u8PwrCntl) | 0x01);
	}

	return 0;
}

/*
*****************************************************************************************
* Procedure: 1. Reset Card (CMD0)
*			 2.	Voltage Check (CMD8)
*****************************************************************************************
*/
DSTATUS ssd1928_SDInit(BYTE disk)
{
	DSTATUS status;
	UINT32  rsp[4];

	if (ssd1928_SDReset(SW_RESET_ALL) < 0)
	{
		xputs("ssd1928_SDInit: reset failed\n");
		status = RES_ERROR;
	}	

	if (ssd1928_SDCardDetect() < 0)
	{
		xputs("No card detected or stablization failed at ssd1928_SDInit(BYTE disk)\n");
		status = RES_NOTRDY;
	}

	if(ssd1928_SDPwrCntl(TRUE) < 0)
	{
		xputs("Power up failed at ssd1928_SDInit(BYTE disk)\n");
		status = RES_NOTRDY;		
	}
	
	if(ssd1928_SDSetClk(0x10) < 0)		//start SD clk to 72MHz/2/32 = 1.125MHz
	{
		xputs("Clock control failed at ssd1928_SDInit(BYTE disk)\n");
		status = RES_PARERR;
	}

	// CMD0: Reset SD card	
	rsp[0] = 0xffffffff;
	xputs("ssd1928_SDInit: Reset SD card (CMD0)...");
	if (send_cmd_SD (CMD_RESET, NORMAL, R0, 0, 0, 0, rsp) < 0) 
	{
		xputs("ssd1928_SDInit: CMD0 Failed\r\n");
		status = RES_ERROR;
	}

	// CMD8: check validity of operating condition
	rsp[0] = 0x000001AA; //Host support 3V, ask for the card
	xputs("ssd1928_SDInit: Send (CMD8)..."); 
	if (send_cmd_SD (CMD_SEND_IF_COND, NORMAL, R48, 0, 0, 0, rsp) < 0) //No CRC check, No Idx check
	{
		xputs("ssd1928_SDInit: CMD8 Failed\r\n");
		status = RES_ERROR;
	}
	
	xputs("sdhc_card_init: Send app cmd (ACMD41) ... ");
	if (send_app_cmd (ACMD_SEND_OCR, NORMAL, R48, 0, 0, rsp) < 0)  //it is CMD55+ACMD41
	{
		xputs("ssd1928_SDInit: ACMD41 Failed\r\n");
	}
	
	return status;
}

