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;
+}
diff --git a/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.h b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.h
new file mode 100644
index 0000000..44eeffe
--- /dev/null
+++ b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.h
@@ -0,0 +1,103 @@
+/******************************************************************************
+ *
+ *  (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.
+ *
+******************************************************************************/
+
+#ifndef __SDHC2_H__
+#define __SDHC2_H__
+
+#include "misc.h"
+#include "sdhc2_controller.h"
+#include "SD.h"
+
+#define UNSTUFF_BITS(resp,start,size)					\
+	({								\
+		const int __size = size;				\
+		const unsigned int __mask = (__size < 32 ? 1 << __size : 0) - 1;	\
+		const int __off = 3 - ((start) / 32);			\
+		const int __shft = (start) & 31;			\
+		unsigned int __res;						\
+									\
+		__res = resp[__off] >> __shft;				\
+		if (__size + __shft > 32)				\
+			__res |= resp[__off-1] << ((32 - __shft) % 32);	\
+		__res & __mask;						\
+	})
+
+// Prototypes
+UINT_T MM4_CardInit(UINT_T BaseAddress, UINT_T InterruptMask);
+
+// Helper / Internal
+UINT MM4_IDCard(P_SDMMC_Properties_T pSDMMCP, UINT_T *pControllerVoltage);
+UINT_T MM4SetBusWidth(UINT8_T value);
+UINT_T MM4HighSpeedTiming(void);
+UINT_T MM4_MMCReadEXTCSD (UINT_T *pBuffer);
+UINT_T MM4_CheckVoltageCompatibility(P_SDMMC_Properties_T pSDMMCP, UINT_T ControllerVoltage);
+UINT_T MM4_SetControllerVoltage (P_MM4_SDMMC_CONTEXT_T pContext);
+UINT_T MM4_CheckCardStatus(P_SDMMC_Properties_T pSDMMCP, UINT_T R1_Resp_Match, UINT_T Mask);
+UINT_T MM4_Interpret_Response(P_SDMMC_Properties_T pSDMMCP, UINT_T ResponseType, UINT_T ResponseTimeOut);
+void MM4_PrepareMMCContext (P_SDMMC_Properties_T pSDMMCP, UINT_T BaseAddress);
+UINT_T MM4_SelectSlot(UINT_T slot);
+void MM4_ISR(P_SDMMC_Properties_T pSDMMCP);
+void MM4_SendDataCommand (P_SDMMC_Properties_T pSDMMCP,
+                  UINT_T Cmd,
+                  UINT_T  Argument,
+                  UINT_T BlockType,
+                  UINT_T DataDirection,
+                  UINT_T  ResType);
+
+void MM4_SendDataCommandNoAuto12 (P_SDMMC_Properties_T pSDMMCP,
+                  UINT_T Cmd,
+                  UINT_T Argument,
+                  UINT_T BlockType,
+                  UINT_T DataDirection,
+                  UINT_T ResType);
+
+void MM4_SendSetupCommand(P_SDMMC_Properties_T pSDMMCP,
+                  UINT_T Cmd,
+                  UINT_T CmdType,
+                  UINT_T Argument,
+                  UINT_T ResType);
+
+UINT_T MM4_MMCAlternateBootMode(UINT_T BaseAddress, UINT_T InterruptMask);
+UINT_T MM4_MMCAlternateBootModeReadTIM(void);
+UINT_T MM4_MMCAlternateBootModeReadResume(void);
+UINT_T MM4_MMCAlternateBootFinalize(void);
+
+void MM4_SetupADMADesc(P_ADMA_DESCRIPTOR pAdmaDesc,
+						 DESC_VAL_INVAL ValidDesc,
+						 END_DESC EndDesc,
+						 DMA_INT_EN DmaInterrupt,
+						 ATTRIBUTES Attributes,
+						 UINT_T Length,
+						 UINT_T Address);
+
+UINT_T MM4_ReadBlocks(void);
+UINT_T MM4_WriteBlocks(void);
+UINT_T MM4_EraseBlocks(void);
+UINT_T MM4_CardShutdown(void);
+void MM4_WriteFifo(P_SDMMC_Properties_T pSDMMCP);
+void MM4_ReadFifo(P_SDMMC_Properties_T pSDMMCP);
+void MM4_SendStopCommand(P_SDMMC_Properties_T pSDMMCP);
+UINT_T MM4SwitchPartition(UINT_T PartitionNumber);
+UINT_T MM4_WaitForOperationComplete(UINT_T TimeOutMillisec );
+void MMCClocks(	int Clks, unsigned int nCmdState_period, GPIO_CFG_T *pMMCClkCfg, GPIO_CFG_T *pMMCCmdCfg	);
+UINT_T MM4_TestBus_SetBusWidth(void);
+UINT_T MM4_SendReceive_TestPattern(UINT_T *pOutput, UINT_T Length);
+
+#endif
+
diff --git a/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.c b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.c
new file mode 100644
index 0000000..860a42e
--- /dev/null
+++ b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.c
@@ -0,0 +1,685 @@
+/******************************************************************************
+ *
+ *  (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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+**
+**  FILENAME:       sdhc_controller.c
+**
+**  PURPOSE: MMC and SD specific low level controller routines for the MM4 controller
+**
+**
+**
+**
+******************************************************************************/
+#include "sdhc2_controller.h"
+#include "misc.h"
+#include "Errors.h"
+#include "timer.h"
+
+void MMC4Gen74Clocks(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+	P_MM4_SD_LEGACY_CTRL_REG pMM4_SD_LEGACY_CTRL_REG;
+	P_MM4_CTRL_REG pP_MM4_CTRL_REG;
+	UINT_T startTime, endTime;
+	UINT_T retval = NoError;
+
+	pMM4_SD_LEGACY_CTRL_REG = (P_MM4_SD_LEGACY_CTRL_REG)&pContext->pMMC4Reg->mm4_legacy_ctrl_reg;
+	pP_MM4_CTRL_REG = (P_MM4_CTRL_REG)&pContext->pMMC4Reg->mm4_mmc_ctrl_reg;
+
+	// Enable capturing status for sending out 74 clock cycles.
+	pP_MM4_CTRL_REG->misc_int_en = 1;
+	pP_MM4_CTRL_REG->misc_int = 1;
+
+	// Enable and start 74 clock cycles
+	pMM4_SD_LEGACY_CTRL_REG->gen_pad_clk_cnt = 74;		// 74 clock cycles.
+	pMM4_SD_LEGACY_CTRL_REG->gen_pad_clk_on = 1;			// Start generating the clocks.
+
+	// Wait for the 74 clock cycles to be generated.	
+	startTime = GetOSCR0();
+  	startTime = GetOSCR0();
+  	do
+  	{
+		if (pP_MM4_CTRL_REG->misc_int)
+			break;		  // 74 clock cycles have been generated.
+
+		endTime = GetOSCR0();
+
+		if (OSCR0IntervalInMilli(startTime, endTime) >= 10)
+			return SDMMCInitializationError;
+  	}while(1);
+
+	return retval;
+}
+
+/******************************************************************************
+  Description:
+    Start MMC/SD Internal bus clock.  MUST be done to start MM4CLK!
+    Only after starting bus clock, communication between
+    controller and card is possible
+  Input Parameters:
+    pContext--Pointer to MMC context structure
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MMC4StartInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+  P_MM4_CNTL2 pMM4_CNTL2;
+  MM4_CNTL2_UNION MM4_cntl2;
+
+  pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+  MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+  MM4_cntl2.mm4_cntl2_bits.inter_clk_en = 1;
+  *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+
+  // Wait for clock to become stable. * TBD * Add timeout
+  do
+  {
+  	MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+  } while (!(MM4_cntl2.mm4_cntl2_bits.inter_clk_stable));
+
+  return;
+}
+
+/******************************************************************************
+  Description:
+    Stops the MMC/SD Internal bus clock.
+  Input Parameters:
+    pContext--Pointer to MMC context structure
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MMC4StopInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+  P_MM4_CNTL2 pMM4_CNTL2;
+  MM4_CNTL2_UNION MM4_cntl2;
+
+  pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+  MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+  MM4_cntl2.mm4_cntl2_bits.inter_clk_en = 0;
+  *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+
+  // Wait for clock to become stable. * TBD * Add timeout
+  do
+  {
+  	MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+  } while (MM4_cntl2.mm4_cntl2_bits.inter_clk_stable);
+
+  return;
+}
+
+
+/******************************************************************************
+  Description:
+    Start MMC bus clock. Only after starting bus clock, communication between
+    controller and card is possible
+  Input Parameters:
+    pContext--Pointer to MMC context structure
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MMC4StartBusClock(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+  P_MM4_CNTL2 pMM4_CNTL2;
+  MM4_CNTL2_UNION MM4_cntl2;
+
+  pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+  MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+  MM4_cntl2.mm4_cntl2_bits.mm4clken = 1;
+
+  *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+  return;
+}
+
+/******************************************************************************
+  Description:
+    Stops MMC bus clock.
+  Input Parameters:
+    pContext--Pointer to MMC context structure
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MMC4StopBusClock (P_MM4_SDMMC_CONTEXT_T pContext)
+{
+  P_MM4_CNTL2 pMM4_CNTL2;
+  MM4_CNTL2_UNION MM4_cntl2;
+
+  // Request bus clock stop
+  pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+  MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+  MM4_cntl2.mm4_cntl2_bits.mm4clken = 0;
+  *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+
+  return;
+}
+
+/******************************************************************************
+  Description:
+    Set a new MMC bus clock rate. This function stops and resumes bus clock.
+  Input Parameters:
+    pContext
+      Pointer to MMC context structure
+    rate
+      bus clock speed
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MMC4SetBusRate(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T rate)
+{
+  P_MM4_CNTL2 pMM4_CNTL2;
+  MM4_CNTL2_UNION MM4_cntl2;
+
+  // Request bus clock stop, set rate, start clock.
+  MMC4StopBusClock (pContext);
+  pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+  MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+
+  // Update the rate and start the clock.
+  MM4_cntl2.mm4_cntl2_bits.sd_freq_sel_lo = (rate & 0xFF);
+  MM4_cntl2.mm4_cntl2_bits.sd_freq_sel_hi = ((rate >> 8) & 3);
+  MM4_cntl2.mm4_cntl2_bits.mm4clken = 1;
+  *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+
+  // Make sure internal bus clock also enabled.
+  MMC4StartInternalBusClock(pContext);
+
+  return;
+}
+
+void MMC4SelectUHSMode(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T mode)
+{
+	UINT8_T ctrl = 0;
+	P_MM4_HOST_CNTL2_UNION pMM4_host_CNTL2;
+	MM4_HOST_CNTL2_UNION MM4_host_cntl2;
+
+	MMC4StopBusClock (pContext);
+
+	pMM4_host_CNTL2 = (P_MM4_HOST_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_acmd12_er);
+	MM4_host_cntl2.mm4_host_cntl2_value = *(VUINT_T *)pMM4_host_CNTL2;
+
+	if (mode & SDH_BUS_SPEED_SDR_CLK_208M) {
+		ctrl |= 0x03;
+	} else if (mode & SDH_BUS_SPEED_SDR_CLK_100M) {
+		ctrl |= 0x02;
+	} else if (mode & SDH_BUS_SPEED_DDR_CLK_50M) {
+		ctrl |= 0x04;
+	} else if (mode & SDH_BUS_SPEED_SDR_CLK_50M) {
+		ctrl |= 0x01;
+	} else if (mode & SDH_BUS_SPEED_DEFAULT) {
+		ctrl |= 0x00;
+	}
+
+	MM4_host_cntl2.mm4_host_cntl2_bits.uhs_mode_sel = ctrl;
+	*(VUINT_T *)pMM4_host_CNTL2 = MM4_host_cntl2.mm4_host_cntl2_value;
+
+	MMC4StartBusClock(pContext);
+
+	return;
+}
+
+void MMC4SetTXIntCLKSet(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T mode1, UINT_T mode2)
+{
+	P_MM4_TX_CFG  pMM4_TX_CFG;
+
+	pMM4_TX_CFG	 =	(P_MM4_TX_CFG)&pContext->pMMC4Reg->mm4_sd_tx_cfg_reg;
+	
+	//set the tx_int_clk_sel that makes the Tih dependant on bus clock rather than base clock
+	pMM4_TX_CFG->tx_int_clk = mode1;
+	pMM4_TX_CFG->tx_mux_sel = mode2;
+}
+
+void MMC4SetRXConfig(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+	UINT_T value = 0;
+	P_MM4_RX_CFG_UNION  pMM4_RX_CFG_UNION;
+	P_MM4_SD_DLINE_CTRL p_MM4_SD_DLINE_CTRL;
+	P_MM4_SD_DLINE_CFG p_MM4_SD_DLINE_CFG;
+
+	pMM4_RX_CFG_UNION	 =	(P_MM4_RX_CFG)&pContext->pMMC4Reg->mm4_sd_rx_cfg_reg;
+	p_MM4_SD_DLINE_CTRL = (P_MM4_SD_DLINE_CTRL)&pContext->pMMC4Reg->mm4_sd_dline_ctrl_reg;
+	p_MM4_SD_DLINE_CFG = (P_MM4_SD_DLINE_CFG)&pContext->pMMC4Reg->mm4_sd_dline_cfg_reg;
+
+	value = pMM4_RX_CFG_UNION->MM4_RX_CFG_value;
+	value &= ~(RX_SDCLK_SEL1_MASK << RX_SDCLK_SEL1_SHIFT);
+	/* clock by SDCLK_SEL0, so it is default setting */
+	value |= 0x1 << RX_SDCLK_SEL1_SHIFT;
+	*(VUINT_T *)pMM4_RX_CFG_UNION = value;
+
+	p_MM4_SD_DLINE_CFG->rx_dline_reg = 0x0;
+	p_MM4_SD_DLINE_CTRL->rx_dline_code = DDR_RX_DELAY;
+	p_MM4_SD_DLINE_CTRL->dline_pu = 1;
+}
+
+void MMC4SetTXConfig(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+	UINT_T value = 0;
+	UINT_T tx_delay = DDR_TX_DELAY;
+	P_MM4_TX_CFG_UNION  pMM4_TX_CFG_UNION;
+	P_MM4_SD_DLINE_CTRL p_MM4_SD_DLINE_CTRL;
+	P_MM4_SD_DLINE_CFG p_MM4_SD_DLINE_CFG;
+
+	pMM4_TX_CFG_UNION	 =	(P_MM4_TX_CFG)&pContext->pMMC4Reg->mm4_sd_tx_cfg_reg;
+	p_MM4_SD_DLINE_CTRL = (P_MM4_SD_DLINE_CTRL)&pContext->pMMC4Reg->mm4_sd_dline_ctrl_reg;
+	p_MM4_SD_DLINE_CFG = (P_MM4_SD_DLINE_CFG)&pContext->pMMC4Reg->mm4_sd_dline_cfg_reg;
+
+	value = pMM4_TX_CFG_UNION->MM4_TX_CFG_value;
+	if (tx_delay)
+	{
+		value &= ~TX_SEL_BUS_CLK; 	//clr bit 30
+		value |= TX_MUX_SEL;		//set bit 31 select DDLL
+	}
+
+	*(VUINT_T *)pMM4_TX_CFG_UNION = value;
+	p_MM4_SD_DLINE_CFG->tx_dline_reg = 0x0;
+	p_MM4_SD_DLINE_CTRL->tx_dline_code = tx_delay & TX_DELAY_MASK;
+	p_MM4_SD_DLINE_CTRL->dline_pu = 1;
+}
+
+/******************************************************************************
+  Description:
+    This routine unmasks and enables or masks and disables required interrupts
+    needed by the driver
+    Input Parameters:
+    	pContext
+      		Pointer to MMC context structure
+			Desire - Enable or Disable the interrupts
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MMC4EnableDisableIntSources(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T Desire)
+{
+  P_MM4_I_STAT pMM4_I_STAT;
+  MM4_I_STAT_UNION MM4_i_stat;
+
+  // Capture existing Value
+  pMM4_I_STAT = (P_MM4_I_STAT)((VUINT32_T) &pContext->pMMC4Reg->mm4_i_sig_en);
+
+  MM4_i_stat.mm4_i_stat_value = *(VUINT_T*)pMM4_I_STAT;
+  // Route the interrupt signal enable register
+  MM4_i_stat.mm4_i_stat_bits.cmdcomp = Desire;
+  MM4_i_stat.mm4_i_stat_bits.xfrcomp = Desire;
+  MM4_i_stat.mm4_i_stat_bits.dmaint = Desire;
+  MM4_i_stat.mm4_i_stat_bits.bufwrrdy = Desire;
+  MM4_i_stat.mm4_i_stat_bits.bufrdrdy = Desire;
+  MM4_i_stat.mm4_i_stat_bits.errint = Desire;
+  MM4_i_stat.mm4_i_stat_bits.ctoerr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.cenderr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.dtoerr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.dcrcerr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.denderr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.admaerr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.crc_stat_err = Desire;
+
+  // Write it out
+  *(VUINT_T*)pMM4_I_STAT = MM4_i_stat.mm4_i_stat_value;
+
+  // Now remove the masks
+  pMM4_I_STAT = (P_MM4_I_STAT)((VUINT32_T) &pContext->pMMC4Reg->mm4_i_stat_en);
+  MM4_i_stat.mm4_i_stat_value = *(VUINT_T*)pMM4_I_STAT;
+  MM4_i_stat.mm4_i_stat_bits.cmdcomp = Desire;
+  MM4_i_stat.mm4_i_stat_bits.xfrcomp = Desire;
+  MM4_i_stat.mm4_i_stat_bits.dmaint = Desire;
+  MM4_i_stat.mm4_i_stat_bits.bufwrrdy = Desire;
+  MM4_i_stat.mm4_i_stat_bits.bufrdrdy = Desire;
+  MM4_i_stat.mm4_i_stat_bits.errint = Desire;
+  MM4_i_stat.mm4_i_stat_bits.ctoerr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.cenderr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.dtoerr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.dcrcerr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.denderr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.admaerr = Desire;
+  MM4_i_stat.mm4_i_stat_bits.crc_stat_err = Desire;
+
+  // Write it out
+  *(VUINT_T*)pMM4_I_STAT = MM4_i_stat.mm4_i_stat_value;
+
+  return;
+}
+
+/******************************************************************************
+  Description:
+    Set the data response timeout value.
+  Input Parameters:
+    pContext
+      Pointer to MMC context structure
+    CounterValue
+      the value which will be written into DTOCNTR
+  Output Parameters:
+    None
+  Returns:
+    None  
+*******************************************************************************/
+void MMC4SetDataTimeout(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T CounterValue)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ // Set the register
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.dtocntr = CounterValue;
+
+ // Write Back
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+ return;
+}
+
+/******************************************************************************
+  Description:
+    This function will induce a software reset of all MMC4 data lines
+  Input Parameters:
+    pContext
+      Pointer to MMC context structure
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MMC4CMDSWReset(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ // Set the register
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.cmdswrst = 1;
+
+ // Write Back
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+ return;
+}
+
+/******************************************************************************
+  Description:
+    This function will induce a software reset of all MMC4 data lines
+  Input Parameters:
+    pContext
+      Pointer to MMC context structure
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MMC4DataSWReset(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ // Set the register
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.datswrst = 1;
+
+ // Write Back
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+ return;
+}
+
+/******************************************************************************
+  Description:
+    This function will induce a full software reset of all MMC4 components except
+	MM4_CAPX
+  Input Parameters:
+    pContext
+      Pointer to MMC context structure
+  Output Parameters:
+    None
+  Returns:
+    None
+*******************************************************************************/
+void MMC4FullSWReset(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ // Set the register
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.mswrst = 1;
+
+ // Write Back
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+ return;
+}
+
+/******************************************************************************
+  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:
+    pContext
+      	Pointer to MMC context 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 MMC4SendDataCommand(P_MM4_SDMMC_CONTEXT_T pContext,
+                  UINT_T Cmd,
+                  UINT_T  Argument,
+                  UINT_T BlockType,
+                  UINT_T DataDirection,
+                  UINT_T ResType, 
+                  UINT_T DMAMode,
+                  UINT_T AutoCmd23En)
+{
+ MM4_CMD_XFRMD_UNION xfrmd;
+ P_MM4_STATE pMM4_STATE;
+ MM4_STATE_UNION MM4_state;
+
+ // Make sure the controller is ready to accept the next command
+ pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state;
+ MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+  
+ do
+  {
+  	MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+  } while (MM4_state.mm4_state_bits.dcmdinhbt);
+
+ // Set the Argument Field
+ pContext->pMMC4Reg->mm4_arg = Argument;
+
+ // Set the Data Transfer Command fields.
+ xfrmd.mm4_cmd_xfrmd_value = 0;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_idx = Cmd;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_type = MM4_CMD_TYPE_NORMAL;
+ xfrmd.mm4_cmd_xfrmd_bits.dpsel = MM4_CMD_DATA;
+// xfrmd.mm4_cmd_xfrmd_bits.idxchken = TRUE;
+// xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE;
+ xfrmd.mm4_cmd_xfrmd_bits.res_type = ResType;
+ xfrmd.mm4_cmd_xfrmd_bits.ms_blksel = BlockType;
+ xfrmd.mm4_cmd_xfrmd_bits.dxfrdir = DataDirection;
+ 
+ //if SDMA/ADMA2
+ if (DMAMode)
+	xfrmd.mm4_cmd_xfrmd_bits.dma_en = TRUE;
+ //CMD23 -> Lets the card know about number of blocks to transfer for the upcoming read/write transaction 
+ //AutoCMD23 should be sent prior to CMD18 or CMD25 if ADMA2 is used and BLK_CNT is disabled for ADMA2
+  //Since AutoCMD23 is sent, AutoCMD12 is not required
+ if(AutoCmd23En)
+ {
+	xfrmd.mm4_cmd_xfrmd_bits.autocmd23 = TRUE;
+	xfrmd.mm4_cmd_xfrmd_bits.blkcnten  = TRUE; // block counter is a better choice than send stop command
+ }
+ else
+ {
+	//For PIO and SDMA mode
+ 	xfrmd.mm4_cmd_xfrmd_bits.autocmd12 = TRUE;
+    xfrmd.mm4_cmd_xfrmd_bits.blkcnten  = TRUE;
+ }
+
+ // Kick off the command
+ pContext->pMMC4Reg->mm4_cmd_xfrmd = xfrmd.mm4_cmd_xfrmd_value;
+
+ return;
+}
+
+
+/******************************************************************************
+  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:
+    pContext
+      	Pointer to MMC context 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 MMC4SendDataCommandNoAuto12(P_MM4_SDMMC_CONTEXT_T pContext,
+                  UINT_T Cmd,
+                  UINT_T  Argument,
+                  UINT_T BlockType,
+                  UINT_T DataDirection,
+                  UINT_T ResType, 
+                  UINT_T DMAMode,
+                  UINT_T Blk_Cnt_Enable)
+{
+ MM4_CMD_XFRMD_UNION xfrmd;
+ P_MM4_STATE pMM4_STATE;
+ MM4_STATE_UNION MM4_state;
+
+ // Make sure the controller is ready to accept the next command
+ pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state;
+ MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+  
+ do
+  {
+  	MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+  } while (MM4_state.mm4_state_bits.dcmdinhbt);
+ // Set the Argument Field
+ pContext->pMMC4Reg->mm4_arg = Argument;
+
+ // Set the Data Transfer Command fields.
+ xfrmd.mm4_cmd_xfrmd_value = 0;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_idx = Cmd;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_type = MM4_CMD_TYPE_NORMAL;
+ xfrmd.mm4_cmd_xfrmd_bits.dpsel = MM4_CMD_DATA;
+// xfrmd.mm4_cmd_xfrmd_bits.idxchken = TRUE;
+// xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE;
+ xfrmd.mm4_cmd_xfrmd_bits.res_type = ResType;
+ xfrmd.mm4_cmd_xfrmd_bits.ms_blksel = BlockType;
+ xfrmd.mm4_cmd_xfrmd_bits.dxfrdir = DataDirection;
+ xfrmd.mm4_cmd_xfrmd_bits.autocmd12 = FALSE;
+
+ if (DMAMode)
+	xfrmd.mm4_cmd_xfrmd_bits.dma_en = TRUE;
+
+ if(Blk_Cnt_Enable)	//Blk_Cnt is not enabled for ADMA2
+	xfrmd.mm4_cmd_xfrmd_bits.blkcnten = TRUE;
+
+ // Kick off the command
+ pContext->pMMC4Reg->mm4_cmd_xfrmd = xfrmd.mm4_cmd_xfrmd_value;
+ return;
+}
+
+/******************************************************************************
+  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:
+    pContext
+      	Pointer to MMC context 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 MMC4SendSetupCommand(P_MM4_SDMMC_CONTEXT_T pContext,
+                  UINT_T Cmd,
+                  UINT_T CmdType,
+                  UINT_T Argument,
+                  UINT_T ResType)
+{
+ MM4_CMD_XFRMD_UNION xfrmd;
+ P_MM4_STATE pMM4_STATE;
+ MM4_STATE_UNION MM4_state;
+ UINT_T startTime, endTime;
+
+ startTime = GetOSCR0();  // get the start time
+ startTime = GetOSCR0();  // get the start time
+ endTime = startTime;
+
+ // Make sure the controller is ready to accept the next command
+ pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state;
+ MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+
+ do
+ {
+       endTime = GetOSCR0();
+
+       if (OSCR0IntervalInMilli(startTime, endTime) > 200)
+              return;	// Let the getresponse routine catch the error
+
+  	MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+  } while (MM4_state.mm4_state_bits.ccmdinhbt);
+
+ // Set the Argument Field
+ pContext->pMMC4Reg->mm4_arg = Argument;
+
+ // Set the Data Transfer Command fields.
+ xfrmd.mm4_cmd_xfrmd_value = 0;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_idx = Cmd;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_type = CmdType;
+// xfrmd.mm4_cmd_xfrmd_bits.idxchken = TRUE;
+ xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE;
+ xfrmd.mm4_cmd_xfrmd_bits.res_type = ResType;
+
+ // Kick off the command
+ pContext->pMMC4Reg->mm4_cmd_xfrmd = xfrmd.mm4_cmd_xfrmd_value;
+ return;
+}
diff --git a/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.h b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.h
new file mode 100644
index 0000000..7a40eac
--- /dev/null
+++ b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.h
@@ -0,0 +1,661 @@
+/******************************************************************************
+ *
+ *  (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.
+ *
+ ******************************************************************************/
+
+
+#ifndef __SDHC2_CONTROLLER_H
+#define __SDHC2_CONTROLLER_H
+
+#include "Typedef.h"
+
+// MMC controller registers definition
+typedef struct 
+{
+  VUINT32_T mm4_sysaddr;                  		// DMA system address				 		0x0
+  VUINT32_T mm4_blk_cntl;                       // Block size control register		 		0x4
+  VUINT32_T mm4_arg;                      		// Command argument					 		0x8
+  VUINT32_T mm4_cmd_xfrmd;                      // Command and transfer mode		 		0xC
+  VUINT32_T mm4_resp0;                          // cmd response 0					 		0x10
+  VUINT32_T mm4_resp1;                          // cmd response 1					 		0x14
+  VUINT32_T mm4_resp2;                          // cmd response 2					 		0x18
+  VUINT32_T mm4_resp3;                          // cmd response 3					 		0x1C
+  VUINT32_T mm4_dp;                             // buffer data port					 		0x20
+  VUINT32_T mm4_state;                          // mm4 state						 		0x24
+  VUINT32_T mm4_cntl1;                          // host control 1					 		0x28
+  VUINT32_T mm4_cntl2;                          // host control 2					 		0x2C
+  VUINT32_T mm4_i_stat;                         // status of current command 		 		0x30
+  VUINT32_T mm4_i_stat_en;                      // interrupt status enable			 		0x34
+  VUINT32_T mm4_i_sig_en;                       // interrupt signal enable			 		0x38
+  VUINT32_T mm4_acmd12_er;                      // auto cmd12 error status			 		0x3C
+  VUINT32_T mm4_cap1_2;                         // capabilities 1,2					 		0x40
+  VUINT32_T mm4_cap3_4;                         // capabilities 3,4							0x44
+  VUINT32_T mm4_sd_max_current1_2;              // max current capabilities					0x48
+  VUINT32_T mm4_sd_max_current3_4;              // max current capabilities					0x4C
+  VUINT32_T mm4_force_event;              		// force event for AutoCMD12 Error Status	0x50
+  VUINT32_T mm4_adma_err_stat;                  // ADMA Error Status						0x54
+  VUINT32_T mm4_adma_system_address1;       	// ADMA Address 63:32						0x58
+  VUINT32_T mm4_adma_system_address2;			// ADMA Address 32:0
+  VUINT32_T mm4_preset_value_for_init_ds; 		//											0x60
+  VUINT32_T mm4_preset_value_for_hs_sdr12;		//											0x64  
+  VUINT32_T mm4_preset_value_for_hs_sdr25_50;	//											0x68  
+  VUINT32_T mm4_preset_value_for_hs_sdr104_50;	//											0x6C  
+  VUINT32_T reserved_X1[28];                    // reserved fields							0x70
+  VUINT32_T mm4_shared_bus_control;        		// Shared Bus Control Register				0xE0
+  VUINT32_T reserved_X2[6];                   	// reserved									0xE4
+  VUINT32_T mm4_sd_slot_int_stat_ctrl_ver;      // SD Interrupt Line and Version Support	0xFC
+  VUINT32_T mm4_vid_pid;                // SD HOST CTRL Vendor ID/Project ID/version ID Register 0x100
+  VUINT32_T mm4_op_ctrl;                // SDHC Opeartion Control register			0x104
+  VUINT32_T mm4_op_ext_reg;                // SDHC Operation extend CTRL Register			0x108
+  VUINT32_T mm4_legacy_ctrl_reg;					// SDHC LEGACY CTRL Parameters Register			0x10C
+  VUINT32_T mm4_legacy_ceata_reg;				// SDHC LEGACY CTRL for CEATA Device Register	0x110
+  VUINT32_T mm4_mmc_ctrl_reg;					// SDHC MMC DEVICE CTRL Registers					0x114
+  VUINT32_T mm4_sd_rx_cfg_reg;					// Receive Timing Config					0x118
+  VUINT32_T mm4_sd_tx_cfg_reg;					// Transmit Timing Config					0x11C
+  VUINT32_T mm4_sd_hwtune_cfg_reg;				// SDHC HW TUNING Configuration Register	0x120
+  VUINT32_T mm4_sd_hwtune_cfg2_reg;				// SDHC HW TUNING Configuration2 Register	0x124
+  VUINT32_T mm4_sd_roundtrip_timing_reg;	// SDHC ROUND TRIP(TRANSIMIT TO RECEIVE) TIMING PARAM Regsiter	0x128
+  VUINT32_T mm4_sd_gpio_cfg_reg;				// SDHC GPIO CFG Register				0x12C
+  VUINT32_T mm4_sd_dline_ctrl_reg;				// SDHC DELAYLINE Control Register	0x130
+  VUINT32_T mm4_sd_dline_cfg_reg;				// SDHC DELAYLINE CFG Register	0x134
+} MM4_SDMMC_T, *P_MM4_SDMMC_T;
+
+/*************************** Register Masks ********************************/
+/**************************************************************************/
+// ******************** MM4_BLK_CNTL **********************************
+typedef struct
+{
+ unsigned int xfr_blksz       : 12;       // Transfer Block Size
+ unsigned int dma_bufsz       : 4;        // Host DMA buffer size
+ unsigned int blk_cnt         : 16;       // Block Count for Current Transfer
+} MM4_BLK_CNTL, *P_MM4_BLK_CNTL;
+
+#define MM4_512_HOST_DMA_BDRY  0x7
+
+// ********************* MM4_CMD_XFRMD ********************************
+typedef struct
+{
+ unsigned int dma_en          : 1;        // DMA enable							0
+ unsigned int blkcnten        : 1;        // Block Count Enable					1
+ unsigned int autocmd12       : 1;        // AutoCMD12      					2
+ unsigned int autocmd23       : 1;        // AutoCMD23							3
+ unsigned int dxfrdir         : 1;        // Data Transfer Direction Select 	4
+ unsigned int ms_blksel       : 1;        // Multi Block Select					5
+ unsigned int reserved2       : 10;        //									6
+ unsigned int res_type        : 2;        // Response Type						16
+ unsigned int reserved3       : 1;  	  //									18
+ unsigned int crcchken        : 1;        // CRC check enable					19
+ unsigned int idxchken        : 1;        // Command Index Check Enable			20
+ unsigned int dpsel           : 1;        // Data present   select				21
+ unsigned int cmd_type        : 2;        // Cmd Type							22
+ unsigned int cmd_idx         : 6;        // Cmd Index							24
+ unsigned int reserved4       : 2;        //									30
+} MM4_CMD_XFRMD, *P_MM4_CMD_XFRMD;
+
+typedef union
+{
+	MM4_CMD_XFRMD mm4_cmd_xfrmd_bits;
+	UINT_T		  mm4_cmd_xfrmd_value;
+} MM4_CMD_XFRMD_UNION, *P_MM4_CMD_XFRMD_UNION; 
+
+#define NO_ARGUMENT					0x0
+#define MM4_CMD_TYPE_NORMAL 		0
+#define MM4_CMD_TYPE_SUSPEND  		1
+#define MM4_CMD_TYPE_RESUME 		2
+#define MM4_CMD_TYPE_ABORT 			3
+#define MM4_CMD_DATA 				1
+#define MM4_CMD_NODATA				0
+#define MM4_NO_RES					0
+#define MM4_136_RES					1
+#define MM4_48_RES					2
+#define MM4_48_RES_WITH_BUSY		3
+
+// this information will be included in the response type argument of relevant apis.
+// it will occupy bits 15:8 of the RespType parameter.
+#define MM4_RT_MASK					0x7f00
+#define MM4_RT_NONE					0x0000
+#define	MM4_RT_R1					0x0100
+#define	MM4_RT_R2					0x0200
+#define	MM4_RT_R3					0x0300
+#define	MM4_RT_R4					0x0400
+#define	MM4_RT_R5					0x0500
+#define	MM4_RT_R6					0x0600
+#define	MM4_RT_R7					0x0700		// sd card interface condition
+
+#define MM4_RT_BUSYMASK				0x8000
+#define MM4_RT_BUSY					0x8000
+
+
+#define MM4_MULTI_BLOCK_TRAN		1
+#define MM4_SINGLE_BLOCK_TRAN		0
+#define MM4_HOST_TO_CARD_DATA		0
+#define MM4_CARD_TO_HOST_DATA		1
+
+// ********************* MM4_STATE ********************************
+typedef struct
+{
+ unsigned int ccmdinhbt		: 1;
+ unsigned int dcmdinhbt		: 1;
+ unsigned int datactv		: 1;
+ unsigned int retuning_req	: 1;
+ unsigned int reserved0		: 4;
+ unsigned int wractv		: 1;
+ unsigned int rdactv		: 1;
+ unsigned int bufwren		: 1;
+ unsigned int bufrden		: 1;
+ unsigned int reserved1		: 4;
+ unsigned int cdinstd		: 1;
+ unsigned int cdstbl		: 1;
+ unsigned int cddetlvl		: 1;
+ unsigned int wpswlvl		: 1;
+ unsigned int lwrdatlvl		: 4;
+ unsigned int cmdlvl		: 1;
+ unsigned int uprdatlvl		: 4;
+ unsigned int reserved2		: 3;
+} MM4_STATE, *P_MM4_STATE;
+
+typedef union
+{
+	MM4_STATE     mm4_state_bits;
+	UINT_T		  mm4_state_value;
+} MM4_STATE_UNION, *P_MM4_STATE_UNION; 
+
+// ********************* MM4_CNTL1 ********************************
+typedef struct
+{
+ unsigned int ledcntl 		: 1;		// 0
+ unsigned int datawidth		: 1;		// 1
+ unsigned int hispeed		: 1;		// 2
+ unsigned int dma_sel		: 2;		// 3
+ unsigned int ex_data_width	: 1;		// 5
+ unsigned int card_det_l	: 1;		// 6
+ unsigned int card_det_s	: 1;		// 7
+ unsigned int buspwr		: 1;		// 8
+ unsigned int vltgsel		: 3;		// 9
+ unsigned int reserved2		: 4;		// 12
+ unsigned int bgreqstp		: 1;		// 16
+ unsigned int contreq		: 1;
+ unsigned int rdwcntl		: 1;
+ unsigned int bgirqen		: 1;
+ unsigned int reserved3		: 12;
+} MM4_CNTL1, *P_MM4_CNTL1;
+
+typedef union
+{
+	MM4_CNTL1     mm4_cntl1_bits;
+	UINT_T		  mm4_cntl1_value;
+} MM4_CNTL1_UNION, *P_MM4_CNTL1_UNION; 
+
+#define MM4_VLTGSEL_1_8		0x5
+#define MM4_VLTGSEL_3_0		0x6
+#define MM4_VLTGSEL_3_3		0x7
+
+// ********************* MM4_CNTL2 ********************************
+typedef struct
+{
+ unsigned int inter_clk_en		: 1;	// Internal Clock Enable
+ unsigned int inter_clk_stable	: 1;	// Internal Clock Stable
+ unsigned int mm4clken			: 1;	// Clock Enable
+ unsigned int reserved1			: 2;	// bits 3,4
+ unsigned int clk_gen_sel		: 1; 	// bit 5
+ unsigned int sd_freq_sel_hi	: 2;	// 6								 
+ unsigned int sd_freq_sel_lo	: 8;	// 8								  
+ unsigned int dtocntr			: 4;	// bit 0 Data Timeout Counter Value
+ unsigned int reserved2			: 4;	//
+ unsigned int mswrst			: 1;	// bit 8 Software Reset for All
+ unsigned int cmdswrst			: 1;	// bit 9 Software Reset for MM4CMD Line
+ unsigned int datswrst			: 1;	// bit 10 Software Reset for MM4DATx Lines
+ unsigned int reserved3			: 5;	// bits 11-15
+} MM4_CNTL2, *P_MM4_CNTL2;
+
+// ********************* MM4_HOST_CNTL2 ********************************
+typedef struct
+{
+ unsigned int reserved 			: 16;	// bit 0~15
+ unsigned int uhs_mode_sel		: 3;	// bit 16-18: UHS Mode Select
+ unsigned int v1_8_sig_en		: 1;	// 1.8V Signaling Enable
+ unsigned int dri_strength_sel	: 2;	// Driver Strength Select
+ unsigned int execute_tunning	: 1;	// Execute Tuning
+ unsigned int samp_clk_sel		: 1; 	// Sampling Clock Select
+ unsigned int reserved1			: 6;	// bits 8~13
+ unsigned int async_int_en		: 1;	// Asynchronous Interrupt Enable
+ unsigned int preset_val_en		: 1;	// Preset Value Enable
+} MM4_HOST_CNTL2, *P_MM4_HOST_CNTL2;
+
+#define SDH_BUS_SPEED_DEFAULT (1<<0)
+#define SDH_BUS_SPEED_SDR_CLK_50M (1<<1)
+#define SDH_BUS_SPEED_SDR_CLK_100M (1<<2)
+#define SDH_BUS_SPEED_SDR_CLK_208M (1<<3)
+#define SDH_BUS_SPEED_DDR_CLK_50M (1<<4)
+
+#define CLOCK_27_MULT		0xE
+
+#if BASE_CLOCK_208MHZ
+//Clock divider settings for 208Mhz bus clock
+#define MM4CLOCK200KHZRATE	0x1FF	// Set also additional SD_FREQ_HI bit.	So SD_FREQ_SEL = 0x1FF = 511 * 2 = 1022 (clock divider)
+#define MM4CLOCK50MHZRATE	2
+#define MM4CLOCK25MHZRATE	4
+#define MM4CLOCK12_5MHZRATE	8
+#define MM4CLOCK6MHZRATE	16 	
+#else
+//Clock divider settings for 104Mhz bus clock
+#define MM4CLOCK200KHZRATE	0xFF	// Set also additional SD_FREQ_HI bit.	So SD_FREQ_SEL = 0x1FF = 511 * 2 = 1022 (clock divider)
+#define MM4CLOCK50MHZRATE	1
+#define MM4CLOCK25MHZRATE	2
+#define MM4CLOCK12_5MHZRATE	4
+#define MM4CLOCK6MHZRATE	8 	 
+#endif
+
+typedef union
+{
+	//Coverity - declare struct volatile to eliminate infinite loop defect
+	volatile MM4_CNTL2     mm4_cntl2_bits;
+	VUINT_T		  mm4_cntl2_value;
+} MM4_CNTL2_UNION, *P_MM4_CNTL2_UNION; 
+
+typedef union
+{
+	//Coverity - declare struct volatile to eliminate infinite loop defect
+	volatile MM4_HOST_CNTL2     mm4_host_cntl2_bits;
+	VUINT_T		  mm4_host_cntl2_value;
+} MM4_HOST_CNTL2_UNION, *P_MM4_HOST_CNTL2_UNION;
+
+// ********************* MM4_I_STAT, MM4_I_STAT_EN, MM4_I_SIGN_EN ************
+typedef struct
+{
+ unsigned int cmdcomp 		: 1;   //0
+ unsigned int xfrcomp		: 1;   //1
+ unsigned int bgevnt		: 1;   //2
+ unsigned int dmaint		: 1;   //3
+ unsigned int bufwrrdy		: 1;   //4
+ unsigned int bufrdrdy		: 1;   //5
+ unsigned int cdins			: 1;   //6
+ unsigned int cdrem			: 1;   //7
+ unsigned int cdint			: 1;   //8
+ unsigned int int_a			: 1;   //9
+ unsigned int int_b			: 1;   //10
+ unsigned int int_c			: 1;   //11
+ unsigned int retuninig_int	: 1;   //12
+ unsigned int reserved0		: 2;   //13
+ unsigned int errint		: 1;   //15
+ unsigned int ctoerr		: 1;   //16
+ unsigned int ccrcerr		: 1;   //17
+ unsigned int cenderr		: 1;   //18
+ unsigned int cidxerr		: 1;   //19
+ unsigned int dtoerr		: 1;   //20
+ unsigned int dcrcerr		: 1;   //21
+ unsigned int denderr		: 1;   //22
+ unsigned int ilmterr		: 1;   //23
+ unsigned int ac12err		: 1;   //24
+ unsigned int admaerr		: 1;   //25
+ unsigned int tune_err		: 1;   //26
+ unsigned int reserved1		: 1;   //27
+ unsigned int spierr		: 1;   //28
+ unsigned int axi_resp_err	: 1;   //29
+ unsigned int cpl_tout_err  : 1;   //30
+ unsigned int crc_stat_err	: 1;   //31
+} MM4_I_STAT, *P_MM4_I_STAT, MM4_I_STAT_EN, *P_MM4_I_STAT_EN, MM4_I_SIGN_EN, *P_MM4_I_SIGN_EN;
+
+#define DISABLE_INTS 	0
+#define ENABLE_INTS		1
+
+typedef union
+{
+	MM4_I_STAT 	  mm4_i_stat_bits;
+	UINT_T		  mm4_i_stat_value;
+} MM4_I_STAT_UNION, *P_MM4_I_STAT_UNION; 
+//#define CLEAR_INTS_MASK		0xFFFF7FFD
+#define CLEAR_INTS_MASK		0xFFFF7FCD
+
+
+// ********************* MM4_ACMD12_ER *******************************************
+typedef struct
+{
+ unsigned int ac12nexe			: 1;   // 0
+ unsigned int ac12toer			: 1;   // 1
+ unsigned int ac12crcer			: 1;   // 2
+ unsigned int ac12ender			: 1;   // 3
+ unsigned int ac12idxer			: 1;   // 4
+ unsigned int reserved0			: 2;   // 5
+ unsigned int cmdnisud			: 1;   // 7
+ unsigned int reserved1			: 8;   // 8
+ unsigned int uhs_mode_sel		: 3;   // 16	
+ unsigned int sgh_v18_en		: 1;   // 19
+ unsigned int drv_strength_sel 	: 2;   // 20 
+ unsigned int exe_tuning		: 1;   // 22
+ unsigned int sampling_clk_sel	: 1;   // 23
+ unsigned int reserved2			: 6;   // 24
+ unsigned int async_int_en		: 1;   // 30
+ unsigned int pre_val_en		: 1;   // 31					
+} MM4_ACMD12_ER, *P_MM4_ACMD12_ER;
+
+// ********************* MM4_CAP0 *******************************************
+typedef struct
+{
+ unsigned int toclkfreq				: 6;
+ unsigned int reserved0				: 1;
+ unsigned int toclkunit				: 1;
+ unsigned int bsclkfreq				: 8;
+ unsigned int max_blk_len			: 2;
+ unsigned int ex_data_width_support	: 1; 
+ unsigned int reserved1				: 1;
+ unsigned int adma2_support			: 1;
+ unsigned int adma1_support			: 1;
+ unsigned int hi_speed_support		: 1;
+ unsigned int sdma_support			: 1;
+ unsigned int sus_res_support		: 1;
+ unsigned int vlg_33_support		: 1;
+ unsigned int vlg_30_support		: 1;
+ unsigned int vlg_18_support		: 1;
+ unsigned int reserved2				: 1;
+ unsigned int sys_bus_64_support	: 1;
+ unsigned int async_int_support		: 1;
+ unsigned int cfg_slot_type			: 1;
+} MM4_CAP1_2, *P_MM4_CAP1_2;
+
+typedef union
+{
+	MM4_CAP1_2 	  mm4_cap1_2_bits;
+	UINT_T		  mm4_cap1_2_value;
+} MM4_CAP1_2_UNION, *P_MM4_CAP1_2_UNION; 
+
+// ********************* MM4_SD_MAX_CURRENT1_2 *******************************************
+typedef struct
+{
+ unsigned int v3_3vmaxi		: 8;
+ unsigned int v3_0vmaxi		: 8;
+ unsigned int v1_8vmaxi		: 8;
+ unsigned int reserved0 	: 8;
+} MM4_SD_MAX_CURRENT1_2, *P_MM4_SD_MAX_CURRENT1_2;
+
+typedef union
+{
+	MM4_SD_MAX_CURRENT1_2 	  	mm4_sd_max_current1_2_bits;
+	UINT_T		  				mm4_sd_max_current1_2_value;
+} MM4_SD_MAX_CURRENT1_2_UNION, *P_MM4_SD_MAX_CURRENT1_2_UNION; 
+
+// ********************* MM4_SD_LEGACY_CTRL_REG *******************************************
+typedef struct
+{
+ UINT pio_rdfc				  : 1;	// Bit 0
+ UINT async_io_en			  : 1;	// Bit 1
+ UINT inand_sel			    : 1;	// Bit 2
+ UINT boot_ack				  : 1; 	// Bit 3
+ UINT squ_empty_check		: 1;	// Bit 4
+ UINT squ_full_check		: 1;	// Bit 5
+ UINT gen_pad_clk_on		: 1;	// Bit 6
+ UINT reserved0				  : 1;	// Bit 7
+ UINT spi_en				    : 1;	// Bit 8
+ UINT spi_error_token	  : 5;	// Bits 9-13
+ UINT reserved1				  : 10;	// Bits 14-23
+ UINT gen_pad_clk_cnt		: 8;	// Bits	24-31
+} MM4_SD_LEGACY_CTRL_REG, *P_MM4_SD_LEGACY_CTRL_REG;
+
+typedef union
+{
+	MM4_SD_LEGACY_CTRL_REG 	MM4_SD_LEGACY_CTRL_REG_bits;
+	UINT_T		  		MM4_SD_LEGACY_CTRL_REG_value;
+} MM4_SD_LEGACY_CTRL_REG_UNION, *P_MM4_SD_LEGACY_CTRL_REG_UNION;
+
+#define DISABLE_PAD_SD_CLOCK_GATING_BIT			(1 << 10)		// 1 means disable dynamic clock gating.
+#define ENABLE_DYNAMIC_CLOCK_GATING_MASK		(~(DISABLE_PAD_SD_CLOCK_GATING_BIT))
+
+// ********************* MM4_CTRL_REG *******************************************
+typedef struct
+{
+ UINT misc_int_int_en	 	: 1;	// Bit 0
+ UINT misc_int_en	 		: 1;	// Bit 1
+ UINT misc_int		 		: 1;	// Bit 2
+ UINT reserved1				: 1;	// Bit 3
+ UINT cpl_complete_int_en	: 1;	// Bit 4
+ UINT cpl_complete_en		: 1;	// Bit 5
+ UINT cpl_complete			: 1;	// Bit 6
+ UINT reserved2		 		: 1;	// Bit 7
+ UINT enhance_strobe_en	 		: 1;	// Bit 8
+ UINT mmc_hs400	 		: 1;	// Bit 9
+ UINT mmc_hs200	 		: 1;	// Bit 10
+ UINT mmc_resetn	 		: 1;	// Bit 11
+ UINT mmc_card				: 1;	// Bit 12
+ UINT reserved3		 		: 11;	// Bit 13
+ UINT data_level		 		: 8;	// Bit 24
+} MM4_CTRL_REG, *P_MM4_CTRL_REG;
+
+typedef union
+{
+	MM4_CTRL_REG		MM4_CTRL_REG_bits;
+	UINT_T					MM4_CTRL_REG_value;
+} MM4_CTRL_REG_UNION, *PMM4_CTRL_REG_UNION;
+
+typedef struct
+{
+	unsigned int adma_state   : 2;
+	unsigned int adma_len_err : 1;
+	unsigned int Rsvd : 29;
+} MM4_ADMA_ERROR_STAT, *P_MM4_ADMA_ERROR_STAT;
+
+typedef struct
+{
+	UINT txholddly0	   : 10; //Bits 0-9
+	UINT rsvd		   : 6; //Bits 10-15
+	UINT txholddly1	   : 10; //Bits 16-25
+	UINT rsvd1		   : 3; //Bits 26-28
+	UINT tx_dline_src_sel   : 1; //Bit 29
+	UINT tx_int_clk	   : 1; //Bit 30
+	UINT tx_mux_sel	   : 1;	//Bit 31
+}MM4_TX_CFG, *P_MM4_TX_CFG;
+
+#define DDR_TX_DELAY 0x55
+#define TX_MUX_SEL      (0x1<<31)
+#define TX_SEL_BUS_CLK  (0x1<<30)
+#define TX_DELAY1_SHIFT 24
+#define TX_DELAY_MASK   0xFF
+
+typedef union
+{
+	MM4_TX_CFG MM4_TX_CFG_bits;
+	UINT_T MM4_TX_CFG_value;
+}MM4_TX_CFG_UNION, *P_MM4_TX_CFG_UNION;
+
+#define DDR_RX_DELAY 0x55
+#define RX_SDCLK_DELAY_SHIFT 16
+#define RX_SDCLK_DELAY_MASK   0xFF
+#define RX_SDCLK_SEL1_MASK	0x3
+#define RX_SDCLK_SEL1_SHIFT	2
+
+typedef struct
+{
+	unsigned int rsvd2  	   : 4;
+	unsigned int tuning_dly_inc: 10;
+	unsigned int sdclk_delay   : 10;
+	unsigned int rsvd1		   : 4;
+	unsigned int sdclk_sel1	   : 2;
+	unsigned int sdclk_sel0	   : 2;	
+}MM4_RX_CFG, *P_MM4_RX_CFG;
+
+typedef union
+{
+	MM4_RX_CFG MM4_RX_CFG_bits;
+	UINT_T MM4_RX_CFG_value;
+}MM4_RX_CFG_UNION, *P_MM4_RX_CFG_UNION;
+
+typedef struct
+{
+	unsigned int dline_pu  	   : 1;
+	unsigned int rsvd1         : 15;
+	unsigned int rx_dline_code : 8;
+	unsigned int tx_dline_code : 8;
+}MM4_SD_DLINE_CTRL, *P_MM4_SD_DLINE_CTRL;
+
+typedef union
+{
+	MM4_SD_DLINE_CTRL MM4_SD_DLINE_CTRL_bits;
+	UINT_T MM4_SD_DLINE_CTRL_value;
+}MM4_SD_DLINE_CTRL_UNION, *P_MM4_SD_DLINE_CTRL_UNION;
+
+typedef struct
+{
+	unsigned int rx_dline_reg  : 8;
+	unsigned int rx_dline_gain : 1;
+	unsigned int rsvd1		     : 7;
+	unsigned int tx_dline_reg  : 8;
+	unsigned int tx_dline_gain : 1;
+	unsigned int rsvd2		     : 7;
+}MM4_SD_DLINE_CFG, *P_MM4_SD_DLINE_CFG;
+
+typedef union
+{
+	MM4_SD_DLINE_CFG MM4_SD_DLINE_CFG_bits;
+	UINT_T MM4_SD_DLINE_CFG_value;
+}MM4_SD_DLINE_CFG_UNION, *P_MM4_SD_DLINE_CFG_UNION;
+
+/*********** End MM4 Register Def's **************************************/
+// response types
+enum {
+  MMC_RESPONSE_NONE = 1L<<8,
+  MMC_RESPONSE_R1 = 2L<<8,
+  MMC_RESPONSE_R1B = 3L<<8,
+  MMC_RESPONSE_R2 = 4L<<8,
+  MMC_RESPONSE_R3 = 5L<<8,
+  MMC_RESPONSE_R4 = 6L<<8,
+  MMC_RESPONSE_R5 = 7L<<8,
+  MMC_RESPONSE_R5B = 8L<<8,
+  MMC_RESPONSE_R6 = 9L<<8,
+  MMC_RESPONSE_R7 = 0xAL<<8,
+  MMC_RESPONSE_MASK = 0x0000FF00
+};
+
+#define SD_OCR_VOLTAGE_3_3_TO_3_6 	0xE00000
+#define SD_OCR_VOLTAGE_1_8_TO_3_3 	0x1F8000
+#define SD_OCR_VOLTAGE_1_8		 	0x80
+#define MMC_OCR_VOLTAGE_ALL			0xFF8000
+#define	MM4FIFOWORDSIZE				0x80
+#define MMC_RESPONSE_R1B_TIMEOUT    0x100
+
+// device context for MMC API, containing anything needed to operate on 
+// this API. It is always first parameter for all APIs.
+typedef struct 
+{
+  P_MM4_SDMMC_T            	pMMC4Reg;				// MMC1 register base
+} MM4_SDMMC_CONTEXT_T, *P_MM4_SDMMC_CONTEXT_T;
+
+//////////////////////ADMA DESCRIPTOR related////////////////////////////////
+//max no. of blocks transferrable by an ADMA descriptor
+#define MAX_TRANS_BLKS_ADMA_DESC 127
+
+//Max no of ADMA descriptors that define the max size of chunk of an image
+#define NO_ADMA_TX_DESCS 260 // 16MB / 127 / 512B = 258
+
+
+typedef enum
+{
+	INVALID_DESC = 0,
+	VALID_DESC   = 1,
+}DESC_VAL_INVAL;
+
+typedef enum
+{
+	NOT_LAST_DESC = 0,
+	LAST_DESC     = 1,
+}END_DESC;
+
+typedef enum
+{
+	NO_DMA_INT = 0,
+	DMA_INT    = 1,
+}DMA_INT_EN;
+
+typedef enum
+{
+	NO_OP     = 0,
+	RSVD      = 1,
+	TRANSFER  = 2,
+	LINK      = 3,
+}ATTRIBUTES; 
+ 
+typedef struct
+{
+	unsigned int desc_val_inval :1;
+	unsigned int end_desc       :1;
+	unsigned int dma_int_en     :1;
+	unsigned int Rsvd0   	    :1;
+	unsigned int attr           :2;
+	unsigned int Rsvd    	    :10;
+	unsigned int Length 	    :16;
+	unsigned int Address        :32;
+} ADMA_DESCRIPTOR, *P_ADMA_DESCRIPTOR;
+//////////////////////////////ADMA////////////////////////////////
+
+#define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
+					     /* DDR mode @1.8V or 3V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
+					     /* DDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_DDR_1_2V)
+#define EXT_CSD_CARD_TYPE_SDR_200_1_8V	(1<<4) /* Card can run at 200MHz */
+					     /* SDR mode @1.8V I/O */
+#define EXT_CSD_CARD_TYPE_SDR_200_1_2V	(1<<5) /* Card can run at 200MHz */
+					     /* SDR mode @1.2V I/O */
+
+typedef enum
+{
+	SDR_1		= 0, // 1 bit data bus
+	SDR_4	    = 1, // 4 bit data bus
+	SDR_8		= 2, // 8 bit data bus
+	DDR_4		= 5, // 4 bit data bus (dual data rate)
+	DDR_8		= 6, // 8 bit data bus (dual data rate)
+}BUS_Width;
+
+//Function Prototypes
+void MMC4StopInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4StartInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4StartBusClock(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4StopBusClock (P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4SetBusRate(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T rate);
+void MMC4SelectUHSMode(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T mode);
+void MMC4SetTXIntCLKEnable(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4SetTXConfig(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4SetRXConfig(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4EnableDisableIntSources(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T Desire);
+void MMC4SetDataTimeout(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T CounterValue);
+void MMC4CMDSWReset(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4DataSWReset(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4FullSWReset(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4SendDataCommand(P_MM4_SDMMC_CONTEXT_T pContext, 
+                  UINT_T Cmd,
+                  UINT_T  Argument, 
+                  UINT_T BlockType,
+                  UINT_T DataDirection,
+                  UINT_T ResType, 
+                  UINT_T DMAMode,
+                  UINT_T AutoCmd23En);
+
+void MMC4SendDataCommandNoAuto12(P_MM4_SDMMC_CONTEXT_T pContext, 
+                  UINT_T Cmd,
+                  UINT_T  Argument, 
+                  UINT_T BlockType,
+                  UINT_T DataDirection,
+                  UINT_T ResType, 
+                  UINT_T DMAMode,
+                  UINT_T Blk_Cnt_Enable);
+
+void MMC4SendSetupCommand(P_MM4_SDMMC_CONTEXT_T pContext, 
+                  UINT_T Cmd,
+                  UINT_T CmdType,  
+                  UINT_T  Argument, 
+                  UINT_T ResType);
+#endif