//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
//  Copyright (C) 2007 Freescale Semiconductor, Inc. All Rights Reserved.
//  THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
//  AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//------------------------------------------------------------------------------

#include "sdmmc.h"

//-----------------------------------------------------------------------------
// External Functions


//-----------------------------------------------------------------------------
// External Variables
extern SDH_HARDWARE_CONTEXT	SDController;

//-----------------------------------------------------------------------------
// Defines
 #define	MMC_CMD_READ_EXTENDED_CSD 8	

//-----------------------------------------------------------------------------
// Types
// the card registers
SDCARD_CARD_REGISTERS sdCardReg;

//-----------------------------------------------------------------------------
// Global Variables
USHORT Card_rca = 0x0;                   /* Relative Card Address */
BOOL bHighDensityCard = FALSE;
UINT32 mmcSpecVersion = 0;

//-----------------------------------------------------------------------------
// Local Variables


//-----------------------------------------------------------------------------
// Local Functions


//-----------------------------------------------------------------------------
//
//  Function: SDMMC_Init
//
//  This function initializes the SD interface.
//
//  Parameters:
//		None.
//
//  Returns:
//		None.
//
//-----------------------------------------------------------------------------
BOOL SDMMC_Init(void)
{   
	BOOL bInit = FALSE;

	OALMSG(OAL_FUNC, (_T("+ SDMMC_Init\r\n")));

	SDConfigPins ();

	if (SDInterface_Init () == FALSE)
	{
		OALMSG(OAL_VERBOSE, (_T("SDMMC_Init Failed!!!!!\r\n")));
		return bInit;
	}

	SDMMC_card_software_reset ();

	if (!SD_Init ())
	{
		SDController.IsMMC = FALSE;
		OALMSG(OAL_INFO, (_T("INFO: Initialized SD Card\r\n")));
		bInit = TRUE;
	}
	else if (!MMC_Init ())
	{
		SDController.IsMMC = TRUE;
		OALMSG(OAL_INFO, (_T("INFO: Initialized MMC Card\r\n")));
		bInit = TRUE;
	}

	OALMSG(OAL_FUNC, (_T("- SDMMC_Init\r\n")));

	return bInit;
}

//-----------------------------------------------------------------------------
//
//  Function: SDMMC_Deinit
//
//  This function de-initializes the flash chip.
//
//  Parameters:
//		None.
//
//  Returns:  
//		None.
//
//-----------------------------------------------------------------------------
BOOL SDMMC_Deinit (void)
{
    return(TRUE);
}

//-----------------------------------------------------------------------------
//
//  Function: SDMMC_get_cid
//
//  This function will return the CID value of card.
//
//  Parameters:
//		None.
//
//  Returns:
//		SDHC_STATUS_PASS or SDHC_STATUS_FAILURE
//
//-----------------------------------------------------------------------------
UINT32 SDMMC_get_cid (void)
{
    SD_BUS_REQUEST sdRequest;
    UINT32 cid_request=SDHC_STATUS_FAILURE;
    PSD_COMMAND_RESPONSE response = &sdRequest.CommandResponse;
	
   OALMSG(OAL_FUNC, (_T("+ SDMMC_get_cid\r\n")));

    /* Configure CMD2 for card */
    /* No Argument is expected for CMD2 */
    SDCard_command_config (&sdRequest, SD_CMD_ALL_SEND_CID, 0, SD_COMMAND, ResponseR2);

    /* Issue CMD2 to card to determine CID contents */
    if(!SDHCSendCmdWaitResp(&sdRequest))
    {
        /* Read Command response  */
        response->ResponseType = ResponseR2;
        SDHCReadResponse (response);
		
        memcpy(sdCardReg.CID, response->ResponseBuffer, SD_CID_REGISTER_SIZE);		
		
        /* Assign cid_request as SUCCESS */
        cid_request = SDHC_STATUS_PASS;
    }
	
	OALMSG(OAL_FUNC, (_T("- SDMMC_get_cid\r\n")));

    return cid_request;
}

