SdMmc/DwMmcHcDxe: read FIFO for small block data

Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
diff --git a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHcDxe.h b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHcDxe.h
index a18cbc5..df68c67 100644
--- a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHcDxe.h
+++ b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHcDxe.h
@@ -70,11 +70,11 @@
 #define DW_MMC_HC_ENUM_TIMER    EFI_TIMER_PERIOD_MILLISECONDS(100)

 

 typedef struct {

-  BOOLEAN                           Enable;

-  EFI_SD_MMC_SLOT_TYPE              SlotType;

-  BOOLEAN                           MediaPresent;

-  BOOLEAN                           Initialized;

-  SD_MMC_CARD_TYPE                  CardType;

+  BOOLEAN                             Enable;

+  EFI_SD_MMC_SLOT_TYPE                SlotType;

+  BOOLEAN                             MediaPresent;

+  BOOLEAN                             Initialized;

+  SD_MMC_CARD_TYPE                    CardType;

 } DW_MMC_HC_SLOT;

 

 typedef struct {

@@ -137,6 +137,7 @@
   EFI_PHYSICAL_ADDRESS                DmaDescPhy;

   UINT32                              DmaDescPages;

   VOID                                *DmaMap;

+  BOOLEAN                             UseDma;

 

   DW_MMC_HC_PRIVATE_DATA              *Private;

 } DW_MMC_HC_TRB;

diff --git a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.c b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.c
index b4e5aac..5038889 100644
--- a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.c
+++ b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.c
@@ -948,7 +948,6 @@
   if (EFI_ERROR (Status)) {

     return Status;

   }

-

   return Status;

 }

 

@@ -1076,6 +1075,7 @@
   UINT32                    DmaDescPhy;

   UINT32                    Idsts;

   UINT32                    BytCnt;

+  UINT32                    BlkSize;

 

   Data    = Trb->DataPhy;

   DataLen = Trb->DataLen;

@@ -1151,13 +1151,25 @@
     return EFI_DEVICE_ERROR;

   }

 

-  BytCnt = DW_MMC_BLOCK_SIZE * Blocks;

+  if (DataLen < DW_MMC_BLOCK_SIZE) {

+    BlkSize = DataLen;

+    BytCnt = DataLen;

+    Remaining = DataLen;

+  } else {

+    BlkSize = DW_MMC_BLOCK_SIZE;

+    BytCnt = DW_MMC_BLOCK_SIZE * Blocks;

+    Remaining = DW_MMC_BLOCK_SIZE * Blocks;

+  }

+  Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_BLKSIZ, FALSE, sizeof (BlkSize), &BlkSize);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "BuildDmaDescTable: set block size fails: %r\n", Status));

+    return Status;

+  }

   Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_BYTCNT, FALSE, sizeof (BytCnt), &BytCnt);

   if (EFI_ERROR (Status)) {

     return Status;

   }

   DmaDesc = Trb->DmaDesc;

-  Remaining = DW_MMC_BLOCK_SIZE * Blocks;

   for (Index = 0; Index < Entries; Index++, DmaDesc++) {

     DmaDesc->Des0 = DW_MMC_IDMAC_DES0_OWN | DW_MMC_IDMAC_DES0_CH |

                     DW_MMC_IDMAC_DES0_DIC;

@@ -1171,7 +1183,8 @@
   // First Descriptor

   Trb->DmaDesc[0].Des0 |= DW_MMC_IDMAC_DES0_FS;

   // Last Descriptor

-  Trb->DmaDesc[Entries - 1].Des0 = DW_MMC_IDMAC_DES0_OWN | DW_MMC_IDMAC_DES0_LD;

+  Trb->DmaDesc[Entries - 1].Des0 &= ~(DW_MMC_IDMAC_DES0_CH | DW_MMC_IDMAC_DES0_DIC);

+  Trb->DmaDesc[Entries - 1].Des0 |= DW_MMC_IDMAC_DES0_OWN | DW_MMC_IDMAC_DES0_LD;

   Trb->DmaDesc[Entries - 1].Des1 = DW_MMC_IDMAC_DES1_BS1 (Remaining + DWMMC_DMA_BUF_SIZE);

   // Set the next field of the Last Descriptor

   Trb->DmaDesc[Entries - 1].Des3 = 0;

@@ -1188,6 +1201,63 @@
   return Status;

 }

 

