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.aggarwal@nxp.com>
Signed-off-by: Vabhav <vabhav.sharma@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
© 2016 - 2024 Red Hat, Inc.