//-----------------------------------------------------------------------------
//
//  Function: SDMMC_set_data_transfer_mode
//
//  This function will put card in transfer mode.
//
//  Parameters:
//		None.
//
//  Returns:
//		SDHC_STATUS_PASS or SDHC_STATUS_FAILURE
//
//-----------------------------------------------------------------------------
UINT32 SDMMC_set_data_transfer_mode (void)
{
    SD_BUS_REQUEST sdRequest;
    UINT32 transfer_status =SDHC_STATUS_FAILURE;
    PSD_COMMAND_RESPONSE response = &sdRequest.CommandResponse;
    UINT32 card_address = (Card_rca << RCA_SHIFT);
	
	OALMSG(OAL_FUNC, (_T("+ SDMMC_set_data_transfer_mode\r\n")));

    /* Configure CMD7 for MMC card */
    /* 16bit card address is expected as Argument */
    SDCard_command_config(&sdRequest,SD_CMD_SELECT_DESELECT_CARD, card_address, 
							SD_COMMAND, ResponseR1b);
	
    /* Sending the card from stand-by to transfer state
    */
    if(!SDHCSendCmdWaitResp(&sdRequest))
    {
		if (!SDMMC_R1b_busy_wait (response))
			transfer_status = SDHC_STATUS_PASS;
    }
	
	OALMSG(OAL_FUNC, (_T("- SDMMC_set_data_transfer_mode\r\n")));

    return transfer_status;
	
}

//-----------------------------------------------------------------------------
//
//  Function: SDMMC_card_software_reset
//
//  This function will issue CMD0 to card. This gives software reset to card.
//
//  Parameters:
//		None.
//
//  Returns:
//		SDHC_STATUS_PASS or SDHC_STATUS_FAILURE
//
//-----------------------------------------------------------------------------
UINT32 SDMMC_card_software_reset(void)
{
    SD_BUS_REQUEST sdRequest;
    UINT32 response = SDHC_STATUS_FAILURE;

	OALMSG(OAL_FUNC, (_T("+ SDMMC_card_software_reset\r\n")));
	
    /*Configure CMD0 for MMC/SD card*/
    /*CMD0 doesnt expect any response */
    SDCard_command_config (&sdRequest,SD_CMD_GO_IDLE_STATE,0,SD_COMMAND,NoResponse);
	
    /*Issue CMD0 to MMC/SD card to put in active state */
    if(SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE)
    {
        response = SDHC_STATUS_PASS;
    }
    
	OALMSG(OAL_FUNC, (_T("- SDMMC_card_software_reset\r\n")));

    return response;
}

//------------------------------------------------------------------------------
//
// Function: SDMMC_card_send_appcmd
//
//	This function will issue an APP CMD (CMD55) to the card
//
// Parameters:
//		None
//
// Returns:
//		SDHC_STATUS_PASS for success/SDHC_STATUS_FAILURE for failure
//
//------------------------------------------------------------------------------ 
UINT32 SDMMC_card_send_appcmd (void)
{
    SD_BUS_REQUEST sdRequest;
    UINT32 response = SDHC_STATUS_FAILURE;
	UINT32 card_address = (Card_rca << RCA_SHIFT);
	
	OALMSG(OAL_FUNC, (_T("+ SDMMC_card_send_appcmd\r\n")));

    /*Configure CMD0 for MMC/SD card*/
    /*CMD0 doesnt expect any response */
    SDCard_command_config (&sdRequest,SD_CMD_APP_CMD, card_address, SD_COMMAND, 
							ResponseR1);
	
    /*Issue CMD0 to MMC/SD card to put in active state */
    if(SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE)
    {
        response = SDHC_STATUS_PASS;
    }

	OALMSG(OAL_FUNC, (_T("- SDMMC_card_send_appcmd\r\n")));

    return response;
}