+EFI_STATUS

+ReadFifo (

+  IN DW_MMC_HC_TRB          *Trb

+  )

+{

+  EFI_STATUS                Status;

+  EFI_PCI_IO_PROTOCOL       *PciIo;

+  UINT32                    Data;

+  UINT32                    Received;

+  UINT32                    Count;

+  UINT32                    Intsts;

+  UINT32                    Sts;

+  UINT32                    FifoCount;

+

+  PciIo   = Trb->Private->PciIo;

+  Received = 0;

+  Count = (Trb->DataLen + 3) / 4;

+  while (1) {

+    Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_RINTSTS, TRUE, sizeof (Intsts), &Intsts);

+    if (EFI_ERROR (Status)) {

+      DEBUG ((DEBUG_ERROR, "ReadFifo: failed to read RINTSTS, Status:%r\n", Status));

+      return Status;

+    }

+    if (Intsts & DW_MMC_INT_DTO) {

+      Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_STATUS, TRUE, sizeof (Sts), &Sts);

+      if (EFI_ERROR (Status)) {

+        DEBUG ((DEBUG_ERROR, "ReadFifo: failed to read STATUS, Status:%r\n", Status));

+        return Status;

+      }

+      // Convert to bytes

+      FifoCount = GET_STS_FIFO_COUNT (Sts) << 2;

+      Count = (MIN (FifoCount, Trb->DataLen) + 3) / 4;

+      Received = 0;

+      // Read FIFO

+      while (Count && (Received < Count)) {

+        Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_FIFO_START, TRUE, sizeof (Data), &Data);

+        if (EFI_ERROR (Status)) {

+          DEBUG ((DEBUG_ERROR, "ReadFifo: failed to read FIFO, Status:%r\n", Status));

+          return Status;

+        }

+        *(UINT32 *)((UINTN)Trb->Data + ((Count - Received - 1) << 2)) = SwapBytes32 (Data);

+        Received++;

+      }

+    }

+    if (Intsts & DW_MMC_INT_CMD_DONE) {

+      break;

+    }

+  }

+  Intsts = ~0;

+  Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_RINTSTS, FALSE, sizeof (Intsts), &Intsts);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "ReadFifo: failed to write RINTSTS, Status:%r\n", Status));

+    return Status;

+  }

+  return EFI_SUCCESS;

+}

