]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmbeddedPkg / Universal / MmcDxe / MmcBlockIo.c
index 04c82613d5b7b80f6641bdeaef6755cc1fcc2e55..d695e25571eca9dddb8a0e09304b5b56631359f2 100644 (file)
@@ -1,26 +1,19 @@
 /** @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
@@ -30,31 +23,32 @@ MmcNotifyState (
 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
@@ -65,11 +59,11 @@ MmcGetCardStatus (
 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
@@ -98,7 +92,7 @@ MmcReset (
 \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
@@ -110,44 +104,156 @@ MmcDetectCard (
 \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
@@ -166,15 +272,6 @@ MmcIoBlocks (
     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
@@ -185,21 +282,43 @@ MmcIoBlocks (
     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
@@ -207,79 +326,44 @@ MmcIoBlocks (
     }\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
@@ -288,11 +372,11 @@ MmcIoBlocks (
 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
@@ -301,11 +385,11 @@ MmcReadBlocks (
 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