This patch adds support for MMC host driver Mmc host driver will produce gEfiMmcHostProtocolGuid which will be consumed by MmcDxe driver of EmbeddedPkg
Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Meenakshi Aggarwal <meenakshi.aggar...@nxp.com> Signed-off-by: Vabhav <vabhav.sha...@nxp.com> --- Platform/NXP/Drivers/MmcHostDxe/MmcHostDxe.c | 418 +++++++++++++++++++++++++ Platform/NXP/Drivers/MmcHostDxe/MmcHostDxe.inf | 42 +++ 2 files changed, 460 insertions(+) create mode 100644 Platform/NXP/Drivers/MmcHostDxe/MmcHostDxe.c create mode 100644 Platform/NXP/Drivers/MmcHostDxe/MmcHostDxe.inf diff --git a/Platform/NXP/Drivers/MmcHostDxe/MmcHostDxe.c b/Platform/NXP/Drivers/MmcHostDxe/MmcHostDxe.c new file mode 100644 index 0000000..81269bf --- /dev/null +++ b/Platform/NXP/Drivers/MmcHostDxe/MmcHostDxe.c @@ -0,0 +1,418 @@ +/** @file + + This file implement the MMC Host Protocol for the NXP SDHC controller. + + Copyright 2017 NXP + + 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/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DevicePathLib.h> +#include <Library/MmcLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Protocol/MmcHost.h> + +UINT8 LastCmd; +struct SdCmd Cmd; + +EFI_GUID mMmcDevicePathGuid = EFI_CALLER_ID_GUID; + +/** + Function to call library function to detect card presence + + @param This Pointer to MMC host protocol structure + +**/ +BOOLEAN +MmcIsCardPresent ( + IN EFI_MMC_HOST_PROTOCOL *This + ) +{ + return DetectCardPresence (); +} + +/** + Function to call library function to verify card is read only + + @param This Pointer to MMC host protocol structure + +**/ +BOOLEAN +MmcIsReadOnly ( + IN EFI_MMC_HOST_PROTOCOL *This + ) +{ + return IsCardReadOnly (); +} + +/** + Function to create command reseponse depeping upon + input command parameter + + @param MmcCmd MMC Command + +**/ +STATIC UINT32 +CreateResponseType ( + IN UINT32 MmcCmd + ) +{ + + UINT32 RespType; + + RespType = 0; + + if (MmcCmd & MMC_CMD_WAIT_RESPONSE) { + RespType = MMC_RSP_PRESENT; + + if (MmcCmd & MMC_CMD_LONG_RESPONSE) { + RespType |= (MMC_RSP_136|MMC_RSP_CRC); + } + else if (!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) { + RespType |= (MMC_RSP_CRC|MMC_RSP_OPCODE); + } + } + + if (MMC_GET_INDX(MmcCmd) == MMC_INDX(12)) { + RespType |= MMC_RSP_BUSY; + } + + return RespType; +} + +/** + Function to send MMC command + + @param This Pointer to MMC host protocol structure + @param MmcCmd MMC Command + @param Argument Argument if any + +**/ +EFI_STATUS +MmcSendCommand ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_CMD MmcCmd, + IN UINT32 Argument + ) +{ + EFI_STATUS Status; + + Cmd.CmdIdx = MMC_GET_INDX (MmcCmd); + Cmd.CmdArg = Argument; + Cmd.RespType = CreateResponseType (MmcCmd); + + //Saved data in Cmd struct for commands that need a read/write. + //This is done because which setting Xfertype register we need + //information of block number and blocksize. + if ((Cmd.CmdIdx == MMC_INDX(6)) || (Cmd.CmdIdx == MMC_INDX(51)) || + (Cmd.CmdIdx == MMC_INDX(17)) || (Cmd.CmdIdx == MMC_INDX(18)) || + (Cmd.CmdIdx == MMC_INDX(24)) || (Cmd.CmdIdx == MMC_INDX(25))) { + + if ((Cmd.CmdIdx == MMC_INDX(6)) && (LastCmd == MMC_INDX(55))) { + Status = SendCmd (&Cmd, NULL); + } + else { + Status = EFI_SUCCESS; + } + } else { + Status = SendCmd (&Cmd, NULL); + } + + LastCmd = Cmd.CmdIdx; + + return Status; +} + +/** + Function to receive MMC command response + + @param This Pointer to MMC host protocol structure + @param Type MMC Command response type + @param Buffer Pointer to response Buffer + +**/ +EFI_STATUS +MmcReceiveResponse ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_RESPONSE_TYPE Type, + IN UINT32* Buffer + ) +{ + EFI_STATUS Status; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Type == MMC_RESPONSE_TYPE_R2) { + Type |= MMC_RSP_136; + } else if (Type == MMC_RESPONSE_TYPE_R1b) { + Type |= MMC_RSP_BUSY; + } + + DEBUG_MSG ("MMC_RESPONSE_TYPE 0x%x for cmd %d \n", Type, LastCmd); + + // if Last sent command is one among 6, 51, 17, 18, 24 and 25, then + // set data to 1 else 0 + if ((LastCmd == MMC_INDX(6)) || (LastCmd == MMC_INDX(51)) || + (LastCmd == MMC_INDX(17)) || (LastCmd == MMC_INDX(18)) || + (LastCmd == MMC_INDX(24)) || (LastCmd == MMC_INDX(25))) { + Status = RcvResp (Type, Buffer, 1); + } else { + Status = RcvResp (Type, Buffer, 0); + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to receive response for %d \n", LastCmd)); + return Status; + } + + return Status; +} + +/** + Function to dump MMC data + + @param Buffer Pointer to MMC data + @param Length Length of MMC data + +**/ +VOID +DumpData ( + IN UINT32* Buffer, + IN UINTN Length + ) +{ +#ifdef MMC_DEBUG_READ + UINT32 Temp; + + DEBUG ((DEBUG_ERROR, "DATA IS (%d) :", Length)); + for (Temp = 1; Temp <= Length; Temp++) { + DEBUG ((DEBUG_ERROR, "0x%x ", Buffer[Temp-1])); + if ((Temp != 0) && !(Temp % 8)) + DEBUG ((DEBUG_ERROR, "--- %d\n", Temp-1)); + } + DEBUG ((DEBUG_ERROR, "\n")); +#endif +} + +/** + Function to read MMC Data Block + + @param This Pointer to MMC host protocol structure + @param Lba + @param Length Length of MMC data + @param Buffer Pointer to MMC data + +**/ +EFI_STATUS +MmcReadBlockData ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32* Buffer + ) +{ + EFI_STATUS RetVal; + EFI_TPL Tpl; + UINT8 Temp; + + // Raise the TPL at the highest level to disable Interrupts. + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + //send Cmd structure here, library will send this command. + RetVal = ReadBlock (Lba, Length, Buffer, Cmd); + + if (Cmd.CmdIdx == MMC_INDX(6)) { + for (Temp = 0; Temp < Length/8; Temp++) { + Buffer[Temp] = SwapBytes32(Buffer[Temp]); + } + } + + if (RetVal == EFI_SUCCESS) { + DumpData(Buffer, Length); + } + + // Restore Tpl + gBS->RestoreTPL (Tpl); + + return RetVal; +} + +/** + Function to write MMC Data Block + + @param This Pointer to MMC host protocol structure + @param Lba + @param Length Length of MMC data block to be written + @param Buffer Pointer to MMC data + +**/ +EFI_STATUS +MmcWriteBlockData ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32* Buffer + ) +{ + EFI_STATUS RetVal; + EFI_TPL Tpl; + + // Raise the TPL at the highest level to disable Interrupts. + Tpl = gBS->RaiseTPL (TPL_NOTIFY); + + //send Cmd structure here, library will send this command. + RetVal = WriteBlock (Lba, Length, Buffer, Cmd); + + // Restore Tpl + gBS->RestoreTPL (Tpl); + + return RetVal; +} + +/** + Function to notify for different MMC states + + @param This Pointer to MMC host protocol structure + @param State MMC State + +**/ +EFI_STATUS +MmcNotifyState ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_STATE State + ) +{ + EFI_STATUS Status; + + switch (State) { + case MmcInvalidState: + ASSERT (0); + break; + case MmcHwInitializationState: + DEBUG ((DEBUG_ERROR, "MmcNotifyState(MmcHwInitializationState)\n")); + + Status = MmcInitialize(); + if (Status != EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR,"Failed to init MMC\n")); + return Status; + } + break; + case MmcIdleState: + case MmcReadyState: + case MmcIdentificationState: + case MmcStandByState: + case MmcTransferState: + case MmcSendingDataState: + case MmcReceiveDataState: + case MmcProgrammingState: + case MmcDisconnectState: + break; + default: + ASSERT (0); + } + return EFI_SUCCESS; +} + +/** + Function to create device PATH for MMC node + + @param This Pointer to MMC host protocol structure + @param DevicePath Pointer to device path protocol structure + +**/ +EFI_STATUS +MmcBuildDevicePath ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; + + NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH)); + CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mMmcDevicePathGuid); + + *DevicePath = NewDevicePathNode; + return EFI_SUCCESS; +} + +/** + Function to set MMC speed + + @param This Pointer to MMC host protocol structure + @param BusClockFreq Bus clock frequency + @param BusWidth Bus width + @param TimingMode Timing mode + +**/ +EFI_STATUS +MmcSetIos ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN UINT32 BusClockFreq, + IN UINT32 BusWidth, + IN UINT32 TimingMode + ) +{ + SetIos (BusClockFreq, BusWidth, TimingMode); + return EFI_SUCCESS; +} + +BOOLEAN +MmcIsMultBlk ( + IN EFI_MMC_HOST_PROTOCOL *This + ) +{ + return TRUE; +} + +EFI_MMC_HOST_PROTOCOL gMmcHost = { + MMC_HOST_PROTOCOL_REVISION, + MmcIsCardPresent, + MmcIsReadOnly, + MmcBuildDevicePath, + MmcNotifyState, + MmcSendCommand, + MmcReceiveResponse, + MmcReadBlockData, + MmcWriteBlockData, + MmcSetIos, + MmcIsMultBlk +}; + +/** + Function to install MMC Host Protocol gEfiMmcHostProtocolGuid +**/ +EFI_STATUS +MmcHostDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiMmcHostProtocolGuid, &gMmcHost, + NULL + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed to install gEfiMmcHostProtocolGuid\n")); + } + + return Status; +} diff --git a/Platform/NXP/Drivers/MmcHostDxe/MmcHostDxe.inf b/Platform/NXP/Drivers/MmcHostDxe/MmcHostDxe.inf new file mode 100644 index 0000000..6761f3e --- /dev/null +++ b/Platform/NXP/Drivers/MmcHostDxe/MmcHostDxe.inf @@ -0,0 +1,42 @@ +#/**@file +# +# Copyright 2017 NXP +# +# 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 = 0x0001001A + BASE_NAME = MmcHostDxe + FILE_GUID = 7948a4ca-2f2e-41ca-90a2-d4420cecbbcf + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = MmcHostDxeEntryPoint + +[Sources.common] + MmcHostDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + Platform/NXP/NxpQoriqLs.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MmcLib + TimerLib + UefiDriverEntryPoint + +[Protocols] + gEfiMmcHostProtocolGuid + +[Depex] + TRUE -- 1.9.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel