[edk2-devel] [PATCH 1/1] EmbeddedPkg: Fix DwEmmc driver bugs

Loh, Tien Hock tien.hock.loh at intel.com
Thu May 2 03:37:19 UTC 2019


From: "Tien Hock, Loh" <tien.hock.loh at intel.com>

This fixes some issues with DwEmmc when using with SDMMC card:
- clear CTYPE when controller initializes
- change SendCommand polling mode to remove unnecessary delay
- Add CMD6 support for SD support
- For pending read/write command, send when DwEmmcReceiveResponse is called
  so that we can properly error check the response
- Fix bug on reading block size less than DWEMMC_BLOCK_SIZE
- Wait for DwEmmcReadBlockData and DwEmmacWriteBlockData to complete
  before returning the function

Signed-off-by: "Tien Hock, Loh" <tien.hock.loh at intel.com>
Cc: Leif Lindholm <leif.lindholm at linaro.org>
Cc: Ard Biesheuvel <ard.biesheuvel at linaro.org>
---
 EmbeddedPkg/Drivers/DwEmmcDxe/DwEmmcDxe.c        | 108 +++++++++++++++++++----
 EmbeddedPkg/Include/Protocol/MmcHost.h           |   1 +
 EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c |   2 +
 3 files changed, 92 insertions(+), 19 deletions(-)

diff --git a/EmbeddedPkg/Drivers/DwEmmcDxe/DwEmmcDxe.c b/EmbeddedPkg/Drivers/DwEmmcDxe/DwEmmcDxe.c
index 68c523a..92b5176 100644
--- a/EmbeddedPkg/Drivers/DwEmmcDxe/DwEmmcDxe.c
+++ b/EmbeddedPkg/Drivers/DwEmmcDxe/DwEmmcDxe.c
@@ -39,6 +39,7 @@ DWEMMC_IDMAC_DESCRIPTOR   *gpIdmacDesc;
 EFI_GUID mDwEmmcDevicePathGuid = EFI_CALLER_ID_GUID;
 STATIC UINT32 mDwEmmcCommand;
 STATIC UINT32 mDwEmmcArgument;