//------------------------------------------------------------------------------
//
// Function: SDMMC_get_csd
//
//	This function will will read CSD register
//
// Parameters:
//		None
//
// Returns:
//		SDHC_STATUS_PASS for success/SDHC_STATUS_FAILURE for failure
//
//------------------------------------------------------------------------------ 
UINT32 SDMMC_get_csd (void)
{
    SD_BUS_REQUEST sdRequest;
    PSD_COMMAND_RESPONSE response = &sdRequest.CommandResponse;
    UINT32 card_address = (Card_rca << RCA_SHIFT);	
    UINT32 csd_request=SDHC_STATUS_FAILURE;	
	
	OALMSG(OAL_FUNC, (_T("+ SDMMC_get_csd\r\n")));

    /* Configure CMD9 for MMC card */
    /* 16bit card address is expected as Argument */
    SDCard_command_config(&sdRequest, SD_CMD_SEND_CSD, card_address, SD_COMMAND, ResponseR2);

    /* Issue Command CMD9 to Extrace CSD register contents
     */     
    if(SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE)
    {
        /* Read Command response */
        response->ResponseType = ResponseR2;
        SDHCReadResponse (response);
		
        /* Assign Response to CSD Strcuture */
		memcpy(sdCardReg.CSD, response->ResponseBuffer, SD_CSD_REGISTER_SIZE);
		csd_request = SDHC_STATUS_PASS;
    }
	
	OALMSG(OAL_FUNC, (_T("- SDMMC_get_csd\r\n")));

    return csd_request;		
}

//------------------------------------------------------------------------------
//
// Function: SDMMC_GetCardCapacity
//
//	This function will will read SD/MMC card capacity
//
// Parameters:
//		None
//
// Returns:
//		Card capacity in number of sectors(each sector of SDHC_SECTOR_SIZE)
//
//------------------------------------------------------------------------------ 
DWORD SDMMC_GetCardCapacity (void)
{
	UINT32 uCsize;
	USHORT uCmult;
	UINT32 uBlkLen;
	DWORD  dwCapacity = 0, dwTotalNumOfSectors = 0;
    SD_BUS_REQUEST sdRequest;
    PSD_COMMAND_RESPONSE response = &sdRequest.CommandResponse;
    CHAR extCSDBuffer[SDHC_BLK_LEN];

	if (bHighDensityCard)
	{
        if (SDController.IsMMC == TRUE)
        {
    		SDCard_command_config(&sdRequest, MMC_CMD_READ_EXTENDED_CSD, 0x00000000, SD_READ, ResponseR1);
    		SetBlockLen (SDHC_BLK_LEN, 1);			// Ext CSD is 1 block of 512 bytes
    		if (SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE) 
    		{
         		response->ResponseType = ResponseR1;
          		SDHCReadResponse (response);
        		if (SDHCDataRead((UINT32 *)&extCSDBuffer[0],SDHC_BLK_LEN) != SDHC_STATUS_FAILURE)
        		{
            		/* Extract Bytes 212-215 to get the high density card capacity in number of sectors */
            		dwTotalNumOfSectors = (*(UINT32 *)&extCSDBuffer[212]);
        			dwCapacity= ((*(UINT32 *)&extCSDBuffer[212])/1024)*SDHC_SECTOR_SIZE;
    			}
     		}
 		}
 		else
 		{
    		/* Extract Bits 48-69 to get the C_SIZE */
        	memcpy (&uCsize, &(sdCardReg.CSD[6]), sizeof (UINT32));
        	uCsize = (uCsize & 0x3FFFFF);
        	
            /* Memory Capacity = (C_SIZE + 1) * 512K byte */
            dwCapacity = (uCsize + 1) * 512;
            dwTotalNumOfSectors = dwCapacity*2;
 		}
	}
	else
	{
		/* Extract Bits 62-73 to get the C_SIZE */
    	memcpy (&uCsize, &(sdCardReg.CSD[7]), sizeof (UINT32));
    	uCsize = ((uCsize & 0x3FFC0) >> 6);
    	
		/* Extract Bits 47-49 to get the C_MULT */
    	memcpy (&uCmult, &(sdCardReg.CSD[5]), sizeof (USHORT));
    	uCmult = ((uCmult & 0x380) >> 7);
    	
		/* Extract Bits 80-83 to get the READ_BL_LEN */
    	uBlkLen = 1 << (sdCardReg.CSD[10] & 0x0F);

        /* Memory Capacity calculation:
         * capacity = BLOCKNR * BLOCK_LEN
         * MULT = 2^(C_MULT + 2)
         * BLOCKNR = (C_SIZE + 1) * MULT
         * BLOCKLEN = 2^READ_BL_LEN
         */
		dwTotalNumOfSectors = (((uCsize + 1) << (uCmult + 2)) * uBlkLen)/SDHC_SECTOR_SIZE;
		dwCapacity = dwTotalNumOfSectors/2;
	}

	OALMSG(OAL_INFO, (_T("Card Capacity %d (Kbytes)\r\n"), dwCapacity));
	
	return (dwTotalNumOfSectors);
}