+

 /**

   Create a new TRB for the SD/MMC cmd request.

 

@@ -1246,10 +1316,6 @@
     goto Error;

   }

 

-  if (Trb->DataLen < Trb->BlockSize) {

-    Trb->BlockSize = (UINT16)Trb->DataLen;

-  }

-

   if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&

        (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||

       ((Private->Slot[Trb->Slot].CardType == SdCardType) &&

@@ -1263,8 +1329,10 @@
     }

 

     PciIo = Private->PciIo;

-    if (Trb->DataLen != 0) {

+    if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) && (Trb->DataLen != 0)) ||

+        ((Private->Slot[Trb->Slot].CardType == SdCardType) && (Trb->DataLen >= DWMMC_FIFO_THRESHOLD))) {

       MapLength = Trb->DataLen;

+      Trb->UseDma = TRUE;

       Status = PciIo->Map (

                         PciIo,

                         Flag,

@@ -1277,9 +1345,7 @@
         Status = EFI_BAD_BUFFER_SIZE;

         goto Error;

       }

-    }

 

-    if (Trb->DataLen) {

       Status = BuildDmaDescTable (Trb);

       if (EFI_ERROR (Status)) {

         PciIo->Unmap (PciIo, Trb->DataMap);

@@ -1290,8 +1356,10 @@
         PciIo->Unmap (PciIo, Trb->DataMap);

         goto Error;

       }

-    }

-  }

+    } else {

+      Trb->UseDma = FALSE;

+    } // Dma

+  } // TuningBlock

 

   if (Event != NULL) {

     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);

@@ -1582,6 +1650,8 @@
   UINT32                              ErrMask;

   UINT32                              Timeout;

   UINT32                              Idsts;

+  UINT32                              BytCnt;

+  UINT32                              BlkSize;

 

   Packet = Trb->Packet;

   PciIo  = Trb->Private->PciIo;

@@ -1643,6 +1713,20 @@
   }

   Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START;

 

+  if (Trb->UseDma == FALSE) {

+    BytCnt = Packet->InTransferLength;

+    Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_BYTCNT, FALSE, sizeof (BytCnt), &BytCnt);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+    BlkSize = Packet->InTransferLength;

+    Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_BLKSIZ, FALSE, sizeof (BlkSize), &BlkSize);

+    if (EFI_ERROR (Status)) {

+      DEBUG ((DEBUG_ERROR, "DwMmcHcReset: set block size fails: %r\n", Status));

+      return Status;

+    }

+  }

+

   Argument = Packet->SdMmcCmdBlk->CommandArgument;

   Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_CMDARG, FALSE, sizeof (Argument), &Argument);

   if (EFI_ERROR (Status)) {

@@ -1661,47 +1745,57 @@
   }

   ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE | DW_MMC_INT_RTO |

             DW_MMC_INT_RCRC | DW_MMC_INT_RE;

-  ErrMask |= DW_MMC_INT_DCRC | DW_MMC_INT_DRT | DW_MMC_INT_SBE;

-  Timeout = 10000;

-  do {

-    Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_RINTSTS, TRUE, sizeof (IntStatus), &IntStatus);

-    if (EFI_ERROR (Status)) {

-      return Status;

-    }

-    if (IntStatus & ErrMask) {

-      return EFI_DEVICE_ERROR;

-    }

-    if (IntStatus & DW_MMC_INT_DTO) {  // Transfer Done

-      break;

-    }

-    if (--Timeout == 0) {

-      break;

-    }

-    MicroSecondDelay (10);

-  } while (!(IntStatus & DW_MMC_INT_CMD_DONE));

-  if (Packet->InTransferLength) {

-    do {

-      Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_IDSTS, TRUE, sizeof (Idsts), &Idsts);

-      if (EFI_ERROR (Status)) {

-        return Status;

-      }

-    } while ((Idsts & DW_MMC_IDSTS_RI) == 0);

-    Status = DwMmcHcStopDma (Private, Trb);

-    if (EFI_ERROR (Status)) {

-      return Status;

-    }

-  } else if (Packet->OutTransferLength) {

-    do {

-      Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_IDSTS, TRUE, sizeof (Idsts), &Idsts);

-      if (EFI_ERROR (Status)) {

-        return Status;

-      }

-    } while ((Idsts & DW_MMC_IDSTS_TI) == 0);

-    Status = DwMmcHcStopDma (Private, Trb);

-    if (EFI_ERROR (Status)) {

-      return Status;

-    }

+  ErrMask |= DW_MMC_INT_DRT | DW_MMC_INT_SBE;

+  if (Packet->InTransferLength || Packet->OutTransferLength) {

+    ErrMask |= DW_MMC_INT_DCRC;

   }

+  if (Trb->UseDma == FALSE) {

+    Status = ReadFifo (Trb);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+  } else {

+    Timeout = 10000;

+    do {

+      Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_RINTSTS, TRUE, sizeof (IntStatus), &IntStatus);

+      if (EFI_ERROR (Status)) {

+        return Status;

+      }

+      if (IntStatus & ErrMask) {

+        return EFI_DEVICE_ERROR;

+      }

+      if (IntStatus & DW_MMC_INT_DTO) {  // Transfer Done

+        break;

+      }

+      if (--Timeout == 0) {

+        break;

+      }

+      MicroSecondDelay (10);

+    } while (!(IntStatus & DW_MMC_INT_CMD_DONE));

+    if (Packet->InTransferLength) {

+      do {

+        Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_IDSTS, TRUE, sizeof (Idsts), &Idsts);

+        if (EFI_ERROR (Status)) {

+          return Status;

+        }

+      } while ((Idsts & DW_MMC_IDSTS_RI) == 0);

+      Status = DwMmcHcStopDma (Private, Trb);

+      if (EFI_ERROR (Status)) {

+        return Status;

+      }

+    } else if (Packet->OutTransferLength) {

+      do {

+        Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_IDSTS, TRUE, sizeof (Idsts), &Idsts);

+        if (EFI_ERROR (Status)) {

+          return Status;

+        }

+      } while ((Idsts & DW_MMC_IDSTS_TI) == 0);

+      Status = DwMmcHcStopDma (Private, Trb);

+      if (EFI_ERROR (Status)) {

+        return Status;

+      }

+    } // Packet->InTransferLength

+  } // UseDma

   switch (Packet->SdMmcCmdBlk->ResponseType) {

     case SdMmcResponseTypeR1:

     case SdMmcResponseTypeR1b:

@@ -1802,6 +1896,9 @@
   UINT32                              Idsts;

 

   Packet  = Trb->Packet;

+  if (Trb->UseDma == FALSE) {

+    return EFI_SUCCESS;

+  }

   if (Packet->InTransferLength) {

     do {

       Status = DwMmcHcRwMmio (Private->PciIo, Trb->Slot, DW_MMC_IDSTS, TRUE, sizeof (Idsts), &Idsts);

diff --git a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.h b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.h
index 84f16fc..9f0380c 100644
--- a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.h
+++ b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.h
@@ -52,9 +52,11 @@
 #define DW_MMC_RINTSTS                0x044

 #define DW_MMC_STATUS                 0x048

 #define DW_MMC_FIFOTH                 0x04c

+#define DW_MMC_GPIO                   0x058

 #define DW_MMC_DEBNCE                 0x064

 #define DW_MMC_USRID                  0x068

 #define DW_MMC_VERID                  0x06c

+#define DW_MMC_HCON                   0x070

 #define DW_MMC_UHSREG                 0x074

 #define DW_MMC_BMOD                   0x080

 #define DW_MMC_DBADDR                 0x088

@@ -63,6 +65,8 @@
 #define DW_MMC_DSCADDR                0x094

 #define DW_MMC_BUFADDR                0x098

 #define DW_MMC_CARDTHRCTL             0x100

+#define DW_MMC_UHSREG_EXT             0x108

+#define DW_MMC_ENABLE_SHIFT           0x110

 #define DW_MMC_FIFO_START             0x200

 

 #define GET_IDSTS_DMAC_FSM(x)                   (((x) >> 13) & 0xf)

@@ -149,6 +153,8 @@
 #define DW_MMC_CTRL_RESET_ALL                   (DW_MMC_CTRL_RESET | DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_DMA_RESET)

 

 #define DW_MMC_STS_DATA_BUSY                    (1 << 9)

+#define DW_MMC_STS_FIFO_COUNT(x)                (((x) & 0x1fff) << 17)   /* Number of filled locations in FIFO */