+STATIC BOOLEAN mIsACmd = FALSE;
 
 EFI_STATUS
 DwEmmcReadBlockData (
@@ -205,6 +206,7 @@ DwEmmcNotifyState (
     MmioWrite32 (DWEMMC_TMOUT, ~0);
     MmioWrite32 (DWEMMC_IDINTEN, 0);
     MmioWrite32 (DWEMMC_BMOD, DWEMMC_IDMAC_SWRESET);
+    MmioWrite32 (DWEMMC_CTYPE, 0);
 
     MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);
     do {
@@ -284,17 +286,15 @@ SendCommand (
   ErrMask = DWEMMC_INT_EBE | DWEMMC_INT_HLE | DWEMMC_INT_RTO |
             DWEMMC_INT_RCRC | DWEMMC_INT_RE;
   ErrMask |= DWEMMC_INT_DCRC | DWEMMC_INT_DRT | DWEMMC_INT_SBE;
+
   do {
-    MicroSecondDelay(500);
     Data = MmioRead32 (DWEMMC_RINTSTS);
-
-    if (Data & ErrMask) {
-      return EFI_DEVICE_ERROR;
-    }
-    if (Data & DWEMMC_INT_DTO) {     // Transfer Done
-      break;
-    }
   } while (!(Data & DWEMMC_INT_CMD_DONE));
+
+  if (Data & ErrMask) {
+    return EFI_DEVICE_ERROR;
+  }
+
   return EFI_SUCCESS;
 }
 
@@ -323,6 +323,15 @@ DwEmmcSendCommand (
     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
            BIT_CMD_SEND_INIT;
     break;
+  case MMC_INDX(6):
+    if(mIsACmd) {
+      Cmd = BIT_CMD_RESPONSE_EXPECT ;
+    }
+    else {
+      Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_DATA_EXPECTED |
+            BIT_CMD_READ;
+    }
+    break;
   case MMC_INDX(7):
     if (Argument)
         Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
@@ -330,9 +339,12 @@ DwEmmcSendCommand (
         Cmd = 0;
     break;
   case MMC_INDX(8):
-    Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
-           BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
-           BIT_CMD_WAIT_PRVDATA_COMPLETE;
+    if (!This->IsEmmc)
+      Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
+             BIT_CMD_WAIT_PRVDATA_COMPLETE ;
+    else
+      Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
+             BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_READ | BIT_CMD_DATA_EXPECTED;
     break;
   case MMC_INDX(9):
     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
@@ -364,21 +376,38 @@ DwEmmcSendCommand (
            BIT_CMD_WAIT_PRVDATA_COMPLETE;
     break;
   case MMC_INDX(30):
-    Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
+    Cmd = BIT_CMD_RESPONSE_EXPECT  |
            BIT_CMD_DATA_EXPECTED;
     break;
+  case MMC_INDX(51):
+    Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_DATA_EXPECTED |
+           BIT_CMD_READ | BIT_CMD_WAIT_PRVDATA_COMPLETE;
+    break;
   default:
-    Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
+    Cmd = BIT_CMD_RESPONSE_EXPECT;
     break;
   }
 
   Cmd |= MMC_GET_INDX(MmcCmd) | BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
+
+  if(MMC_INDX(55) == MMC_GET_INDX(MmcCmd))
+    mIsACmd = TRUE;
+  else
+    mIsACmd = FALSE;
+
+  if (!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) {
+    Cmd |= BIT_CMD_CHECK_RESPONSE_CRC;
+  }
+
   if (IsPendingReadCommand (Cmd) || IsPendingWriteCommand (Cmd)) {
     mDwEmmcCommand = Cmd;
     mDwEmmcArgument = Argument;
   } else {
+    mDwEmmcCommand = Cmd;
+    mDwEmmcArgument = Argument;
     Status = SendCommand (Cmd, Argument);
   }
+
   return Status;
 }
 
@@ -389,6 +418,11 @@ DwEmmcReceiveResponse (
   IN UINT32*                    Buffer
   )
 {
+  EFI_STATUS Status = EFI_SUCCESS;
+
+  if(IsPendingReadCommand (mDwEmmcCommand) || IsPendingWriteCommand(mDwEmmcCommand))
+    Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument);
+
   if (Buffer == NULL) {
     return EFI_INVALID_PARAMETER;
   }
@@ -406,7 +440,7 @@ DwEmmcReceiveResponse (
     Buffer[2] = MmioRead32 (DWEMMC_RESP2);
     Buffer[3] = MmioRead32 (DWEMMC_RESP3);
   }
-  return EFI_SUCCESS;
+  return Status;
 }
 
 VOID
@@ -461,7 +495,10 @@ PrepareDmaData (
 
   Cnt = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;
   Blks = (Length + DWEMMC_BLOCK_SIZE - 1) / DWEMMC_BLOCK_SIZE;
-  Length = DWEMMC_BLOCK_SIZE * Blks;
+
+  if(Length >= DWEMMC_BLOCK_SIZE) {
+    Length = DWEMMC_BLOCK_SIZE * Blks;
+  }
 
   for (Idx = 0; Idx < Cnt; Idx++) {
     (IdmacDesc + Idx)->Des0 = DWEMMC_IDMAC_DES0_OWN | DWEMMC_IDMAC_DES0_CH |
@@ -499,11 +536,18 @@ StartDma (
   Data |= DWEMMC_CTRL_INT_EN | DWEMMC_CTRL_DMA_EN | DWEMMC_CTRL_IDMAC_EN;
   MmioWrite32 (DWEMMC_CTRL, Data);
   Data = MmioRead32 (DWEMMC_BMOD);
+
   Data |= DWEMMC_IDMAC_ENABLE | DWEMMC_IDMAC_FB;
   MmioWrite32 (DWEMMC_BMOD, Data);
 
-  MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);
-  MmioWrite32 (DWEMMC_BYTCNT, Length);
+  if(Length < DWEMMC_BLOCK_SIZE) {
+    MmioWrite32 (DWEMMC_BLKSIZ, Length);
+    MmioWrite32 (DWEMMC_BYTCNT, Length);
+  }
+  else {
+    MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);
+    MmioWrite32 (DWEMMC_BYTCNT, Length);
+  }
 }
 
 EFI_STATUS
@@ -515,8 +559,9 @@ DwEmmcReadBlockData (
   )
 {
   EFI_STATUS  Status;
-  UINT32      DescPages, CountPerPage, Count;
+  UINT32      DescPages, CountPerPage, Count, ErrMask;
   EFI_TPL     Tpl;
+  UINTN Rintsts = 0;
 
   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
 
@@ -539,6 +584,18 @@ DwEmmcReadBlockData (
     DEBUG ((DEBUG_ERROR, "Failed to read data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status));
     goto out;
   }
+
+  while(!((MmioRead32(DWEMMC_RINTSTS) & (DWEMMC_INT_DTO)))) {
+    Rintsts = MmioRead32 (DWEMMC_RINTSTS);
+  }
+  ErrMask = DWEMMC_INT_EBE | DWEMMC_INT_HLE | DWEMMC_INT_RTO |
+            DWEMMC_INT_RCRC | DWEMMC_INT_RE | DWEMMC_INT_DCRC |
+            DWEMMC_INT_DRT | DWEMMC_INT_SBE;
+
+  if (Rintsts & ErrMask) {
+    Status = EFI_DEVICE_ERROR;
+    goto out;
+  }
 out:
   // Restore Tpl
   gBS->RestoreTPL (Tpl);
@@ -554,8 +611,9 @@ DwEmmcWriteBlockData (
   )
 {
   EFI_STATUS  Status;
-  UINT32      DescPages, CountPerPage, Count;
+  UINT32      DescPages, CountPerPage, Count, ErrMask;
   EFI_TPL     Tpl;
+  UINTN Rintsts = 0;
 
   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
 
@@ -578,6 +636,18 @@ DwEmmcWriteBlockData (
     DEBUG ((DEBUG_ERROR, "Failed to write data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status));
     goto out;
   }
+
+  while(!((MmioRead32(DWEMMC_RINTSTS) & (DWEMMC_INT_DTO)))) {
+    Rintsts = MmioRead32 (DWEMMC_RINTSTS);
+  }
+  ErrMask = DWEMMC_INT_EBE | DWEMMC_INT_HLE | DWEMMC_INT_RTO |
+            DWEMMC_INT_RCRC | DWEMMC_INT_RE | DWEMMC_INT_DCRC |
+            DWEMMC_INT_DRT | DWEMMC_INT_SBE;
+
+  if (Rintsts & ErrMask) {
+    Status = EFI_DEVICE_ERROR;
+    goto out;
+  }
 out:
   // Restore Tpl
   gBS->RestoreTPL (Tpl);
diff --git a/EmbeddedPkg/Include/Protocol/MmcHost.h b/EmbeddedPkg/Include/Protocol/MmcHost.h
index 9e07082..ae8ea5d 100644
--- a/EmbeddedPkg/Include/Protocol/MmcHost.h
+++ b/EmbeddedPkg/Include/Protocol/MmcHost.h
@@ -169,6 +169,7 @@ struct _EFI_MMC_HOST_PROTOCOL {
   MMC_SETIOS              SetIos;
   MMC_ISMULTIBLOCK        IsMultiBlock;
 
+  BOOLEAN                 IsEmmc;
 };
 
 #define MMC_HOST_PROTOCOL_REVISION    0x00010002    // 1.2
diff --git a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c
index 4dc0be1..fa1eda2 100755
--- a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c
+++ b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c
@@ -770,8 +770,10 @@ InitializeMmcDevice (
   }
 
   if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {
+    MmcHostInstance->MmcHost->IsEmmc = FALSE;
     Status = InitializeSdMmcDevice (MmcHostInstance);
   } else {
+    MmcHostInstance->MmcHost->IsEmmc = TRUE;
     Status = InitializeEmmcDevice (MmcHostInstance);
   }
   if (EFI_ERROR (Status)) {
-- 
2.2.2


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#39899): https://edk2.groups.io/g/devel/message/39899
Mute This Topic: https://groups.io/mt/31451576/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list