//------------------------------------------------------------------------------
//
// Function: SDMMC_set_blocklen
//
//	This function will will set the maximum read/write Block Length
//
// Parameters:
//		None
//
// Returns:
//		SDHC_STATUS_PASS for success/SDHC_STATUS_FAILURE for failure
//
//------------------------------------------------------------------------------ 
UINT32 SDMMC_set_blocklen (UINT32 BlockLen)
{
    SD_BUS_REQUEST sdRequest;
	UINT32 status = SDHC_STATUS_FAILURE;

	OALMSG(OAL_FUNC, (_T("+ SDMMC_set_blocklen\r\n")));

	if (BlockLen < SDHC_BLK_LEN)
		BlockLen = SDHC_BLK_LEN;
	
	/* Configure CMD16 to set block length as 512 bytes.*/
    SDCard_command_config(&sdRequest, SD_CMD_SET_BLOCKLEN, BlockLen, SD_COMMAND, ResponseR1);

    if(SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE)
    {
        status = SDHC_STATUS_PASS;
    }
	
	OALMSG(OAL_FUNC, (_T("- SDMMC_set_blocklen\r\n")));

    return status;		
}

//------------------------------------------------------------------------------
//
// Function: SDMMC_send_rca
//
//	This function will send/set RCA for SD/MMC card..
//
// Parameters:
//		isMMC[in] - TRUE for MMC else FALSE for SD card
//
// Returns:
//		SDHC_STATUS_PASS for success/SDHC_STATUS_FAILURE for failure
//
//------------------------------------------------------------------------------ 
UINT32 SDMMC_send_rca (BOOL isMMC)
{
    SD_BUS_REQUEST sdRequest;
    SD_CARD_STATUS CardStatus=0;
    UINT32 rca_request=SDHC_STATUS_FAILURE;
    PSD_COMMAND_RESPONSE response = &sdRequest.CommandResponse;
    UINT32 card_address = 0;

	OALMSG(OAL_FUNC, (_T("+ SDMMC_send_rca\r\n")));
	if (isMMC)
	{
		Card_rca = 0x1;
		card_address = (Card_rca << RCA_SHIFT);	
	}
	
    /* Configure CMD3 for MMC card */
    /* 32bit card address is expected as Argument */
    SDCard_command_config(&sdRequest, SD_CMD_MMC_SET_RCA, card_address, SD_COMMAND, ResponseR1);
	                                      
    /* Assigns relative address to the card
    */
    if(SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE)
    {
        /* Read Command response */
		response->ResponseType = ResponseR1;
        SDHCReadResponse (response);
		if (!isMMC)
		{
			// RCA is in bytes 3,4
			Card_rca = (SD_CARD_RCA)response->ResponseBuffer[3];
			Card_rca |= ((SD_CARD_RCA)response->ResponseBuffer[4]) << 8;
		}
		memcpy((&CardStatus), &response->ResponseBuffer[1], sizeof(SD_CARD_STATUS));
		CardStatus = SD_STATUS_CURRENT_STATE(CardStatus);
		
		if(CardStatus == SD_STATUS_CURRENT_STATE_IDENT)
			rca_request = SDHC_STATUS_PASS;
    }
		
	OALMSG(OAL_FUNC, (_T("- SDMMC_send_rca %d\r\n"), CardStatus));

    return rca_request;
}

