diff options
Diffstat (limited to 'SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/eMMCDxe')
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 |