summaryrefslogtreecommitdiff
path: root/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe
diff options
context:
space:
mode:
Diffstat (limited to 'SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe')
-rwxr-xr-xSamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.c1378
-rwxr-xr-xSamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.h308
-rwxr-xr-xSamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.inf64
-rwxr-xr-xSamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.c721
-rwxr-xr-xSamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.h322
-rwxr-xr-xSamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_CMD.h165
-rwxr-xr-xSamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMC_Fvb.c587
7 files changed, 3545 insertions, 0 deletions
diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.c
new file mode 100755
index 000000000..87f937924
--- /dev/null
+++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.c
@@ -0,0 +1,1378 @@
+/** @file
+ MMC/SD Card driver for Secure Digital Host Controller
+
+ This driver always produces a BlockIo protocol but it starts off with no Media
+ present. A TimerCallBack detects when media is inserted or removed and after
+ a media change event a call to BlockIo ReadBlocks/WriteBlocks will cause the
+ media to be detected (or removed) and the BlockIo Media structure will get
+ updated. No MMC/SD Card harward registers are updated until the first BlockIo
+ ReadBlocks/WriteBlocks after media has been insterted (booting with a card
+ plugged in counts as an insertion event).
+
+ Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Protocol/ExynosGpio.h>
+#include <Platform/ArmPlatform.h>
+#include <Platform/Exynos5250.h>
+#include <Platform/Arndale5250.h>
+
+#include "eMMCDxe.h"
+
+
+
+#define DateInformation "20120723_007"
+
+
+MSHC_OPERATION_MODE MSHC_operation_mode=MSHC_FIFO;
+//MSHC_OPERATION_MODE MSHC_operation_mode=MSHC_IDMA;
+
+
+//#undef EFI_D_INFO
+//#define EFI_D_INFO 1
+
+
+
+CARD_INFO gCardInfo;
+BOOLEAN gMediaChange = TRUE;
+BOOLEAN gCardInit = FALSE;
+
+
+EFI_BLOCK_IO_MEDIA gSDMMCMedia = {
+ SIGNATURE_32('e','m','m','c'), // MediaId
+ FALSE, // RemovableMedia
+ TRUE, // MediaPresent
+ FALSE, // LogicalPartition
+ FALSE, // ReadOnly
+ FALSE, // WriteCaching
+ 512, // BlockSize
+ 4, // IoAlign
+ 0, // Pad
+ 0 // LastBlock
+};
+
+typedef struct {
+ VENDOR_DEVICE_PATH Mmc;
+ EFI_DEVICE_PATH End;
+} MSHC_DEVICE_PATH;
+
+MSHC_DEVICE_PATH gMSHCDevicePath = {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ (UINT8)(sizeof(VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
+ 0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ 0
+ }
+};
+
+
+
+//
+// Internal Functions
+//
+
+
+
+
+VOID
+ParseCardCIDData (
+ UINT32 Response0,
+ UINT32 Response1,
+ UINT32 Response2,
+ UINT32 Response3
+ )
+{
+ gCardInfo.CIDData.MDT = ((Response0 >> 8) & 0xFFF);
+ gCardInfo.CIDData.PSN = (((Response0 >> 24) & 0xFF) | ((Response1 & 0xFFFFFF) << 8));
+ gCardInfo.CIDData.PRV = ((Response1 >> 24) & 0xFF);
+ gCardInfo.CIDData.PNM[4] = ((Response2) & 0xFF);
+ gCardInfo.CIDData.PNM[3] = ((Response2 >> 8) & 0xFF);
+ gCardInfo.CIDData.PNM[2] = ((Response2 >> 16) & 0xFF);
+ gCardInfo.CIDData.PNM[1] = ((Response2 >> 24) & 0xFF);
+ gCardInfo.CIDData.PNM[0] = ((Response3) & 0xFF);
+ gCardInfo.CIDData.OID = ((Response3 >> 8) & 0xFFFF);
+ gCardInfo.CIDData.MID = ((Response3 >> 24) & 0xFF);
+}
+
+
+EFI_STATUS
+MSHC_SendCmd (
+ UINTN Cmd,
+ UINTN CmdInterruptEnableVal,
+ UINTN CmdArgument
+ )
+{
+ UINTN MmcStatus = 0;
+ volatile UINTN RetryCount = 0;
+ int cmd_flags = 0;
+ int timeout=0;
+ UINT32 SdMmcBaseAddr;
+ //UINT32 MSHCRintStatus=0;
+
+ DEBUG ((EFI_D_INFO, "CMD = %d\n", (Cmd&0x3F)));
+
+ timeout = MAX_RETRY_COUNT;
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+
+ //1. Check if Data busy or not
+ while(MmioRead32(SdMmcBaseAddr + MSHCI_STATUS) & (DATA_BUSY))
+ {
+ if (timeout == 0)
+ {
+ DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd timeout : CMD = %d\n", Cmd));
+ return EFI_DEVICE_ERROR;
+ }
+ timeout--;
+ MicroSecondDelay(1);
+ }
+
+ // 2. Check if Raw interrupt is command done
+ /*MSHCRintStatus = MmioRead32(SdMmcBaseAddr + MSHCI_RINTSTS);
+ if ((MSHCRintStatus & (INTMSK_CDONE|INTMSK_ACD)) == 0)
+ {
+ DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd interrupt error : INT = %x\n", MmioRead32(SdMmcBaseAddr + MSHCI_RINTSTS)));
+ } */
+
+ // 3. Clear Raw interrupt
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_ALL);
+
+ // 4. prepare data
+ //mshci_reset_fifo();
+
+ //5. Set command argument register
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMDARG), CmdArgument);
+
+ // 6. transfer data
+
+ //Enable interrupt enable events to occur
+ // EVT1 do not need interrupt mask, use Raw interrupt
+ //MmioWrite32 ((SdMmcBaseAddr + MSHCI_INTMSK), CmdInterruptEnableVal);
+
+ // 7. trasfer data
+
+ //8. Send a command
+ cmd_flags = (Cmd & 0x3F);
+ if(Cmd & (RSPTYP48 | RSPTYP48B | RSPTYP136))
+ {
+ cmd_flags |= CMD_RESP_EXP_BIT;
+ if(Cmd & RSPTYP136)
+ cmd_flags |= CMD_RESP_LENGTH_BIT;
+ }
+
+ if((Cmd==CMD17)|(Cmd==CMD18)|(Cmd==CMD8))
+ {
+ cmd_flags |= CMD_DATA_EXP_BIT;
+ //DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Read\n"));
+ }
+
+ if((Cmd==CMD24)|(Cmd==CMD25))
+ {
+ cmd_flags |= CMD_DATA_EXP_BIT | CMD_RW_BIT;
+ //DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Write\n"));
+
+ }
+
+ if (Cmd & ENCMDCRC)
+ {
+ cmd_flags |= CMD_CHECK_CRC_BIT;
+ }
+ cmd_flags |= (CMD_STRT_BIT | CMD_USE_HOLD_REG | CMD_WAIT_PRV_DAT_BIT|CMD_SENT_AUTO_STOP_BIT);
+ //cmd_flags |= (CMD_STRT_BIT | CMD_USE_HOLD_REG | CMD_WAIT_PRV_DAT_BIT);
+ DEBUG ((EFI_D_INFO, "CMD flag = 0x%x\n", cmd_flags));
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), cmd_flags);
+ MicroSecondDelay(1);
+
+ //9. Check for the Raw interrupt
+ //wait for command complete by busy waiting.
+ for (RetryCount; RetryCount<MAX_RETRY_COUNT; RetryCount++)
+ {
+ MmcStatus = MmioRead32(SdMmcBaseAddr + MSHCI_RINTSTS);
+ if (MmcStatus & INTMSK_CDONE)
+ {
+ break;
+ }
+ }
+
+ if (RetryCount == MAX_RETRY_COUNT)
+ {
+ DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd timeout CMD:%d RINT:0x%x\n",(Cmd&0x3F) ,MmcStatus));
+ return EFI_TIMEOUT;
+ }
+
+ if(MmcStatus & INTMSK_RTO)
+ {
+ DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Response timeout CMD:%d RINT:0x%x\n", (Cmd & 0x3F),MmcStatus));
+ return EFI_TIMEOUT;
+
+ }
+ else if (MmcStatus & INTMSK_RE)
+ {
+ DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Response Error RINT:0x%x\n", MmcStatus));
+ return EFI_TIMEOUT;
+ }
+ else if(MmcStatus & INTMSK_RCRC)
+ DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Response CRC Err RINT:0x%x\n", MmcStatus));
+ else if(MmcStatus & INTMSK_DCRC)
+ DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd Data CRC Err RINT:0x%x\n", MmcStatus));
+ else if(MmcStatus & INTMSK_HLE)
+ DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd HLE Err RINT:0x%x\n", MmcStatus));
+ else if(MmcStatus & INTMSK_SBE)
+ DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd SBE Err RINT:0x%x\n", MmcStatus));
+ else if(MmcStatus & INTMSK_EBE)
+ DEBUG ((EFI_D_ERROR, "MSHC::MSHC_SendCmd EBE Err RINT:0x%x\n", MmcStatus));
+
+ return EFI_SUCCESS;
+}
+
+/**
+Super block size : 4MB (16GB density)
+Argument (Boot Size) =(Number of Super Block for boot partition) / 2
+
+**/
+EFI_STATUS MSHC_BOOT_Partition(UINT32 bootsize, UINT32 rpmbsize)
+{
+ UINTN CmdArgument;
+ EFI_STATUS Status = RETURN_SUCCESS;
+ UINT32 BootSize, RPMBSize;
+
+ /* Only use this command for raw eMMC moviNAND */
+ /* Enter backdoor mode */
+ CmdArgument = 0xefac62ec;
+ Status = MSHC_SendCmd (CMD62, CMD62_INT_EN, CmdArgument);
+
+ /* Boot partition changing mode */
+ CmdArgument = 0xcbaea7;
+ Status = MSHC_SendCmd (CMD62, CMD62_INT_EN, CmdArgument);
+
+ //BootSize = ((bootsize*1024)/128);
+ BootSize = (bootsize*2);
+
+ /* Arg: boot partition size */
+ CmdArgument = BootSize;
+ Status = MSHC_SendCmd (CMD62, CMD62_INT_EN, CmdArgument);
+
+ //RPMBSize = ((rpmbsize*1024)/128);
+ RPMBSize = (rpmbsize*2);
+
+ /* Arg: RPMB partition size */
+ CmdArgument = RPMBSize;
+ Status = MSHC_SendCmd (CMD62, CMD62_INT_EN, CmdArgument);
+
+ return Status;
+
+}
+
+EFI_STATUS MSHC_EMMC_Boot_Open()
+{
+ UINTN CmdArgument;
+ EFI_STATUS Status = RETURN_SUCCESS;
+
+ DEBUG ((EFI_D_INFO, "emmc open\n" ));
+ /* Boot ack enable, boot partition enable , boot partition access */
+ CmdArgument = ((3<<24)|(179<<16)|(((1<<6)|(1<<3)|(1<<0))<<8));
+ Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, CmdArgument);
+ if (!EFI_ERROR(Status))
+ {
+ /* 4bit transfer mode at booting time. */
+ CmdArgument = ((3<<24)|(177<<16)|((1<<0)<<8));
+ Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, CmdArgument);
+ if (EFI_ERROR(Status))
+ {
+ DEBUG ((EFI_D_ERROR, "emmc open fail 2nd CMD6\n" ));
+ }
+ }
+ else
+ {
+ DEBUG ((EFI_D_ERROR, "emmc open fail first CMD6\n" ));
+ }
+
+ return Status;
+}
+
+EFI_STATUS MSHC_EMMC_Boot_Close()
+{
+ UINTN CmdArgument;
+ EFI_STATUS Status = RETURN_SUCCESS;
+
+ DEBUG ((EFI_D_INFO, "emmc close\n" ));
+ CmdArgument = ((3<<24)|(179<<16)|(((1<<6)|(1<<3)|(0<<0))<<8));
+ Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, CmdArgument);
+ if (EFI_ERROR(Status))
+ {
+ DEBUG ((EFI_D_ERROR, "emmc close fail \n" ));
+ }
+ return Status;
+}
+
+
+void PrintCardInfo()
+{
+ DEBUG ((EFI_D_INFO, "MSHC::READ_BL_LEN %d\n", gCardInfo.CSDData.READ_BL_LEN));
+ DEBUG ((EFI_D_INFO, "MSHC::CSize %d\n", gCardInfo.CSDData.C_SIZELow2 | (gCardInfo.CSDData.C_SIZEHigh10 << 2)));
+ DEBUG ((EFI_D_INFO, "MSHC::MULTI %d\n", gCardInfo.CSDData.C_SIZE_MULT));
+
+}
+
+
+#define EXT_CSD_SIZE 128
+UINT32 Ext_csd[EXT_CSD_SIZE];
+VOID GetEXTCSD()
+{
+ gCardInfo.NumBlocks = 0;
+ gCardInfo.TotalNumBlocks = 30801920;
+
+ UINTN cmdarg = 0;
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_HS_TIMING << 16) |
+ (0 << 8);
+ Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, cmdarg);
+
+ cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_BUS_WIDTH << 16) |
+ (EXT_CSD_BUS_WIDTH_1 << 8);
+ Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, cmdarg);
+
+ cmdarg = 0;
+ Status = MSHC_SendCmd (CMD8, CMD8_INT_EN, cmdarg);
+
+ gCardInfo.BlockSize = BLEN_512BYTES;
+
+ if (!EFI_ERROR(Status))
+ {
+ DEBUG ((EFI_D_INFO, "MSHC::EXT CSD \n"));
+ //PrepareTransfer(&Ext_csd[0], 1, READ);
+ //MSHC_ReadDMA(&Ext_csd[0], 1);
+ MSHC_ReadFIFO(EXT_CSD_SIZE, &Ext_csd[0]);
+ gCardInfo.NumBlocks = Ext_csd[EXT_CSD_SEC_CNT/4];
+ gCardInfo.Extcsd.boot_size_multi = Ext_csd[BOOT_SIZE_MULTI/4];
+ gCardInfo.Extcsd.boot_size_multi = (gCardInfo.Extcsd.boot_size_multi>>16)&0xff;
+ //MicroSecondDelay(5000);
+
+ DEBUG ((EFI_D_INFO, "MSHC::num blocks %d\n", gCardInfo.NumBlocks));
+ DEBUG ((1, "MSHC::eMMC Size:%dMB\n", (gCardInfo.NumBlocks/2048)));
+ DEBUG ((1, "MSHC::Boot partition Size:%dMB\n", ((gCardInfo.TotalNumBlocks-gCardInfo.NumBlocks)/2048)));
+ DEBUG ((EFI_D_INFO, "MSHC::Ext CSD boot block %d\n", (gCardInfo.Extcsd.boot_size_multi)));
+
+ }
+ else
+ {
+ gCardInfo.NumBlocks = 0x1D4C000;
+ DEBUG ((EFI_D_ERROR, "MSHC:: default block number : 0x1D4C000"));
+ }
+
+}
+
+
+EFI_STATUS
+PerformCardIdenfication (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN CmdArgument = 0;
+ //UINTN Response = 0;
+ //UINTN RetryCount = 0;
+ UINTN TempRes0,TempRes1,TempRes2,TempRes3;
+ //BOOLEAN SDCmd8Supported = FALSE;
+ UINT32 SdMmcBaseAddr;
+ int timeout = MAX_RETRY_COUNT;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+ gCardInfo.CardType = MMC_CARD;
+
+ //1. Send CMD0 command. go to IDLE
+ Status = MSHC_SendCmd (CMD0, CMD0_INT_EN, CmdArgument);
+
+ // 2. Send CMD1 while OCR is not busy and get OCR register
+ do {
+ CmdArgument = OCR_HCS | MMC_VDD_32_33 | MMC_VDD_33_34;
+ Status = MSHC_SendCmd (CMD1, CMD1_INT_EN, CmdArgument);
+
+ if (EFI_ERROR(Status))
+ {
+ DEBUG ((EFI_D_ERROR, "MSHC::CMD1 fails.\n"));
+ }
+
+ MicroSecondDelay(100);
+ } while (!(MmioRead32 (SdMmcBaseAddr + MSHCI_RESP0)& OCR_BUSY) && timeout--);
+
+ if (timeout <= 0)
+ {
+ DEBUG ((EFI_D_ERROR, "MSHC::CMD1 OCR busy timeout.\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ DEBUG ((EFI_D_INFO, "MSHC::CMD1 OCR 0x%x\n", MmioRead32(SdMmcBaseAddr + MSHCI_RESP0)));
+
+ ((UINT32 *) &(gCardInfo.OCRData))[0] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0));
+
+ //3. send CMD2 to get CID register
+ CmdArgument = 0;
+ Status = MSHC_SendCmd (CMD2, CMD2_INT_EN, CmdArgument);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "CMD2 fails. Status: %x\n", Status));
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "CMD2 response: %x %x %x %x\n", MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)), \
+ MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP1)), \
+ MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP2)), \
+ MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP3))));
+
+ TempRes0 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0));
+ TempRes1 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP1));
+ TempRes2 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP2));
+ TempRes3 = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP3));
+
+ //Parse CID register data.
+ ParseCardCIDData(TempRes0 << 8, (TempRes1 << 8) | (TempRes0 >> 24),
+ (TempRes2 << 8) | (TempRes1 >> 24), (TempRes3 << 8) | (TempRes2 >> 24));
+
+ //4. send CMD3 to get RCA register
+ CmdArgument = 0;
+ Status = MSHC_SendCmd (CMD3, CMD3_INT_EN, CmdArgument);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "CMD3 fails. Status: %x\n", Status));
+ return Status;
+ }
+
+ //Set RCA for the detected card. RCA is CMD3 response.
+ DEBUG ((EFI_D_INFO, "MSHC::CMD3 RCA 0x%x\n", MmioRead32(SdMmcBaseAddr + MSHCI_RESP0)));
+ gCardInfo.RCA = (MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0)) >> 16);
+ DEBUG ((EFI_D_INFO, "CMD3 response: RCA %x\n", gCardInfo.RCA));
+
+ gBS->Stall(1000); //Need Debug by wprkfgur
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+GetCardSpecificData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN CmdArgument;
+ UINTN TempRes[4],i;
+ UINT32 SdMmcBaseAddr;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+
+ //Send CMD9 to retrieve CSD.
+ CmdArgument = gCardInfo.RCA << 16;
+ Status = MSHC_SendCmd (CMD9, CMD9_INT_EN, CmdArgument);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "CMD9 fails. Status: %x\n", Status));
+ return Status;
+ }
+
+ TempRes[0] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP0));
+ TempRes[1] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP1));
+ TempRes[2] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP2));
+ TempRes[3] = MmioRead32 ((SdMmcBaseAddr + MSHCI_RESP3));
+
+ //Populate 128-bit CSD register data.
+ for (i = 0 ; i < 4; i++) {
+ ((UINT32 *)&(gCardInfo.CSDData))[i] = TempRes[i];
+ }
+
+ DEBUG ((EFI_D_INFO, "CMD9 response: %x %x %x %x\n", ((UINT32 *)&(gCardInfo.CSDData))[0], ((UINT32 *)&(gCardInfo.CSDData))[1], ((UINT32 *)&(gCardInfo.CSDData))[2], ((UINT32 *)&(gCardInfo.CSDData))[3]));
+ return Status;
+}
+
+EFI_STATUS
+PerformCardConfiguration (
+ VOID
+ )
+{
+ UINTN CmdArgument = 0;
+ EFI_STATUS Status;
+ UINT32 SdMmcBaseAddr;
+ //UINTN FifoCount = 0;
+ //UINTN Count=0;
+ UINT32 OMval;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+ OMval = MmioRead32(0x10040000);
+ DEBUG ((EFI_D_INFO, "MSHC::OM read 0x%x \n", OMval));
+
+ //Send CMD7
+ CmdArgument = gCardInfo.RCA << 16;
+ Status = MSHC_SendCmd (CMD7, CMD7_INT_EN, CmdArgument);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "CMD7 fails. Status: %x\n", Status));
+ return Status;
+ }
+
+ //Send CMD16 to set the block length
+ //CmdArgument = gCardInfo.BlockSize;
+ CmdArgument = BLEN_512BYTES;
+ Status = MSHC_SendCmd (CMD16, CMD16_INT_EN, CmdArgument);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "CMD16 fails. Status: %x\n", Status));
+ return Status;
+ }
+
+ if(OMval!=OM_EMMC)
+ {
+ GetEXTCSD();
+ if(gCardInfo.Extcsd.boot_size_multi!= MSHC_BOOT_SIZE_MULTI)
+ {
+ MSHC_BOOT_Partition(MSHC_BOOT_SIZE, MSHC_RPMB_SIZE);
+ DEBUG ((EFI_D_INFO, "MSHC::Doing Boot partition \n"));
+ }
+ else
+ {
+ DEBUG ((EFI_D_INFO, "MSHC::Alread boot partition \n", Status));
+ }
+ }
+ else
+ {
+ DEBUG ((1, "MSHC::eMMC booting \n"));
+ gCardInfo.TotalNumBlocks = 30801920;
+ gCardInfo.NumBlocks = 30588928;
+ }
+
+ // set device into 4-bit data bus mode
+ //Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, 0x2);
+ // set device into 8-bit data bus mode
+ CmdArgument = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_BUS_WIDTH <<16) |
+ (EXT_CSD_BUS_WIDTH_8_DDR <<8);
+ Status = MSHC_SendCmd (ACMD6, ACMD6_INT_EN, CmdArgument);
+ if (!EFI_ERROR (Status)) {
+ // Set host controler into 8-bit mode
+ MmioOr32 ((SdMmcBaseAddr + MSHCI_CTYPE), CARD_WIDTH8);
+ //MmioOr32 ((SdMmcBaseAddr + MSHCI_CTYPE), CARD_WIDTH14);
+ DEBUG ((EFI_D_INFO, "8-bit mode\n"));
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+ReadBlockData (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ OUT VOID *Buffer,
+ IN UINTN BlockCount
+ )
+{
+ EFI_STATUS Status = EFI_INVALID_PARAMETER;
+ UINTN DataSize = This->Media->BlockSize/4;
+
+ DEBUG ((EFI_D_INFO, "MSHC::ReadBlockData start \n"));
+
+ if(MSHC_operation_mode == MSHC_FIFO)
+ {
+ Status = MSHC_ReadFIFO(DataSize, Buffer);
+ }
+
+ else if(MSHC_operation_mode == MSHC_IDMA)
+ {
+ Status = MSHC_ReadDMA(Buffer, BlockCount);
+ }
+
+ return Status;
+}
+
+
+EFI_STATUS
+WriteBlockData (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ OUT VOID *Buffer,
+ IN UINTN BlockCount
+ )
+{
+ EFI_STATUS Status = EFI_INVALID_PARAMETER;
+ UINTN DataSize = This->Media->BlockSize/4;
+
+ if(MSHC_operation_mode == MSHC_FIFO)
+ {
+ Status = MSHC_WriteFIFO(DataSize, Buffer);
+ }
+ else if(MSHC_operation_mode == MSHC_IDMA)
+ {
+ Status = MSHC_WriteDMA(Buffer, BlockCount);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EraseBlockData (
+ IN UINT32 Partition,
+ IN UINTN StartBlock,
+ IN UINTN NumBlock
+ )
+{
+ UINTN cmdarg = 0;
+ EFI_STATUS status = EFI_SUCCESS;
+
+ if(Partition!=MSHC_BOOT_PARTITION)
+ {
+ DEBUG ((EFI_D_ERROR, "EraseBlockData failed \n"));
+ status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ /* MMC High Capacity erase minimum size is 512KB */
+ if (NumBlock < 1024) {
+ if (NumBlock < 512)
+ NumBlock = 1;
+ else
+ NumBlock = 2;
+ } else {
+ if (0 == (NumBlock%1024)) {
+ NumBlock = (NumBlock / 1024);
+ } else {
+ NumBlock = (NumBlock / 1024) + 1;
+ }
+ }
+ DEBUG ((EFI_D_INFO, "EraseBlockData start:%d, Numblock:%d\n", StartBlock, NumBlock));
+
+ cmdarg = StartBlock;
+ status = MSHC_SendCmd (CMD35, 0, cmdarg);
+ if(status!=EFI_SUCCESS)
+ {
+ DEBUG ((EFI_D_ERROR, "EraseBlockData CMD35 failed \n"));
+ status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ cmdarg = StartBlock + NumBlock;
+ status = MSHC_SendCmd (CMD36, 0, cmdarg);
+ if(status!=EFI_SUCCESS)
+ {
+ DEBUG ((EFI_D_ERROR, "EraseBlockData CMD36 failed \n"));
+ status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ cmdarg = 0;
+ status = MSHC_SendCmd (CMD38, 0, cmdarg);
+ if(status!=EFI_SUCCESS)
+ {
+ DEBUG ((EFI_D_ERROR, "EraseBlockData CMD38 failed \n"));
+ status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Exit:
+
+ return status;
+}
+
+
+EFI_STATUS
+TransferBlock (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINTN Lba,
+ IN OUT VOID *Buffer,
+ IN UINTN BlockCount,
+ IN OPERATION_TYPE OperationType
+ )
+{
+ EFI_STATUS Status;
+ UINTN Cmd = 0;
+ UINTN CmdInterruptEnable = 0;
+ UINTN CmdArgument = 0;
+
+ // 1. FIFO reset
+ // MSHC_SendCmd do the fifo reset
+
+ // 2. prepare transfer
+
+ DEBUG ((EFI_D_INFO, "SDHC::TransferBlock : Lba = %d, Buffer = 0x%x, Type = %d\n", Lba, Buffer, OperationType));
+ //Populate the command information based on the operation type.
+ if (OperationType == READ)
+ {
+ if(BlockCount>1)
+ {
+ Cmd = CMD18; //multi block read
+ CmdInterruptEnable = CMD18_INT_EN;
+ }
+ else
+ {
+ Cmd = CMD17; //Single block read
+ CmdInterruptEnable = CMD17_INT_EN;
+ }
+
+ }
+ else if (OperationType == WRITE)
+ {
+ if(BlockCount>1)
+ {
+ Cmd = CMD25; //multi block write
+ CmdInterruptEnable = CMD25_INT_EN;
+ }
+ else
+ {
+ Cmd = CMD24; //Single block write
+ CmdInterruptEnable = CMD24_INT_EN;
+ }
+ }
+ PrepareTransfer(Buffer, BlockCount, OperationType);
+
+ //Set command argument based on the card access mode (Byte mode or Block mode)
+ if (gCardInfo.OCRData.AccessMode & BIT1) {
+ CmdArgument = Lba;
+ } else {
+ CmdArgument = Lba * This->Media->BlockSize;
+ }
+
+ //Send Command.
+ Status = MSHC_SendCmd (Cmd, CmdInterruptEnable, CmdArgument);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "CMD%d fails. Status: %x\n", (Cmd&0x3F), Status));
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "CMD%d succeed! \n", (Cmd&0x3F)));
+
+ //Read or Write data.
+ if (OperationType == READ) {
+ Status = ReadBlockData (This, Buffer, BlockCount);
+ if (EFI_ERROR(Status)) {
+ DEBUG((EFI_D_ERROR, "ReadBlockData fails.\n"));
+ return Status;
+ }
+ } else if (OperationType == WRITE) {
+ Status = WriteBlockData (This, Buffer, BlockCount);
+ if (EFI_ERROR(Status)) {
+ DEBUG((EFI_D_ERROR, "WriteBlockData fails.\n"));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+CardPresent (
+ VOID
+ )
+{
+ return TRUE;
+}
+
+EFI_STATUS
+DetectCard (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ //UINT32 SdMmcBaseAddr;
+
+ //DEBUG ((EFI_D_INFO, "===================================\n"));
+ DEBUG ((EFI_D_INFO, "===MSHC: Version %a ===\n", DateInformation));
+ //DEBUG ((EFI_D_INFO, "===================================\n"));
+
+ //SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+
+ if (!CardPresent ()) {
+ return EFI_NO_MEDIA;
+ }
+
+ //Initialize MMC host controller clocks.
+ Status = InitializeMSHC ();
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status));
+ return Status;
+ }
+
+ // EVT1 InitializeSDHC do the SW Reset
+ //Soft reset for all.
+ //MmioWrite32((SdMmcBaseAddr + SDHC_SWRST_OFFSET), SRA);
+ //gBS->Stall(1000);
+ //while ((MmioRead32 ((SdMmcBaseAddr + SDHC_SWRST_OFFSET)) & SRA) != 0x0);
+
+ //Set the clock frequency to 400KHz.
+ UpdateMSHCClkFrequency (MSHC_CLK_400);
+
+ //Card idenfication
+ Status = PerformCardIdenfication ();
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "No MMC/SD card detected.\n"));
+ return Status;
+ }
+
+ //Get CSD (Card specific data) for the detected card.
+ Status = GetCardSpecificData();
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //Configure the card in data transfer mode.
+ Status = PerformCardConfiguration();
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //Patch the Media structure.
+ gSDMMCMedia.LastBlock = (gCardInfo.NumBlocks - 1);
+ //gSDMMCMedia.BlockSize = gCardInfo.BlockSize;
+ gSDMMCMedia.BlockSize = 512;
+ gSDMMCMedia.ReadOnly = 0;
+ gSDMMCMedia.MediaPresent = TRUE;
+ gSDMMCMedia.MediaId++;
+
+ UpdateMSHCClkFrequency(MSHC_CLK_50M);
+ DEBUG ((EFI_D_INFO, "SD Card Media Change on Handle 0x%08x\n", gImageHandle));
+
+ return Status;
+}
+
+
+EFI_STATUS
+SdReadWrite (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINTN Lba,
+ OUT VOID *Buffer,
+ IN UINTN BufferSize,
+ IN OPERATION_TYPE OperationType
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINTN RetryCount = 0;
+ UINTN BlockCount;
+ UINTN BytesToBeTranferedThisPass = 0;
+ UINTN BytesRemainingToBeTransfered=0;
+ EFI_TPL OldTpl;
+ //BOOLEAN Update;
+ UINT32 SdMmcBaseAddr;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+
+ if(gMediaChange==TRUE)
+ {
+ Status = DetectCard();
+ gMediaChange = FALSE;
+ gCardInit = TRUE;
+ }
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "MSHC::Card initialization fail .\n"));
+ gCardInit = FALSE;
+ goto Done;
+ }
+
+if(gCardInit)
+{
+ DEBUG ((EFI_D_INFO, "MSHC::SdReadWrite is called Buffersize:%d \n", BufferSize));
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (Lba > This->Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((EFI_D_ERROR, "MSHC::SdReadWrite EFI_INVALID_PARAMETER\n"));
+ goto Done;
+ }
+
+ if ((BufferSize % This->Media->BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ DEBUG ((EFI_D_ERROR, "MSHC::SdReadWrite EFI_BAD_BUFFER_SIZE\n"));
+ goto Done;
+ }
+
+ //Check if the data lines are not in use.
+ while ((RetryCount++ < MAX_RETRY_COUNT) && (MmioRead32 ((SdMmcBaseAddr + MSHCI_STATUS)) & DATA_BUSY));
+ if (RetryCount == MAX_RETRY_COUNT) {
+ Status = EFI_TIMEOUT;
+ DEBUG ((EFI_D_ERROR, "MSHC::SdReadWrite EFI_TIMEOUT\n"));
+ goto Done;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ BytesRemainingToBeTransfered = BufferSize;
+
+ if(MSHC_operation_mode == MSHC_IDMA)
+ {
+ while (BytesRemainingToBeTransfered > 0) {
+ // Turn OFF DMA path until it is debugged
+ BytesToBeTranferedThisPass = (BytesRemainingToBeTransfered >= MAX_MSHC_TRANSFER_SIZE) ? MAX_MSHC_TRANSFER_SIZE : BytesRemainingToBeTransfered;
+ //BytesToBeTranferedThisPass = This->Media->BlockSize;
+
+ BlockCount = BytesToBeTranferedThisPass/This->Media->BlockSize;
+ Status = TransferBlock (This, Lba, Buffer,BlockCount, OperationType);
+
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status));
+ goto DoneRestoreTPL;
+ }
+
+ BytesRemainingToBeTransfered -= BytesToBeTranferedThisPass;
+ Lba += BlockCount;
+ Buffer = (UINT8 *)Buffer + (This->Media->BlockSize*BlockCount);
+ DEBUG ((EFI_D_INFO, "SdReadWrite::Buf:0x%x, ToBe:0x%x Rema:0x%x \n", BufferSize, BytesToBeTranferedThisPass, BytesRemainingToBeTransfered));
+
+ }
+ }
+ else
+ {
+ while (BytesRemainingToBeTransfered > 0) {
+ // Turn OFF DMA path until it is debugged
+ // BytesToBeTranferedThisPass = (BytesToBeTranferedThisPass >= MAX_SDHC_TRANSFER_SIZE) ? MAX_SDHC_TRANSFER_SIZE : BytesRemainingToBeTransfered;
+ BytesToBeTranferedThisPass = This->Media->BlockSize;
+
+ BlockCount = BytesToBeTranferedThisPass/This->Media->BlockSize;
+
+ if (BlockCount > 1) {
+ // Status = DmaBlocks (This, Lba, Buffer, BlockCount, OperationType);
+ } else {
+ //Transfer a block worth of data.
+ Status = TransferBlock (This, Lba, Buffer, BlockCount,OperationType);
+
+ }
+
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status));
+ goto DoneRestoreTPL;
+ }
+
+ BytesRemainingToBeTransfered -= BytesToBeTranferedThisPass;
+ Lba += BlockCount;
+ Buffer = (UINT8 *)Buffer + This->Media->BlockSize;
+ }
+
+ }
+
+
+DoneRestoreTPL:
+
+ gBS->RestoreTPL (OldTpl);
+
+Done:
+
+ return Status;
+}
+else
+ return EFI_TIMEOUT;
+
+
+}
+
+
+/**
+
+ Reset the Block Device.
+
+
+
+ @param This Indicates a pointer to the calling context.
+
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+
+
+ @retval EFI_SUCCESS The device was reset.
+
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+
+ not be reset.
+
+
+
+**/
+EFI_STATUS
+EFIAPI
+MSHCReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ DEBUG ((EFI_D_INFO, " MSHC::MSHCReset is called\n"));
+ MSHC_reset_all();
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Read BufferSize bytes from Lba into Buffer.
+
+
+
+ @param This Indicates a pointer to the calling context.
+
+ @param MediaId Id of the media, changes every time the media is replaced.
+
+ @param Lba The starting Logical Block Address to read from
+
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+
+ responsible for either having implicit or explicit ownership of the buffer.
+
+
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+
+ or the buffer is not on proper alignment.
+
+EFI_STATUS
+
+**/
+
+
+#define EMMC_TEST 0
+#if EMMC_TEST
+#define EMMC_TEST_SIZE (MAX_MSHC_TRANSFER_SIZE+1024)
+UINT32 bWrite[EMMC_TEST_SIZE];
+UINT32 bRead[EMMC_TEST_SIZE];
+//INTN EFIAPI CompareMem (IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
+//two buffers are identical, then 0 is returned. Otherwise, the value returned is the first mismatched byte
+
+void MSHC_Test( IN EFI_BLOCK_IO_PROTOCOL *This)
+{
+ UINTN i=0;
+ UINTN Count;
+ INTN ret;
+ EFI_STATUS Status;
+ DEBUG ((EFI_D_INFO, "MSHC::Read Write test %dB\n", EMMC_TEST_SIZE));
+
+ for(i=0; i<EMMC_TEST_SIZE; i++)
+ {
+ bWrite[i]=i;
+ }
+
+//multi
+ for(Count=100; Count<102; Count++)
+ {
+ //Lba=n;
+ //DEBUG ((EFI_D_INFO, "MSHC::Read Write test : %d\n", Count));
+ ZeroMem (&bRead[0], sizeof(bRead));
+ DEBUG ((EFI_D_INFO, "ZR : 0x%x, 0x%x, 0x%x, 0x%x\n",
+ bRead[0], bRead[1], bRead[2], bRead[3]));
+
+ Status = SdReadWrite (This, (UINTN)Count, &bWrite[0], EMMC_TEST_SIZE, WRITE);
+ Status = SdReadWrite (This, (UINTN)Count, &bRead[0], EMMC_TEST_SIZE, READ);
+
+ DEBUG ((EFI_D_INFO, "W: 0x%x, 0x%x, 0x%x, 0x%x ",
+ bWrite[0], bWrite[1], bWrite[2], bWrite[3]));
+ DEBUG ((EFI_D_INFO, "R : 0x%x, 0x%x, 0x%x, 0x%x\n",
+ bRead[0], bRead[1], bRead[2], bRead[3]));
+
+ ret = CompareMem(&bRead[0],&bWrite[0],EMMC_TEST_SIZE);
+
+ if(ret==0)
+ DEBUG ((1, "MSHC::Read Write OK!!\n"));
+ else
+ DEBUG ((1, "MSHC::Read Write Failed bWrite[%d]=0x%x : bRead[%d]=0x%x\n", ret, bWrite[ret], ret, bRead[ret]));
+
+
+ }
+
+
+}
+#endif
+
+
+#define FVB_TEST 0
+
+#if FVB_TEST
+#define FVB_TEST_SIZE 1336//(64)
+#define FVB_Offset 64 //0
+UINT32 FVB_Read[512*3];
+UINT32 FVB_Write[512*3];
+UINT32 Temp[512*3];
+void FVB_Test(IN EFI_BLOCK_IO_PROTOCOL *This)
+{
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *Fvbhandle;
+ EFI_STATUS status = EFI_SUCCESS;
+ EFI_LBA Lba = 10;
+ UINTN NumBytes=FVB_TEST_SIZE;
+ UINT32 i;
+ INTN ret;
+ UINTN Offset=FVB_Offset;
+ //EFI_FVB_ATTRIBUTES_2 *Attribute=NULL;
+ UINTN blocksize=0, numofblocks=0;
+ UINTN EraseStartBlock=10, EraseNumBlocks=5;
+ EFI_PHYSICAL_ADDRESS *Address=NULL;
+
+
+ Fvbhandle = (EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *)This;
+ DEBUG ((1, "FVB_Test Start \n"));
+
+ status = SdReadWrite (This, 0, &Temp[0], 512, READ);
+ if(status!=EFI_SUCCESS)
+ {
+ DEBUG ((1, "FVB_Test Card Init Failed !!\n"));
+ goto Exit;
+ }
+
+ for(i=0; i<512; i++)
+ {
+ FVB_Write[i]=i;
+ }
+ ZeroMem (&FVB_Read[0], 512);
+
+ //DEBUG ((1, "FVB_Test FvbGetAttributes \n"));
+ //FvbGetAttributes(Fvbhandle, Attribute);
+ FvbGetPhysicalAddress(Fvbhandle, Address);
+ FvbGetBlockSize(Fvbhandle, 0, &blocksize, &numofblocks);
+ DEBUG ((1, "FVB_Test erase\n"));
+ FvbEraseBlocks(Fvbhandle, EraseStartBlock, EraseNumBlocks, EFI_LBA_LIST_TERMINATOR);
+
+ DEBUG ((1, "FVB_Test Offset : %d Num : %d\n", Offset, NumBytes));
+ status = FvbWrite(Fvbhandle, Lba, Offset, &NumBytes, (UINT8 *)&FVB_Write[Offset]);
+ if(status!=EFI_SUCCESS)
+ {
+ DEBUG ((1, "FVB_Test write fail !!\n"));
+ goto Exit;
+ }
+
+ status = FvbRead(Fvbhandle, Lba, Offset, &NumBytes, (UINT8 *)&FVB_Read[0]);
+ if(status!=EFI_SUCCESS)
+ {
+ DEBUG ((1, "FVB_Test read fail !!\n"));
+ goto Exit;
+ }
+
+ DEBUG ((1, "FVB W: 0x%x, 0x%x, 0x%x, 0x%x ",
+ FVB_Write[Offset], FVB_Write[Offset+1], FVB_Write[Offset+2], FVB_Write[Offset+3]));
+ DEBUG ((1, "FVB R : 0x%x, 0x%x, 0x%x, 0x%x\n",
+ FVB_Read[0], FVB_Read[1], FVB_Read[2], FVB_Read[3]));
+
+ ret = CompareMem(&FVB_Write[Offset], &FVB_Read[0], FVB_TEST_SIZE);
+
+ if(ret==0)
+ DEBUG ((1, "MSHC::FVB_Test OK!!\n"));
+ else
+ DEBUG ((1, "MSHC::ERROR !!! FVB_Test Failed bWrite[%d]=0x%x : bRead[%d]=0x%x\n", ret, FVB_Write[ret], ret, FVB_Read[ret]));
+
+ Exit:
+ if(status!=EFI_SUCCESS)
+ DEBUG ((1, "FVB_Test fail !!\n"));
+
+}
+
+#endif
+
+
+
+EFI_STATUS
+EFIAPI
+MSHCReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status=EFI_SUCCESS;
+ DEBUG ((EFI_D_INFO, "MSHC::MSHCReadBlocks : MediaId = %x, Lba = %d, BufferSize = %d, Buffer = 0x%x\n",
+ MediaId, (UINTN)Lba, BufferSize, Buffer));
+
+ Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, READ);
+
+#if 0
+#if FVB_TEST
+ FVB_Test(This);
+#else
+#if EMMC_TEST
+ MSHC_Test(This);
+#else
+ //Perform Read operation.
+ Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, READ);
+#endif
+#endif //#if FVB_TEST
+#endif
+
+ return Status;
+
+}
+
+
+/**
+
+ Write BufferSize bytes from Lba into Buffer.
+
+
+
+ @param This Indicates a pointer to the calling context.
+
+ @param MediaId The media ID that the write request is for.
+
+ @param Lba The starting logical block address to be written. The caller is
+
+ responsible for writing to only legitimate locations.
+
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+
+ @param Buffer A pointer to the source buffer for the data.
+
+
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+
+ or the buffer is not on proper alignment.
+
+
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+MSHCWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+#if EMMC_TEST
+ UINT32 Count=0;
+ UINT32 ret;
+#endif
+
+ DEBUG ((EFI_D_INFO, "MSHC::MSHCWriteBlocks : MediaId = 0x%x, Lba = %d, BufferSize = %d, Buffer = 0x%x\n",
+ MediaId, (UINTN)Lba, BufferSize, Buffer));
+
+ //Perform write operation.
+ Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, WRITE);
+
+
+#if 0
+#if EMMC_TEST
+ Count = (BufferSize >= MAX_MSHC_TRANSFER_SIZE) ? MAX_MSHC_TRANSFER_SIZE : BufferSize;
+ DEBUG ((1, "\nMSHC::Read Write Test [0x%x] Start \n", Count));
+ ZeroMem (&bRead[0], sizeof(bRead));
+ CopyMem(&bWrite[0], (VOID *)Buffer, Count);
+ Status = SdReadWrite (This, (UINTN)Lba, &bRead[0], Count, READ);
+ DEBUG ((1, "W : 0x%x, 0x%x, 0x%x, 0x%x\n",
+ bWrite[7], bWrite[8], bWrite[9], bWrite[10]));
+
+ DEBUG ((1, "R : 0x%x, 0x%x, 0x%x, 0x%x\n",
+ bRead[7], bRead[8], bRead[9], bRead[10]));
+
+ ret = CompareMem(&bRead[0],&bWrite[0],Count);
+
+ if(ret==0)
+ DEBUG ((1, "MSHC::Read Write Test OK!!\n"));
+ else
+ DEBUG ((1, "MSHC::Read Write Test Failed -.- bRead[%d]=0x%x bWrite[%d]=0x%x \n", ret, bRead[ret], ret, bWrite[ret]));
+
+#endif
+#endif
+
+
+ return Status;
+
+}
+
+
+/**
+
+ Flush the Block Device.
+
+
+
+ @param This Indicates a pointer to the calling context.
+
+
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
+
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+
+
+**/
+EFI_STATUS
+EFIAPI
+MSHCFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ DEBUG ((EFI_D_INFO, "MSHC::MSHCFlushBlocks is called\n"));
+ return EFI_SUCCESS;
+}
+
+
+EFI_BLOCK_IO_PROTOCOL gBlockIo = {
+ EFI_BLOCK_IO_INTERFACE_REVISION, // Revision
+ &gSDMMCMedia, // *Media
+ MSHCReset, // Reset
+ MSHCReadBlocks, // ReadBlocks
+ MSHCWriteBlocks, // WriteBlocks
+ MSHCFlushBlocks // FlushBlocks
+};
+
+
+EFI_STATUS
+EFIAPI
+MSHCInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ ZeroMem (&gCardInfo, sizeof (CARD_INFO));
+
+//Publish BlockIO.
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiBlockIoProtocolGuid, &gBlockIo,
+ &gEfiDevicePathProtocolGuid, &gMSHCDevicePath,
+ NULL
+ );
+
+ DEBUG ((EFI_D_INFO, "MSHC::MSHCInitialize:0x%x\n", Status));
+ return Status;
+}
diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.h
new file mode 100755
index 000000000..e410d669e
--- /dev/null
+++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.h
@@ -0,0 +1,308 @@
+/** @file
+
+ Copyright (c) 2011, Samsung Electronics Co. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _MSHCDXE_H_
+#define _MSHCDXE_H_
+
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include "eMMCDxe_5250.h"
+#include "eMMCDxe_CMD.h"
+
+/**
+eMMC partition Gaia EVT1
+
+boot partition-1 : 100M store BL1, BL2, UEFI, TZSW
+boot partition-2 : 100M not used
+RPMB : 16M for secure team
+General purpose-1 : not used
+General purpose-2 : not used
+General purpose-3 : not used
+General purpose-4 : not used
+
+boot partition-1 start offset
+BL1: 0
+BL2: 16
+UEFI : 32
+TZSW : 2592~3104
+NV data area : 3200
+NV data for security team : 3200
+NV data for general purpose : 3400
+**/
+
+#define MSHC_BOOT_SIZE 100
+#define MSHC_RPMB_SIZE 0
+#define MSHC_BOOT_SIZE_MULTI (MSHC_BOOT_SIZE*2)
+#define MSHC_BOOT_SECURE_OFFSET 3200
+#define MSHC_BOOT_SECURE_SIZE 512 // 256k
+
+#define MSHC_BOOT_PARTITION 0
+#define MSHC_RPMB_PARTITION 1
+#define MSHC_USER_PARTITION 2
+
+#define BLEN_512BYTES (0x200)
+#define BLKSIZE_1 (0x1)
+
+#define OM_EMMC 0x8
+
+#define MAX_RETRY_COUNT (100000)
+#define MMC_REFERENCE_CLK (96000000)
+#define MSHC_CLK_400 (400)
+#define MSHC_CLK_25M (25000)
+#define MSHC_CLK_50M (50000)
+
+#define OCR_BUSY 0x80000000
+#define OCR_HCS 0x40000000
+
+#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
+#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
+
+
+#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
+#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in EXT_CSD byte
+ addressed by index which are
+ 1 in value field */
+#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits in EXT_CSD byte
+ addressed by index, which are
+ 1 in value field */
+#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target byte to value */
+/*
+ * EXT_CSD fields
+ */
+
+#define EXT_CSD_BUS_WIDTH 183 /* R/W */
+#define EXT_CSD_HS_TIMING 185 /* R/W */
+#define EXT_CSD_CARD_TYPE 196 /* RO */
+#define EXT_CSD_REV 192 /* RO */
+#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
+#define BOOT_SIZE_MULTI 226 /* RO */
+#define PARTITIONING_SUPPORT 160 /* RO */
+
+/*
+ * EXT_CSD field definitions
+ */
+
+/* Card */
+#define EXT_CSD_CMD_SET_NORMAL (1<<0)
+#define EXT_CSD_CMD_SET_SECURE (1<<1)
+#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
+
+#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_52_DDR_18_30 (1<<2) /* Card can run at 52MHz DDR 1.8V or 3V */
+#define EXT_CSD_CARD_TYPE_52_DDR_12 (1<<3) /* Card can run at 52MHz DDR 1.2V */
+
+#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
+#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
+#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
+#define EXT_CSD_BUS_WIDTH_4_DDR 5 /* Card is in 4 bit DDR mode */
+#define EXT_CSD_BUS_WIDTH_8_DDR 6 /* Card is in 8 bit DDR mode */
+
+
+typedef struct {
+ UINT32 hs_max_dtr;
+ UINT32 sectors;
+ UINT32 boot_size_multi; //226
+ UINT32 Partitioning_Support; //160
+}mmc_ext_csd;
+
+
+typedef struct {
+ UINT32 Reserved0: 7; // 0
+ UINT32 V170_V195: 1; // 1.70V - 1.95V
+ UINT32 V200_V260: 7; // 2.00V - 2.60V
+ UINT32 V270_V360: 9; // 2.70V - 3.60V
+ UINT32 RESERVED_1: 5; // Reserved
+ UINT32 AccessMode: 2; // 00b (byte mode), 10b (sector mode)
+ UINT32 Busy: 1; // This bit is set to LOW if the card has not finished the power up routine
+}OCR;
+
+typedef struct {
+ UINT32 NOT_USED; // 1 [0:0]
+ UINT32 CRC; // CRC7 checksum [7:1]
+ UINT32 MDT; // Manufacturing date [19:8]
+ UINT32 RESERVED_1; // Reserved [23:20]
+ UINT32 PSN; // Product serial number [55:24]
+ UINT8 PRV; // Product revision [63:56]
+ UINT8 PNM[5]; // Product name [64:103]
+ UINT16 OID; // OEM/Application ID [119:104]
+ UINT8 MID; // Manufacturer ID [127:120]
+}CID;
+
+typedef struct {
+ UINT8 NOT_USED: 1; // Not used, always 1 [0:0]
+ UINT8 CRC: 7; // CRC [7:1]
+
+ UINT8 RESERVED_1: 2; // Reserved [9:8]
+ UINT8 FILE_FORMAT: 2; // File format [11:10]
+ UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12]
+ UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13]
+ UINT8 COPY: 1; // Copy flag (OTP) [14:14]
+ UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15]
+
+ UINT16 RESERVED_2: 5; // Reserved [20:16]
+ UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21]
+ UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22]
+ UINT16 R2W_FACTOR: 3; // Write speed factor [28:26]
+ UINT16 RESERVED_3: 2; // Reserved [30:29]
+ UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31]
+
+ UINT32 WP_GRP_SIZE: 7; // Write protect group size [38:32]
+ UINT32 SECTOR_SIZE: 7; // Erase sector size [45:39]
+ UINT32 ERASE_BLK_EN: 1; // Erase single block enable [46:46]
+ UINT32 C_SIZE_MULT: 3; // Device size multiplier [49:47]
+ UINT32 VDD_W_CURR_MAX: 3; // Max. write current @ VDD max [52:50]
+ UINT32 VDD_W_CURR_MIN: 3; // Max. write current @ VDD min [55:53]
+ UINT32 VDD_R_CURR_MAX: 3; // Max. read current @ VDD max [58:56]
+ UINT32 VDD_R_CURR_MIN: 3; // Max. read current @ VDD min [61:59]
+ UINT32 C_SIZELow2: 2; // Device size [63:62]
+
+ UINT32 C_SIZEHigh10: 10;// Device size [73:64]
+ UINT32 RESERVED_4: 2; // Reserved [75:74]
+ UINT32 DSR_IMP: 1; // DSR implemented [76:76]
+ UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77]
+ UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78]
+ UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79]
+ UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80]
+ UINT32 CCC: 12;// Card command classes [95:84]
+
+ UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96]
+ UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+ UINT8 TAAC ; // Data read access-time 1 [119:112]
+
+ UINT8 RESERVED_5: 6; // Reserved [125:120]
+ UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126]
+}CSD;
+
+
+
+typedef struct {
+ UINT8 NOT_USED: 1; // Not used, always 1 [0:0]
+ UINT8 CRC: 7; // CRC [7:1]
+ UINT8 RESERVED_1: 2; // Reserved [9:8]
+ UINT8 FILE_FORMAT: 2; // File format [11:10]
+ UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12]
+ UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13]
+ UINT8 COPY: 1; // Copy flag (OTP) [14:14]
+ UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15]
+ UINT16 RESERVED_2: 5; // Reserved [20:16]
+ UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21]
+ UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22]
+ UINT16 R2W_FACTOR: 3; // Write speed factor [28:26]
+ UINT16 RESERVED_3: 2; // Reserved [30:29]
+ UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31]
+ UINT16 WP_GRP_SIZE: 7; // Write protect group size [38:32]
+ UINT16 SECTOR_SIZE: 7; // Erase sector size [45:39]
+ UINT16 ERASE_BLK_EN: 1; // Erase single block enable [46:46]
+ UINT16 RESERVED_4: 1; // Reserved [47:47]
+ UINT32 C_SIZELow16: 16;// Device size [69:48]
+ UINT32 C_SIZEHigh6: 6; // Device size [69:48]
+ UINT32 RESERVED_5: 6; // Reserved [75:70]
+ UINT32 DSR_IMP: 1; // DSR implemented [76:76]
+ UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77]
+ UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78]
+ UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79]
+ UINT16 READ_BL_LEN: 4; // Max. read data block length [83:80]
+ UINT16 CCC: 12;// Card command classes [95:84]
+ UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96]
+ UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+ UINT8 TAAC ; // Data read access-time 1 [119:112]
+ UINT8 RESERVED_6: 6; // 0 [125:120]
+ UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126]
+}CSD_SDV2;
+
+typedef enum {
+ UNKNOWN_CARD,
+ MMC_CARD, //MMC card
+ SD_CARD, //SD 1.1 card
+ SD_CARD_2, //SD 2.0 or above standard card
+ SD_CARD_2_HIGH, //SD 2.0 or above high capacity card
+ SD_CARD_MAX
+} CARD_TYPE;
+
+
+
+typedef enum {
+ MSHC_IDMA,
+ MSHC_FIFO
+}MSHC_OPERATION_MODE;
+
+typedef struct {
+ UINT16 RCA;
+ UINTN BlockSize;
+ UINTN NumBlocks;
+ UINTN TotalNumBlocks;
+ UINTN ClockFrequencySelect;
+ CARD_TYPE CardType;
+ OCR OCRData;
+ CID CIDData;
+ CSD CSDData;
+ mmc_ext_csd Extcsd;
+} CARD_INFO;
+
+
+EFI_STATUS
+DetectCard (VOID);
+void mshci_reset_fifo(void);
+
+extern EFI_BLOCK_IO_PROTOCOL gBlockIo;
+extern EFI_BLOCK_IO_MEDIA gSDMMCMedia;
+extern CARD_INFO gCardInfo;
+extern BOOLEAN gCardInit;
+
+extern EFI_STATUS
+SdReadWrite (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINTN Lba,
+ OUT VOID *Buffer,
+ IN UINTN BufferSize,
+ IN OPERATION_TYPE OperationType
+ );
+EFI_STATUS
+EraseBlockData (
+ IN UINT32 Partition,
+ IN UINTN StartBlock,
+ IN UINTN NumBlock
+ );
+
+
+
+#endif
+
diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.inf b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.inf
new file mode 100755
index 000000000..45e9ed1a4
--- /dev/null
+++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe.inf
@@ -0,0 +1,64 @@
+#/** @file
+#
+# Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = eMMCDxe
+ FILE_GUID = 39ad4d3f-dee8-4708-ac4e-46c8335c48a6
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = MSHCInitialize
+
+
+[Sources.common]
+ eMMCDxe.c
+ eMMCDxe_5250.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SamsungPlatformPkg/ExynosPkg/Exynos5250/ExynosPkg.dec
+ SamsungPlatformPkg/SamsungPlatformPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ SamsungPlatformPkg/ArndaleBoardPkg/ArndaleBoardPkg.dec
+ ArmPkg/ArmPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ IoLib
+ TimerLib
+ MemoryAllocationLib
+ UncachedMemoryAllocationLib
+
+[Guids]
+
+[Protocols]
+ gEfiBlockIoProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gSamsungPlatformGpioProtocolGuid ## GPIO Protocol
+ gEfiFirmwareVolumeBlockProtocolGuid
+
+[Pcd]
+ gExynosPkgTokenSpaceGuid.PcdCmuBase
+ gExynosPkgTokenSpaceGuid.PcdSdMmcCH0Base
+ gExynosPkgTokenSpaceGuid.PcdEmmcDMABufferBase
+
+[FixedPcd.common]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+
+[Depex]
+ TRUE
+
+
diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.c
new file mode 100755
index 000000000..511b079d4
--- /dev/null
+++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.c
@@ -0,0 +1,721 @@
+/** @file
+ MMC/SD Card driver for Secure Digital Host Controller
+
+ This driver always produces a BlockIo protocol but it starts off with no Media
+ present. A TimerCallBack detects when media is inserted or removed and after
+ a media change event a call to BlockIo ReadBlocks/WriteBlocks will cause the
+ media to be detected (or removed) and the BlockIo Media structure will get
+ updated. No MMC/SD Card harward registers are updated until the first BlockIo
+ ReadBlocks/WriteBlocks after media has been insterted (booting with a card
+ plugged in counts as an insertion event).
+
+ Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UncachedMemoryAllocationLib.h>
+#include <Protocol/ExynosGpio.h>
+#include <Platform/ArmPlatform.h>
+#include <Platform/Exynos5250.h>
+#include <Platform/Arndale5250.h>
+
+
+#include "eMMCDxe.h"
+
+//#undef EFI_D_INFO
+//#define EFI_D_INFO 1
+
+#define DMA_UNCACHE_ALLOC 0
+#if DMA_UNCACHE_ALLOC
+UINT32 *DMABuffer;
+#endif
+void MSHC_reset_all(void)
+{
+ int count;
+ volatile int ctl_val=0;
+ UINT32 SdMmcBaseAddr;
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+
+ /* Wait max 100 ms */
+ count = 10000;
+
+ /* before reset ciu, it should check DATA0. if when DATA0 is low and
+ it resets ciu, it might make a problem */
+ while ((MmioRead32 ((SdMmcBaseAddr + MSHCI_STATUS)) & (1<<9))){
+ if (count == 0) {
+ DEBUG ((EFI_D_ERROR, "MMC controller never released. \n"));
+ return;
+ }
+ count--;
+ MicroSecondDelay(1);
+ }
+
+ // Reset CIU
+ ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL));
+ ctl_val |= CTRL_RESET;
+ MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val);
+
+ //Reset FIFO
+ MSHC_reset_fifo();
+
+ //Reset DMA
+ ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL));
+ ctl_val |= DMA_RESET;
+ MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val);
+
+ //Set auto stop CMD
+ ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL));
+ ctl_val |= SEND_AS_CCSD;
+ MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val);
+
+}
+
+
+void MSHC_Set_DDR(int BusMode)
+{
+
+ UINT32 clkphase;
+ //clkphase = 0x03030002; //cmd response error at 50M RINT=0x46 error, RE and CD, RCRC
+ //clkphase = 0x03020001; //data read error at 50M SBE
+ UINT32 SdMmcBaseAddr;
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+
+ if(BusMode==BUSMODE_DDR)
+ {
+ DEBUG ((EFI_D_INFO, "MSHC DDR .\n"));
+ MmioWrite32((SdMmcBaseAddr + MSHCI_UHS_REG), UHS_DDR);
+ clkphase = 0x03020001;
+ }
+ else
+ {
+ DEBUG ((EFI_D_INFO, "MSHC Non DDR .\n"));
+ MmioWrite32((SdMmcBaseAddr + MSHCI_UHS_REG), UHS_NON_DDR);
+ clkphase = 0x03030002;
+ }
+ MmioWrite32((SdMmcBaseAddr + MSHCI_CLKSEL), clkphase);
+
+}
+
+
+void MSHC_5250_init(void)
+{
+ UINT32 SdMmcBaseAddr;
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+
+ /* Power Enable Register */
+ MmioWrite32((SdMmcBaseAddr + MSHCI_PWREN), POWER_ENABLE);
+ //MSHC_Set_DDR(BUSMODE_DDR);
+
+ MSHC_reset_all();
+
+ // Initialize FIFO
+ MmioWrite32((SdMmcBaseAddr + MSHCI_FIFOTH), (MSIZE_8 | TX_WMARK_DEFAULT | RX_WMARK_DEFAULT));
+
+ /* It clears all pending interrupts */
+ MmioWrite32((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_ALL);
+ /* It dose not use Interrupt. Disable all */
+ MmioWrite32((SdMmcBaseAddr + MSHCI_INTMSK), 0);
+
+ //UpdateMSHCClkFrequency(MSHC_CLK_400);
+
+ /* Set auto stop command */
+ //MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), (1<<10));
+
+ /* set debounce filter value*/
+ MmioWrite32((SdMmcBaseAddr + MSHCI_DEBNCE), (0xfffff));
+
+ /* clear card type. set 1-bit mode */
+ MmioWrite32((SdMmcBaseAddr + MSHCI_CTYPE), 0x0);
+
+ /* set bus mode register for IDMAC */
+ MmioWrite32((SdMmcBaseAddr + MSHCI_BMOD), (BMOD_IDMAC_RESET));
+
+ /* disable all interrupt source of IDMAC */
+ MmioWrite32((SdMmcBaseAddr + MSHCI_IDINTEN), (0x0));
+
+ /* set max timeout */
+ MmioWrite32((SdMmcBaseAddr + MSHCI_TMOUT), (0xffffffff));
+
+ MmioWrite32((SdMmcBaseAddr + MSHCI_BLKSIZ), BLEN_512BYTES);
+ MmioWrite32((SdMmcBaseAddr + MSHCI_CLKSEL), 0x03030002);
+
+}
+
+EFI_STATUS
+InitializeMSHC (
+ VOID
+ )
+{
+
+ EFI_STATUS Status;
+ EXYNOS_GPIO *Gpio;
+ UINT32 CumBaseAddr;
+ //UINT32 SdMmcBaseAddr;
+ UINT32 i, clock;
+ volatile UINT32 ctl_val;
+
+
+ Status = gBS->LocateProtocol(&gSamsungPlatformGpioProtocolGuid, NULL, (VOID **)&Gpio);
+ ASSERT_EFI_ERROR(Status);
+
+ CumBaseAddr = PcdGet32(PcdCmuBase);
+ //SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+
+ //MmioWrite32((SdMmcBaseAddr + SDHC_SWRST_OFFSET), SRA);
+
+ // Set Clock Source for using MPLL
+ ctl_val = MmioRead32((CumBaseAddr + CLK_SRC_FSYS_OFFSET));
+ ctl_val &= ~(0xf);
+ ctl_val |= (0x6);
+ MmioWrite32((CumBaseAddr + CLK_SRC_FSYS_OFFSET), ctl_val);
+ //MmioAndThenOr32 ((CumBaseAddr + CLK_SRC_FSYS_OFFSET), ~(0xF), (0x6));
+
+ // CLK mask
+ ctl_val = MmioRead32((CumBaseAddr + CLK_SRC_MASK_FSYS_OFFSET));
+ ctl_val |= (0x1);
+ MmioWrite32((CumBaseAddr + CLK_SRC_MASK_FSYS_OFFSET), ctl_val);
+
+ // CLK gating
+ ctl_val = MmioRead32((CumBaseAddr + CLK_GATE_IP_FSYS_OFFSET));
+ ctl_val |= (0x1<<12);
+ MmioWrite32((CumBaseAddr + CLK_GATE_IP_FSYS_OFFSET), ctl_val);
+
+
+ /* MMC2 clock div */
+ clock = 800; //MPLL in MHz
+ for(i=0; i<= 0xf; i++)
+ {
+ if((clock / (i+1)) <= 90) {
+ MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xF << 0), (i << 0));
+ break;
+ }
+ }
+
+
+ // 2. GPIO setting
+ // Set GPIO for using SD/MMC CH0 for eMMC
+ Gpio->Set(Gpio,SD_0_CLK,GPIO_MODE_SPECIAL_FUNCTION_2);
+ Gpio->Set(Gpio,SD_0_CMD,GPIO_MODE_SPECIAL_FUNCTION_2);
+ //Gpio->Set(Gpio,SD_0_CDn,GPIO_MODE_SPECIAL_FUNCTION_2);
+
+ //Set CDn as HIGH
+ Gpio->Set(Gpio,SD_0_CDn, GPIO_MODE_OUTPUT_1);
+
+
+ Gpio->Set(Gpio,SD_0_DATA0,GPIO_MODE_SPECIAL_FUNCTION_2);
+ Gpio->Set(Gpio,SD_0_DATA1,GPIO_MODE_SPECIAL_FUNCTION_2);
+ Gpio->Set(Gpio,SD_0_DATA2,GPIO_MODE_SPECIAL_FUNCTION_2);
+ Gpio->Set(Gpio,SD_0_DATA3,GPIO_MODE_SPECIAL_FUNCTION_2);
+ Gpio->Set(Gpio,SD_0_DATA4,GPIO_MODE_SPECIAL_FUNCTION_2);
+ Gpio->Set(Gpio,SD_0_DATA5,GPIO_MODE_SPECIAL_FUNCTION_2);
+ Gpio->Set(Gpio,SD_0_DATA6,GPIO_MODE_SPECIAL_FUNCTION_2);
+ Gpio->Set(Gpio,SD_0_DATA7,GPIO_MODE_SPECIAL_FUNCTION_2);
+
+ Gpio->SetPull(Gpio,SD_0_CLK,GPIO_PULL_NONE);
+ Gpio->SetPull(Gpio,SD_0_CMD,GPIO_PULL_NONE);
+ Gpio->SetPull(Gpio,SD_0_CDn,GPIO_PULL_UP);
+ Gpio->SetPull(Gpio,SD_0_DATA0,GPIO_PULL_UP);
+ Gpio->SetPull(Gpio,SD_0_DATA1,GPIO_PULL_UP);
+ Gpio->SetPull(Gpio,SD_0_DATA2,GPIO_PULL_UP);
+ Gpio->SetPull(Gpio,SD_0_DATA3,GPIO_PULL_UP);
+ Gpio->SetPull(Gpio,SD_0_DATA4,GPIO_PULL_UP);
+ Gpio->SetPull(Gpio,SD_0_DATA5,GPIO_PULL_UP);
+ Gpio->SetPull(Gpio,SD_0_DATA6,GPIO_PULL_UP);
+ Gpio->SetPull(Gpio,SD_0_DATA7,GPIO_PULL_UP);
+
+Gpio->SetStrength(Gpio,SD_0_CLK,GPIO_DRV_3X);
+Gpio->SetStrength(Gpio,SD_0_CMD,GPIO_DRV_3X);
+Gpio->SetStrength(Gpio,SD_0_CDn,GPIO_DRV_3X);
+Gpio->SetStrength(Gpio,SD_0_DATA0,GPIO_DRV_3X);
+Gpio->SetStrength(Gpio,SD_0_DATA1,GPIO_DRV_3X);
+Gpio->SetStrength(Gpio,SD_0_DATA2,GPIO_DRV_3X);
+Gpio->SetStrength(Gpio,SD_0_DATA3,GPIO_DRV_3X);
+Gpio->SetStrength(Gpio,SD_0_DATA4,GPIO_DRV_3X);
+Gpio->SetStrength(Gpio,SD_0_DATA5,GPIO_DRV_3X);
+Gpio->SetStrength(Gpio,SD_0_DATA6,GPIO_DRV_3X);
+Gpio->SetStrength(Gpio,SD_0_DATA7,GPIO_DRV_3X);
+
+ MSHC_5250_init();
+#if DMA_UNCACHE_ALLOC
+ DMABuffer = (UINT32 *)UncachedAllocatePool(EMMC_DMA_PHYSICAL_BUFFER_SIZE/2);
+ if(DMABuffer==NULL)
+ {
+ DEBUG ((EFI_D_ERROR, "MSHC::DMA alloc failed \n"));
+ }
+#endif
+ return EFI_SUCCESS;
+
+}
+
+void MSHC_reset_fifo(void)
+{
+ volatile int ctl_val=0;
+ UINT32 SdMmcBaseAddr;
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+ //Reset FIFO
+ ctl_val = MmioRead32((SdMmcBaseAddr + MSHCI_CTRL));
+ ctl_val |= FIFO_RESET;
+ MmioWrite32((SdMmcBaseAddr + MSHCI_CTRL), ctl_val);
+
+}
+
+
+VOID MSHC_clock_onoff (int value)
+{
+ volatile UINT32 loop_count = 0x100000;
+ UINT32 SdMmcBaseAddr;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+
+ if(value==CLK_ENABLE)
+ {
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKENA), (0x1<<0));
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), 0);
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), CMD_ONLY_CLK);
+ do {
+ if((MmioRead32 (SdMmcBaseAddr + MSHCI_CMD) & CMD_STRT_BIT)==0)
+ break;
+ loop_count--;
+ } while (loop_count);
+ }
+ else
+ {
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKENA), (0x0<<0));
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), 0);
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), CMD_ONLY_CLK);
+ do {
+ if((MmioRead32 (SdMmcBaseAddr + MSHCI_CMD) & CMD_STRT_BIT)==0)
+ break;
+ loop_count--;
+ } while (loop_count);
+ }
+
+ if (loop_count == 0) {
+ DEBUG ((EFI_D_ERROR, "MSHC::clockonoff : Clk = %d\n", value));
+ }
+
+}
+
+
+VOID
+UpdateMSHCClkFrequency (
+ UINTN NewCLK
+ )
+{
+ UINT32 CumBaseAddr;
+ UINT32 SdMmcBaseAddr;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+ CumBaseAddr = PcdGet32(PcdCmuBase);
+
+ // Disable all clocks to not provide the clock to the card
+//(CONFIG_CPU_EXYNOS5250_EVT1)
+ MSHC_clock_onoff(CLK_DISABLE);
+ //MmioAnd32 ((SdMmcBaseAddr + CLKCON_OFFSET), ~(0xF));
+
+ //Set new clock frequency.
+ if (NewCLK == MSHC_CLK_400)
+ {
+ DEBUG ((EFI_D_INFO, "MSHC::CLK=400.\n"));
+ // MPLL=800, cclk_in=100, 100M/250=400k
+ //MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xFFFF), 0xE008);
+ MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xFFFF), 0x1);
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKDIV), 125);
+ }
+ else if (NewCLK == MSHC_CLK_25M)
+ {
+ DEBUG ((EFI_D_INFO, "MSHC::CLK=25M.\n"));
+ // DDR mode use CLKDIV MPLL = 800, SCLK = 400, cclk_in=100M
+ MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xFFFF), 0x1);
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKDIV), 2);
+ }
+ else if(NewCLK == MSHC_CLK_50M)
+ {
+ DEBUG ((EFI_D_INFO, "MSHC::CLK=50M.\n"));
+ // DDR mode use CLKDIV MPLL = 800, SCLK = 400, cclk_in=100M
+ MmioAndThenOr32 ((CumBaseAddr + CLK_DIV_FSYS1_OFFSET), ~(0xFFFF), 0x1);
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CLKDIV), 1);
+
+ MSHC_Set_DDR(BUSMODE_DDR);
+ //MmioWrite32 ((SdMmcBaseAddr + MSHCI_CMD), CMD_ONLY_CLK);
+ }
+
+//#if defined(CONFIG_CPU_EXYNOS5250_EVT1)
+ MSHC_clock_onoff(CLK_ENABLE);
+ //MmioOr32 ((SdMmcBaseAddr + CLKCON_OFFSET), ICE);
+
+ //Poll till Internal Clock Stable
+ //while ((MmioRead32 ((SdMmcBaseAddr + CLKCON_OFFSET)) & ICS) != ICS);
+
+ //Set Clock enable to 0x1 to provide the clock to the card
+ //MmioOr32 ((SdMmcBaseAddr + CLKCON_OFFSET), CCE);
+
+}
+
+extern MSHC_OPERATION_MODE MSHC_operation_mode;
+void mshci_set_mdma_desc(UINT8 *desc_vir, UINT8 *desc_phy,
+ UINT32 des0, UINT32 des1, UINT32 des2)
+{
+ ((struct mshci_idmac *)(desc_vir))->des0 = des0;
+ ((struct mshci_idmac *)(desc_vir))->des1 = des1;
+ ((struct mshci_idmac *)(desc_vir))->des2 = des2;
+ ((struct mshci_idmac *)(desc_vir))->des3 = (UINT32)desc_phy +
+ sizeof(struct mshci_idmac);
+}
+
+
+VOID
+PrepareTransfer (
+IN OUT VOID *Buffer, UINTN BlockCount, IN OPERATION_TYPE OperationType
+ )
+{
+ UINT32 SdMmcBaseAddr;
+ UINT32 EmmcDMABufferBase;
+ volatile UINT32 MshcRegValue;
+ struct mshci_idmac *pdesc_dmac;
+ UINT32 des_flag;
+ UINTN i=0;
+ UINT32 ByteCnt=0;
+ UINT32 BlockCnt=BlockCount;
+// UINT32 MSH_uDES_A_0, MSH_uDES_A_1, MSH_uDES_A_2, MSH_uDES_A_3;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+#if DMA_UNCACHE_ALLOC
+ EmmcDMABufferBase = (UINT32)DMABuffer;
+#else
+ EmmcDMABufferBase = PcdGet32(PcdEmmcDMABufferBase);
+#endif
+ //pdesc_dmac = idmac_desc;
+ pdesc_dmac = (struct mshci_idmac *)EmmcDMABufferBase;
+
+ if(MSHC_operation_mode==MSHC_FIFO)
+ {
+ MSHC_reset_fifo();
+
+ // 1. enable interrupt mode
+ MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_CTRL);
+ MshcRegValue |= INT_ENABLE;
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CTRL), MshcRegValue);
+
+ // 2. DDR mode
+
+ // 3. set BLKSIZE
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_BLKSIZ), BLEN_512BYTES);
+ //MmioWrite32 ((SdMmcBaseAddr + MSHCI_BLKSIZ), BLKSIZE_1);
+
+ // 4. set BYTCNT
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_BYTCNT), BLEN_512BYTES);
+
+ //Setting Data timeout counter value to max value.
+ MmioWrite32((SdMmcBaseAddr + MSHCI_TMOUT), (0xffffffff));
+
+ }
+ else if(MSHC_operation_mode==MSHC_IDMA)
+ {
+ ZeroMem ((VOID *)EmmcDMABufferBase, PHY_BUF_OFFSET);//20120608
+ if(OperationType==WRITE)
+ {
+ CopyMem((VOID *)(EmmcDMABufferBase+PHY_BUF_OFFSET), (VOID *)Buffer, BlockCount*BLEN_512BYTES);
+ //DEBUG ((EFI_D_INFO, "MSHC_DMA prepare WRITE:%d Block \n", BlockCount));
+ }
+ else
+ {
+ //DEBUG ((EFI_D_INFO, "MSHC_DMA prepare READ:%d Block \n", BlockCount));
+ }
+
+ MSHC_reset_fifo();
+
+ //IDMA reset
+ MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_BMOD);
+ MshcRegValue |= (BMOD_IDMAC_RESET);
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_BMOD), MshcRegValue);
+
+
+ // 1. enable IDMA at CTRL
+ MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_CTRL);
+ MshcRegValue &= ~(INT_ENABLE);
+ MshcRegValue |= (ENABLE_IDMAC);
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_CTRL), MshcRegValue);
+
+
+ // 2. enable IDMA at BMODE
+ //Set Block Size and Block count.
+ MshcRegValue = MmioRead32(SdMmcBaseAddr + MSHCI_BMOD);
+ MshcRegValue |= (BMOD_IDMAC_ENABLE | BMOD_IDMAC_FB);
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_BMOD), MshcRegValue);
+
+ // interrupt enable
+ MmioWrite32((SdMmcBaseAddr + MSHCI_IDINTEN), (0x337));
+
+#if 0
+#if 0
+ // set descriptor singlechain
+ des_flag = 0x8000000E;
+ MSH_uDES_A_0 = (EmmcDMABufferBase+0x02F000);
+ MSH_uDES_A_1 = (EmmcDMABufferBase+0x02F004);
+ MSH_uDES_A_2 = (EmmcDMABufferBase+0x02F008);
+ MSH_uDES_A_3 = (EmmcDMABufferBase+0x02F00C);
+ MmioWrite32(MSH_uDES_A_0, 0x8000000E);
+ MmioWrite32(MSH_uDES_A_1, (ByteCount));
+ MmioWrite32(MSH_uDES_A_2, (EmmcDMABufferBase+PHY_BUF_OFFSET));
+ MmioWrite32(MSH_uDES_A_3, MSH_uDES_A_0);
+#endif
+
+
+
+ des_flag = (MSHCI_IDMAC_OWN | MSHCI_IDMAC_FS | MSHCI_IDMAC_DIC | MSHCI_IDMAC_LD);
+ mshci_set_mdma_desc((UINT8 *)pdesc_dmac,
+ (UINT8 *)pdesc_dmac,
+ des_flag, ByteCount,
+ ((UINT32)(EmmcDMABufferBase + PHY_BUF0_OFFSET)));
+
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_DBADDR), (UINT32)pdesc_dmac);
+
+
+
+#else
+
+ for(i=0; ; i++)
+ {
+ // set descriptor multichain
+ des_flag = (MSHCI_IDMAC_OWN|MSHCI_IDMAC_CH);
+ des_flag |= (i==0) ? MSHCI_IDMAC_FS:0;
+ if(BlockCnt<=8)
+ {
+ //DEBUG ((EFI_D_INFO, "DESC LD\n"));
+ des_flag |= (MSHCI_IDMAC_LD);
+ mshci_set_mdma_desc((UINT8 *)pdesc_dmac,
+ //(UINT8 *)pdesc_dmac,
+ (UINT8 *)(EmmcDMABufferBase-sizeof(struct mshci_idmac)),
+ des_flag, BlockCnt*BLEN_512BYTES,
+ ((UINT32)((EmmcDMABufferBase + PHY_BUF_OFFSET)+(UINT32)(i*PHY_BUF_SIZE))));
+ break;
+
+ }
+ //DEBUG ((EFI_D_INFO, "DESC FS\n"));
+ mshci_set_mdma_desc((UINT8 *)pdesc_dmac,
+ (UINT8 *)pdesc_dmac,
+ des_flag, BLEN_512BYTES*8,
+ ((UINT32)((EmmcDMABufferBase + PHY_BUF_OFFSET)+(UINT32)(i*PHY_BUF_SIZE))));
+
+ BlockCnt -=8;
+ pdesc_dmac++;
+
+ }
+
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_DBADDR), (UINT32)EmmcDMABufferBase);
+
+#endif
+
+ // 3. set BLKSIZE
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_BLKSIZ), BLEN_512BYTES);
+
+ // 4. set BYTCNT
+ ByteCnt = (BlockCount*BLEN_512BYTES);
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_BYTCNT), ByteCnt);
+
+ //Setting Data timeout counter value to max value.
+ MmioWrite32((SdMmcBaseAddr + MSHCI_TMOUT), (0xffffffff));
+ DEBUG ((EFI_D_INFO, "Block:%d BYTCNT:0x%x ByteCnt:0x%x\n", BlockCount,MmioRead32(SdMmcBaseAddr + MSHCI_BYTCNT), ByteCnt));
+
+ }
+
+}
+
+EFI_STATUS MSHC_ReadFIFO(IN UINTN Size32, OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ UINT32 SdMmcBaseAddr;
+ UINTN *DataBuffer = Buffer;
+ UINTN BufSize=Size32;
+ UINTN FifoCount=0;
+ UINTN Count=0;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+ //Check controller status to make sure there is no error.
+
+ while (BufSize)
+ {
+ if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_RXDR)
+ {
+
+ //Read block worth of data.
+ FifoCount = GET_FIFO_COUNT(MmioRead32 (SdMmcBaseAddr + MSHCI_STATUS));
+ DEBUG ((EFI_D_INFO, "MSHC::ReadBlock DTO FIFO:%d\n", FifoCount));
+ for (Count = 0; Count < FifoCount; Count++)
+ {
+ *DataBuffer++ = MmioRead32 (SdMmcBaseAddr + MSHCI_FIFO);
+ }
+ MmioWrite32((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_RXDR);
+ BufSize -= FifoCount;
+ }
+
+ else if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_DTO)
+ {
+
+ //Read block worth of data.
+ FifoCount = GET_FIFO_COUNT(MmioRead32 (SdMmcBaseAddr + MSHCI_STATUS));
+ DEBUG ((EFI_D_INFO, "MSHC::ReadBlock DTO FIFO:%d\n", FifoCount));
+ for (Count = 0; Count < FifoCount; Count++)
+ {
+ *DataBuffer++ = MmioRead32 (SdMmcBaseAddr + MSHCI_FIFO);
+ }
+ MmioWrite32((SdMmcBaseAddr + MSHCI_RINTSTS), INTMSK_DTO);
+ BufSize -= FifoCount;
+ }
+
+ else if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & (INTMSK_DCRC|INTMSK_DRTO|INTMSK_HTO|INTMSK_FRUN))
+ {
+ DEBUG ((EFI_D_INFO, "MSHC::ReadBlock Error RINT:0x%x\n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ }
+
+ if(BufSize==0)
+ {
+ Status = EFI_SUCCESS;
+ }
+ else
+ {
+ Status = EFI_BAD_BUFFER_SIZE;
+ }
+ return Status;
+}
+
+EFI_STATUS MSHC_WriteFIFO(IN UINTN Size32, IN VOID *Buffer)
+{
+ UINT32 SdMmcBaseAddr;
+ UINTN *DataBuffer = Buffer;
+ UINTN BufSize=Size32;
+ UINTN Count=0;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+
+ if(BufSize>FIFO_SIZE)
+ {
+ DEBUG ((EFI_D_INFO, "MSHC::Error MSHC_WriteFIFO Bad buffer size\n"));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ //Write block worth of data.
+ for (Count = 0; Count < BufSize; Count++)
+ {
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_FIFO), *DataBuffer++);
+ }
+ return EFI_SUCCESS;
+
+}
+
+/*typedef
+VOID
+CopyMem (
+ IN VOID *Destination,
+ IN VOID *Source,
+ IN UINTN Length
+ );*/
+
+EFI_STATUS MSHC_ReadDMA(OUT VOID *Buffer, IN UINTN BlockCount)
+{
+ EFI_STATUS Status;
+ UINT32 SdMmcBaseAddr;
+ UINT32 EmmcDMABufferBase;
+ UINTN Count=MAX_RETRY_COUNT;
+ //UINT32 MshcRegValue;
+ //UINT32 TransferSize=0;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+#if DMA_UNCACHE_ALLOC
+ EmmcDMABufferBase = (UINT32)DMABuffer;
+#else
+ EmmcDMABufferBase = PcdGet32(PcdEmmcDMABufferBase);
+#endif
+ //Check controller status to make sure there is no error.
+
+ while (Count)
+ {
+ if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_DTO)
+ {
+ //TransferSize = MmioRead32 (SdMmcBaseAddr + MSHCI_TBBCNT);
+ CopyMem((VOID *)Buffer, (VOID *)(EmmcDMABufferBase+PHY_BUF_OFFSET), BlockCount*BLEN_512BYTES);
+ DEBUG ((EFI_D_INFO, "MSHC_ReadDMA Over %d Blocks\n", BlockCount));
+ break;
+ }
+ else if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & (DATA_ERR|DATA_TOUT))
+ {
+ DEBUG ((EFI_D_ERROR, "MSHC_ReadDMA Err RINT:0x%x\n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)));
+ }
+
+ else
+ {
+ Count--;
+ MicroSecondDelay(1);
+ DEBUG ((EFI_D_INFO, ".\n"));
+ }
+
+ }
+
+ if(Count!=0)
+ {
+ Status = EFI_SUCCESS;
+ }
+ else
+ {
+ DEBUG ((EFI_D_ERROR, "MSHC_ReadDMA bad buffer size RINT:0x%x\n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)));
+ Status = EFI_BAD_BUFFER_SIZE;
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_PLDMND), 7);
+
+ }
+ return Status;
+}
+
+EFI_STATUS MSHC_WriteDMA(IN VOID *Buffer, IN UINTN BlockCount)
+{
+ EFI_STATUS Status;
+ UINT32 SdMmcBaseAddr;
+ UINTN Count=MAX_RETRY_COUNT;
+
+ SdMmcBaseAddr = PcdGet32(PcdSdMmcCH0Base);
+ //Check controller status to make sure there is no error.
+
+ while (Count)
+ {
+ if((MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)) & INTMSK_DTO)
+ {
+ DEBUG ((EFI_D_INFO, "MSHC_writeDMA Over %d blocks\n", BlockCount));
+ break;
+ }
+ else
+ {
+ MicroSecondDelay(1);
+ Count--;
+ }
+
+ }
+
+ if(Count!=0)
+ {
+ Status = EFI_SUCCESS;
+ }
+ else
+ {
+ Status = EFI_BAD_BUFFER_SIZE;
+ MmioWrite32 ((SdMmcBaseAddr + MSHCI_PLDMND), 7);
+ DEBUG ((EFI_D_ERROR, "MSHC_writeDMA bad buffer size RINT:0x%x \n", MmioRead32 (SdMmcBaseAddr + MSHCI_RINTSTS)));
+ }
+ return Status;
+}
diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.h
new file mode 100755
index 000000000..56638ba44
--- /dev/null
+++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_5250.h
@@ -0,0 +1,322 @@
+/** @file
+
+ Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _MSHCDXE_5250_H_
+#define _MSHCDXE_5250_H_
+
+
+/*
+ * Controller registers
+ */
+/*****************************************************/
+/* MSHC Internal Registers */
+/*****************************************************/
+
+#define MSHCI_CTRL 0x00 /* Control */
+#define MSHCI_PWREN 0x04 /* Power-enable */
+#define MSHCI_CLKDIV 0x08 /* Clock divider */
+#define MSHCI_CLKSRC 0x0C /* Clock source */
+#define MSHCI_CLKENA 0x10 /* Clock enable */
+#define MSHCI_TMOUT 0x14 /* Timeout */
+#define MSHCI_CTYPE 0x18 /* Card type */
+#define MSHCI_BLKSIZ 0x1C /* Block Size */
+#define MSHCI_BYTCNT 0x20 /* Byte count */
+#define MSHCI_INTMSK 0x24 /* Interrupt Mask */
+#define MSHCI_CMDARG 0x28 /* Command Argument */
+#define MSHCI_CMD 0x2C /* Command */
+#define MSHCI_RESP0 0x30 /* Response 0 */
+#define MSHCI_RESP1 0x34 /* Response 1 */
+#define MSHCI_RESP2 0x38 /* Response 2 */
+#define MSHCI_RESP3 0x3C /* Response 3 */
+#define MSHCI_MINTSTS 0x40 /* Masked interrupt status */
+#define MSHCI_RINTSTS 0x44 /* Raw interrupt status */
+#define MSHCI_STATUS 0x48 /* Status */
+#define MSHCI_FIFOTH 0x4C /* FIFO threshold */
+#define MSHCI_CDETECT 0x50 /* Card detect */
+#define MSHCI_WRTPRT 0x54 /* Write protect */
+#define MSHCI_GPIO 0x58 /* General Purpose IO */
+#define MSHCI_TCBCNT 0x5C /* Transferred CIU byte count */
+#define MSHCI_TBBCNT 0x60 /* Transferred host/DMA to/from byte count */
+#define MSHCI_DEBNCE 0x64 /* Card detect debounce */
+#define MSHCI_USRID 0x68 /* User ID */
+#define MSHCI_VERID 0x6C /* Version ID */
+#define MSHCI_HCON 0x70 /* Hardware Configuration */
+#define MSHCI_UHS_REG 0x74 /* UHS and DDR setting */
+#define MSHCI_BMOD 0x80 /* Bus mode register */
+#define MSHCI_PLDMND 0x84 /* Poll demand */
+#define MSHCI_DBADDR 0x88 /* Descriptor list base address */
+#define MSHCI_IDSTS 0x8C /* Internal DMAC status */
+#define MSHCI_IDINTEN 0x90 /* Internal DMAC interrupt enable */
+#define MSHCI_DSCADDR 0x94 /* Current host descriptor address */
+#define MSHCI_BUFADDR 0x98 /* Current host buffer address */
+#define MSHCI_CLKSEL 0x9C /* Drv/sample clock selection register */
+#define MSHCI_WAKEUPCON 0xA0 /* Wakeup control register */
+#define MSHCI_CLOCKCON 0xA4 /* Clock (delay) control register */
+#define MSHCI_FIFO 0x200
+#define MSHCI_FIFODAT(x) (x) /* FIFO data read write */
+
+
+/*****************************************************
+ * Control Register Register
+ * MSHCI_CTRL - offset 0x00
+ *****************************************************/
+
+#define CTRL_RESET (0x1<<0) /* Reset DWC_mobile_storage controller */
+#define FIFO_RESET (0x1<<1) /* Reset FIFO */
+#define DMA_RESET (0x1<<2) /* Reset DMA interface */
+#define INT_ENABLE (0x1<<4) /* Global interrupt enable/disable bit */
+#define DMA_ENABLE (0x1<<5) /* DMA transfer mode enable/disable bit */
+#define READ_WAIT (0x1<<6) /* For sending read-wait to SDIO cards */
+#define SEND_IRQ_RESP (0x1<<7) /* Send auto IRQ response */
+#define ABRT_READ_DATA (0x1<<8)
+#define SEND_CCSD (0x1<<9)
+#define SEND_AS_CCSD (0x1<<10)
+#define CEATA_INTSTAT (0x1<<11)
+#define CARD_VOLA (0xF<<16)
+#define CARD_VOLB (0xF<<20)
+#define ENABLE_OD_PULLUP (0x1<<24)
+#define ENABLE_IDMAC (0x1<<25)
+#define MSHCI_RESET_ALL (0x1)
+
+/*****************************************************
+ * Power Enable Register
+ * MSHCI_PWREN - offset 0x04
+ *****************************************************/
+#define POWER_ENABLE (0x1<<0)
+
+/*****************************************************
+* Clock Enable Register
+* MSHCI_CLKENA - offset 0x10
+*****************************************************/
+#define CLK_SDMMC_MAX (48000000) /* 96Mhz. it SHOULDBE optimized */
+#define CLK_ENABLE (0x1<<0)
+#define CLK_DISABLE (0x0<<0)
+
+
+/*****************************************************
+ * Interrupt Mask Register
+ * MSHCI_INTMSK - offset 0x24
+ *****************************************************/
+#define INT_MASK (0xFFFF<<0)
+#define SDIO_INT_MASK (0xFFFF<<16)
+#define SDIO_INT_ENABLE (0x1<<16)
+
+/* interrupt bits */
+#define INTMSK_ALL 0xFFFFFFFF
+#define INTMSK_CDETECT (0x1<<0)
+#define INTMSK_RE (0x1<<1)
+#define INTMSK_CDONE (0x1<<2)
+#define INTMSK_DTO (0x1<<3)
+#define INTMSK_TXDR (0x1<<4)
+#define INTMSK_RXDR (0x1<<5)
+#define INTMSK_RCRC (0x1<<6)
+#define INTMSK_DCRC (0x1<<7)
+#define INTMSK_RTO (0x1<<8)
+#define INTMSK_DRTO (0x1<<9)
+#define INTMSK_HTO (0x1<<10)
+#define INTMSK_FRUN (0x1<<11)
+#define INTMSK_HLE (0x1<<12)
+#define INTMSK_SBE (0x1<<13)
+#define INTMSK_ACD (0x1<<14)
+#define INTMSK_EBE (0x1<<15)
+#define INTMSK_DMA (INTMSK_ACD|INTMSK_RXDR|INTMSK_TXDR)
+
+#define INT_SRC_IDMAC (0x0)
+#define INT_SRC_MINT (0x1)
+
+
+/*****************************************************
+ * Command Register
+ * MSHCI_CMD - offset 0x2C
+ *****************************************************/
+
+#define CMD_RESP_EXP_BIT (0x1<<6)
+#define CMD_RESP_LENGTH_BIT (0x1<<7)
+#define CMD_CHECK_CRC_BIT (0x1<<8)
+#define CMD_DATA_EXP_BIT (0x1<<9)
+#define CMD_RW_BIT (0x1<<10)
+#define CMD_TRANSMODE_BIT (0x1<<11)
+#define CMD_SENT_AUTO_STOP_BIT (0x1<<12)
+#define CMD_WAIT_PRV_DAT_BIT (0x1<<13)
+#define CMD_ABRT_CMD_BIT (0x1<<14)
+#define CMD_SEND_INIT_BIT (0x1<<15)
+#define CMD_CARD_NUM_BITS (0x1F<<16)
+#define CMD_SEND_CLK_ONLY (0x1<<21)
+#define CMD_READ_CEATA (0x1<<22)
+#define CMD_CCS_EXPECTED (0x1<<23)
+#define CMD_USE_HOLD_REG (0x1<<29)
+#define CMD_STRT_BIT (0x1<<31)
+#define CMD_ONLY_CLK (CMD_STRT_BIT | CMD_SEND_CLK_ONLY | \
+ CMD_WAIT_PRV_DAT_BIT)
+
+/*****************************************************
+ * Raw Interrupt Register
+ * MSHCI_RINTSTS - offset 0x44
+ *****************************************************/
+#define INT_STATUS (0xFFFF<<0)
+#define SDIO_INTR (0xFFFF<<16)
+#define DATA_ERR (INTMSK_EBE|INTMSK_SBE|INTMSK_HLE|INTMSK_FRUN |\
+ INTMSK_EBE |INTMSK_DCRC)
+#define DATA_TOUT (INTMSK_HTO|INTMSK_DRTO)
+#define DATA_STATUS (DATA_ERR|DATA_TOUT|INTMSK_RXDR|INTMSK_TXDR|INTMSK_DTO)
+#define CMD_STATUS (INTMSK_RTO|INTMSK_RCRC|INTMSK_CDONE|INTMSK_RE)
+#define CMD_ERROR (INTMSK_RCRC|INTMSK_RTO|INTMSK_RE)
+
+
+/*****************************************************
+ * Status Register
+ * MSHCI_STATUS - offset 0x48
+ *****************************************************/
+#define FIFO_RXWTRMARK (0x1<<0)
+#define FIFO_TXWTRMARK (0x1<<1)
+#define FIFO_EMPTY (0x1<<2)
+#define FIFO_FULL (0x1<<3)
+#define CMD_FSMSTAT (0xF<<4)
+#define DATA_3STATUS (0x1<<8)
+#define DATA_BUSY (0x1<<9)
+#define DATA_MCBUSY (0x1<<10)
+#define RSP_INDEX (0x3F<<11)
+#define FIFO_COUNT (0x1FFF<<17)
+#define DMA_ACK (0x1<<30)
+#define DMA_REQ (0x1<<31)
+#define FIFO_WIDTH (0x4)
+#define FIFO_DEPTH (0x20)
+#define FIFO_SIZE (0x80)
+#define GET_FIFO_COUNT(x) (((x)&0x3ffe0000)>>17)
+
+
+
+/*****************************************************
+ * FIFO Threshold Watermark Register
+ * MSHCI_FIFOTH - offset 0x4C
+ *****************************************************/
+#define TX_WMARK (0xFFF<<0)
+#define RX_WMARK (0xFFF<<16)
+#define MSIZE_MASK (0x7<<28)
+
+/* DW DMA Mutiple Transaction Size */
+#define MSIZE_1 (0<<28)
+#define MSIZE_4 (1<<28)
+#define MSIZE_8 (2<<28)
+#define MSIZE_16 (3<<28)
+#define MSIZE_32 (4<<28)
+#define MSIZE_64 (5<<28)
+#define MSIZE_128 (6<<28)
+#define MSIZE_256 (7<<28)
+
+#define TX_WMARK_DEFAULT (0x10<<0)
+#define RX_WMARK_DEFAULT (0x10<<16)
+
+//#define TX_WMARK_DEFAULT (0x40<<0)
+//#define RX_WMARK_DEFAULT (0x3F<<16)
+
+
+/*****************************************************
+ * Bus Mode Register
+ * MSHCI_UHS_REG - offset 0x74
+ *****************************************************/
+#define UHS_DDR (0x1<<16)
+#define UHS_NON_DDR (0x0<<16)
+#define BUSMODE_DDR 1
+#define BUSMODE_NON_DDR 0
+
+/*****************************************************
+ * Bus Mode Register
+ * MSHCI_BMOD - offset 0x80
+ *****************************************************/
+#define BMOD_IDMAC_RESET (0x1<<0)
+#define BMOD_IDMAC_FB (0x1<<1)
+#define BMOD_IDMAC_ENABLE (0x1<<7)
+
+/*****************************************************
+ * Hardware Configuration Register
+ * MSHCI_IDSTS - offset 0x8c
+ *****************************************************/
+#define IDSTS_FSM (0xf<<13)
+#define IDSTS_EB (0x7<<10)
+#define IDSTS_AIS (0x1<<9)
+#define IDSTS_NIS (0x1<<8)
+#define IDSTS_CES (0x1<<5)
+#define IDSTS_DU (0x1<<4)
+#define IDSTS_FBE (0x1<<2)
+#define IDSTS_RI (0x1<<1)
+#define IDSTS_TI (0x1<<0)
+
+
+/*****************************************************
+ * Card Type Register
+ * MSHCI_CTYPE - offset 0x18
+ *****************************************************/
+#define CARD_WIDTH14 (0xFFFF<<0)
+#define CARD_WIDTH8 (0xFFFF<<16)
+
+struct mshci_idmac {
+ UINT32 des0;
+ UINT32 des1;
+ UINT32 des2;
+ UINT32 des3;
+#define MSHCI_IDMAC_OWN (1<<31)
+#define MSHCI_IDMAC_ER (1<<5)
+#define MSHCI_IDMAC_CH (1<<4)
+#define MSHCI_IDMAC_FS (1<<3)
+#define MSHCI_IDMAC_LD (1<<2)
+#define MSHCI_IDMAC_DIC (1<<1)
+#define INTMSK_IDMAC_ALL (0x337)
+#define INTMSK_IDMAC_ERROR (0x214)
+};
+
+typedef enum {
+ READ,
+ WRITE
+} OPERATION_TYPE;
+
+
+/*****************************************************
+ * DMA Buffer structure
+ *
+ * CH0 for eMMC 0x40300000--0x40380000
+ * CH2 for SD Card 0x40380000--0x40400000
+
+
+ *****************************************************/
+#define EMMC_DMA_PHYSICAL_BUFFER_BASE 0x40300000
+#define EMMC_DMA_PHYSICAL_BUFFER_SIZE 0x00100000 //1MB
+#define PHY_BUF_OFFSET 0x1000 //4K
+#define PHY_BUF_SIZE 0x1000 //4K
+
+#define MAX_MSHC_TRANSFER_SIZE 0x40000 //512blocks, 256KB
+
+
+
+/*****************************************************
+ * External Functions
+ *****************************************************/
+
+
+EFI_STATUS InitializeMSHC (VOID);
+VOID UpdateMSHCClkFrequency (UINTN NewCLK);
+void MSHC_reset_fifo(void);
+extern void MSHC_reset_all(void);
+extern VOID PrepareTransfer (IN OUT VOID *Buffer, UINTN ByteCount, IN OPERATION_TYPE OperationType);
+extern EFI_STATUS MSHC_ReadFIFO(IN UINTN Size32, OUT VOID *Buffer);
+extern EFI_STATUS MSHC_WriteFIFO(IN UINTN Size32, IN VOID *Buffer);
+void mshci_set_mdma_desc(UINT8 *desc_vir, UINT8 *desc_phy,
+ UINT32 des0, UINT32 des1, UINT32 des2);
+EFI_STATUS MSHC_ReadDMA(OUT VOID *Buffer, IN UINTN BlockCount);
+EFI_STATUS MSHC_WriteDMA(IN VOID *Buffer, IN UINTN BlockCount);
+
+
+
+#endif
+
diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_CMD.h b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_CMD.h
new file mode 100755
index 000000000..615da0799
--- /dev/null
+++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMCDxe_CMD.h
@@ -0,0 +1,165 @@
+/** @file
+
+ Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _MSHCDXE_CMD_H_
+#define _MSHCDXE_CMD_H_
+
+
+
+#define HosttoCard 0x1
+#define CardtoHost 0x0
+
+#define ENDMA BIT0
+#define ENBLKCNT BIT1
+#define RD1WT0 BIT4
+#define MUL1SIN0 BIT5
+#define RSPTYP136 (0x1 << 16)
+#define RSPTYP48 (0x2 << 16)
+#define RSPTYP48B (0x3 << 16)
+#define ENCMDCRC BIT19
+#define ENCMDIDX BIT20
+#define DATAPRNT BIT21
+
+
+#define CMDCOMP BIT0
+#define TRNSCOMP BIT1
+#define RDYFORWT BIT4
+#define RDYFORRD BIT5
+#define CARDINSERT BIT6
+#define CARDREMOVE BIT7
+#define ERRINT BIT15
+#define CMDTOUTERR BIT16
+#define CMDCRCERR BIT17
+#define CMDEBITERR BIT18
+#define CMDIDXERR BIT19
+#define DATATOUTERR BIT20
+#define DATACRCERR BIT21
+#define DATAEBITERR BIT22
+
+
+
+
+/* Command Definitions */
+#define INDX(CMD_INDX) (CMD_INDX & 0x3F)
+
+#define CMD0 INDX(0)
+#define CMD0_INT_EN (CMDCOMP | CMDEBITERR)
+
+#define CMD1 (INDX(1) | RSPTYP48)
+#define CMD1_INT_EN (CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define CMD2 (INDX(2) | ENCMDCRC | RSPTYP136)
+#define CMD2_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define CMD3 (INDX(3) | ENCMDIDX | ENCMDCRC | RSPTYP48)
+#define CMD3_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define CMD5 (INDX(5) | RSPTYP48)
+#define CMD5_INT_EN (CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define CMD7 (INDX(7) | ENCMDIDX | ENCMDCRC | RSPTYP48)
+#define CMD7_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define CMD8 (INDX(8) | ENCMDIDX | ENCMDCRC | RSPTYP48)
+#define CMD8_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+//Reserved(0)[12:31], Supply voltage(1)[11:8], check pattern(0xCE)[7:0] = 0x1CE
+#define CMD8_ARG (0x0UL << 12 | BIT8 | 0xCEUL << 0)
+
+#define CMD9 (INDX(9) | ENCMDCRC | RSPTYP136)
+#define CMD9_INT_EN (CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define CMD13 (INDX(13) | RSPTYP48)
+#define CMD13_INT_EN (CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+
+//#define CMD16 (INDX(16) | ENCMDIDX | ENCMDCRC | RSPTYP48)
+#define CMD16 (INDX(16) | ENCMDIDX | RSPTYP48)
+#define CMD16_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define CMD17 (INDX(17) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 | RD1WT0)
+#define CMD17_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORRD | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR)
+
+//#define CMD18 (INDX(18) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 | MUL1SIN0 | RD1WT0 | ENBLKCNT | ENDMA)
+#define CMD18 (INDX(18) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 )
+#define CMD18_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORRD | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR)
+
+#define CMD23 (INDX(23) | ENCMDIDX | ENCMDCRC | RSPTYP48)
+#define CMD23_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define CMD24 (INDX(24) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48)
+#define CMD24_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORWT | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR)
+
+//#define CMD25 (INDX(25) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48 | MUL1SIN0 | ENBLKCNT | ENDMA)
+#define CMD25 (INDX(25) | DATAPRNT | ENCMDIDX | ENCMDCRC | RSPTYP48)
+#define CMD25_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | TRNSCOMP | RDYFORWT | CMDTOUTERR | DATATOUTERR | DATACRCERR | DATAEBITERR | CMDEBITERR)
+
+#define CMD35 (INDX(35) | ENCMDCRC | RSPTYP48)
+#define CMD36 (INDX(36) | ENCMDCRC | RSPTYP48)
+#define CMD38 (INDX(38) |RSPTYP48)
+
+#define CMD55 (INDX(55) | ENCMDIDX | ENCMDCRC | RSPTYP48)
+#define CMD55_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define ACMD41 (INDX(41) | RSPTYP48)
+#define ACMD41_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define ACMD6 (INDX(6) | RSPTYP48)
+#define ACMD6_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+#define CMD62 (INDX(62) | RSPTYP48)
+#define CMD62_INT_EN (CMDIDXERR | CMDCRCERR | CMDCOMP | CMDEBITERR | CMDTOUTERR)
+
+
+
+/*
+EFI_STATUS
+EFI_SUCCESS 0
+
+EFI_LOAD_ERROR 1
+EFI_INVALID_PARAMETER 2
+EFI_UNSUPPORTED 3
+EFI_BAD_BUFFER_SIZE 4
+EFI_BUFFER_TOO_SMALL 5
+EFI_NOT_READY 6
+EFI_DEVICE_ERROR 7
+EFI_WRITE_PROTECTED 8
+EFI_OUT_OF_RESOURCES 9
+EFI_VOLUME_CORRUPTED 10
+EFI_VOLUME_FULL 11
+EFI_NO_MEDIA 12
+EFI_MEDIA_CHANGED 13
+EFI_NOT_FOUND 14
+EFI_ACCESS_DENIED 15
+EFI_NO_RESPONSE 16
+EFI_NO_MAPPING 17
+EFI_TIMEOUT 18
+EFI_NOT_STARTED 19
+EFI_ALREADY_STARTED 20
+EFI_ABORTED 21
+EFI_ICMO_ERROR 22
+EFI_TFTP_ERROR 23
+EFI_PROTOCOL_ERROR 24
+EFI_INCOMPATIBLE_VERSION 25
+EFI_SECURITY_VIOLATION 26
+EFI_CRC_ERROR 27
+EFI_END_OF_MEDIA 28
+EFI_END_OF_FILE 31
+EFI_INVALID_LANGUAGE 32
+EFI_COMPROMISED_DATA 33
+
+
+*/
+
+#endif
+
diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMC_Fvb.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMC_Fvb.c
new file mode 100755
index 000000000..ee8d1c902
--- /dev/null
+++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe/eMMC_Fvb.c
@@ -0,0 +1,587 @@
+/** @file
+ eMMC firmware volume block protocol driver
+ Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UncachedMemoryAllocationLib.h>
+
+#include <Protocol/FirmwareVolumeBlock.h>
+#include "eMMCDxe.h"
+
+
+//#undef EFI_D_INFO
+//#define EFI_D_INFO 1
+
+
+EFI_FVB_ATTRIBUTES_2 gAttribute = (EFI_FVB2_READ_STATUS|EFI_FVB2_WRITE_STATUS|EFI_FVB2_ALIGNMENT_32);
+UINT32 *FVBMemAddr;
+
+/**
+ The GetAttributes() function retrieves the attributes and
+ current settings of the block.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the
+ attributes and current settings are
+ returned. Type EFI_FVB_ATTRIBUTES_2 is defined
+ in EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were
+ returned.
+
+**/
+
+EFI_STATUS
+EFIAPI
+FvbGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ *Attributes = gAttribute;
+ DEBUG ((EFI_D_INFO, "FvbGetAttributes 0x%x\n", gAttribute));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The SetAttributes() function sets configurable firmware volume
+ attributes and returns the new settings of the firmware volume.
+
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Attributes On input, Attributes is a pointer to
+ EFI_FVB_ATTRIBUTES_2 that contains the
+ desired firmware volume settings. On
+ successful return, it contains the new
+ settings of the firmware volume. Type
+ EFI_FVB_ATTRIBUTES_2 is defined in
+ EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+ @retval EFI_INVALID_PARAMETER The attributes requested are in
+ conflict with the capabilities
+ as declared in the firmware
+ volume header.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ gAttribute |= *Attributes;
+ *Attributes = gAttribute;
+ DEBUG ((EFI_D_INFO, "FvbSetAttributes 0x%x\n", gAttribute));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The GetPhysicalAddress() function retrieves the base address of
+ a memory-mapped firmware volume. This function should be called
+ only for memory-mapped firmware volumes.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Address Pointer to a caller-allocated
+ EFI_PHYSICAL_ADDRESS that, on successful
+ return from GetPhysicalAddress(), contains the
+ base address of the firmware volume.
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ UINT32 NVBase = PcdGet32(PcdFlashNvStorageVariableBase);
+ UINT32 NVSize = PcdGet32(PcdFlashNvStorageVariableSize);
+
+ DEBUG ((EFI_D_INFO, "FvbGetPhysicalAddress Base:0x%x, Size:0x%x\n", NVBase, NVSize));
+
+ if(FVBMemAddr==NULL)
+ {
+ FVBMemAddr = (UINT32 *)UncachedAllocatePool(NVSize);
+ DEBUG ((EFI_D_INFO, "FvbGetPhysicalAddress MEM Alloc 0x%x\n", FVBMemAddr));
+
+ if(FVBMemAddr==NULL)
+ {
+ DEBUG ((EFI_D_ERROR, "FvbGetPhysicalAddress Alloc failed \n"));
+ return EFI_UNSUPPORTED;
+ }
+ }
+ else
+ {
+ DEBUG ((EFI_D_INFO, "FvbGetPhysicalAddress already Allocated 0x%x \n", FVBMemAddr));
+ }
+
+ CopyMem((VOID *)FVBMemAddr, (VOID *)NVBase, NVSize);
+ Address = (EFI_PHYSICAL_ADDRESS *)FVBMemAddr;
+ DEBUG ((EFI_D_INFO, "FvbGetPhysicalAddress Addr:0x%x\n", Address));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The GetBlockSize() function retrieves the size of the requested
+ block. It also returns the number of additional blocks with
+ the identical size. The GetBlockSize() function is used to
+ retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba Indicates the block for which to return the size.
+
+ @param BlockSize Pointer to a caller-allocated UINTN in which
+ the size of the block is returned.
+
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in
+ which the number of consecutive blocks,
+ starting with Lba, is returned. All
+ blocks in this range have a size of
+ BlockSize.
+
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ )
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ *BlockSize = gSDMMCMedia.BlockSize;
+ *NumberOfBlocks = 512;
+ DEBUG ((EFI_D_INFO, "FvbGetBlockSize numblocks:%d\n", *NumberOfBlocks));
+ return status;
+}
+
+
+
+/**
+ Reads the specified number of bytes into a buffer from the specified block.
+
+ The Read() function reads the requested number of bytes from the
+ requested block and stores them in the provided buffer.
+ Implementations should be mindful that the firmware volume
+ might be in the ReadDisabled state. If it is in this state,
+ the Read() function must return the status code
+ EFI_ACCESS_DENIED without modifying the contents of the
+ buffer. The Read() function must also prevent spanning block
+ boundaries. If a read is requested that would span a block
+ boundary, the read must read up to the boundary but not
+ beyond. The output parameter NumBytes must be set to correctly
+ indicate the number of bytes actually read. The caller must be
+ aware that a read may be partially completed.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba The starting logical block index
+ from which to read.
+
+ @param Offset Offset into the block at which to begin reading.
+
+ @param NumBytes Pointer to a UINTN. At entry, *NumBytes
+ contains the total size of the buffer. At
+ exit, *NumBytes contains the total number of
+ bytes read.
+
+ @param Buffer Pointer to a caller-allocated buffer that will
+ be used to hold the data that is read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully,
+ and contents are in Buffer.
+
+ @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA
+ boundary. On output, NumBytes
+ contains the total number of bytes
+ returned in Buffer.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ ReadDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is not
+ functioning correctly and could
+ not be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ EFI_BLOCK_IO_PROTOCOL *EFIBlockIO = (EFI_BLOCK_IO_PROTOCOL *)This;
+ EFI_STATUS status = EFI_SUCCESS;
+ VOID *TempBuf = NULL;
+ UINT32 NumBlock;
+ UINT32 AllocSize=0;
+ Lba += MSHC_BOOT_SECURE_OFFSET;
+
+ DEBUG ((EFI_D_INFO, "FvbRead Offset : %d, Numbytes : %d\n", Offset, *NumBytes));
+
+ if(gCardInit==TRUE)
+ {
+ if (0 == (*NumBytes%gSDMMCMedia.BlockSize))
+ {
+ NumBlock = (*NumBytes/gSDMMCMedia.BlockSize);
+ }
+ else
+ {
+ NumBlock = (*NumBytes/gSDMMCMedia.BlockSize) + 1;
+ }
+ //DEBUG ((EFI_D_INFO, "FvbRead numblock : %d, BlockSize : %d\n", NumBlock, gSDMMCMedia.BlockSize));
+
+ AllocSize = NumBlock*gSDMMCMedia.BlockSize;
+ TempBuf = AllocatePool(AllocSize);
+ //ZeroMem (TempBuf, NumBlock*gSDMMCMedia.BlockSize);
+ if(TempBuf==NULL)
+ {
+ DEBUG ((EFI_D_ERROR, "FvbRead AllocatePool Failed!!\n"));
+ status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ status = SdReadWrite(EFIBlockIO, Lba, TempBuf, AllocSize, READ);
+ if(status!=EFI_SUCCESS)
+ {
+ DEBUG ((EFI_D_ERROR, "FvbRead Failed 0x%x\n", status));
+ status = EFI_ACCESS_DENIED;
+ goto Exit;
+ }
+
+ CopyMem((VOID *)Buffer, (VOID *)(TempBuf+Offset), *NumBytes);
+ }
+
+ Exit:
+
+ if (TempBuf != NULL)
+ {
+ FreePool(TempBuf);
+ }
+
+ return status;
+}
+
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ The Write() function writes the specified number of bytes from
+ the provided buffer to the specified block and offset. If the
+ firmware volume is sticky write, the caller must ensure that
+ all the bits of the specified range to write are in the
+ EFI_FVB_ERASE_POLARITY state before calling the Write()
+ function, or else the result will be unpredictable. This
+ unpredictability arises because, for a sticky-write firmware
+ volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
+ state but cannot flip it back again. Before calling the
+ Write() function, it is recommended for the caller to first call
+ the EraseBlocks() function to erase the specified block to
+ write. A block erase cycle will transition bits from the
+ (NOT)EFI_FVB_ERASE_POLARITY state back to the
+ EFI_FVB_ERASE_POLARITY state. Implementations should be
+ mindful that the firmware volume might be in the WriteDisabled
+ state. If it is in this state, the Write() function must
+ return the status code EFI_ACCESS_DENIED without modifying the
+ contents of the firmware volume. The Write() function must
+ also prevent spanning block boundaries. If a write is
+ requested that spans a block boundary, the write must store up
+ to the boundary but not beyond. The output parameter NumBytes
+ must be set to correctly indicate the number of bytes actually
+ written. The caller must be aware that a write may be
+ partially completed. All writes, partial or otherwise, must be
+ fully flushed to the hardware before the Write() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba The starting logical block index to write to.
+
+ @param Offset Offset into the block at which to begin writing.
+
+ @param NumBytes The pointer to a UINTN. At entry, *NumBytes
+ contains the total size of the buffer. At
+ exit, *NumBytes contains the total number of
+ bytes actually written.
+
+ @param Buffer The pointer to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an
+ LBA boundary. On output, NumBytes
+ contains the total number of bytes
+ actually written.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ WriteDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning
+ and could not be written.
+
+
+**/
+EFI_STATUS
+EFIAPI
+FvbWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_BLOCK_IO_PROTOCOL *EFIBlockIO = (EFI_BLOCK_IO_PROTOCOL *)This;
+ EFI_STATUS status = EFI_SUCCESS;
+ VOID *TempBuf = NULL;
+ UINT32 NumBlock;
+ UINT32 AllocSize=0;
+ Lba += MSHC_BOOT_SECURE_OFFSET;
+
+ DEBUG ((EFI_D_INFO, "FvbWrite Offset : %d, Numbyte : %d\n", Offset, *NumBytes));
+
+ if(gCardInit==TRUE)
+ {
+ if (0 == (*NumBytes%gSDMMCMedia.BlockSize))
+ {
+ NumBlock = (*NumBytes/gSDMMCMedia.BlockSize);
+ }
+ else
+ {
+ NumBlock = (*NumBytes/gSDMMCMedia.BlockSize) + 1;
+ }
+ //DEBUG ((EFI_D_INFO, "FvbWrite numblock : %d, BlockSize : %d\n", NumBlock, gSDMMCMedia.BlockSize));
+
+ AllocSize = (NumBlock*gSDMMCMedia.BlockSize);
+ TempBuf = AllocatePool(AllocSize);
+ //ZeroMem (TempBuf, NumBlock*gSDMMCMedia.BlockSize);
+ if(TempBuf==NULL)
+ {
+ DEBUG ((EFI_D_ERROR, "FvbWrite AllocatePool Failed!!\n"));
+ status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ status = SdReadWrite(EFIBlockIO, Lba, TempBuf, AllocSize, READ);
+ if(status!=EFI_SUCCESS)
+ {
+ DEBUG ((EFI_D_ERROR, "FvbWrite Read Failed 0x%x\n", status));
+ status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ CopyMem((VOID *)(TempBuf+Offset), (VOID *)Buffer, *NumBytes);
+
+ status = SdReadWrite(EFIBlockIO, Lba, TempBuf, AllocSize, WRITE);
+ if(status!=EFI_SUCCESS)
+ {
+ DEBUG ((EFI_D_ERROR, "FvbWrite Write Failed 0x%x\n", status));
+ status = EFI_ACCESS_DENIED;
+ goto Exit;
+ }
+ }
+ else
+ {
+ DEBUG ((EFI_D_ERROR, "FvbWrite Error eMMC is not ready\n"));
+ }
+
+ Exit:
+
+ if (TempBuf != NULL)
+ {
+ FreePool(TempBuf);
+ }
+
+ return status;
+}
+
+
+/**
+ Erases and initializes a firmware volume block.
+
+ The EraseBlocks() function erases one or more blocks as denoted
+ by the variable argument list. The entire parameter list of
+ blocks must be verified before erasing any blocks. If a block is
+ requested that does not exist within the associated firmware
+ volume (it has a larger index than the last block of the
+ firmware volume), the EraseBlocks() function must return the
+ status code EFI_INVALID_PARAMETER without modifying the contents
+ of the firmware volume. Implementations should be mindful that
+ the firmware volume might be in the WriteDisabled state. If it
+ is in this state, the EraseBlocks() function must return the
+ status code EFI_ACCESS_DENIED without modifying the contents of
+ the firmware volume. All calls to EraseBlocks() must be fully
+ flushed to the hardware before the EraseBlocks() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
+ instance.
+
+ @param ... The variable argument list is a list of tuples.
+ Each tuple describes a range of LBAs to erase
+ and consists of the following:
+ - An EFI_LBA that indicates the starting LBA
+ - A UINTN that indicates the number of blocks to
+ erase.
+
+ The list is terminated with an
+ EFI_LBA_LIST_TERMINATOR. For example, the
+ following indicates that two ranges of blocks
+ (5-7 and 10-11) are to be erased: EraseBlocks
+ (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
+
+ @retval EFI_SUCCESS The erase request successfully
+ completed.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ WriteDisabled state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning
+ correctly and could not be written.
+ The firmware device may have been
+ partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
+ in the variable argument list do
+ not exist in the firmware volume.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbEraseBlocks (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ ...
+ )
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ UINTN StartBlock, NumBlock;
+ UINTN Index;
+ VA_LIST Marker;
+
+ VA_START (Marker, This);
+
+ for (Index = 0, status = EFI_SUCCESS; !EFI_ERROR (status); Index++)
+ {
+ StartBlock = VA_ARG (Marker, UINTN);
+ NumBlock = VA_ARG (Marker, UINTN);
+ DEBUG ((EFI_D_INFO, "FvbEraseBlocks start:%d numblock:%d\n", StartBlock, NumBlock));
+
+ if(StartBlock==0xFFFFFFFF)
+ {
+ break;
+ }
+
+ StartBlock += MSHC_BOOT_SECURE_OFFSET;
+ /* MMC High Capacity erase minimum size is 512KB */
+ status = EraseBlockData(MSHC_BOOT_PARTITION, StartBlock, NumBlock);
+ }
+
+ VA_END (Marker);
+ return status;
+}
+
+
+//
+// Making this global saves a few bytes in image size
+//
+EFI_HANDLE gFvbHandle = NULL;
+
+
+///
+/// The Firmware Volume Block Protocol is the low-level interface
+/// to a firmware volume. File-level access to a firmware volume
+/// should not be done using the Firmware Volume Block Protocol.
+/// Normal access to a firmware volume must use the Firmware
+/// Volume Protocol. Typically, only the file system driver that
+/// produces the Firmware Volume Protocol will bind to the
+/// Firmware Volume Block Protocol.
+///
+EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL gFvbProtocol = {
+ FvbGetAttributes,
+ FvbSetAttributes,
+ FvbGetPhysicalAddress,
+ FvbGetBlockSize,
+ FvbRead,
+ FvbWrite,
+ FvbEraseBlocks,
+ ///
+ /// The handle of the parent firmware volume.
+ ///
+ NULL
+};
+
+
+#if 0
+/**
+ Initialize the state information for the CPU Architectural Protocol
+
+ @param ImageHandle of the loaded driver
+ @param SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS Protocol registered
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
+ @retval EFI_DEVICE_ERROR Hardware problems
+
+**/
+EFI_STATUS
+EFIAPI
+FvbDxeInitialize ()
+{
+ EFI_STATUS Status;
+
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gFvbHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid, &gFvbProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ // SetVertAddressEvent ()
+
+ // GCD Map NAND as RT
+
+ return Status;
+}
+#endif