//------------------------------------------------------------------------------
//
// Function: SDMMC_R1b_busy_wait
//
//	This function will wait during a command with R1b response type till the
//	SD state changes back to normal
//
// Parameters:
//		isMMC[in] - TRUE for MMC else FALSE for SD card
//
// Returns:
//		SDHC_STATUS_PASS for success/SDHC_STATUS_FAILURE for failure
//
//------------------------------------------------------------------------------ 
UINT32 SDMMC_R1b_busy_wait (PSD_COMMAND_RESPONSE pResp)
{
    SD_BUS_REQUEST sdRequest;
    SD_CARD_STATUS CardStatus=0;
    UINT32 wait_request=SDHC_STATUS_FAILURE;
    UINT32 card_address = (Card_rca << RCA_SHIFT);	
    SD_CARD_STATUS  CardState = SD_STATUS_CURRENT_STATE_TRAN;
	UINT32 StartTime = OEMEthGetSecs();

	OALMSG(OAL_FUNC, (_T("+ SDMMC_R1b_busy_wait\r\n")));

	do
	{
		/* Configure CMD13 to read status of the card becuase CMD6 has R1b response */
		SDCard_command_config(&sdRequest, SD_CMD_SEND_STATUS, card_address, SD_COMMAND ,ResponseR1);
		
		if(!SDHCSendCmdWaitResp(&sdRequest))
		{
			/* Read Command response */
			pResp->ResponseType = ResponseR1;
			SDHCReadResponse (pResp);
			memcpy((&CardStatus), &pResp->ResponseBuffer[1], sizeof(SD_CARD_STATUS));
		}
	} while ((SD_STATUS_CURRENT_STATE (CardStatus) != CardState) && 
		      (OEMEthGetSecs() - StartTime < SDHC_DELAY_TIMEOUT));

	if (SD_STATUS_CURRENT_STATE (CardStatus) == CardState)
		wait_request = SDHC_STATUS_PASS;
	else
		OALMSG(OAL_INFO, (_T("R1b_busy_wait timed out State - %d\r\n"), SD_STATUS_CURRENT_STATE (CardStatus)));

	OALMSG(OAL_FUNC, (_T("- SDMMC_R1b_busy_wait\r\n")));
		
    return wait_request;
}

//------------------------------------------------------------------------------
//
// Function: SDCard_command_config
//
//	This function will configure the command paramteres for card.
//
// Parameters:
//		pReq[out] - structure required to configure and issue commands
//		CommandCode[in] - Command code to issue
//		argument[in] - argument to be passed for a particular command
//		transfer[in] - Transfer type of the command
//		respType[in] - Response type of the command
//
// Returns:
//		None
//
//------------------------------------------------------------------------------ 
void SDCard_command_config (PSD_BUS_REQUEST pReq,UCHAR CommandCode, DWORD argument,
                            SD_TRANSFER_CLASS transfer,SD_RESPONSE_TYPE respType)
{
	
    /* Configure Command index */	
    pReq->CommandCode = CommandCode;
	
    /* Configure Command Argument */
    pReq->CommandArgument = argument;
	
    /* Configure Data transfer type */
    pReq->TransferClass = transfer;
	
    /* Configure Response Format */
    pReq->CommandResponse.ResponseType = respType;
}


//-----------------------------------------------------------------------------
//
//  Function: SDMMC_GetInfo
//
//  This function determines the size characteristics for the SD memory 
//
//  Parameters:
//      pFlashInfo 
//          [out] A pointer to a structure that contains the size 
//          characteristics for the flash memory device.
//
//  Returns:  
//      Returns TRUE on success. Returns FALSE on failure.
//
//-----------------------------------------------------------------------------
BOOL SDMMC_GetInfo(PFlashInfo pFlashInfo)
{
    if (!pFlashInfo)
        return(FALSE);

    pFlashInfo->flashType           = (FLASH_TYPE)SDMMC;
    pFlashInfo->wDataBytesPerSector = SDHC_SECTOR_SIZE;
    pFlashInfo->dwNumBlocks         = SDHC_BLOCK_CNT;
    pFlashInfo->wSectorsPerBlock    = SDHC_SECTOR_CNT;
    pFlashInfo->dwBytesPerBlock     = (pFlashInfo->wSectorsPerBlock * pFlashInfo->wDataBytesPerSector);

    return(TRUE);
}


//-----------------------------------------------------------------------------
//
//  Function: SDMMC_GetBlockStatus
//
//  This function returns the status of a block.
//
//  Parameters:
//      blockID 
//          [in] The block number used to check status.
//
//  Returns:  
//      Flags to describe the status of the block.
//
//-----------------------------------------------------------------------------
DWORD SDMMC_GetBlockStatus(BLOCK_ID blockID)
{
    // Remove-W4: Warning C4100 workaround
    UNREFERENCED_PARAMETER(blockID);

    return(BLOCK_STATUS_UNKNOWN);
}


