/** @file\r
*\r
-* Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
+* Copyright (c) 2011-2020, ARM Limited. All rights reserved.\r
*\r
-* This program and the accompanying materials\r
-* are licensed and made available under the terms and conditions of the BSD License\r
-* which accompanies this distribution. The full text of the license may be found at\r
-* http://opensource.org/licenses/bsd-license.php\r
-*\r
-* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+* SPDX-License-Identifier: BSD-2-Clause-Patent\r
*\r
**/\r
\r
#include <Library/BaseMemoryLib.h>\r
-#include <Library/TimerLib.h>\r
\r
#include "Mmc.h"\r
\r
EFI_STATUS\r
MmcNotifyState (\r
- IN MMC_HOST_INSTANCE *MmcHostInstance,\r
- IN MMC_STATE State\r
+ IN MMC_HOST_INSTANCE *MmcHostInstance,\r
+ IN MMC_STATE State\r
)\r
{\r
MmcHostInstance->State = State;\r
EFI_STATUS\r
EFIAPI\r
MmcGetCardStatus (\r
- IN MMC_HOST_INSTANCE *MmcHostInstance\r
+ IN MMC_HOST_INSTANCE *MmcHostInstance\r
)\r
{\r
- EFI_STATUS Status;\r
- UINT32 Response[4];\r
- UINTN CmdArg;\r
- EFI_MMC_HOST_PROTOCOL *MmcHost;\r
+ EFI_STATUS Status;\r
+ UINT32 Response[4];\r
+ UINTN CmdArg;\r
+ EFI_MMC_HOST_PROTOCOL *MmcHost;\r
\r
- Status = EFI_SUCCESS;\r
+ Status = EFI_SUCCESS;\r
MmcHost = MmcHostInstance->MmcHost;\r
- CmdArg = 0;\r
+ CmdArg = 0;\r
\r
if (MmcHost == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
if (MmcHostInstance->State != MmcHwInitializationState) {\r
- //Get the Status of the card.\r
+ // Get the Status of the card.\r
CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status));\r
+ DEBUG ((DEBUG_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status));\r
return Status;\r
}\r
\r
- //Read Response\r
+ // Read Response\r
MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
PrintResponseR1 (Response[0]);\r
}\r
EFI_STATUS\r
EFIAPI\r
MmcReset (\r
- IN EFI_BLOCK_IO_PROTOCOL *This,\r
- IN BOOLEAN ExtendedVerification\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
)\r
{\r
- MMC_HOST_INSTANCE *MmcHostInstance;\r
+ MMC_HOST_INSTANCE *MmcHostInstance;\r
\r
MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
\r
\r
EFI_STATUS\r
MmcDetectCard (\r
- EFI_MMC_HOST_PROTOCOL *MmcHost\r
+ EFI_MMC_HOST_PROTOCOL *MmcHost\r
)\r
{\r
if (!MmcHost->IsCardPresent (MmcHost)) {\r
\r
EFI_STATUS\r
MmcStopTransmission (\r
- EFI_MMC_HOST_PROTOCOL *MmcHost\r
+ EFI_MMC_HOST_PROTOCOL *MmcHost\r
)\r
{\r
- EFI_STATUS Status;\r
- UINT32 Response[4];\r
+ EFI_STATUS Status;\r
+ UINT32 Response[4];\r
+\r
// Command 12 - Stop transmission (ends read or write)\r
// Normally only needed for streaming transfers or after error.\r
Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);\r
if (!EFI_ERROR (Status)) {\r
MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response);\r
}\r
+\r
return Status;\r
}\r
\r
-#define MMCI0_BLOCKLEN 512\r
-#define MMCI0_TIMEOUT 10000\r
+#define MMCI0_BLOCKLEN 512\r
+#define MMCI0_TIMEOUT 10000\r
+\r
+STATIC\r
+EFI_STATUS\r
+MmcTransferBlock (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINTN Cmd,\r
+ IN UINTN Transfer,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN CmdArg;\r
+ INTN Timeout;\r
+ UINT32 Response[4];\r
+ MMC_HOST_INSTANCE *MmcHostInstance;\r
+ EFI_MMC_HOST_PROTOCOL *MmcHost;\r
+\r
+ MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
+ MmcHost = MmcHostInstance->MmcHost;\r
+\r
+ if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {\r
+ // Set command argument based on the card capacity\r
+ // if 0 : SDSC card\r
+ // if 1 : SDXC/SDHC\r
+ if (MmcHostInstance->CardInfo.OCRData.AccessMode & SD_CARD_CAPACITY) {\r
+ CmdArg = Lba;\r
+ } else {\r
+ CmdArg = MultU64x32 (Lba, This->Media->BlockSize);\r
+ }\r
+ } else {\r
+ // Set command argument based on the card access mode (Byte mode or Block mode)\r
+ if ((MmcHostInstance->CardInfo.OCRData.AccessMode & MMC_OCR_ACCESS_MASK) ==\r
+ MMC_OCR_ACCESS_SECTOR)\r
+ {\r
+ CmdArg = Lba;\r
+ } else {\r
+ CmdArg = MultU64x32 (Lba, This->Media->BlockSize);\r
+ }\r
+ }\r
+\r
+ Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a(MMC_CMD%d): Error %r\n", __func__, Cmd, Status));\r
+ return Status;\r
+ }\r
+\r
+ if (Transfer == MMC_IOBLOCKS_READ) {\r
+ // Read Data\r
+ Status = MmcHost->ReadBlockData (MmcHost, Lba, BufferSize, Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_BLKIO, "%a(): Error Read Block Data and Status = %r\n", __func__, Status));\r
+ MmcStopTransmission (MmcHost);\r
+ return Status;\r
+ }\r
+\r
+ Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a() : Error MmcProgrammingState\n", __func__));\r
+ return Status;\r
+ }\r
+ } else {\r
+ // Write Data\r
+ Status = MmcHost->WriteBlockData (MmcHost, Lba, BufferSize, Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_BLKIO, "%a(): Error Write Block Data and Status = %r\n", __func__, Status));\r
+ MmcStopTransmission (MmcHost);\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ // Command 13 - Read status and wait for programming to complete (return to tran)\r
+ Timeout = MMCI0_TIMEOUT;\r
+ CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
+ Response[0] = 0;\r
+ while ( !(Response[0] & MMC_R0_READY_FOR_DATA)\r
+ && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
+ && Timeout--)\r
+ {\r
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
+ if (!EFI_ERROR (Status)) {\r
+ MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
+ if (Response[0] & MMC_R0_READY_FOR_DATA) {\r
+ break; // Prevents delay once finished\r
+ }\r
+ }\r
+ }\r
+\r
+ if (BufferSize > This->Media->BlockSize) {\r
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_BLKIO, "%a(): Error and Status:%r\n", __func__, Status));\r
+ }\r
+\r
+ MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response);\r
+ }\r
+\r
+ Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));\r
+ return Status;\r
+ }\r
+\r
+ return Status;\r
+}\r
\r
EFI_STATUS\r
MmcIoBlocks (\r
- IN EFI_BLOCK_IO_PROTOCOL *This,\r
- IN UINTN Transfer,\r
- IN UINT32 MediaId,\r
- IN EFI_LBA Lba,\r
- IN UINTN BufferSize,\r
- OUT VOID *Buffer\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINTN Transfer,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
)\r
{\r
- UINT32 Response[4];\r
- EFI_STATUS Status;\r
- UINTN CmdArg;\r
- INTN Timeout;\r
- UINTN Cmd;\r
- MMC_HOST_INSTANCE *MmcHostInstance;\r
- EFI_MMC_HOST_PROTOCOL *MmcHost;\r
- UINTN BytesRemainingToBeTransfered;\r
- UINTN BlockCount;\r
-\r
- BlockCount = 1;\r
+ UINT32 Response[4];\r
+ EFI_STATUS Status;\r
+ UINTN CmdArg;\r
+ INTN Timeout;\r
+ UINTN Cmd;\r
+ MMC_HOST_INSTANCE *MmcHostInstance;\r
+ EFI_MMC_HOST_PROTOCOL *MmcHost;\r
+ UINTN BytesRemainingToBeTransfered;\r
+ UINTN BlockCount;\r
+ UINTN ConsumeSize;\r
+ UINT32 MaxBlock;\r
+ UINTN RemainingBlock;\r
+\r
+ BlockCount = 1;\r
MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
ASSERT (MmcHostInstance != NULL);\r
MmcHost = MmcHostInstance->MmcHost;\r
return EFI_NO_MEDIA;\r
}\r
\r
- // All blocks must be within the device\r
- if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) {\r
- return EFI_WRITE_PROTECTED;\r
- }\r
-\r
// Reading 0 Byte is valid\r
if (BufferSize == 0) {\r
return EFI_SUCCESS;\r
return EFI_BAD_BUFFER_SIZE;\r
}\r
\r
+ if (MMC_HOST_HAS_ISMULTIBLOCK (MmcHost) && MmcHost->IsMultiBlock (MmcHost)) {\r
+ BlockCount = BufferSize / This->Media->BlockSize;\r
+ }\r
+\r
+ // All blocks must be within the device\r
+ if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
// Check the alignment\r
if ((This->Media->IoAlign > 2) && (((UINTN)Buffer & (This->Media->IoAlign - 1)) != 0)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ // Max block number in single cmd is 65535 blocks.\r
+ MaxBlock = 0xFFFF;\r
+ RemainingBlock = BlockCount;\r
BytesRemainingToBeTransfered = BufferSize;\r
while (BytesRemainingToBeTransfered > 0) {\r
+ if (RemainingBlock <= MaxBlock) {\r
+ BlockCount = RemainingBlock;\r
+ } else {\r
+ BlockCount = MaxBlock;\r
+ }\r
\r
// Check if the Card is in Ready status\r
- CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
+ CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
Response[0] = 0;\r
- Timeout = 20;\r
- while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
+ Timeout = 20;\r
+ while ( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
&& (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
- && Timeout--) {\r
+ && Timeout--)\r
+ {\r
Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
if (!EFI_ERROR (Status)) {\r
MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
}\r
\r
if (0 == Timeout) {\r
- DEBUG ((EFI_D_ERROR, "The Card is busy\n"));\r
+ DEBUG ((DEBUG_ERROR, "The Card is busy\n"));\r
return EFI_NOT_READY;\r
}\r
\r
- //Set command argument based on the card access mode (Byte mode or Block mode)\r
- if (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1) {\r
- CmdArg = Lba;\r
- } else {\r
- CmdArg = Lba * This->Media->BlockSize;\r
- }\r
-\r
if (Transfer == MMC_IOBLOCKS_READ) {\r
- // Read a single block\r
- Cmd = MMC_CMD17;\r
- } else {\r
- // Write a single block\r
- Cmd = MMC_CMD24;\r
- }\r
- Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "MmcIoBlocks(MMC_CMD%d): Error %r\n", Cmd, Status));\r
- return Status;\r
- }\r
-\r
- if (Transfer == MMC_IOBLOCKS_READ) {\r
- // Read one block of Data\r
- Status = MmcHost->ReadBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Read Block Data and Status = %r\n", Status));\r
- MmcStopTransmission (MmcHost);\r
- return Status;\r
- }\r
- Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcProgrammingState\n"));\r
- return Status;\r
+ if (BlockCount == 1) {\r
+ // Read a single block\r
+ Cmd = MMC_CMD17;\r
+ } else {\r
+ // Read multiple blocks\r
+ Cmd = MMC_CMD18;\r
}\r
} else {\r
- // Write one block of Data\r
- Status = MmcHost->WriteBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Write Block Data and Status = %r\n", Status));\r
- MmcStopTransmission (MmcHost);\r
- return Status;\r
+ if (BlockCount == 1) {\r
+ // Write a single block\r
+ Cmd = MMC_CMD24;\r
+ } else {\r
+ // Write multiple blocks\r
+ Cmd = MMC_CMD25;\r
}\r
}\r
\r
- // Command 13 - Read status and wait for programming to complete (return to tran)\r
- Timeout = MMCI0_TIMEOUT;\r
- CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
- Response[0] = 0;\r
- while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
- && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
- && Timeout--) {\r
- Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
- if (!EFI_ERROR (Status)) {\r
- MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
- if ((Response[0] & MMC_R0_READY_FOR_DATA)) {\r
- break; // Prevents delay once finished\r
- }\r
- }\r
- NanoSecondDelay (100);\r
+ ConsumeSize = BlockCount * This->Media->BlockSize;\r
+ if (BytesRemainingToBeTransfered < ConsumeSize) {\r
+ ConsumeSize = BytesRemainingToBeTransfered;\r
}\r
\r
- Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
+ Status = MmcTransferBlock (This, Cmd, Transfer, MediaId, Lba, ConsumeSize, Buffer);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));\r
- return Status;\r
+ DEBUG ((DEBUG_ERROR, "%a(): Failed to transfer block and Status:%r\n", __func__, Status));\r
}\r
\r
- BytesRemainingToBeTransfered -= This->Media->BlockSize;\r
- Lba += BlockCount;\r
- Buffer = (UINT8 *)Buffer + This->Media->BlockSize;\r
+ RemainingBlock -= BlockCount;\r
+ BytesRemainingToBeTransfered -= ConsumeSize;\r
+ if (BytesRemainingToBeTransfered > 0) {\r
+ Lba += BlockCount;\r
+ Buffer = (UINT8 *)Buffer + ConsumeSize;\r
+ }\r
}\r
\r
return EFI_SUCCESS;\r
EFI_STATUS\r
EFIAPI\r
MmcReadBlocks (\r
- IN EFI_BLOCK_IO_PROTOCOL *This,\r
- IN UINT32 MediaId,\r
- IN EFI_LBA Lba,\r
- IN UINTN BufferSize,\r
- OUT VOID *Buffer\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
)\r
{\r
return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer);\r
EFI_STATUS\r
EFIAPI\r
MmcWriteBlocks (\r
- IN EFI_BLOCK_IO_PROTOCOL *This,\r
- IN UINT32 MediaId,\r
- IN EFI_LBA Lba,\r
- IN UINTN BufferSize,\r
- IN VOID *Buffer\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
)\r
{\r
return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer);\r