ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.c b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.c
new file mode 100644
index 0000000..236ac95
--- /dev/null
+++ b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.c
@@ -0,0 +1,2004 @@
+/******************************************************************************
+ *
+ *  (C)Copyright 2005 - 2011 Marvell. All Rights Reserved.
+ *  
+ *  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
+ *  The copyright notice above does not evidence any actual or intended 
+ *  publication of such source code.
+ *  This Module contains Proprietary Information of Marvell and should be
+ *  treated as Confidential.
+ *  The information in this file is provided for the exclusive use of the 
+ *  licensees of Marvell.
+ *  Such users have the right to use, modify, and incorporate this code into 
+ *  products for purposes authorized by the license agreement provided they 
+ *  include this notice and the associated copyright notice with any such
+ *  product. 
+ *  The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include "predefines.h"
+#include "sdmmc_api.h"
+#include "sdhc2.h"
+#include "Errors.h"
+#include "PlatformConfig.h"
+#include "xllp_dfc_defs.h"
+#include "loadoffsets.h"
+
+static MM4_SDMMC_CONTEXT_T MM4_Context;	// Only need one
+extern ADMA_DESCRIPTOR *admaDesc;
+
+UINT_T MM4_MMCDecodeCID(void)
+{
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+	UINT_T ManufactureID; // Manufactor ID
+	UINT_T OID; // OEM/Application ID
+	UINT_T SerialNumber;
+	UINT_T ProductName; // last 32bits
+	UINT_T ProductRevision;
+
+	ManufactureID	= UNSTUFF_BITS(pSDMMCP->CardReg.CID.CID_VALUE, 120, 8);
+	OID			 	= UNSTUFF_BITS(pSDMMCP->CardReg.CID.CID_VALUE, 104, 8);
+	ProductName		= UNSTUFF_BITS(pSDMMCP->CardReg.CID.CID_VALUE, 56, 32);
+	SerialNumber	= UNSTUFF_BITS(pSDMMCP->CardReg.CID.CID_VALUE, 16, 32);
+	ProductRevision	= UNSTUFF_BITS(pSDMMCP->CardReg.CID.CID_VALUE, 48, 8);
+
+	switch (ManufactureID)
+	{
+		case 0x45:
+		case 0x02:
+			obm_printf("Manufacturer: SanDisK\n\r");
+			break;
+
+		case 0xfe:
+		case 0x13:
+			obm_printf("Manufacturer: Micron\n\r");
+			break;
+
+		case 0x70:
+			obm_printf("Manufacturer: Kingston\n\r");
+			break;
+
+		case 0x11:
+			obm_printf("Manufacturer: Toshiba\n\r");
+			break;
+
+		case 0x90:
+			obm_printf("Manufacturer: Hynix\n\r");
+			break;
+
+		case 0x15:
+			obm_printf("Manufacturer: Samsung\n\r");
+			break;
+
+		default:
+			obm_printf("New Manufacturer: 0x%08x\n\r", ManufactureID);
+			break;
+	}
+
+}
+
+UINT_T MM4_MMCDecodeEXTCSD(void)
+{
+	UINT8_T pBuffer[512];
+	UINT_T ret = NoError;
+	UINT_T sectors;
+	UINT64 capacity;
+	UINT8_T erase_group_define, card_type;
+	UINT_T boot_partition_size;
+	UINT8_T spec_version; // system specification version number
+	
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+	ret = MM4_MMCReadEXTCSD((UINT_T *)pBuffer);
+	if (ret != NoError)
+		return ret;
+
+	if (pBuffer[212] || pBuffer[213] || pBuffer[214] || pBuffer[215]) // SEC_COUNT
+	{
+		sectors = pBuffer[212] | (pBuffer[213] << 8) | (pBuffer[214] << 16) | (pBuffer[215] << 24);
+		capacity = sectors;
+		capacity *= 512; // capacity equals to sectors multiply by 512B
+	#if USE_SERIAL_DEBUG
+		obm_printf("sectors: 0x%08x\n\r", sectors);
+		obm_printf("capacity MB: %d\n\r", sectors/2/1024);
+	#endif
+
+		if (pSDMMCP->AccessMode == SECTOR_ACCESS)
+		{
+			pSDMMCP->CardCapacity = sectors;
+		}
+		else
+		{
+			pSDMMCP->CardCapacity = capacity;
+		}
+	}
+
+	erase_group_define = pBuffer[175]; // ERASE_GROUP_DEF
+	if (erase_group_define)
+	{
+		pSDMMCP->EraseSize = pBuffer[224] * 512 * 1024; // overwrite it, and erase unit size = 512KB * HC_ERASE_GRP_SIZE
+	}
+	
+	boot_partition_size = pBuffer[226] * 128 *1024; // BOOT_SIZE_MULT * 128KB
+	if (pSDMMCP->AccessMode == SECTOR_ACCESS)
+	{
+		pSDMMCP->BootPartitionSize = boot_partition_size / HARD512BLOCKLENGTH;
+	}
+	else
+	{
+		pSDMMCP->BootPartitionSize = boot_partition_size;
+	}
+
+	#if USE_SERIAL_DEBUG
+	obm_printf("Boot Partition Size: %dMB\n\r", boot_partition_size/1024/1024);
+	obm_printf("pSDMMCP->BootPartitionSize: 0x%08x\n\r", pSDMMCP->BootPartitionSize);
+	#endif
+	
+	card_type = pBuffer[196] & 0xf; // CARD_TYPE
+	pSDMMCP->DeviceType = card_type;
+
+	obm_printf("pSDMMCP->DeviceType: 0x%x\n\r", pSDMMCP->DeviceType);
+
+	spec_version = pBuffer[192];
+	switch (spec_version)
+	{
+		case 0:
+			obm_printf("MMC Version 4.0\n\r");
+			break;
+		case 1:
+			obm_printf("MMC Version 4.1\n\r");
+			break;
+		case 2:
+			obm_printf("MMC Version 4.2\n\r");
+			break;
+		case 3:
+			obm_printf("MMC Version 4.3\n\r");
+			break;
+		case 5:
+			obm_printf("MMC Version 4.41\n\r");
+			break;
+		case 6:
+			obm_printf("MMC Version 4.5\n\r");
+			break;
+
+		case 4:
+		default:
+			obm_printf("Reserved Version: %d\n\r", spec_version);
+			break;
+	}
+
+	return ret;
+}
+
+/**********************************************************
+*   MM4_CardInit
+*      Initializes the inserted card
+*   Input:
+*	   none
+*   Output:
+*      none
+*   Returns:
+*      WTP recoginized Success/Fail return code
+***********************************************************/
+UINT_T MM4_CardInit(UINT_T BaseAddress, UINT_T InterruptMask)
+{
+	UINT_T argument,Retval;
+	UINT_T controllervoltage;
+	P_MM4_SDMMC_CONTEXT_T pContext;
+
+	// Initialize Flash Properties
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+	// Assign pContext and clock values
+	MM4_PrepareMMCContext (pSDMMCP, BaseAddress);
+	pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+	// enable ints moved out of ConfigureMMC to here
+	//      because pending interrupts (left over from bootrom
+	//      mmc activity) were kicking off before the context
+	//		had enough info for the isr to service the request.
+	// now pads have been set up, and the context has
+	// enough information to service interrupts (specifically,
+	// it has the mm4 base regs address). ok to enable ints.
+	EnablePeripheralIRQInterrupt(InterruptMask);
+
+	// Issue a full reset.
+	MMC4FullSWReset(pContext);
+
+	// Enable and start clocks
+	MMC4SetBusRate(pContext, MM4CLOCK200KHZRATE);
+
+	// Set Read Response Timeout
+	MMC4SetDataTimeout(pContext, CLOCK_27_MULT);
+
+	// Unmask and Enable interrupts
+	MMC4EnableDisableIntSources(pContext, ENABLE_INTS);
+
+	//MMC4Gen74Clocks(pContext);
+
+	Retval = MM4_IDCard(pSDMMCP, &controllervoltage);
+	if (Retval != NoError)
+		//return Retval;
+		return SDMMCNotFound;
+
+	// Set up State
+	pSDMMCP->State = INITIALIZE;
+
+	// SD and MMC joint functionality again
+	// At this point we should have our OCR contents. See if they match the voltage range we choose for the controller
+	Retval = MM4_CheckVoltageCompatibility(pSDMMCP, controllervoltage);
+	if (Retval != NoError)
+		return SDMMCInitializationError; // We couldn't find any cards
+
+	//send CMD2 to get the CID numbers
+	argument = NO_ARGUMENT;
+	MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD2, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R2 | MM4_136_RES);
+	Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R2, 0x10);
+
+	if (Retval != NoError)
+		return SDMMCInitializationError;
+
+	#if USE_SERIAL_DEBUG
+	MM4_MMCDecodeCID();
+	#endif
+
+	// Next its CMD3 to assign an RCA to the cards
+	if (pSDMMCP->SD == XLLP_SD)
+	{
+		argument = NO_ARGUMENT;
+	 	MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD3, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R6 | MM4_48_RES);
+	 	Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R6, 0x10);
+	}
+	else
+	{
+		pSDMMCP->CardReg.RCA = (pSDMMCP->CardReg.CID.SerialNum) << 16;
+		argument = pSDMMCP->CardReg.RCA;
+	 	MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD3, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+	 	Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x10);
+	}
+	if (Retval != NoError)
+		return SDMMCInitializationError;
+
+	//send CMD13 to check the status of the card
+	Retval = MM4_CheckCardStatus(pSDMMCP, 0x700, R1_LOCKEDCARDMASK);		// Make sure card is stdby mode
+	if (Retval != NoError)
+		return SDMMCInitializationError;
+
+	// now we are beyond the point where some cards have subtle non-compliance issues with the spec.
+	// for example, some cards leave the error bits from unrecognized commands (like 55 & 41) set
+	// until this point - which is correct (since CMD3 was the first R1 type command). 
+	// other cards clear them earlier, which is incorrect - but presents fewer initialization failures. 
+	// at this point it is safe, and necessary, to begin rigorously examining all error status bits.
+	pSDMMCP->StrictErrorCheck = 1;
+
+	// Send CMD 9 to retrieve the CSD
+	argument = pSDMMCP->CardReg.RCA;
+ 	MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD9, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R2 | MM4_136_RES);
+ 	Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R2, 0x100);
+
+	// Save off some information from the CSD
+	// There is no page size for SDMMC. However save some information so slot type functionality will work
+	pSDMMCP->pFlashP->BlockSize = pSDMMCP->pFlashP->PageSize = pSDMMCP->ReadBlockSize;	 
+
+	//send CMD7 to get card into transfer state
+	argument = pSDMMCP->CardReg.RCA;
+ 	MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD7, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);	// fixme: from standby to transfer state should be an r1, not r1b
+ 	Retval |= MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+
+	//send CMD13 to check the status of the card
+	Retval |= MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK);		// Make sure card is transfer mode
+	if (Retval != NoError)
+		return SDMMCInitializationError;
+
+	// CMD 16 Set Block Length
+	argument = pSDMMCP->ReadBlockSize;
+ 	MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD16, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+ 	Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+
+	// Set the block length for the controller
+	pContext->pMMC4Reg->mm4_blk_cntl = argument;
+
+	// Check if High Speed is enabled in the fuses
+	if(MMCHighSpeedTimingEnabled())
+		Retval = MM4HighSpeedTiming();
+	else
+		MMC4SetBusRate(pContext, MM4CLOCK12_5MHZRATE);
+
+	//send CMD13 to check the status of the card
+	Retval = MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK);		// Make sure card is transfer mode
+	if (Retval != NoError)
+		return SDMMCInitializationError;
+
+	Retval = MM4_MMCDecodeEXTCSD(); // MMC decodes extension CSD register
+	if (Retval != NoError)
+		return SDMMCInitializationError;
+
+	if (pSDMMCP->DeviceType & EXT_CSD_CARD_TYPE_DDR_52)
+	{
+		obm_printf("DDR mode\n\r");
+		
+		// eMMC DDR mode, set bit31, clear bit30
+		//MMC4SetTXIntCLKSet(pContext, 0, 1);
+		MMC4SetTXConfig(pContext);
+		MMC4SetRXConfig(pContext);
+		
+		MMC4SelectUHSMode(pContext, SDH_BUS_SPEED_DDR_CLK_50M); // host to DDR mode
+
+		Retval = MM4SetBusWidth(DDR_8); //set the bus width to 8, eMMC to DDR mode
+		if (Retval != NoError)
+			return SDMMCInitializationError;
+	}
+	else
+	{
+		obm_printf("SDR mode\n\r");
+		
+		//#if HELN
+		// Helan eMMC DDR mode, set bit30, clear bit31
+		MMC4SetTXIntCLKSet(pContext, 1, 0);
+		//#endif
+		
+		Retval = MM4SetBusWidth(SDR_8); //set the bus width to 8, eMMC to SDR mode
+		if (Retval != NoError)
+			return SDMMCInitializationError;
+	}
+
+	//send CMD13 to check the status of the card
+	Retval = MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK);		// Make sure card is transfer mode
+	if (Retval != NoError)
+		return SDMMCInitializationError;
+
+	// Enable SDMA/ADMA Mode based on support
+#if MMC_SDMA_MODE
+	obm_printf("SDMA mode\n\r");
+	pSDMMCP->SDMMC_DMA_Mode = SDMA;
+#elif MMC_ADMA_MODE
+	obm_printf("ADMA2 mode\n\r");
+	pSDMMCP->SDMMC_DMA_Mode = ADMA2;
+#else
+	obm_printf("NODMA mode\n\r");
+	pSDMMCP->SDMMC_DMA_Mode = NODMA;
+#endif
+
+	// Set up State, Ready for Data transfers
+	pSDMMCP->State = READY;
+
+    return NoError;
+}
+
+/**********************************************************
+*   MM4_IDCard
+*      Identifies which type of card was inserted
+*   Input:
+*	   none
+*   Output:
+*      none
+*   Returns:
+*      WTP recoginized Success/Fail return code
+***********************************************************/
+UINT MM4_IDCard(P_SDMMC_Properties_T pSDMMCP, UINT_T *pControllerVoltage)
+{
+	// Local Variables
+	P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;	// Assign our context value
+	P_MM4_CTRL_REG pP_MM4_CTRL_REG;
+	UINT_T AnyError = 0;
+	UINT_T argument = 0;
+	UINT_T Retval = 0;
+	UINT_T HighCapacity = 0;
+	UINT_T attempts = 0;
+	UINT_T Ncr = 0x100;			// command response timeout.
+
+	// Assign some context
+	pP_MM4_CTRL_REG = (P_MM4_CTRL_REG)&pContext->pMMC4Reg->mm4_mmc_ctrl_reg;
+
+	// Enable power
+	*pControllerVoltage = MM4_SetControllerVoltage(pContext);
+	pContext->pMMC4Reg->mm4_blk_cntl = 0;
+
+	// Send CMD0 (GO_IDLE_STATE) to get card into idle state
+	MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD0, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_NONE | MM4_NO_RES);
+	AnyError += MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_NONE, Ncr);
+
+	// Check for High Capacity Cards First
+	do
+	{
+		// Start with SD
+		pP_MM4_CTRL_REG->mmc_card = 0;
+
+		// Try High Voltage range first:
+		// Note: this is a valid command for SD cards in the idle state.
+		//       for mmc cards in the idle state, this is not valid, so no reponse is generated.
+		//       however, even some SD cards may miss this command, so that's why it is
+		//       sent out twice. See SD spec, step 4 of figure 9 in card init and id section.
+		argument = (SDVHS_2_7_TO_3_6 << SDVHSARGSHIFT) | SDVHSCHECKPATTERN;		// 2.7-3.6V Range
+		MM4_SendSetupCommand(pSDMMCP, XLLP_SD_CMD8, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R7 | MM4_48_RES);
+
+		// get the response (if any) to XLLP_SD_CMD8.
+		MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R7, Ncr);
+
+		// Check for High Capacity Cards
+		HighCapacity = (pSDMMCP->SD_VHS == argument);
+	} while (!HighCapacity && ++attempts < 2);
+
+	pSDMMCP->SD = XLLP_SD;
+
+	// First time, pass NULL argument to get back values card is compatible with
+	// Send appropriate CMD Sequence to Identify the type of card inserted
+	argument = 0;
+	attempts = 0;
+	pSDMMCP->CardReg.OCR = 0;			// Make sure to clear out OCR.
+	
+	do
+	{
+		switch (pSDMMCP->SD)
+		{
+		 case XLLP_SD:		// Assume SD
+			MM4_SendSetupCommand(pSDMMCP, XLLP_SD_CMD55, MM4_CMD_TYPE_NORMAL, 0, MM4_RT_R1 | MM4_48_RES);
+			MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, Ncr);
+
+
+			MM4_SendSetupCommand(pSDMMCP, XLLP_SD_ACMD41, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R3 | MM4_48_RES);
+			MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R3, Ncr);
+
+			if (pSDMMCP->CardReg.OCR == 0)
+			{
+				pSDMMCP->SD = XLLP_MMC;
+			}
+			else
+			{
+				Retval = NoError;
+			}
+			break;
+		 case XLLP_MMC:		// Assume MMC
+			pP_MM4_CTRL_REG->mmc_card = 1;
+			MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD1, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R3 | MM4_48_RES);
+			AnyError += MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R3, Ncr);
+
+			if (pSDMMCP->CardReg.OCR == 0)
+			{
+				Retval = NotFoundError;
+			}
+			else
+			{
+				Retval = NoError;
+			}
+			break;
+		}
+
+		argument = pSDMMCP->CardReg.OCR | 0x40000000;
+		attempts++;
+		Delay(100);
+	} while (((pSDMMCP->CardReg.OCR & 0x80000000) != 0x80000000) && (AnyError == 0) && (attempts < 10000));
+	if ((pSDMMCP->CardReg.OCR & 0x80000000) != 0x80000000)
+		return NotFoundError;
+	
+	// Assign Access Mode.
+	if (pSDMMCP->CardReg.OCR & OCR_ACCESS_MODE_MASK)
+		pSDMMCP->AccessMode = SECTOR_ACCESS;
+	else
+		pSDMMCP->AccessMode = BYTE_ACCESS;
+
+	return Retval;
+}
+
+/***************************************************************
+*   MM4SetBusWidth()
+* 	Sets the Bus width highest bus width supported.
+*   Input: UINT_T Width 
+*   Output:
+*   Returns: NoError, ReadError or NotSupportedError
+*      
+*****************************************************************/
+UINT_T MM4SetBusWidth(UINT8_T value)
+{
+	UINT8_T SDBusWidth = 0;
+	MMC_CMD6_OVERLAY Cmd6;
+	P_MM4_SDMMC_CONTEXT_T pContext;
+	P_MM4_CNTL1 pMM4_CNTL1;
+	UINT_T Retval = NoError;
+	
+	// Initialize Flash Properties
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ 	// Assign our context value
+ 	pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+	pMM4_CNTL1 = (P_MM4_CNTL1) &pContext->pMMC4Reg->mm4_cntl1;
+
+	// Check supported configurations first
+	if (pSDMMCP->SD == XLLP_SD)
+	{
+		// Assume 1 bit Mode.
+		SDBusWidth = SCRSD1BITMODE;
+	}
+	else
+	{
+		// Issue CMD 6 to set BUS WIDTH bits in EXT_CSD register byte 183
+		Cmd6.MMC_CMD6_Layout.Access 	= EXT_CSD_ACCESS_WRITE_BYTE;			//Write Byte
+		Cmd6.MMC_CMD6_Layout.CmdSet 	= 0;									// Don't Care
+		Cmd6.MMC_CMD6_Layout.Index 		= BUS_WIDTH_MMC_EXT_CSD_OFFSET; 			// Choose Bus Width
+		Cmd6.MMC_CMD6_Layout.Reserved0 	= 0;
+		Cmd6.MMC_CMD6_Layout.Reserved1 	= 0;
+		Cmd6.MMC_CMD6_Layout.Value 		= value;	// Choose 8 bit mode.
+
+ 		MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD6, MM4_CMD_TYPE_NORMAL, Cmd6.MMC_CMD6_Bits, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+
+		// Wait for the Read to Complete
+		while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));		// TBD add timeout Let the ISR run, we'll either get a fault or finish
+
+		Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, MMC_RESPONSE_R1B_TIMEOUT);
+		if (Retval != NoError)
+			return Retval;
+	}
+
+	//send CMD13 to check the status of the card
+	Retval |= MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK);		// Make sure card is transfer mode
+	if (Retval != NoError)
+	{
+	 	pSDMMCP->State = READY;
+		return Retval;
+	}
+
+	// Now change the controller to boost bus width
+	//if (pSDMMCP->SD == XLLP_SD)
+	//{
+	//  	if (SDBusWidth == SCRSD4BITMODE)
+	//	{
+	//	  	pMM4_CNTL1->datawidth  = 1;		// Move to 4-bit mode
+	//		return NoError;
+	//	}
+	//}
+	//else
+	if (pSDMMCP->SD == XLLP_MMC)
+		pMM4_CNTL1->ex_data_width = 1;		// Move to 8-bit mode.
+
+	return NoError;
+}
+
+/***************************************************************
+*   MM4HighSpeedTiming()
+* 	Sets the Bus speed to high speed timing
+*   Input:
+*   Output:
+*   Returns: NoError, ReadError or NotSupportedError
+*      
+*****************************************************************/
+UINT_T MM4HighSpeedTiming(void)
+{
+	MMC_CMD6_OVERLAY Cmd6;
+	P_MM4_SDMMC_CONTEXT_T pContext;
+	P_MM4_CNTL1 pMM4_CNTL1;
+	UINT_T Retval = NoError;
+	
+	// Initialize Flash Properties
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ 	// Assign our context value
+ 	pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+	pMM4_CNTL1 = (P_MM4_CNTL1) &pContext->pMMC4Reg->mm4_cntl1;
+
+	// Check supported configurations first
+	if (pSDMMCP->SD == XLLP_SD)
+	{
+		MMC4SetBusRate(pContext, MM4CLOCK12_5MHZRATE);
+		return NoError;
+	}
+	else
+	{
+		// Issue CMD 6 to set BUS WIDTH bits in EXT_CSD register byte 183
+		Cmd6.MMC_CMD6_Layout.Access 	= EXT_CSD_ACCESS_WRITE_BYTE;			//Write Byte
+		Cmd6.MMC_CMD6_Layout.CmdSet 	= 0;									// Don't Care
+		Cmd6.MMC_CMD6_Layout.Index 		= HS_TIMING_MMC_EXT_CSD_OFFSET; 			// Choose Bus Width
+		Cmd6.MMC_CMD6_Layout.Reserved0 	= 0;
+		Cmd6.MMC_CMD6_Layout.Reserved1 	= 0;
+		Cmd6.MMC_CMD6_Layout.Value 		= (UINT8_T) 1;	// Choose High Speed Timing.
+    	 
+ 		MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD6, MM4_CMD_TYPE_NORMAL, Cmd6.MMC_CMD6_Bits, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+
+		// Wait for the Read to Complete
+		while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));
+
+		Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, MMC_RESPONSE_R1B_TIMEOUT);
+		if (Retval != NoError)
+			return Retval;
+	}
+
+	//send CMD13 to check the status of the card
+	Retval |= MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK);		// Make sure card is transfer mode
+	if (Retval != NoError)
+	{
+	 	pSDMMCP->State = READY;
+		MMC4SetBusRate(pContext, MM4CLOCK12_5MHZRATE);						// Failed, stick with lower speed
+		return NoError;
+	}
+	else
+		pMM4_CNTL1->hispeed = 1;
+
+	// Now change the speed to max through the controller 
+	MMC4SetBusRate(pContext, MM4CLOCK50MHZRATE);
+
+	return NoError;
+}
+
+/***************************************************************
+*   MM4SwitchPartition
+*		If the Card supports partitioning (eSD) this routine will switch to the appropriate 
+* 		partition by using extended partition command set CMD37.
+*   Input:
+*		PartitionNumber - Contains the partition Number to switch to and enable bits for the boot partitions.
+*   Output:
+*   Returns: NoError, ReadError or NotSupportedError
+*      
+*****************************************************************/
+UINT_T MM4SwitchPartition(UINT_T PartitionNumber)
+{
+	UINT_T argument, Cmd;
+	UINT_T Retval = NoError;
+	MMC_CMD6_OVERLAY Cmd6;
+
+	// Initialize Flash Properties
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+	// Must set partition
+	if (pSDMMCP->SD == XLLP_SD)
+	{
+		// CMD 43 Select Partition
+		Cmd = XLLP_eSD_CMD43;
+		argument = PartitionNumber << 24;//partition number goes in bits [31:24], rest are 0's
+		MM4_SendSetupCommand(pSDMMCP, Cmd, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+		Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, MMC_RESPONSE_R1B_TIMEOUT);
+	}
+	else
+	{
+		// Issue CMD 6 to clear PARTITION_ACCESS bits in EXT_CSD register byte 179
+		Cmd6.MMC_CMD6_Layout.Access 	= EXT_CSD_ACCESS_CLEAR_BITS;				// Clear bits
+		Cmd6.MMC_CMD6_Layout.CmdSet 	= 0;                		  				// Don't Care
+		Cmd6.MMC_CMD6_Layout.Index 		= PARTITION_CONFIG_MMC_EXT_CSD_OFFSET;       // Choose Boot Config
+		Cmd6.MMC_CMD6_Layout.Reserved0 	= 0;
+		Cmd6.MMC_CMD6_Layout.Reserved1 	= 0;
+		Cmd6.MMC_CMD6_Layout.Value 		= PARTITION_ACCESS_BITS;				 		// Clear out Partition Access bits
+
+		MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD6, MM4_CMD_TYPE_NORMAL, Cmd6.MMC_CMD6_Bits, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+
+		// Wait for the Read to Complete
+		while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));
+
+		Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, 0x500);
+		if (Retval != NoError)
+			return Retval;
+
+		// Now issue CMD 6 again to set the right bits.
+		Cmd6.MMC_CMD6_Layout.Access 	= EXT_CSD_ACCESS_SET_BITS;				// Clear bits
+		Cmd6.MMC_CMD6_Layout.CmdSet 	= 0;                		  			// Don't Care
+		Cmd6.MMC_CMD6_Layout.Index 		= PARTITION_CONFIG_MMC_EXT_CSD_OFFSET;   // Choose Boot Config
+		Cmd6.MMC_CMD6_Layout.Reserved0 	= 0;
+		Cmd6.MMC_CMD6_Layout.Reserved1 	= 0;
+		Cmd6.MMC_CMD6_Layout.Value 		= PartitionNumber;			 			// Set the correct partition
+
+		MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD6, MM4_CMD_TYPE_NORMAL, Cmd6.MMC_CMD6_Bits, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+
+		// Wait for the Read to Complete
+		while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));
+
+		Retval |= MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, 0x500);
+		if (Retval != NoError)
+			return Retval;
+	}
+
+	Retval |= MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK);
+	if (Retval != NoError)
+	{
+		pSDMMCP->State = READY;
+		return SDMMC_SWITCH_ERROR;
+	}
+	return NoError;
+}
+
+/**********************************************************
+*   MM4_CardShutdown
+*      Shuts down the MM4 hardware
+*   Input:
+*   Output:
+*      none
+*   Returns:
+*      WTP recoginized Success/Fail return code
+***********************************************************/
+UINT_T MM4_CardShutdown(void)
+{
+	P_MM4_SDMMC_CONTEXT_T pContext;
+	P_MM4_CNTL1 pMM4_CNTL1;
+
+	// Initialize Flash Properties
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+	pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+	pMM4_CNTL1 = (P_MM4_CNTL1) &pContext->pMMC4Reg->mm4_cntl1;
+
+
+	// send a CMD0, go idle here so the card gets into the idle state.
+	// even though that forces any subsequent software, like the os,
+	// to rediscover and reinit the card, this is worth doing. by
+	// putting the card into the idle state, it will be able to handle
+	// any bootrom flash probe operation if a platform reset occurs
+	// before the OS has completely initialized the device.
+	//
+	// Send CMD0 (GO_IDLE_STATE) to get card into idle state
+	MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD0, MM4_CMD_TYPE_NORMAL, 0, MM4_RT_NONE | MM4_NO_RES);
+	MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_NONE, 1);
+
+	// Disable Bus Power
+	pMM4_CNTL1->buspwr = 1;
+
+	// Stop Bus Clock
+	MMC4StopBusClock (pSDMMCP->pContext);
+
+	// Mask all interrupts
+	MMC4EnableDisableIntSources(pSDMMCP->pContext, DISABLE_INTS);
+
+	// Disable internal clocks.
+	MMC4StopInternalBusClock(pSDMMCP->pContext);
+
+	return NoError;
+}
+
+/****************************************************************
+*    MM4PrepareMMCContext
+*		Sets certain Peripheral register address
+*    Input:
+* 		P_SDMMC_Properties_T pSDMMCP - pointer to the SDMMC context structure
+*    Output:
+*		none
+*    Returns:
+*       none
+*****************************************************************/
+void MM4_PrepareMMCContext (P_SDMMC_Properties_T pSDMMCP, UINT_T BaseAddress)
+{
+	pSDMMCP->pContext = &MM4_Context;
+
+	// First fill out pContext
+	((P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext)->pMMC4Reg = (P_MM4_SDMMC_T) BaseAddress;
+}
+
+/****************************************************************
+*    MM4_SetControllerVoltage
+*		Inspects the Capabilities Register for supported voltage types by the
+*		controller. Then programs the CNTL1 register with the desired range.
+*		Enables bus power
+*    Input:
+* 		P_MM4_SDMMC_CONTEXT_T pContext
+*    Output:
+*		none
+*    Returns:
+*       none
+*****************************************************************/
+UINT_T MM4_SetControllerVoltage (P_MM4_SDMMC_CONTEXT_T pContext)
+{
+	UINT_T controllervoltage;
+	P_MM4_CNTL1 pMM4_CNTL1 = (P_MM4_CNTL1) &pContext->pMMC4Reg->mm4_cntl1;
+	MM4_CNTL1_UNION MM4_cntl1;
+
+	// Capture the Value
+	MM4_cntl1.mm4_cntl1_value = *(VUINT_T*) pMM4_CNTL1;
+
+	// Note that this really doesn't control voltage, it just needs to match one of the supported values in the capabilities 2 register.
+	controllervoltage = MM4_VLTGSEL_3_3;
+
+	// Set the voltage to controller
+	MM4_cntl1.mm4_cntl1_bits.vltgsel = controllervoltage;
+
+	// Enable Bus Power
+	MM4_cntl1.mm4_cntl1_bits.buspwr = 1;
+
+	// Write back out.
+	*(VUINT_T*) pMM4_CNTL1 = MM4_cntl1.mm4_cntl1_value;
+
+	return controllervoltage;
+}
+
+/****************************************************************
+*    MM4_CheckVoltageCompatibility
+*		Checks to make sure that the OCR register of the device supports the
+*		voltage range that was selected for the controller
+*    Input:
+* 		P_MM4_SDMMC_CONTEXT_T pContext, UINT_T ControllerVoltage
+*    Output:
+*		none
+*    Returns:
+*       none
+*****************************************************************/
+UINT_T MM4_CheckVoltageCompatibility(P_SDMMC_Properties_T pSDMMCP, UINT_T ControllerVoltage)
+{
+	// Check SD vs MMC
+	if (pSDMMCP->SD == XLLP_SD)
+	{
+		switch (ControllerVoltage)
+		{
+			case MM4_VLTGSEL_3_3:
+				if (pSDMMCP->CardReg.OCR & SD_OCR_VOLTAGE_3_3_TO_3_6)
+					return NoError;
+
+			case MM4_VLTGSEL_3_0:
+				if (pSDMMCP->CardReg.OCR & SD_OCR_VOLTAGE_1_8_TO_3_3)
+					return NoError;
+
+			case MM4_VLTGSEL_1_8:
+				if (pSDMMCP->CardReg.OCR & SD_OCR_VOLTAGE_1_8)
+					return NoError;
+		}
+	}
+	else
+	{
+		if ((pSDMMCP->CardReg.OCR & MMC_OCR_VOLTAGE_ALL) == MMC_OCR_VOLTAGE_ALL)
+			return NoError;
+	}
+	return SDMMCDeviceVoltageNotSupported;
+}
+
+
+/******************************************************************************
+  Description:
+    Set up the registers of the controller to start the transaction to
+    communicate to the card for data related command.  The commands are clearly defined in the MMC
+    specification.
+  Input Parameters:
+	   P_SDMMC_Properties_T pSDMMCP - Generic SD/MMC driver properties structure
+  Cmd
+		Command Index - See MMC or SD specification
+  argument
+      	the argument of  the command. MSW is for ARGH and LSW is for ARGL
+  BlockType
+	  	Multiple or Single Block Type
+  ResType
+		Expected response type
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+
+void MM4_SendDataCommand (P_SDMMC_Properties_T pSDMMCP,
+                  UINT_T Cmd,
+                  UINT_T  Argument,
+                  UINT_T BlockType,
+                  UINT_T DataDirection,
+                  UINT_T ResType)
+{
+	// Assign our context value
+	P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+	// no need to clear out any fault state that may be left over from a previously failed transaction.
+	// that's because the caller has set State to read or write before calling here.
+ 
+	// No Response to the command yet
+	pSDMMCP->CardReponse.CommandComplete = 0;
+	pSDMMCP->CardReponse.TransferComplete = 0;
+
+	// save the info for use by the isr:
+	pSDMMCP->Trans.RespType = (ResType >> 8) & 0x000000ff;
+	pSDMMCP->Trans.Cmd = Cmd;	// Fixme: how to know when to set the ACMD flag?
+
+	MMC4SendDataCommand(pContext,
+                  Cmd,
+                  Argument,
+                  BlockType,
+                  DataDirection,
+                  ResType & 0x000000ff, // clear out any bits not for the SD_CMD.RES_TYPE field
+                  ((pSDMMCP->SDMMC_DMA_Mode == NODMA) ? 0 : 1),
+                  ((pSDMMCP->SDMMC_DMA_Mode == ADMA2) ? 1 : 0));	
+}
+
+/******************************************************************************
+  Description:
+    Set up the registers of the controller to start the transaction to
+    communicate to the card for data related command.  The commands are clearly defined in the MMC
+    specification.
+  Input Parameters:
+	   P_SDMMC_Properties_T pSDMMCP - Generic SD/MMC driver properties structure
+  Cmd
+		Command Index - See MMC or SD specification
+  argument
+      	the argument of  the command. MSW is for ARGH and LSW is for ARGL
+  BlockType
+	  	Multiple or Single Block Type
+  ResType
+		Expected response type
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MM4_SendDataCommandNoAuto12 (P_SDMMC_Properties_T pSDMMCP,
+                  UINT_T Cmd,
+                  UINT_T  Argument,
+                  UINT_T BlockType,
+                  UINT_T DataDirection,
+                  UINT_T ResType)
+{
+	// Assign our context value
+	P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+	// no need to clear out any fault state that may be left over from a previously failed transaction.
+	// that's because the caller has set State to read or write before calling here.
+ 
+	// No Response to the command yet
+	pSDMMCP->CardReponse.CommandComplete = 0;
+	pSDMMCP->CardReponse.TransferComplete = 0;
+
+	// save the info for use by the isr:
+	pSDMMCP->Trans.RespType = (ResType >> 8) & 0x000000ff;
+	pSDMMCP->Trans.Cmd = Cmd;	// Fixme: how to know when to set the ACMD flag?
+
+	MMC4SendDataCommandNoAuto12(pContext,
+                  Cmd,
+                  Argument,
+                  BlockType,
+                  DataDirection,
+                  ResType & 0x000000ff, // clear out any bits not for the SD_CMD.RES_TYPE field
+                  ((pSDMMCP->SDMMC_DMA_Mode == NODMA) ? 0 : 1),
+                  ((pSDMMCP->SDMMC_DMA_Mode == ADMA2) ? 0 : 1)); //Block count is disabled for ADMA2		
+}
+
+/******************************************************************************
+  Description:
+    Set up the registers of the controller to start the transaction to
+    communicate to the card for setup related commands.
+    The commands are clearly defined in the MMC specification.
+  Input Parameters:
+	   P_SDMMC_Properties_T pSDMMCP - Generic SD/MMC driver properties structure
+	Cmd
+		Command Index - See MMC or SD specification
+    argument
+      	the argument of  the command. MSW is for ARGH and LSW is for ARGL
+	ResType
+		Expected response type
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MM4_SendSetupCommand(P_SDMMC_Properties_T pSDMMCP,
+                  UINT_T Cmd,
+                  UINT_T CmdType,
+                  UINT_T Argument,
+                  UINT_T ResType)
+{
+	// Assign our context value
+	P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+	// clear out any fault status that may be left over from a previously failed transaction.
+	pSDMMCP->State = READY;
+ 
+	// No Response to the command yet
+	pSDMMCP->CardReponse.CommandComplete = 0;
+	pSDMMCP->CardReponse.TransferComplete = 0;
+
+	// save the info for use by the isr:
+	pSDMMCP->Trans.RespType = (ResType >> 8) & 0x000000ff;
+	pSDMMCP->Trans.Cmd = Cmd;	// Fixme: how to know when to set the ACMD flag?
+
+	MMC4SendSetupCommand(pContext,
+                  Cmd,
+                  CmdType,
+                  Argument,
+                  ResType & 0x000000ff);	// clear out any bits not for the SD_CMD.RES_TYPE field
+}
+
+/****************************************************************
+*   MM4_Read_Response
+*	   	Reads the response from the Controller Buffer Registers to the Local Buffer.
+* 		According to the last command and response type it does the correct interpretation.
+*		There is also a timeout as the routine waits for the ISR to signal last command completion.
+*   Input:
+*	   	P_SDMMC_Properties_T pSDMMCP - Generic SD/MMC driver properties structure
+* 		ResponseType - See SD/MMC specifications
+*		ResponseTimeOut - A time out value in millisec's
+*   Output:
+*      	none
+*   Returns:
+*      	MM4InterpretTimeOutError or NoError
+*****************************************************************/
+UINT_T MM4_Interpret_Response(P_SDMMC_Properties_T pSDMMCP, UINT_T ResponseType, UINT_T ResponseTimeOut)
+{
+	UINT_T i, temp, temp2, temp3, startTime, endTime;
+	UINT_T Retval = NoError;
+	P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;		// Assign our context value
+	P_MM4_CMD_XFRMD_UNION pMM4_XFRMD;
+
+	startTime = GetOSCR0();   // get the start time
+	endTime = startTime;
+
+	// Overlap XFRMD register contents using uniun
+	pMM4_XFRMD = (P_MM4_CMD_XFRMD_UNION) &pContext->pMMC4Reg->mm4_cmd_xfrmd;
+
+	// Wait for the Response based on the CommandComplete interrupt signal
+	while (1)
+	{
+		// if the command had an error, the command may have aborted
+		// without setting the command complete bit. for example,
+		// if no response is received, then the command is aborted,
+		// the MM4_ISR sets the state to FAULT, and command complete
+		// will not assert. check for such a scenario here.
+		if( pSDMMCP->State == FAULT )
+		{
+			Retval = SDMMC_GENERAL_ERROR;
+			break; // continue to capture command response to return a more specific error
+		}
+
+		if (pSDMMCP->CardReponse.CommandComplete)
+		{
+			if(ResponseType != MMC_RESPONSE_R1B)
+				break; // Done no issue.
+			else if (pSDMMCP->CardReponse.TransferComplete)
+				break; 	// R1B type commands now require MMC xfer_complete bit to be set
+		}
+	
+		// check if too much time has elapsed. if so, timeout.
+		endTime = GetOSCR0();
+
+		if (OSCR0IntervalInMilli(startTime, endTime) > ResponseTimeOut)
+		{
+			Retval = MM4InterpretTimeOutError;
+			return Retval;
+		}
+	}
+
+	// Read in the Buffers
+	switch (ResponseType)
+	{
+  	case MMC_RESPONSE_NONE:
+		break;
+	case MMC_RESPONSE_R1:
+	case MMC_RESPONSE_R1B:
+		pSDMMCP->CardReponse.R1_RESP = pSDMMCP->CardReponse.pBuffer[0];
+		break;
+	case MMC_RESPONSE_R2:			// This is for CID or CSD register
+	{
+	 	if (pMM4_XFRMD->mm4_cmd_xfrmd_bits.cmd_idx == XLLP_MMC_CMD9) //CSD
+	 	{
+			// Copy the CSD values from the buffer
+			for (i=0; i<4; i++)
+				pSDMMCP->CardReg.CSD.CSD_VALUE[i] = pSDMMCP->CardReponse.pBuffer[i];
+
+			UINT16_T MMC_RESPONSE[8]; // for shift CSD register
+
+			MMC_RESPONSE[7] = (UINT16_T)((pSDMMCP->CardReg.CSD.CSD_VALUE[3] >> 16) & 0xffff);
+			MMC_RESPONSE[6] = (UINT16_T)(pSDMMCP->CardReg.CSD.CSD_VALUE[3] & 0xffff);
+			MMC_RESPONSE[5] = (UINT16_T)((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 16) & 0xffff);
+			MMC_RESPONSE[4] = (UINT16_T)(pSDMMCP->CardReg.CSD.CSD_VALUE[2] & 0xffff);
+			MMC_RESPONSE[3] = (UINT16_T)((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 16) & 0xffff);
+			MMC_RESPONSE[2] = (UINT16_T)(pSDMMCP->CardReg.CSD.CSD_VALUE[1] & 0xffff);
+			MMC_RESPONSE[1] = (UINT16_T)((pSDMMCP->CardReg.CSD.CSD_VALUE[0] >> 16) & 0xffff);
+			MMC_RESPONSE[0] = (UINT16_T)(pSDMMCP->CardReg.CSD.CSD_VALUE[0] & 0xffff);
+	
+
+			pSDMMCP->CardReg.CSD.CSD_VALUE[0] = (UINT32_T)(MMC_RESPONSE[5] >> 8 | MMC_RESPONSE[6] << 8 | MMC_RESPONSE[7] << 24);
+			pSDMMCP->CardReg.CSD.CSD_VALUE[1] = (UINT32_T)(MMC_RESPONSE[3] >> 8 | MMC_RESPONSE[4] << 8 | MMC_RESPONSE[5] << 24);
+			pSDMMCP->CardReg.CSD.CSD_VALUE[2] = (UINT32_T)(MMC_RESPONSE[1] >> 8 | MMC_RESPONSE[2] << 8 | MMC_RESPONSE[3] << 24);
+			pSDMMCP->CardReg.CSD.CSD_VALUE[3] = (UINT32_T)(MMC_RESPONSE[0] << 8 | MMC_RESPONSE[1] << 24);
+
+			// Optionally we could record maximum block lengths from the CSD.
+			// But some devices cheat and put incorrect values in this field.
+			// Save off read Block Size, play it safe, for now hard code to 512 Bytes
+			pSDMMCP->ReadBlockSize = HARD512BLOCKLENGTH;
+			// Save off Write Block Size
+			pSDMMCP->WriteBlockSize = HARD512BLOCKLENGTH;
+
+			// Capture Erase Granularity.
+			if (pSDMMCP->SD == XLLP_SD)
+			{
+				// Check Erase Single Block Enable - Bit 46
+				if ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 14) & 1)
+					pSDMMCP->EraseSize = pSDMMCP->WriteBlockSize;
+				else
+				{
+					pSDMMCP->EraseSize = ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 7) & 0x7F) + 1;
+					pSDMMCP->EraseSize *= pSDMMCP->WriteBlockSize;
+				}
+			}
+			else // MMC Card
+			{
+				// if the card use high capacity erase unit size, pSDMMCP->EraseSize will be overwritten
+
+				//pSDMMCP->EraseSize = ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 5) & 0x1F) + 1;  		// Get ERASE_GRP_MULT
+				//pSDMMCP->EraseSize *= (((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 10) & 0x1F) + 1);	// Get ERASE_GRP_SIZE
+				pSDMMCP->EraseSize = ((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 5) & 0x1F) + 1;  		// Get ERASE_GRP_MULT
+				pSDMMCP->EraseSize *= (((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 10) & 0x1F) + 1);	// Get ERASE_GRP_SIZE
+				pSDMMCP->EraseSize *= pSDMMCP->WriteBlockSize;
+			}
+
+			// Now calculate the capacity of this card
+			// the execution of CMD9 is before CMD8
+			// if the card is larger than 2GB, pSDMMCP->CardCapacity will be overwritten
+			
+			//temp = ((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 16) & 0xF); 		// Get READ_BL_LEN
+			temp = ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 16) & 0xF); 		// Get READ_BL_LEN
+			temp = 1 << temp; 
+			
+			// Now we have Max Block Length
+			//temp2 = ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 15) & 0x7) + 2; 	// Get C_SIZE_MULT
+			temp2 = ((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 15) & 0x7) + 2; 	// Get C_SIZE_MULT
+			temp2 = 1 << temp2;
+			
+			//temp3 = ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 30) & 0x3);		// Get C_SIZE
+			temp3 = ((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 30) & 0x3);		// Get C_SIZE
+			//temp3 |= ((pSDMMCP->CardReg.CSD.CSD_VALUE[2] & 0x3FF) << 2);	// Get C_SIZE
+			temp3 |= ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] & 0x3FF) << 2);	// Get C_SIZE
+			temp3++;
+			
+			pSDMMCP->CardCapacity = temp3 * temp2 * temp;		// Total Size of the card in Bytes
+		}
+	 	else // Assume CID
+	 	{
+			// Copy the CSD values from the buffer
+			for (i=0; i<4; i++)
+				pSDMMCP->CardReg.CID.CID_VALUE[i] = pSDMMCP->CardReponse.pBuffer[i];
+
+			UINT16_T MMC_RESPONSE1[8]; // for shift CID register
+
+			MMC_RESPONSE1[7] = (UINT16_T)((pSDMMCP->CardReg.CID.CID_VALUE[3] >> 16) & 0xffff);
+			MMC_RESPONSE1[6] = (UINT16_T)(pSDMMCP->CardReg.CID.CID_VALUE[3] & 0xffff);
+			MMC_RESPONSE1[5] = (UINT16_T)((pSDMMCP->CardReg.CID.CID_VALUE[2] >> 16) & 0xffff);
+			MMC_RESPONSE1[4] = (UINT16_T)(pSDMMCP->CardReg.CID.CID_VALUE[2] & 0xffff);
+			MMC_RESPONSE1[3] = (UINT16_T)((pSDMMCP->CardReg.CID.CID_VALUE[1] >> 16) & 0xffff);
+			MMC_RESPONSE1[2] = (UINT16_T)(pSDMMCP->CardReg.CID.CID_VALUE[1] & 0xffff);
+			MMC_RESPONSE1[1] = (UINT16_T)((pSDMMCP->CardReg.CID.CID_VALUE[0] >> 16) & 0xffff);
+			MMC_RESPONSE1[0] = (UINT16_T)(pSDMMCP->CardReg.CID.CID_VALUE[0] & 0xffff);
+	
+
+			pSDMMCP->CardReg.CID.CID_VALUE[0] = (UINT32_T)(MMC_RESPONSE1[5] >> 8 | MMC_RESPONSE1[6] << 8 | MMC_RESPONSE1[7] << 24);
+			pSDMMCP->CardReg.CID.CID_VALUE[1] = (UINT32_T)(MMC_RESPONSE1[3] >> 8 | MMC_RESPONSE1[4] << 8 | MMC_RESPONSE1[5] << 24);
+			pSDMMCP->CardReg.CID.CID_VALUE[2] = (UINT32_T)(MMC_RESPONSE1[1] >> 8 | MMC_RESPONSE1[2] << 8 | MMC_RESPONSE1[3] << 24);
+			pSDMMCP->CardReg.CID.CID_VALUE[3] = (UINT32_T)(MMC_RESPONSE1[0] << 8 | MMC_RESPONSE1[1] << 24);
+		
+			// Now capture the serial number from the CID - 32 bit number
+			if (pSDMMCP->SD == XLLP_MMC)
+			{
+				//pSDMMCP->CardReg.CID.SerialNum = (pSDMMCP->CardReg.CID.CID_VALUE[0] >> 16) & (0xFF);
+				pSDMMCP->CardReg.CID.SerialNum = (pSDMMCP->CardReg.CID.CID_VALUE[3] >> 16) & (0xFFFF);
+				//pSDMMCP->CardReg.CID.SerialNum |= (pSDMMCP->CardReg.CID.CID_VALUE[1] << 16);
+				pSDMMCP->CardReg.CID.SerialNum |= (pSDMMCP->CardReg.CID.CID_VALUE[2] << 16);
+			}
+			else
+			{
+				pSDMMCP->CardReg.CID.SerialNum = (pSDMMCP->CardReg.CID.CID_VALUE[0] >> 24) & (0xFF);
+				pSDMMCP->CardReg.CID.SerialNum |= (pSDMMCP->CardReg.CID.CID_VALUE[1] << 8);
+			}
+	 	}
+	 	break;
+	}
+	case MMC_RESPONSE_R3:
+	{
+		pSDMMCP->CardReg.OCR = pSDMMCP->CardReponse.pBuffer[0];
+		break;
+	}
+	case MMC_RESPONSE_R4:				// These modes are not supported by the driver
+	case MMC_RESPONSE_R5:
+	case MMC_RESPONSE_R5B:
+		break;
+	case MMC_RESPONSE_R6:				// Publishes RCA for SD cards
+	{
+		pSDMMCP->CardReg.RCA = pSDMMCP->CardReponse.pBuffer[0];
+		break;
+	}
+	case MMC_RESPONSE_R7:
+	{
+		pSDMMCP->SD_VHS = pSDMMCP->CardReponse.pBuffer[0];
+		break;
+	}
+ 	}
+	return Retval;
+}
+
+/****************************************************************
+*   SDMMCGetMatchWaitCardStatus
+*      	Gets the status of the card by issuing CMD 13. The rerturn from the routine is based
+* 		on a check against the expected value which is passed in
+*   Input:
+*      	pSDMMCP - pointer to the current context
+*      	MaxWaitMSec - Maximum wait time in millisec
+* 	   	R1_Resp_Match - Desired Value to be matched
+*   Output:
+*      	none
+*   Returns:
+*      	none
+*****************************************************************/
+UINT_T MM4_CheckCardStatus(P_SDMMC_Properties_T pSDMMCP, UINT_T R1_Resp_Match, UINT_T Mask)
+{
+	UINT_T argument, cardStatus, retval;
+
+   	//send CMD13 to check the status of the card
+   	argument = pSDMMCP->CardReg.RCA;
+	MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD13, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+	retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+
+	// Mask out undesired check bits
+	cardStatus = (pSDMMCP->CardReponse.R1_RESP) & Mask;
+
+	if ((cardStatus == R1_Resp_Match) && (retval == NoError))
+		return NoError;
+	else
+		return MM4CheckCardStatusTimeOutError;
+}
+
+/***********************************************************
+*    MM4_ReadBlocks()
+*       Reads the given block off of the SD/MMC card and
+*       into LocalAddr or empty buffer
+*    input:
+*		none
+*    output:
+*       LocalAddr will contain the contents of the block
+*    returns:
+*       none
+************************************************************/
+UINT_T MM4_ReadBlocks(void)
+{
+	UINT_T argument;
+	UINT_T Retval = NoError;
+	P_MM4_SDMMC_CONTEXT_T pContext;
+	P_MM4_BLK_CNTL pMM4_BLK_CNTL;
+	P_MM4_CNTL1 pMM4_CNTL1;
+	UINT_T total_blks,loadaddr,blks_to_txfr;
+	UINT_T i=0;
+
+	// Initialize Flash Properties
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ 	// Assign our context value
+ 	pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+	// Must set MMC NUMBLK
+	pMM4_BLK_CNTL = (P_MM4_BLK_CNTL) &pContext->pMMC4Reg->mm4_blk_cntl;
+	//blk_cnt is used in PIO/SDMA mode
+	pMM4_BLK_CNTL->blk_cnt = pSDMMCP->Trans.NumBlocks;
+	pMM4_CNTL1 = (P_MM4_CNTL1)&pContext->pMMC4Reg->mm4_cntl1;
+	
+	total_blks = pSDMMCP->Trans.NumBlocks;
+	loadaddr = pSDMMCP->Trans.LocalAddr;
+
+	if (pSDMMCP->SDMMC_DMA_Mode == SDMA)
+	{
+		pMM4_BLK_CNTL->dma_bufsz = MM4_512_HOST_DMA_BDRY;
+		pContext->pMMC4Reg->mm4_sysaddr = pSDMMCP->Trans.LocalAddr;
+	} 
+	else if (pSDMMCP->SDMMC_DMA_Mode == ADMA2)
+	{
+		memset(admaDesc, 0, sizeof(ADMA_DESCRIPTOR)*NO_ADMA_TX_DESCS);
+		while(total_blks)
+		{
+			blks_to_txfr = (total_blks > MAX_TRANS_BLKS_ADMA_DESC)? MAX_TRANS_BLKS_ADMA_DESC: total_blks,
+			MM4_SetupADMADesc(
+				&admaDesc[i],
+				VALID_DESC,
+				(total_blks > MAX_TRANS_BLKS_ADMA_DESC)? NOT_LAST_DESC: LAST_DESC,
+				NO_DMA_INT,
+				TRANSFER,
+				blks_to_txfr,
+				loadaddr);
+			total_blks -=  blks_to_txfr;
+			loadaddr +=  blks_to_txfr * pSDMMCP->ReadBlockSize;
+			i++;
+		}
+		pMM4_CNTL1->dma_sel = 2;  //ADMA2
+
+		//Set the ADMA register to the address of descriptor table
+		pContext->pMMC4Reg->mm4_adma_system_address1 = (UINT_T)&admaDesc[0];
+
+		// Set the block count register to the total number of blocks for transterring
+		// and the max limmit is 65535
+		pMM4_BLK_CNTL->blk_cnt = pSDMMCP->Trans.NumBlocks;
+
+		//AutoCMD23 should be sent prior to CMD18 or CMD25 if ADMA is used and BLK_CNT is disabled
+		//mm4_sysaddr holds the argument field for Auto CMD23 that is the number of blocks
+		pContext->pMMC4Reg->mm4_sysaddr = pSDMMCP->Trans.NumBlocks;
+
+		#if ENABLE_MMU
+		dcache_clean_range(&admaDesc[0], sizeof(ADMA_DESCRIPTOR)*NO_ADMA_TX_DESCS);
+		#endif
+	} 
+
+	#if ENABLE_MMU && (MMC_ADMA_MODE || MMC_SDMA_MODE)
+	// if MMU is enabled, for DMA operations need to invalidate data cache for data consistency
+	dcache_invalidate_range(pSDMMCP->Trans.LocalAddr, pSDMMCP->Trans.NumBlocks * 512);
+	#endif
+
+	// Set up State
+	pSDMMCP->State = READ;
+
+	// Do a CMD 18 Read Multiple Block
+	// In byte mode addressing; all addresses need to be specified as byte offsets.
+	argument = pSDMMCP->Trans.CardAddress;
+	if (pSDMMCP->AccessMode == BYTE_ACCESS)
+		argument *= HARD512BLOCKLENGTH;
+
+	// Kick off the Read
+	MM4_SendDataCommand(pSDMMCP, XLLP_MMC_CMD18, argument, MM4_MULTI_BLOCK_TRAN, MM4_CARD_TO_HOST_DATA, MM4_RT_R1 | MM4_48_RES);
+
+	// Wait for the Read to Complete
+	while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));
+
+	// Get the Card Response
+	Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+	if ((Retval != NoError) || ((pSDMMCP->CardReponse.R1_RESP & R1_LOCKEDCARDMASK) != 0x900) || (pSDMMCP->State == FAULT))
+	{
+		Retval = SDMMCReadError;
+		pSDMMCP->State = FAULT;
+	}
+	else
+	{
+		pSDMMCP->State = READY;
+	}
+
+	return Retval;
+}
+
+// fixme: change this to use an r1b type...
+UINT_T MM4_WaitReady(UINT_T TimeOutMilliSec)
+{
+	UINT_T startTime, endTime;
+	UINT_T writecomplete = 0;
+	UINT_T Retval = NoError;
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+	UINT_T argument = pSDMMCP->CardReg.RCA;
+
+	// issue a series of get status commands until the (new) status indicates ready.
+	// limit the amount of time to wait to the input parameter TimeOutMilliSec
+	startTime = GetOSCR0();
+	startTime = GetOSCR0();
+	do
+	{
+   		//send CMD13 to check the status of the card
+		MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD13, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+		Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);	// FIXME: this timeout value should be dependent on CSD and operating configuration
+		if (Retval != NoError) break;	// failed to complete transaction
+
+		// examine the new status, which was just extracted from the response field of the get stauts command.
+		if( ( pSDMMCP->CardReponse.R1_RESP & 0x00000100 ) == 0x00000100 ) // card_status:READY_FOR_DATA asserted. write is complete.
+		{
+			writecomplete = 1;
+			break;			
+		}
+
+		endTime = GetOSCR0();			// check for end of wait interval
+	}
+	while( OSCR0IntervalInMilli(startTime, endTime) < TimeOutMilliSec );
+
+	return writecomplete;
+}
+
+/***********************************************************
+*    MM4_WriteBlocks()
+*		Writes the required number of blocks to CardAddress
+*    input:
+*		none
+*    output:
+*       Address starting with CardAddress will contain content from LocalAddress
+*    returns:
+*       none
+************************************************************/
+UINT_T MM4_WriteBlocks(void)
+{
+	UINT_T argument;
+	UINT_T Retval = NoError;
+	P_MM4_SDMMC_CONTEXT_T pContext;
+	P_MM4_BLK_CNTL pMM4_BLK_CNTL;
+	P_MM4_CNTL1 pMM4_CNTL1;
+	UINT_T total_blks,loadaddr,blks_to_txfr;
+	UINT_T i=0;
+
+	// Initialize Flash Properties
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ 	// Assign our context value
+ 	pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+	// Must set MMC NUMBLK
+	pMM4_BLK_CNTL = (P_MM4_BLK_CNTL) &pContext->pMMC4Reg->mm4_blk_cntl;
+	//Required for PIO and SDMA mode
+	pMM4_BLK_CNTL->blk_cnt = pSDMMCP->Trans.NumBlocks;
+	pMM4_CNTL1 = (P_MM4_CNTL1)&pContext->pMMC4Reg->mm4_cntl1;
+
+	total_blks = pSDMMCP->Trans.NumBlocks;
+	loadaddr = pSDMMCP->Trans.LocalAddr;
+	if (pSDMMCP->SDMMC_DMA_Mode == SDMA)
+	{
+		pMM4_BLK_CNTL->dma_bufsz = MM4_512_HOST_DMA_BDRY;
+		pContext->pMMC4Reg->mm4_sysaddr = pSDMMCP->Trans.LocalAddr;
+	} 
+	else if(pSDMMCP->SDMMC_DMA_Mode == ADMA2)
+	{
+		memset(admaDesc, 0, sizeof(ADMA_DESCRIPTOR)*NO_ADMA_TX_DESCS);
+		while(total_blks)
+		{
+			blks_to_txfr = (total_blks > MAX_TRANS_BLKS_ADMA_DESC)? MAX_TRANS_BLKS_ADMA_DESC: total_blks,
+		   	MM4_SetupADMADesc(&admaDesc[i], 
+				VALID_DESC, 
+				(total_blks > MAX_TRANS_BLKS_ADMA_DESC)? NOT_LAST_DESC: LAST_DESC,
+				NO_DMA_INT, 
+				TRANSFER, 
+				blks_to_txfr, 
+				loadaddr);
+			total_blks -=  blks_to_txfr;
+			loadaddr   +=  blks_to_txfr * pSDMMCP->ReadBlockSize;
+			i++;
+		}
+		pMM4_CNTL1->dma_sel = 2;  //ADMA2
+
+		//Set the ADMA register to the address of descriptor table
+		pContext->pMMC4Reg->mm4_adma_system_address1 = (UINT_T)&admaDesc[0];
+
+		// Set the block count register to the total number of blocks for transterring
+		// and the max limmit is 65535
+		pMM4_BLK_CNTL->blk_cnt = pSDMMCP->Trans.NumBlocks;
+
+		//AutoCMD23 should be sent prior to CMD18 or CMD25 if ADMA is used and BLK_CNT is disabled
+		//mm4_sysaddr holds the argument field for Auto CMD23 that is the number of blocks
+		pContext->pMMC4Reg->mm4_sysaddr = pSDMMCP->Trans.NumBlocks;
+
+		#if ENABLE_MMU
+		dcache_clean_range(&admaDesc[0], sizeof(ADMA_DESCRIPTOR)*NO_ADMA_TX_DESCS);
+		#endif
+	} 
+
+	#if ENABLE_MMU && (MMC_ADMA_MODE || MMC_SDMA_MODE)
+	// if MMU is enabled, for DMA operations need to clean data cache for data consistency
+	dcache_clean_range(pSDMMCP->Trans.LocalAddr, pSDMMCP->Trans.NumBlocks * 512);
+	#endif
+
+	// Set up State
+	pSDMMCP->State = WRITE;
+
+	// Do a CMD 25 Write Multiple Blocks
+	// In byte mode addressing; all addresses need to be specified as byte offsets.
+	argument = pSDMMCP->Trans.CardAddress;
+	if (pSDMMCP->AccessMode == BYTE_ACCESS)
+		argument *= HARD512BLOCKLENGTH;
+
+	MM4_SendDataCommand(pSDMMCP, XLLP_MMC_CMD25, argument, MM4_MULTI_BLOCK_TRAN, MM4_HOST_TO_CARD_DATA, MM4_RT_R1 | MM4_48_RES);
+
+	// Wait for the Write to Complete
+	while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));		// TBD add timeout Let the ISR run, we'll either get a fault or finish
+
+	// Get the Card Response
+	Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+	if ((Retval != NoError) || (pSDMMCP->State == FAULT) || ((pSDMMCP->CardReponse.R1_RESP & R1_NOMASK) != 0x900))
+	{
+		Retval = WriteError;
+		pSDMMCP->State = FAULT;
+		return Retval;
+	}
+
+	// the write data transfer completed...now must wait for the card to assert the ready line.
+	// (the ready status from the last data transfer is meaningless here because it was left 
+	//  over from the write command that initiated the data transfer.)
+	//
+	// section 7.7.2 of the mmc 4.3 spec defines a formula for the timeout value.
+	// for now, just use a constant. Samsung KLMxGxxExM defines max write timeout as 600 ms
+	// FIXME: implement the formula, which is based on info from the CSD...
+
+	if( !MM4_WaitReady(600) )
+	{
+		Retval = WriteError;
+		pSDMMCP->State = FAULT;
+		return Retval;
+	}
+
+	pSDMMCP->State = READY;
+	return NoError;
+}
+
+/***********************************************************
+*    MM4_EraseBlocks()
+*		Erases required number of blocks at CardAddress
+*    input:
+*		none
+*    output:
+*		Blocks erased on erase group alignment
+*    returns:
+*       none
+************************************************************/
+UINT_T MM4_EraseBlocks(void)
+{
+	UINT_T argument, Cmd;
+	UINT_T Retval = NoError;
+
+	// Initialize Flash Properties
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+	// CMD 32/35 Define Erase Group Start Address
+	if (pSDMMCP->SD == XLLP_SD)
+		Cmd = XLLP_SD_CMD32;
+	else
+		Cmd = XLLP_MMC_CMD35;
+
+	// In byte mode addressing; all addresses need to be specified as byte offsets.
+	argument = pSDMMCP->Trans.CardAddress;
+	if (pSDMMCP->AccessMode == BYTE_ACCESS)
+		argument *= HARD512BLOCKLENGTH;
+
+	MM4_SendSetupCommand(pSDMMCP, Cmd, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+
+	// Wait for the command to Complete
+	while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));		// TBD add timeout Let the ISR run, we'll either get a fault or finish
+
+	if( pSDMMCP->State == FAULT )	// This state entered if ISR detected an error.
+	{
+		return SDMMC_ERASE_PARAM_ERROR;
+	}
+	
+	Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+	if (Retval != NoError)
+	{
+		pSDMMCP->State = FAULT;
+		return EraseError;
+	}
+
+	// CMD 33/36 Define Erase Group End Address
+	if (pSDMMCP->SD == XLLP_SD)
+		Cmd = XLLP_SD_CMD33;
+	else
+		Cmd = XLLP_MMC_CMD36;
+
+	// In byte mode addressing; all addresses need to be specified as byte offsets.
+	argument = pSDMMCP->Trans.CardAddress + pSDMMCP->Trans.TransWordSize*4;
+	if (pSDMMCP->AccessMode == BYTE_ACCESS)
+		argument *= HARD512BLOCKLENGTH;
+
+	MM4_SendSetupCommand(pSDMMCP, Cmd, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+
+	// Wait for the command to Complete
+	while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));		// TBD add timeout Let the ISR run, we'll either get a fault or finish
+
+	if( pSDMMCP->State == FAULT )	// This state entered if ISR detected an error.
+	{
+		return SDMMC_ERASE_PARAM_ERROR;
+	}
+	
+	Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+	if (Retval != NoError)
+	{
+		pSDMMCP->State = FAULT;
+		return EraseError;
+	}
+
+	// CMD 38
+	Cmd = XLLP_MMC_CMD38;
+	if (pSDMMCP->Trans.CardAddress % pSDMMCP->EraseSize ||
+	    (pSDMMCP->Trans.TransWordSize*4) % pSDMMCP->EraseSize)
+		argument = 0x1; /* trim */
+	else
+		argument = 0x0; /* erase */
+	MM4_SendSetupCommand(pSDMMCP, Cmd, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+
+	// Wait for the command to Complete
+	while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));		// TBD add timeout Let the ISR run, we'll either get a fault or finish
+
+	if( pSDMMCP->State == FAULT )	// This state entered if ISR detected an error.
+	{
+		return SDMMC_ERASE_PARAM_ERROR;
+	}
+	
+	Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, 0x8000);
+	if (Retval != NoError)
+	{
+		Retval = EraseError;
+		pSDMMCP->State = FAULT;
+	}
+	else
+	{
+		pSDMMCP->State = READY;
+	}
+	return Retval;
+}
+
+/***********************************************************
+*   SDMMCWriteFifo
+*      Writes 2048 bytes (512 words) to the FIFO
+*   Input:
+*      P_SDMMC_Properties_T pSDMMCP - pointer to the SDMMC context structure
+*   Output:
+*      none
+*   Returns:
+*      none
+*************************************************************/
+void MM4_WriteFifo(P_SDMMC_Properties_T pSDMMCP)
+{
+	int i, t = 0;
+	UINT_T Buffer =0x0;
+	P_MM4_SDMMC_CONTEXT_T pContext;
+	volatile UINT_T *pMMC_TX_Fifo;
+
+ 	// Assign our context value
+ 	pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+	pMMC_TX_Fifo = (volatile UINT_T *)&(pContext->pMMC4Reg->mm4_dp);
+	t = pSDMMCP->Trans.WordIndex;
+
+	// Ignore Pre Bytes
+	for (i=0; (i < MM4FIFOWORDSIZE) && (t < pSDMMCP->Trans.StartDiscardWords); i++, t++)
+		*pMMC_TX_Fifo = Buffer;
+
+	// Write Requested Data
+	for (; ((i < MM4FIFOWORDSIZE) && (t < (pSDMMCP->Trans.TransWordSize-pSDMMCP->Trans.EndDiscardWords))); i++, t++)
+		*pMMC_TX_Fifo = ((UINT_T*) pSDMMCP->Trans.LocalAddr)[t];
+
+	// Ignore Trailing Bytes
+	for (; (i < MM4FIFOWORDSIZE) && (t < pSDMMCP->Trans.TransWordSize); i++, t++)
+		*pMMC_TX_Fifo = Buffer;
+
+	pSDMMCP->Trans.WordIndex = t;
+
+}
+
+/***********************************************************
+*   MM4_ReadFifo
+*      Reads the contents of the read fifo (512 words)
+*   Input:
+*      P_SDMMC_Properties_T pSDMMCP - pointer to the SDMMC context structure
+*   Output:
+*      buffer will contain the contents of the read fifo
+*   Returns:
+*      none
+*************************************************************/
+void MM4_ReadFifo(P_SDMMC_Properties_T pSDMMCP)
+{
+	int i, t = 0;
+	UINT_T Buffer =0x0;
+	P_MM4_SDMMC_CONTEXT_T pContext;
+	volatile UINT_T *pMMC_RX_Fifo;
+
+ 	// Assign our context value
+ 	pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+	pMMC_RX_Fifo = (volatile UINT_T *)&(pContext->pMMC4Reg->mm4_dp);
+	t = pSDMMCP->Trans.WordIndex;
+
+	// Ignore Pre Bytes
+	for (i=0; (i < MM4FIFOWORDSIZE) && (t < pSDMMCP->Trans.StartDiscardWords); i++, t++)
+		Buffer = *pMMC_RX_Fifo;
+
+	// Read Requested Data
+	for (; ((i < MM4FIFOWORDSIZE) && (t < (pSDMMCP->Trans.TransWordSize-pSDMMCP->Trans.EndDiscardWords))); i++, t++)
+		((UINT_T*) pSDMMCP->Trans.LocalAddr)[t] = *pMMC_RX_Fifo;
+
+	// Ignore Trailing Bytes
+	for (; (i < MM4FIFOWORDSIZE) && (t < pSDMMCP->Trans.TransWordSize); i++, t++)
+		Buffer = *pMMC_RX_Fifo;
+
+	pSDMMCP->Trans.WordIndex = t;
+}
+
+/****************************************************************
+*   MM4_SendStopCommand
+*	Issues a stop command for open ended read and write block operations
+*
+*   Input:
+*      P_SDMMC_Properties_T pSDMMCP - pointer to the SDMMC context structure
+*   Output:
+*      none
+*   Returns:
+*      none
+*****************************************************************/
+void MM4_SendStopCommand(P_SDMMC_Properties_T pSDMMCP)
+{
+	if(pSDMMCP->State == READ)
+	{
+ 		// Send a CMD 12 to stop transmissions.
+		MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD12, MM4_CMD_TYPE_NORMAL, NULL, MM4_RT_R1 | MM4_48_RES);	// fixme: r1 for read, r1b for write.
+		MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+	}
+	if(pSDMMCP->State == WRITE)
+	{
+ 		// Send a CMD 12 to stop transmissions.
+		MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD12, MM4_CMD_TYPE_NORMAL, NULL, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);	// fixme: r1 for read, r1b for write.
+		MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, MMC_RESPONSE_R1B_TIMEOUT);
+	}
+}
+
+/****************************************************************
+*   MM4_ISR
+*      	Interrupt Service Routine for SDMMC controller
+*		Controls flow and catches faults asynchronously
+*   Input:
+*	   P_SDMMC_Properties_T pSDMMCP
+*   Output:
+*      none
+*   Returns:
+*      none
+*****************************************************************/
+void MM4_ISR(P_SDMMC_Properties_T pSDMMCP)
+{
+	UINT_T i;
+	UINT_T i_stat_copy;												// Keep a copy of i stat register
+	UINT_T i_err_stat;												// contains only error status bits.
+	UINT_T i_acmd12_err_stat;
+	P_MM4_I_STAT  p_i_stat_copy;										// Pointer to the copy.
+	UINT_T	cmderror = 0;
+	UINT_T	resptype;
+	P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;		// Assign our context value
+	UINT_T  r1_resp_error_bits = 0xfdffc080;    // that strange mask is all possible error bits in the card stat field.
+
+   	// Assign required pointers to registers
+	VUINT_T *pmm4_resp0 = (VUINT_T *)(&pContext->pMMC4Reg->mm4_resp0);
+	VUINT_T *pmm4_acmd12_er = (VUINT_T *)(&pContext->pMMC4Reg->mm4_acmd12_er);
+	VUINT_T *pmm4_istat = (VUINT_T *)(&pContext->pMMC4Reg->mm4_i_stat);
+	VUINT_T *pmm4_sysaddr = (VUINT_T *)(&pContext->pMMC4Reg->mm4_sysaddr);
+	 
+	// Grab snapshot copies of i_stat
+	i_stat_copy = *(UINT_T *) (&pContext->pMMC4Reg->mm4_i_stat);		// Grab a single copy.
+	p_i_stat_copy = (P_MM4_I_STAT)&i_stat_copy;
+
+	// command response will send out anyway, no matter command completed or not
+	for (i = 0; i < 4; i++)
+		pSDMMCP->CardReponse.pBuffer[i] = pmm4_resp0[i];
+
+	// Check for any error
+	if( p_i_stat_copy->cmdcomp )
+	{
+		// if we're in strict error checking mode, and 		
+		// if the completing command has an R1 or R1B status, 
+		// look for any error bits in the card status field
+		if( pSDMMCP->StrictErrorCheck )
+		{
+			resptype = (pSDMMCP->Trans.RespType << 8) & MM4_RT_MASK;		// convert to a value more convenient for comparisons...
+			if( resptype == MM4_RT_R1 )
+			{
+				cmderror = (*pmm4_resp0 & r1_resp_error_bits );	// that strange mask is all possible error bits.
+			}
+		}
+		else cmderror = 0;	// don't examine error because not strict error checking mode or this is not an R1 type of command.
+	}
+
+	if (p_i_stat_copy->errint || cmderror )
+	{ 
+		// each error condition has its own handling/recovery requirements....
+		
+		// move the error bits down to a low halfword so the defines in sd.h 
+		// can be used. (they were based on 16 bit io access)
+		i_err_stat = i_stat_copy >> 16;
+		pSDMMCP->DeviceStatus = i_stat_copy;
+
+		// check & handle each error condition
+
+		// the following errors require an sd host controller reset:
+		if( ( i_err_stat & SD_ERROR_INT_STATUS_AXI_RESP_ERR     ) ||
+			( i_err_stat & SD_ERROR_INT_STATUS_DATA_TIMEOUT_ERR ) ||
+			( i_err_stat & SD_ERROR_INT_STATUS_CMD_TIMEOUT_ERR  ) ||
+			cmderror )
+		{
+			MMC4CMDSWReset(pContext);	// this cleas the command inhibit flag in sd_present_state_1.
+			MMC4DataSWReset(pContext);	// this clears the data inhibit flag and stops mclk.
+		}
+
+		// acmd 12 error requires examining a separate error status register:
+		else if( i_err_stat & SD_ERROR_INT_STATUS_AUTO_CMD12_ERR )
+		{
+			i_acmd12_err_stat = *pmm4_acmd12_er;
+
+			// any acmd12 error requires an sd host controller reset
+			// because there's no way to know if the command was processed.
+			MMC4CMDSWReset(pContext);	// this cleas the command inhibit flag in sd_present_state_1.
+			MMC4DataSWReset(pContext);	// this clears the data inhibit flag and stops mclk.
+
+			// clear the acmd12 error bits.
+			*pmm4_acmd12_er = i_acmd12_err_stat;
+		}
+
+		// clear the general error status bits
+		*pmm4_istat = i_stat_copy;
+		i = *pmm4_istat;				// Must make a dummy read to allow interrupts to clear.
+
+		// set a flag so the caller knows this request failed.
+		pSDMMCP->State = FAULT;
+
+		// done with handling an error condition.
+		// nothing more to do.
+		return;
+	}
+
+	// is this an sdma interrupt event?
+	if(*pmm4_istat & (1u<<3))	// bit 3 is dmaint
+	{
+		// the transfer halted because the boundary specified in ... was reached.
+		// rewriting the sysaddr with the next address allows the transfer to resume.
+		// fortunately the sysaddr register itself contains the next address.
+		// so, just re-write the sysaddr register with its own current contents.
+	    //Coverity -  10008: Self Assignment error - No Effect. 
+	    //This is OK. That's the way the hardware works!
+	    if (pSDMMCP->SDMMC_DMA_Mode == SDMA)
+	    {
+	    	i = *pmm4_sysaddr;
+		    *pmm4_sysaddr = i;	// sysaddr points to next addr to write.
+	    }
+
+		// for ADMA2, no ISR for per DMA transfer, when all data transfer complete, it will generate XFER_COMP ISR
+		if (pSDMMCP->SDMMC_DMA_Mode == ADMA2)
+			pSDMMCP->State = READY;
+
+		*pmm4_istat = (1u<<3);	// bit 3 is dmaint
+		i = *pmm4_istat;		// read-back to ensure write completes
+
+	}
+	// fall through the rest of the isr.
+	// end of dmaint handling.
+
+	// Has the Command completed? If so read the response register
+	if (p_i_stat_copy->cmdcomp)
+	{
+ 		// Indicate that the response has been read
+		pSDMMCP->CardReponse.CommandComplete = 1;
+	}
+
+	if (p_i_stat_copy->xfrcomp)
+	{
+ 		// Indicate that the response has been read
+		pSDMMCP->CardReponse.TransferComplete = 1;
+	}
+
+	// Are we DMA enabled?
+	if((pSDMMCP->SDMMC_DMA_Mode))
+	{
+		if (p_i_stat_copy->xfrcomp)
+	 		pSDMMCP->State = READY;
+ 	}
+
+	// Clear the interrupts
+	*pmm4_istat = i_stat_copy; 	// Clear the interrupt source.
+	i = *pmm4_istat;			// Must make a dummy read to allow interrupts to clear.
+
+	if(pSDMMCP->SDMMC_DMA_Mode == NODMA)
+	{
+		// Handle State based interrupts XFRCOMP, BUFRDRDY, BUFWRRDY
+		switch (pSDMMCP->State)
+		{
+			case WRITE:
+			{
+				if (p_i_stat_copy->bufwrrdy)
+					MM4_WriteFifo(pSDMMCP);
+
+				// Are we done sending all of data?
+				if (pSDMMCP->Trans.TransWordSize == pSDMMCP->Trans.WordIndex)
+					pSDMMCP->State = DATATRAN;
+
+				break;
+			}
+			case READ:
+			{
+				if (p_i_stat_copy->bufrdrdy)
+					MM4_ReadFifo(pSDMMCP);
+
+				// Are we done sending all of data?
+				if (pSDMMCP->Trans.TransWordSize == pSDMMCP->Trans.WordIndex)
+					pSDMMCP->State = DATATRAN;
+
+				break;
+			}
+			case DATATRAN:
+			{
+				// Wait for Transfer Complete Signal
+				if (p_i_stat_copy->xfrcomp)
+					pSDMMCP->State = READY;
+
+				break;
+			}
+			default:
+				break;
+		}
+	}
+	return;
+}
+
+/***************************************************************
+*   MM4_MMCReadEXTCSD
+* 	Reads in 512 bytes of Extended CSD 
+*   Input: Pointer to 512 byte buffer
+*   Output:
+*   Returns: NoError, ReadError or NotSupportedError
+*      
+*****************************************************************/
+UINT_T MM4_MMCReadEXTCSD (UINT_T *pBuffer)
+{
+	UINT_T Retval;
+	P_MM4_SDMMC_CONTEXT_T pContext;
+ 	P_MM4_CNTL1 pMM4_CNTL1;
+ 	P_MM4_BLK_CNTL pMM4_BLK_CNTL;
+	ADMA_DESCRIPTOR admaDesc;
+
+	// Initialize Flash Properties
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+	if (pSDMMCP->SD == XLLP_SD)
+		return NoError; 			// This is an MMC command only!
+
+	// Assign our context value
+	pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+	pMM4_CNTL1 = (P_MM4_CNTL1) &pContext->pMMC4Reg->mm4_cntl1;
+
+	// Set up State
+	pSDMMCP->State = READ;
+
+	// This requires a transfer over the data lines.
+	pMM4_BLK_CNTL = (P_MM4_BLK_CNTL) &pContext->pMMC4Reg->mm4_blk_cntl;
+	pMM4_BLK_CNTL->blk_cnt = 0;
+	if (pSDMMCP->SDMMC_DMA_Mode == SDMA)
+	{
+		pMM4_BLK_CNTL->dma_bufsz = MM4_512_HOST_DMA_BDRY;
+	    pContext->pMMC4Reg->mm4_sysaddr = (UINT_T) pBuffer;
+	} //MMC_SDMA_MODE
+	else if(pSDMMCP->SDMMC_DMA_Mode == ADMA2)
+	{
+		 MM4_SetupADMADesc(&admaDesc, 
+					  	   VALID_DESC, 
+					  	   LAST_DESC,
+					  	   NO_DMA_INT, 
+					  	   TRANSFER, 
+					  	   1,//EXT_CSD is sent as a block of data 
+					  	   (UINT_T)pBuffer);
+        pMM4_CNTL1->dma_sel = 2;  //ADMA2
+	   //Set the ADMA register to the address of descriptor table
+        pContext->pMMC4Reg->mm4_adma_system_address1 = (UINT_T)&admaDesc;	
+	}
+	pSDMMCP->Trans.StartDiscardWords = 0;
+	pSDMMCP->Trans.EndDiscardWords = 0;								// We'll take all 512 bytes
+	pSDMMCP->Trans.TransWordSize = pSDMMCP->ReadBlockSize / 4; 		// Total Transfer Size including pre and post bytes
+	pSDMMCP->Trans.LocalAddr = (UINT_T) pBuffer;
+	pSDMMCP->Trans.WordIndex = 0;									// Stores Index of Current write position
+
+	MM4_SendDataCommandNoAuto12(pSDMMCP, XLLP_MMC_CMD8, NO_ARGUMENT, MM4_SINGLE_BLOCK_TRAN, MM4_CARD_TO_HOST_DATA, MM4_RT_R1 | MM4_48_RES);
+
+	// Wait for the Write to Complete
+	while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));
+
+	if( pSDMMCP->State == FAULT )	// This state entered if ISR detected an error.
+	{
+		return SDMMCReadError;
+	}
+
+	//send CMD13 to check the status of the card
+	Retval |= MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK);		// Make sure card is transfer mode
+
+	pSDMMCP->State = READY;
+
+	if (Retval != NoError)
+		return SDMMC_SWITCH_ERROR;
+
+	return NoError;
+}
+
+/***********************************************************
+*    MM4_SetupADMADesc()
+*       Function to setup ADMA descriptor i.e; fills the descriptor contents
+*    input:
+*		P_ADMA_DESCRIPTOR -> Address of the ADMA descriptor
+*		DESC_VAL_INVAL    -> Indicates whether the descriptor is valid or not
+*		END_DESC		  -> Indicates if the current descriptor is the last of the chain
+*		ATTRIBUTES		  -> Indicates the type of descriptor whether it is transfer type or link type
+*		NumBlocks 		  -> Number of blocks that are transferred by this descriptor
+*		Address			  -> Destination address if the descriptor is of type transfer or the descriptor
+*							 it is linked to if it is of type link
+*    output:
+*       Fills the input descriptor
+*    returns:
+*       none
+************************************************************/
+void MM4_SetupADMADesc(P_ADMA_DESCRIPTOR pAdmaDesc,
+						 DESC_VAL_INVAL ValidDesc,
+						 END_DESC EndDesc,
+						 DMA_INT_EN DmaInterrupt,
+						 ATTRIBUTES Attributes,
+						 UINT_T NumBlocks,
+						 UINT_T Address)
+{
+	// Initialize Flash Properties
+	P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+	memset(pAdmaDesc,0, sizeof(ADMA_DESCRIPTOR));
+	pAdmaDesc->Address         =  Address;
+	pAdmaDesc->Length          =  NumBlocks * pSDMMCP->ReadBlockSize;
+	pAdmaDesc->Rsvd            =  0;
+	pAdmaDesc->attr            =  Attributes;
+	pAdmaDesc->Rsvd0           =  0;  	
+	pAdmaDesc->dma_int_en      =  DmaInterrupt;
+	pAdmaDesc->end_desc        =  EndDesc; 
+	pAdmaDesc->desc_val_inval  =  ValidDesc; 
+	return;
+}