//-----------------------------------------------------------------------------
//
//  Function: SDMMC_SetBlockStatus
//
//  This function sets the status of a block.
//
//  Parameters:
//      blockID 
//          [in] The block number used to set status. 
//
//      dwStatus
//          [in] The status value to set.
//
//  Returns:  
//      Returns TRUE on success. Returns FALSE on failure.
//
//-----------------------------------------------------------------------------
BOOL SDMMC_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)
{
    // Remove-W4: Warning C4100 workaround
    UNREFERENCED_PARAMETER(blockID);
    UNREFERENCED_PARAMETER(dwStatus);

    return(TRUE);
}

//-----------------------------------------------------------------------------
//
// Function: SDMMC_EraseBlock
//
// Function Erases the specified flash block. 
//
// Parameters:
//      blockID 
//          [in] block number to erase.
//
// Returns:  
//      TRUE/FALSE for success
//
//-----------------------------------------------------------------------------
BOOL SDMMC_EraseBlock(BLOCK_ID blockID, UINT32 num_blocks)
{
	SD_BUS_REQUEST sdRequest;
    PSD_COMMAND_RESPONSE response = &sdRequest.CommandResponse;
    BOOL erase_request = FALSE;	
	DWORD startErase = blockID, endErase = blockID + num_blocks;
	UCHAR startEraseBlockCmd = SD_CMD_ERASE_WR_BLK_START, 
		endEraseBlockCmd = SD_CMD_ERASE_WR_BLK_END;
	
	OALMSG(OAL_FUNC, (_T("- SDMMC_EraseBlock\r\n")));

	if (bHighDensityCard == FALSE)
	{
		startErase = blockID * SDHC_BLK_LEN;
		endErase  = (blockID + num_blocks) * SDHC_BLK_LEN;
	}

	if ((SDController.IsMMC == TRUE) && (mmcSpecVersion >= MMC_SPEC_VER_4_0))
	{
		startEraseBlockCmd = MMC_CMD_ERASE_WR_BLK_START;
		endEraseBlockCmd = MMC_CMD_ERASE_WR_BLK_END;
	}

    /* Configure CMD32 to select the first block to erase */
    SDCard_command_config(&sdRequest, startEraseBlockCmd, startErase,
							SD_COMMAND, ResponseR1);

    if(SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE)
    {
        /* Configure CMD33 to select the ending block to erase */
		SDCard_command_config(&sdRequest, endEraseBlockCmd, endErase,
							SD_COMMAND, ResponseR1);

		if(SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE)
		{
			/* Configure CMD38 to start to erase */
			SDCard_command_config(&sdRequest, SD_CMD_ERASE, 0, SD_COMMAND, ResponseR1b);
			if(SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE)
			{
				if (!SDMMC_R1b_busy_wait (response))
					erase_request=TRUE;
			}
		}
    }
	
	OALMSG(OAL_FUNC, (_T("- SDMMC_EraseBlock %x\r\n"), erase_request));

    return erase_request;
}

//-----------------------------------------------------------------------------
//
// Function: SDMMC_ReadSector
//
// Function Reads the requested sector data and metadata from the flash media. 
//
// Parameters:
//      startSectorAddr 
//          [in] starting sector address.
//
//      pSectorBuff 
//          [in] Ptr to  buffer that contains sector data read from flash.
//				 Set to NULL if  data is not needed.
//
//      pSectorInfoBuff 
//          [in] Buffer for an array of sector information structures.
//				 One sector	information entry for every sector to be read. 
//				 Set to NULL if not needed.
//
//      dwNumSectors 
//          [in] Number of sectors to read.
//
// Returns:  
//      TRUE/FALSE for success
//
//-----------------------------------------------------------------------------
BOOL SDMMC_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff,
					  PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
    SD_BUS_REQUEST sdRequest;
	PSD_COMMAND_RESPONSE response = &sdRequest.CommandResponse;
	UINT32 status = SDHC_STATUS_FAILURE;
    BOOL read_status = FALSE;