+#define GET_STS_FIFO_COUNT(x)                   (((x) >> 17) & 0x1fff)

 

 #define DW_MMC_BMOD_SWR                         (1 << 0)         /* Software Reset */

 #define DW_MMC_BMOD_FB                          (1 << 1)         /* Fix Burst */

@@ -157,15 +163,25 @@
 #define DW_MMC_IDSTS_TI                         (1 << 0)         /* Transmit Interrupt */

 #define DW_MMC_IDSTS_RI                         (1 << 1)         /* Receive Interrupt */

 

-#define DW_MMC_FIFO_TWMARK(x)                   (x & 0xfff)

-#define DW_MMC_FIFO_RWMARK(x)                   ((x & 0x1ff) << 16)

-#define DW_MMC_DMA_BURST_SIZE(x)                ((x & 0x7) << 28)

+#define DW_MMC_FIFO_TWMARK(x)                   ((x) & 0xfff)

+#define DW_MMC_FIFO_RWMARK(x)                   (((x) & 0x1ff) << 16)

+#define DW_MMC_DMA_BURST_SIZE(x)                (((x) & 0x7) << 28)

 

-#define DW_MMC_CARD_RD_THR(x)                   ((x & 0xfff) << 16)

+#define DW_MMC_CARD_RD_THR(x)                   (((x) & 0xfff) << 16)

 #define DW_MMC_CARD_RD_THR_EN                   (1 << 0)

 

 #define UHS_DDR_MODE                            (1 << 16)

 

