From: Jan Dąbroś <[email protected]>

For multiple block write operation it is necessary to poll for device status
to be ready for next transaction. For sending SD_DEVICE_STATUS command it is
necessary to know device RCA. In order to make it possible, there is new
field added to SD_DEVICE structure called "Rca".

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jan Dabros <[email protected]>
Signed-off-by: Marcin Wojtas <[email protected]>
---
 MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c | 61 +++++++++++++++++++++++++++++++++++
 MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c     |  3 ++
 MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h     |  1 +
 3 files changed, 65 insertions(+)

diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c 
b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
index 411f353..2ce65e8 100644
--- a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
+++ b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
@@ -336,6 +336,57 @@ SdSendStopTransmission (
 }
 
 /**
+  Check if card is ready for next data transfer by reading its status.
+
+  @param[in]  Device            A pointer to the SD_DEVICE instance.
+
+  @retval EFI_SUCCESS           Card is ready for next data transfer.
+  @retval EFI_DEVICE_ERROR      Card status is erroneous.
+  @retval EFI_TIMEOUT           Card is busy.
+
+**/
+STATIC
+EFI_STATUS
+SdIsReady (
+  SD_DEVICE *Device,
+  UINT16 Rca,
+  UINTN Timeout
+  )
+{
+  EFI_STATUS Status;
+  UINT32 DevStatus;
+
+  do {
+    Status = SdSendStatus (Device, Rca, &DevStatus);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_INFO, "Cannot read SD status\n"));
+      return Status;
+    }
+    // Check device status
+    if ((DevStatus & (1 << 8)) && (DevStatus & (0xf << 9)) != (7 << 9)) {
+      break;
+    } else if (DevStatus & ~0x0206BF7F) {
+      DEBUG ((EFI_D_ERROR, "SD Status error\n"));
+      return EFI_DEVICE_ERROR;
+    }
+
+    gBS->Stall (1000);
+  } while (Timeout--);
+
+  if (Timeout <= 0) {
+    DEBUG ((EFI_D_ERROR, "SD Status timeout\n"));
+    return EFI_TIMEOUT;
+  }
+
+  if (DevStatus & (1 << 7)) {
+    DEBUG ((EFI_D_ERROR, "SD switch error\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
   Read/write single block through sync or async I/O request.
 
   @param[in]  Device            A pointer to the SD_DEVICE instance.
@@ -712,6 +763,16 @@ SdReadWrite (
     }
     DEBUG ((EFI_D_INFO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", 
IsRead ? "Read" : "Write", Lba, BlockNum, Token->Event, Status));
 
+    if (FeaturePcdGet(PcdSdForcePioMode)) {
+      if (!IsRead) {
+        if (SdIsReady (Device, Device->Rca, 1000) == EFI_SUCCESS) {
+          Status = EFI_SUCCESS;
+        }
+        else
+          Status = EFI_DEVICE_ERROR;
+      }
+    }
+
     Lba   += BlockNum;
     Buffer = (UINT8*)Buffer + BufferSize;
     Remaining -= BlockNum;
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c 
b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c
index f657fb9..fe0573d 100644
--- a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c
+++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c
@@ -83,6 +83,7 @@ SD_DEVICE mSdDeviceTemplate = {
   {                            // ModelName
     0,
   },
+  0,
   NULL                         // Private
 };
 
@@ -224,6 +225,8 @@ DiscoverUserArea (
     return Status;
   }
 
+  Device->Rca = Rca;
+
   Status = SdSendStatus (Device, Rca, &DevStatus);
   if (EFI_ERROR (Status)) {
     return Status;
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h 
b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h
index 0ba72b7..17008c0 100644
--- a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h
+++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h
@@ -114,6 +114,7 @@ struct _SD_DEVICE {
   // The delimiters of these fields are whitespace.
   //
   CHAR16                                ModelName[SD_MODEL_NAME_MAX_LEN];
+  CHAR16                                Rca;
   SD_DRIVER_PRIVATE_DATA                *Private;
 } ;
 
-- 
1.8.3.1

_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to