DWORD dwReadArg = startSectorAddr;
	UCHAR cmdCode = SD_CMD_READ_SINGLE_BLOCK;
    // Remove-W4: Warning C4100 workaround
    UNREFERENCED_PARAMETER(pSectorInfoBuff);

	OALMSG(OAL_FUNC, (_T("+ SDMMC_ReadSector\r\n")));

	/* Configure interface block and number of blocks */
	SetBlockLen (SDHC_BLK_LEN, dwNumSectors);
    
	if (bHighDensityCard == FALSE)
	{
		dwReadArg = startSectorAddr * SDHC_BLK_LEN;
	}
		
	if (dwNumSectors > 1)
		cmdCode = SD_CMD_READ_MULTIPLE_BLOCK;

	/* Comfigure command for single/multiple block read */	
	SDCard_command_config(&sdRequest, cmdCode, dwReadArg, SD_READ, ResponseR1);	
     	
    if(!SDHCSendCmdWaitResp(&sdRequest))
    {
        /* Call interface Data read function */
        status = SDHCDataRead((UINT32 *)pSectorBuff,dwNumSectors * SDHC_BLK_LEN);
		if ((status == SDHC_STATUS_PASS) && (dwNumSectors != 1))
		{
			/* Issue Stop Transmission command for multiple block read */
			SDCard_command_config(&sdRequest, SD_CMD_STOP_TRANSMISSION, 0, SD_COMMAND, ResponseR1b);
			if(SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE)
			{
				status = SDMMC_R1b_busy_wait (response);
			}
		}
		if (status == SDHC_STATUS_PASS)
			read_status = TRUE;
    }

	OALMSG(OAL_FUNC, (_T("- SDMMC_ReadSector %x\r\n"), read_status));

    return read_status;
}

//-----------------------------------------------------------------------------
//
// Function: SDMMC_WriteSector
//
// Function Writes the requested sector data and metadata to the flash media. 
//
// Parameters:
//      startSectorAddr 
//          [in] starting physical sector address.
//
//      pSectorBuff 
//          [in] Ptr to  buffer that contains sector data to write.
//				 Set to NULL if  data is not needed.
//
//      pSectorInfoBuff 
//          [in] Buffer for an array of sector information structures.
//				 One sector	information entry for every sector to be written.
//				 Set to NULL if not needed.
//
//      dwNumSectors 
//          [in] Number of sectors to write.
//
// Returns:  
//      TRUE/FALSE for success
//
//-----------------------------------------------------------------------------
BOOL SDMMC_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff,
					   PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
	SD_BUS_REQUEST sdRequest;
	PSD_COMMAND_RESPONSE response = &sdRequest.CommandResponse;
	UINT32 status = SDHC_STATUS_FAILURE;
    BOOL write_status = FALSE;
     DWORD dwWriteArg = startSectorAddr;
	UCHAR cmdCode = SD_CMD_WRITE_BLOCK;

    // Remove-W4: Warning C4100 workaround
    UNREFERENCED_PARAMETER(pSectorInfoBuff);

	OALMSG(OAL_FUNC, (_T("+ SDMMC_WriteSector\r\n")));

	/* Configure interface block and number of blocks */
	SetBlockLen (SDHC_BLK_LEN, dwNumSectors);
    
	if (bHighDensityCard == FALSE)
	{
		dwWriteArg = startSectorAddr * SDHC_BLK_LEN;
	}
		
	if (dwNumSectors > 1)
		cmdCode = SD_CMD_WRITE_MULTIPLE_BLOCK;

	/* Comfigure command for single/multiple block write */	
	SDCard_command_config(&sdRequest, cmdCode, dwWriteArg, SD_WRITE, ResponseR1);	
     	
    if(!SDHCSendCmdWaitResp(&sdRequest))
    {
        /* Call interface Write read function */
        status = SDHCDataWrite((UINT32 *)pSectorBuff,dwNumSectors * SDHC_BLK_LEN);
		if ((status == SDHC_STATUS_PASS) && (dwNumSectors != 1))
		{
			/* Issue Stop Transmission command for multiple block read */
			SDCard_command_config(&sdRequest, SD_CMD_STOP_TRANSMISSION, 0, SD_COMMAND, ResponseR1b);
			if(SDHCSendCmdWaitResp(&sdRequest) != SDHC_STATUS_FAILURE)
			{
				status = SDMMC_R1b_busy_wait (response);
			}
		}
		if (status == SDHC_STATUS_PASS)
			write_status = TRUE;
    }

	OALMSG(OAL_FUNC, (_T("- SDMMC_WriteSector %x\r\n"), write_status));

    return write_status;
}