+#define GENCLK_DIV                              7

+

+#define DW_MMC_GPIO_CLK_DIV(x)                  (((x) & 0xf) << 8)

+#define DW_MMC_GPIO_USE_SAMPLE_DLY(x)           (((x) & 1) << 13)

+#define DW_MMC_GPIO_CLK_ENABLE                  BIT16

+

+#define UHSEXT_SAMPLE_PHASE(x)                  (((x) & 0x1f) << 16)

+#define UHSEXT_SAMPLE_DRVPHASE(x)               (((x) & 0x1f) << 21)

+#define UHSEXT_SAMPLE_DLY(x)                    (((x) & 0x1f) << 26)

+

 #define DWMMC_DMA_BUF_SIZE                      (512 * 8)

 #define DWMMC_FIFO_THRESHOLD                    16

 

diff --git a/Drivers/SdMmc/DwMmcHcDxe/SdDevice.c b/Drivers/SdMmc/DwMmcHcDxe/SdDevice.c
index 48f2b67..1bccdee 100644
--- a/Drivers/SdMmc/DwMmcHcDxe/SdDevice.c
+++ b/Drivers/SdMmc/DwMmcHcDxe/SdDevice.c
@@ -918,6 +918,8 @@
   BOOLEAN                        Xpc;

   BOOLEAN                        S18r;

   UINT64                         MaxCurrent;

+  SD_SCR                         Scr;

+  SD_CSD                         Csd;

 

   PciIo    = Private->PciIo;

   PassThru = &Private->PassThru;

@@ -941,7 +943,7 @@
   // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.

   //

   Status = SdioSendOpCond (PassThru, Slot, 0, FALSE);

-  if (!EFI_ERROR (Status)) {

+  if (EFI_ERROR (Status)) {

     DEBUG ((DEBUG_INFO, "SdCardIdentification: Found SDIO device, ignore it as we don't support\n"));

     return EFI_DEVICE_ERROR;

   }

@@ -1013,6 +1015,24 @@
     DEBUG ((DEBUG_ERROR, "SdCardIdentification: Selecting card fails with %r\n", Status));

     return Status;

   }

+

+  Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, 1);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardSwitchBusWidth fails with %r\n", Status));

+    return Status;

+  }

+

+  Status = SdCardGetScr (PassThru, Slot, Rca, &Scr);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardGetScr fails with %r\n", Status));

+    return Status;

+  }

+

+  Status = SdCardGetCsd (PassThru, Slot, Rca, &Csd);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardGetCsd fails with %r\n", Status));

+    return Status;

+  }

   //

   // Enter Data Tranfer Mode.

   //