It's done by producing EFI_ERASE_BLOCK_PROTOCOL protocol instance.

Cc: Wu, Hao A <[email protected]>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Feng Tian <[email protected]>
---
 MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c | 411 ++++++++++++++++++++++++++++++
 MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h |  39 ++-
 MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c     |  74 +++++-
 MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h     |   5 +
 MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf   |   3 +-
 MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c     | 384 ++++++++++++++++++++++++++++
 MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h     |  39 ++-
 MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c         |  15 ++
 MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h         |   7 +-
 MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf       |   3 +-
 10 files changed, 974 insertions(+), 6 deletions(-)

diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c 
b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c
index edb438b..a12cd63 100644
--- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c
+++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c
@@ -47,6 +47,8 @@ AsyncIoCallback (
 
   if (EFI_ERROR (Request->Packet.TransactionStatus)) {
     Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
+  } else {
+    Request->Token->TransactionStatus = EFI_SUCCESS;
   }
 
   RemoveEntryList (&Request->Link);
@@ -1589,3 +1591,412 @@ EmmcSecurityProtocolOut (
   return Status;
 }
 
+/**
+  Set the erase start address through sync or async I/O request.
+
+  @param[in]  Partition         A pointer to the EMMC_PARTITION instance.
+  @param[in]  StartLba          The starting logical block address to be 
erased.
+  @param[in]  Token             A pointer to the token associated with the 
transaction.
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in 
a series of cmds.
+                                This parameter is only meaningful in async I/O 
request.
+
+  @retval EFI_SUCCESS           The request is executed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a 
lack of resources.
+  @retval Others                The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcEraseBlockStart (
+  IN  EMMC_PARTITION            *Partition,
+  IN  EFI_LBA                   StartLba,
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,
+  IN  BOOLEAN                   IsEnd
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
+  EMMC_DEVICE                          *Device;
+  EMMC_REQUEST                         *EraseBlockStart;
+  EFI_TPL                              OldTpl;
+
+  EraseBlockStart = NULL;
+
+  Device   = Partition->Device;
+  PassThru = Device->Private->PassThru;
+
+  EraseBlockStart = AllocateZeroPool (sizeof (EMMC_REQUEST));
+  if (EraseBlockStart == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+
+  EraseBlockStart->Signature = EMMC_REQUEST_SIGNATURE;
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+  InsertTailList (&Partition->Queue, &EraseBlockStart->Link);
+  gBS->RestoreTPL (OldTpl);
+  EraseBlockStart->Packet.SdMmcCmdBlk    = &EraseBlockStart->SdMmcCmdBlk;
+  EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
+  EraseBlockStart->Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
+
+  EraseBlockStart->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_START;
+  EraseBlockStart->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+  if (Device->SectorAddressing) {
+    EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
+  } else {
+    EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 
(StartLba, Partition->BlockMedia.BlockSize);
+  }
+
+  EraseBlockStart->IsEnd = IsEnd;
+  EraseBlockStart->Token = Token;
+
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    AsyncIoCallback,
+                    EraseBlockStart,
+                    &EraseBlockStart->Event
+                    );
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+  } else {
+    EraseBlockStart->Event = NULL;
+  }
+
+  Status = PassThru->PassThru (PassThru, Device->Slot, 
&EraseBlockStart->Packet, EraseBlockStart->Event);
+
+Error:
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    //
+    // For asynchronous operation, only free request and event in error case.
+    // The request and event will be freed in asynchronous callback for 
success case.
+    //
+    if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
+      RemoveEntryList (&EraseBlockStart->Link);
+      if (EraseBlockStart->Event != NULL) {
+        gBS->CloseEvent (EraseBlockStart->Event);
+      }
+      FreePool (EraseBlockStart);
+    }
+  } else {
+    //
+    // For synchronous operation, free request whatever the execution result 
is.
+    //
+    if (EraseBlockStart != NULL) {
+      RemoveEntryList (&EraseBlockStart->Link);
+      FreePool (EraseBlockStart);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Set the erase end address through sync or async I/O request.
+
+  @param[in]  Partition         A pointer to the EMMC_PARTITION instance.
+  @param[in]  EndLba            The ending logical block address to be erased.
+  @param[in]  Token             A pointer to the token associated with the 
transaction.
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in 
a series of cmds.
+                                This parameter is only meaningful in async I/O 
request.
+
+  @retval EFI_SUCCESS           The request is executed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a 
lack of resources.
+  @retval Others                The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcEraseBlockEnd (
+  IN  EMMC_PARTITION            *Partition,
+  IN  EFI_LBA                   EndLba,
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,
+  IN  BOOLEAN                   IsEnd
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
+  EMMC_DEVICE                          *Device;
+  EMMC_REQUEST                         *EraseBlockEnd;
+  EFI_TPL                              OldTpl;
+
+  EraseBlockEnd = NULL;
+
+  Device   = Partition->Device;
+  PassThru = Device->Private->PassThru;
+
+  EraseBlockEnd = AllocateZeroPool (sizeof (EMMC_REQUEST));
+  if (EraseBlockEnd == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+
+  EraseBlockEnd->Signature = EMMC_REQUEST_SIGNATURE;
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+  InsertTailList (&Partition->Queue, &EraseBlockEnd->Link);
+  gBS->RestoreTPL (OldTpl);
+  EraseBlockEnd->Packet.SdMmcCmdBlk    = &EraseBlockEnd->SdMmcCmdBlk;
+  EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
+  EraseBlockEnd->Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
+
+  EraseBlockEnd->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_END;
+  EraseBlockEnd->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+  if (Device->SectorAddressing) {
+    EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
+  } else {
+    EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, 
Partition->BlockMedia.BlockSize);
+  }
+
+  EraseBlockEnd->IsEnd = IsEnd;
+  EraseBlockEnd->Token = Token;
+
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    AsyncIoCallback,
+                    EraseBlockEnd,
+                    &EraseBlockEnd->Event
+                    );
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+  } else {
+    EraseBlockEnd->Event = NULL;
+  }
+
+  Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, 
EraseBlockEnd->Event);
+
+Error:
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    //
+    // For asynchronous operation, only free request and event in error case.
+    // The request and event will be freed in asynchronous callback for 
success case.
+    //
+    if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
+      RemoveEntryList (&EraseBlockEnd->Link);
+      if (EraseBlockEnd->Event != NULL) {
+        gBS->CloseEvent (EraseBlockEnd->Event);
+      }
+      FreePool (EraseBlockEnd);
+    }
+  } else {
+    //
+    // For synchronous operation, free request whatever the execution result 
is.
+    //
+    if (EraseBlockEnd != NULL) {
+      RemoveEntryList (&EraseBlockEnd->Link);
+      FreePool (EraseBlockEnd);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Erase specified blocks through sync or async I/O request.
+
+  @param[in]  Partition         A pointer to the EMMC_PARTITION instance.
+  @param[in]  Token             A pointer to the token associated with the 
transaction.
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in 
a series of cmds.
+                                This parameter is only meaningful in async I/O 
request.
+
+  @retval EFI_SUCCESS           The request is executed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a 
lack of resources.
+  @retval Others                The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcEraseBlock (
+  IN  EMMC_PARTITION            *Partition,
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,
+  IN  BOOLEAN                   IsEnd
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
+  EMMC_DEVICE                          *Device;
+  EMMC_REQUEST                         *EraseBlock;
+  EFI_TPL                              OldTpl;
+
+  EraseBlock = NULL;
+
+  Device   = Partition->Device;
+  PassThru = Device->Private->PassThru;
+
+  EraseBlock = AllocateZeroPool (sizeof (EMMC_REQUEST));
+  if (EraseBlock == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+
+  EraseBlock->Signature = EMMC_REQUEST_SIGNATURE;
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+  InsertTailList (&Partition->Queue, &EraseBlock->Link);
+  gBS->RestoreTPL (OldTpl);
+  EraseBlock->Packet.SdMmcCmdBlk    = &EraseBlock->SdMmcCmdBlk;
+  EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
+  EraseBlock->Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
+
+  EraseBlock->SdMmcCmdBlk.CommandIndex = EMMC_ERASE;
+  EraseBlock->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+
+  EraseBlock->IsEnd = IsEnd;
+  EraseBlock->Token = Token;
+
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    AsyncIoCallback,
+                    EraseBlock,
+                    &EraseBlock->Event
+                    );
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+  } else {
+    EraseBlock->Event = NULL;
+  }
+
+  Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, 
EraseBlock->Event);
+
+Error:
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    //
+    // For asynchronous operation, only free request and event in error case.
+    // The request and event will be freed in asynchronous callback for 
success case.
+    //
+    if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
+      RemoveEntryList (&EraseBlock->Link);
+      if (EraseBlock->Event != NULL) {
+        gBS->CloseEvent (EraseBlock->Event);
+      }
+      FreePool (EraseBlock);
+    }
+  } else {
+    //
+    // For synchronous operation, free request whatever the execution result 
is.
+    //
+    if (EraseBlock != NULL) {
+      RemoveEntryList (&EraseBlock->Link);
+      FreePool (EraseBlock);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Erase a specified number of device blocks.
+
+  @param[in]       This           Indicates a pointer to the calling context.
+  @param[in]       MediaId        The media ID that the erase request is for.
+  @param[in]       Lba            The starting logical block address to be
+                                  erased. The caller is responsible for erasing
+                                  only legitimate locations.
+  @param[in, out]  Token          A pointer to the token associated with the
+                                  transaction.
+  @param[in]       Size           The size in bytes to be erased. This must be
+                                  a multiple of the physical block size of the
+                                  device.
+
+  @retval EFI_SUCCESS             The erase request was queued if Event is not
+                                  NULL. The data was erased correctly to the
+                                  device if the Event is NULL.to the device.
+  @retval EFI_WRITE_PROTECTED     The device cannot be erased due to write
+                                  protection.
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting
+                                  to perform the erase operation.
+  @retval EFI_INVALID_PARAMETER   The erase request contains LBAs that are not
+                                  valid.
+  @retval EFI_NO_MEDIA            There is no media in the device.
+  @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcEraseBlocks (
+  IN     EFI_ERASE_BLOCK_PROTOCOL      *This,
+  IN     UINT32                        MediaId,
+  IN     EFI_LBA                       Lba,
+  IN OUT EFI_ERASE_BLOCK_TOKEN         *Token,
+  IN     UINTN                         Size
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_BLOCK_IO_MEDIA                    *Media;
+  UINTN                                 BlockSize;
+  UINTN                                 BlockNum;
+  EFI_LBA                               LastLba;
+  UINT8                                 PartitionConfig;
+  EMMC_PARTITION                        *Partition;
+  EMMC_DEVICE                           *Device;
+
+  Status    = EFI_SUCCESS;
+  Partition = EMMC_PARTITION_DATA_FROM_ERASEBLK (This);
+  Device    = Partition->Device;
+  Media     = &Partition->BlockMedia;
+
+  if (MediaId != Media->MediaId) {
+    return EFI_MEDIA_CHANGED;
+  }
+
+  if (Media->ReadOnly) {
+    return EFI_WRITE_PROTECTED;
+  }
+
+  //
+  // Check parameters.
+  //
+  BlockSize = Media->BlockSize;
+  if ((Size % BlockSize) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  BlockNum  = Size / BlockSize;
+  if ((Lba + BlockNum - 1) > Media->LastBlock) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  LastLba = Lba + BlockNum - 1;
+
+  //
+  // Check if needs to switch partition access.
+  //
+  PartitionConfig = Device->ExtCsd.PartitionConfig;
+  if ((PartitionConfig & 0x7) != Partition->PartitionType) {
+    PartitionConfig &= (UINT8)~0x7;
+    PartitionConfig |= Partition->PartitionType;
+    Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, 
PartitionConfig), PartitionConfig, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    Device->ExtCsd.PartitionConfig = PartitionConfig;
+  }
+
+  Status = EmmcEraseBlockStart (Partition, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, 
FALSE);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = EmmcEraseBlockEnd (Partition, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, 
FALSE);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = EmmcEraseBlock (Partition, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  DEBUG ((EFI_D_ERROR, "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with 
%r\n", Lba, BlockNum, Token->Event, Status));
+
+  return Status;
+}
+
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h 
b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h
index f0e1312..c8a6c5c 100644
--- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h
+++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h
@@ -4,7 +4,7 @@
   This file defines common data structures, macro definitions and some module
   internal function header files.
 
-  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
@@ -462,5 +462,42 @@ EmmcSecurityProtocolOut (
   IN VOID                                     *PayloadBuffer
   );
 
+/**
+  Erase a specified number of device blocks.
+
+  @param[in]       This           Indicates a pointer to the calling context.
+  @param[in]       MediaId        The media ID that the erase request is for.
+  @param[in]       Lba            The starting logical block address to be
+                                  erased. The caller is responsible for erasing
+                                  only legitimate locations.
+  @param[in, out]  Token          A pointer to the token associated with the
+                                  transaction.
+  @param[in]       Size           The size in bytes to be erased. This must be
+                                  a multiple of the physical block size of the
+                                  device.
+
+  @retval EFI_SUCCESS             The erase request was queued if Event is not
+                                  NULL. The data was erased correctly to the
+                                  device if the Event is NULL.to the device.
+  @retval EFI_WRITE_PROTECTED     The device cannot be erased due to write
+                                  protection.
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting
+                                  to perform the erase operation.
+  @retval EFI_INVALID_PARAMETER   The erase request contains LBAs that are not
+                                  valid.
+  @retval EFI_NO_MEDIA            There is no media in the device.
+  @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcEraseBlocks (
+  IN     EFI_ERASE_BLOCK_PROTOCOL      *This,
+  IN     UINT32                        MediaId,
+  IN     EFI_LBA                       Lba,
+  IN OUT EFI_ERASE_BLOCK_TOKEN         *Token,
+  IN     UINTN                         Size
+  );
+
 #endif
 
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c 
b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c
index 2dd2981..6e156e9 100644
--- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c
+++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c
@@ -68,6 +68,11 @@ EMMC_PARTITION mEmmcPartitionTemplate = {
     EmmcSecurityProtocolIn,
     EmmcSecurityProtocolOut
   },
+  {                            // EraseBlock
+    EFI_ERASE_BLOCK_PROTOCOL_REVISION,
+    1,
+    EmmcEraseBlocks
+  },
   {
     NULL,
     NULL
@@ -369,6 +374,16 @@ DiscoverAllPartitions (
       Partition->Enable = TRUE;
       Partition->BlockMedia.LastBlock = DivU64x32 (Capacity, 
Partition->BlockMedia.BlockSize) - 1;
     }
+
+    if ((ExtCsd->EraseGroupDef & BIT0) == 0) {
+      if (Csd->WriteBlLen < 9) {
+        Partition->EraseBlock.EraseLengthGranularity = 1;
+      } else {
+        Partition->EraseBlock.EraseLengthGranularity = (Csd->EraseGrpMult + 1) 
* (Csd->EraseGrpSize + 1) * (1 << (Csd->WriteBlLen - 9));
+      }
+    } else {
+      Partition->EraseBlock.EraseLengthGranularity = 1024 * 
ExtCsd->HcEraseGrpSize;
+    }
   }
 
   return EFI_SUCCESS;
@@ -438,10 +453,32 @@ InstallProtocolOnPartition (
                     &Partition->BlockIo2,
                     NULL
                     );
-   if (EFI_ERROR (Status)) {
+    if (EFI_ERROR (Status)) {
       goto Error;
     }
 
+    if (Partition->PartitionType != EmmcPartitionRPMB) {
+      Status = gBS->InstallProtocolInterface (
+                      &Partition->Handle,
+                      &gEfiEraseBlockProtocolGuid,
+                      EFI_NATIVE_INTERFACE,
+                      &Partition->EraseBlock
+                      );
+      if (EFI_ERROR (Status)) {
+        gBS->UninstallMultipleProtocolInterfaces (
+               &Partition->Handle,
+               &gEfiDevicePathProtocolGuid,
+               Partition->DevicePath,
+               &gEfiBlockIoProtocolGuid,
+               &Partition->BlockIo,
+               &gEfiBlockIo2ProtocolGuid,
+               &Partition->BlockIo2,
+               NULL
+               );
+        goto Error;
+      }
+    }
+
     if (((Partition->PartitionType == EmmcPartitionUserData) ||
         (Partition->PartitionType == EmmcPartitionBoot1) ||
         (Partition->PartitionType == EmmcPartitionBoot2)) &&
@@ -461,6 +498,8 @@ InstallProtocolOnPartition (
                &Partition->BlockIo,
                &gEfiBlockIo2ProtocolGuid,
                &Partition->BlockIo2,
+               &gEfiEraseBlockProtocolGuid,
+               &Partition->EraseBlock,
                NULL
                );
         goto Error;
@@ -954,6 +993,7 @@ EmmcDxeDriverBindingStop (
   EFI_BLOCK_IO_PROTOCOL                  *BlockIo;
   EFI_BLOCK_IO2_PROTOCOL                 *BlockIo2;
   EFI_STORAGE_SECURITY_COMMAND_PROTOCOL  *StorageSecurity;
+  EFI_ERASE_BLOCK_PROTOCOL               *EraseBlock;
   LIST_ENTRY                             *Link;
   LIST_ENTRY                             *NextLink;
   EMMC_REQUEST                           *Request;
@@ -1096,6 +1136,38 @@ EmmcDxeDriverBindingStop (
     }
 
     //
+    // If Erase Block Protocol is installed, then uninstall this protocol.
+    //
+    Status = gBS->OpenProtocol (
+                    ChildHandleBuffer[Index],
+                    &gEfiEraseBlockProtocolGuid,
+                    (VOID **) &EraseBlock,
+                    This->DriverBindingHandle,
+                    Controller,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+
+    if (!EFI_ERROR (Status)) {
+      Status = gBS->UninstallProtocolInterface (
+                      ChildHandleBuffer[Index],
+                      &gEfiEraseBlockProtocolGuid,
+                      &Partition->EraseBlock
+                      );
+      if (EFI_ERROR (Status)) {
+        gBS->OpenProtocol (
+          Controller,
+          &gEfiSdMmcPassThruProtocolGuid,
+          (VOID **) &Partition->Device->Private->PassThru,
+          This->DriverBindingHandle,
+          ChildHandleBuffer[Index],
+          EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+          );
+        AllChildrenStopped = FALSE;
+        continue;
+      }
+    }
+
+    //
     // If Storage Security Command Protocol is installed, then uninstall this 
protocol.
     //
     Status = gBS->OpenProtocol (
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h 
b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h
index 0c50d62..0ae4ecc 100644
--- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h
+++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h
@@ -25,6 +25,7 @@
 #include <Protocol/BlockIo.h>
 #include <Protocol/BlockIo2.h>
 #include <Protocol/StorageSecurityCommand.h>
+#include <Protocol/EraseBlock.h>
 
 #include <Protocol/DevicePath.h>
 
@@ -57,6 +58,9 @@ extern EFI_COMPONENT_NAME2_PROTOCOL     
gEmmcDxeComponentName2;
 #define EMMC_PARTITION_DATA_FROM_SSP(a) \
     CR(a, EMMC_PARTITION, StorageSecurity, EMMC_PARTITION_SIGNATURE)
 
+#define EMMC_PARTITION_DATA_FROM_ERASEBLK(a) \
+    CR(a, EMMC_PARTITION, EraseBlock, EMMC_PARTITION_SIGNATURE)
+
 //
 // Take 2.5 seconds as generic time out value, 1 microsecond as unit.
 //
@@ -97,6 +101,7 @@ typedef struct {
   EFI_BLOCK_IO2_PROTOCOL                BlockIo2;
   EFI_BLOCK_IO_MEDIA                    BlockMedia;
   EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
+  EFI_ERASE_BLOCK_PROTOCOL              EraseBlock;
 
   LIST_ENTRY                            Queue;
 
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf 
b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
index a10bcd2..7b05049 100644
--- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
+++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
@@ -4,7 +4,7 @@
 #  It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper 
layer
 #  access the EMMC device.
 #
-#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
 #
 #  This program and the accompanying materials
 #  are licensed and made available under the terms and conditions of the BSD 
License
@@ -60,6 +60,7 @@
   gEfiBlockIoProtocolGuid                      ## BY_START
   gEfiBlockIo2ProtocolGuid                     ## BY_START
   gEfiStorageSecurityCommandProtocolGuid       ## SOMETIMES_PRODUCES
+  gEfiEraseBlockProtocolGuid                   ## BY_START
   ## TO_START
   ## BY_START
   gEfiDevicePathProtocolGuid
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c 
b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
index b7a5fe4..a9106a9 100644
--- a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
+++ b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
@@ -43,6 +43,8 @@ AsyncIoCallback (
 
   if (EFI_ERROR (Request->Packet.TransactionStatus)) {
     Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
+  } else {
+    Request->Token->TransactionStatus = EFI_SUCCESS;
   }
 
   RemoveEntryList (&Request->Link);
@@ -970,4 +972,386 @@ SdFlushBlocksEx (
   return EFI_SUCCESS;
 }
 
+/**
+  Set the erase start address through sync or async I/O request.
+
+  @param[in]  Device            A pointer to the SD_DEVICE instance.
+  @param[in]  StartLba          The starting logical block address to be 
erased.
+  @param[in]  Token             A pointer to the token associated with the 
transaction.
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in 
a series of cmds.
+                                This parameter is only meaningful in async I/O 
request.
+
+  @retval EFI_SUCCESS           The request is executed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a 
lack of resources.
+  @retval Others                The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdEraseBlockStart (
+  IN  SD_DEVICE                 *Device,
+  IN  EFI_LBA                   StartLba,
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,
+  IN  BOOLEAN                   IsEnd
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
+  SD_REQUEST                           *EraseBlockStart;
+  EFI_TPL                              OldTpl;
+
+  EraseBlockStart = NULL;
+  PassThru        = Device->Private->PassThru;
+
+  EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));
+  if (EraseBlockStart == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+
+  EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+  InsertTailList (&Device->Queue, &EraseBlockStart->Link);
+  gBS->RestoreTPL (OldTpl);
+  EraseBlockStart->Packet.SdMmcCmdBlk    = &EraseBlockStart->SdMmcCmdBlk;
+  EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
+  EraseBlockStart->Packet.Timeout        = SD_GENERIC_TIMEOUT;
+
+  EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;
+  EraseBlockStart->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+  if (Device->SectorAddressing) {
+    EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
+  } else {
+    EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 
(StartLba, Device->BlockMedia.BlockSize);
+  }
+
+  EraseBlockStart->IsEnd = IsEnd;
+  EraseBlockStart->Token = Token;
+
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    AsyncIoCallback,
+                    EraseBlockStart,
+                    &EraseBlockStart->Event
+                    );
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+  } else {
+    EraseBlockStart->Event = NULL;
+  }
+
+  Status = PassThru->PassThru (PassThru, Device->Slot, 
&EraseBlockStart->Packet, EraseBlockStart->Event);
+
+Error:
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    //
+    // For asynchronous operation, only free request and event in error case.
+    // The request and event will be freed in asynchronous callback for 
success case.
+    //
+    if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
+      RemoveEntryList (&EraseBlockStart->Link);
+      if (EraseBlockStart->Event != NULL) {
+        gBS->CloseEvent (EraseBlockStart->Event);
+      }
+      FreePool (EraseBlockStart);
+    }
+  } else {
+    //
+    // For synchronous operation, free request whatever the execution result 
is.
+    //
+    if (EraseBlockStart != NULL) {
+      RemoveEntryList (&EraseBlockStart->Link);
+      FreePool (EraseBlockStart);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Set the erase end address through sync or async I/O request.
+
+  @param[in]  Device            A pointer to the SD_DEVICE instance.
+  @param[in]  EndLba            The ending logical block address to be erased.
+  @param[in]  Token             A pointer to the token associated with the 
transaction.
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in 
a series of cmds.
+                                This parameter is only meaningful in async I/O 
request.
+
+  @retval EFI_SUCCESS           The request is executed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a 
lack of resources.
+  @retval Others                The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdEraseBlockEnd (
+  IN  SD_DEVICE                 *Device,
+  IN  EFI_LBA                   EndLba,
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,
+  IN  BOOLEAN                   IsEnd
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
+  SD_REQUEST                           *EraseBlockEnd;
+  EFI_TPL                              OldTpl;
+
+  EraseBlockEnd = NULL;
+  PassThru      = Device->Private->PassThru;
+
+  EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));
+  if (EraseBlockEnd == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+
+  EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+  InsertTailList (&Device->Queue, &EraseBlockEnd->Link);
+  gBS->RestoreTPL (OldTpl);
+  EraseBlockEnd->Packet.SdMmcCmdBlk    = &EraseBlockEnd->SdMmcCmdBlk;
+  EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
+  EraseBlockEnd->Packet.Timeout        = SD_GENERIC_TIMEOUT;
+
+  EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;
+  EraseBlockEnd->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+  if (Device->SectorAddressing) {
+    EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
+  } else {
+    EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, 
Device->BlockMedia.BlockSize);
+  }
+
+  EraseBlockEnd->IsEnd = IsEnd;
+  EraseBlockEnd->Token = Token;
+
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    AsyncIoCallback,
+                    EraseBlockEnd,
+                    &EraseBlockEnd->Event
+                    );
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+  } else {
+    EraseBlockEnd->Event = NULL;
+  }
+
+  Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, 
EraseBlockEnd->Event);
+
+Error:
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    //
+    // For asynchronous operation, only free request and event in error case.
+    // The request and event will be freed in asynchronous callback for 
success case.
+    //
+    if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
+      RemoveEntryList (&EraseBlockEnd->Link);
+      if (EraseBlockEnd->Event != NULL) {
+        gBS->CloseEvent (EraseBlockEnd->Event);
+      }
+      FreePool (EraseBlockEnd);
+    }
+  } else {
+    //
+    // For synchronous operation, free request whatever the execution result 
is.
+    //
+    if (EraseBlockEnd != NULL) {
+      RemoveEntryList (&EraseBlockEnd->Link);
+      FreePool (EraseBlockEnd);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Erase specified blocks through sync or async I/O request.
+
+  @param[in]  Device            A pointer to the SD_DEVICE instance.
+  @param[in]  Token             A pointer to the token associated with the 
transaction.
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in 
a series of cmds.
+                                This parameter is only meaningful in async I/O 
request.
+
+  @retval EFI_SUCCESS           The request is executed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a 
lack of resources.
+  @retval Others                The request could not be executed successfully.
+
+**/
+EFI_STATUS
+SdEraseBlock (
+  IN  SD_DEVICE                 *Device,
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,
+  IN  BOOLEAN                   IsEnd
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
+  SD_REQUEST                           *EraseBlock;
+  EFI_TPL                              OldTpl;
+
+  EraseBlock = NULL;
+  PassThru   = Device->Private->PassThru;
+
+  EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));
+  if (EraseBlock == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+
+  EraseBlock->Signature = SD_REQUEST_SIGNATURE;
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+  InsertTailList (&Device->Queue, &EraseBlock->Link);
+  gBS->RestoreTPL (OldTpl);
+  EraseBlock->Packet.SdMmcCmdBlk    = &EraseBlock->SdMmcCmdBlk;
+  EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
+  EraseBlock->Packet.Timeout        = SD_GENERIC_TIMEOUT;
+
+  EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;
+  EraseBlock->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+
+  EraseBlock->IsEnd = IsEnd;
+  EraseBlock->Token = Token;
+
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    AsyncIoCallback,
+                    EraseBlock,
+                    &EraseBlock->Event
+                    );
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+  } else {
+    EraseBlock->Event = NULL;
+  }
+
+  Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, 
EraseBlock->Event);
+
+Error:
+  if ((Token != NULL) && (Token->Event != NULL)) {
+    //
+    // For asynchronous operation, only free request and event in error case.
+    // The request and event will be freed in asynchronous callback for 
success case.
+    //
+    if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
+      RemoveEntryList (&EraseBlock->Link);
+      if (EraseBlock->Event != NULL) {
+        gBS->CloseEvent (EraseBlock->Event);
+      }
+      FreePool (EraseBlock);
+    }
+  } else {
+    //
+    // For synchronous operation, free request whatever the execution result 
is.
+    //
+    if (EraseBlock != NULL) {
+      RemoveEntryList (&EraseBlock->Link);
+      FreePool (EraseBlock);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Erase a specified number of device blocks.
+
+  @param[in]       This           Indicates a pointer to the calling context.
+  @param[in]       MediaId        The media ID that the erase request is for.
+  @param[in]       Lba            The starting logical block address to be
+                                  erased. The caller is responsible for erasing
+                                  only legitimate locations.
+  @param[in, out]  Token          A pointer to the token associated with the
+                                  transaction.
+  @param[in]       Size           The size in bytes to be erased. This must be
+                                  a multiple of the physical block size of the
+                                  device.
+
+  @retval EFI_SUCCESS             The erase request was queued if Event is not
+                                  NULL. The data was erased correctly to the
+                                  device if the Event is NULL.to the device.
+  @retval EFI_WRITE_PROTECTED     The device cannot be erased due to write
+                                  protection.
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting
+                                  to perform the erase operation.
+  @retval EFI_INVALID_PARAMETER   The erase request contains LBAs that are not
+                                  valid.
+  @retval EFI_NO_MEDIA            There is no media in the device.
+  @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+SdEraseBlocks (
+  IN     EFI_ERASE_BLOCK_PROTOCOL      *This,
+  IN     UINT32                        MediaId,
+  IN     EFI_LBA                       Lba,
+  IN OUT EFI_ERASE_BLOCK_TOKEN         *Token,
+  IN     UINTN                         Size
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_BLOCK_IO_MEDIA                    *Media;
+  UINTN                                 BlockSize;
+  UINTN                                 BlockNum;
+  EFI_LBA                               LastLba;
+  SD_DEVICE                             *Device;
+
+  Status = EFI_SUCCESS;
+  Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);
+  Media  = &Device->BlockMedia;
+
+  if (MediaId != Media->MediaId) {
+    return EFI_MEDIA_CHANGED;
+  }
+
+  if (Media->ReadOnly) {
+    return EFI_WRITE_PROTECTED;
+  }
+
+  //
+  // Check parameters.
+  //
+  BlockSize = Media->BlockSize;
+  if ((Size % BlockSize) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  BlockNum  = Size / BlockSize;
+  if ((Lba + BlockNum - 1) > Media->LastBlock) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  LastLba = Lba + BlockNum - 1;
+
+  Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, 
FALSE);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  DEBUG ((EFI_D_ERROR, "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with 
%r\n", Lba, BlockNum, Token->Event, Status));
+
+  return Status;
+}
 
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h 
b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h
index 36e20de..227b45b 100644
--- a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h
+++ b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h
@@ -4,7 +4,7 @@
   This file defines common data structures, macro definitions and some module
   internal function header files.
 
-  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
@@ -217,5 +217,42 @@ SdFlushBlocksEx (
   IN OUT EFI_BLOCK_IO2_TOKEN     *Token
   );
 
+/**
+  Erase a specified number of device blocks.
+
+  @param[in]       This           Indicates a pointer to the calling context.
+  @param[in]       MediaId        The media ID that the erase request is for.
+  @param[in]       Lba            The starting logical block address to be
+                                  erased. The caller is responsible for erasing
+                                  only legitimate locations.
+  @param[in, out]  Token          A pointer to the token associated with the
+                                  transaction.
+  @param[in]       Size           The size in bytes to be erased. This must be
+                                  a multiple of the physical block size of the
+                                  device.
+
+  @retval EFI_SUCCESS             The erase request was queued if Event is not
+                                  NULL. The data was erased correctly to the
+                                  device if the Event is NULL.to the device.
+  @retval EFI_WRITE_PROTECTED     The device cannot be erased due to write
+                                  protection.
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting
+                                  to perform the erase operation.
+  @retval EFI_INVALID_PARAMETER   The erase request contains LBAs that are not
+                                  valid.
+  @retval EFI_NO_MEDIA            There is no media in the device.
+  @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+SdEraseBlocks (
+  IN     EFI_ERASE_BLOCK_PROTOCOL      *This,
+  IN     UINT32                        MediaId,
+  IN     EFI_LBA                       Lba,
+  IN OUT EFI_ERASE_BLOCK_TOKEN         *Token,
+  IN     UINTN                         Size
+  );
+
 #endif
 
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c 
b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c
index 7ed80b6..f657fb9 100644
--- a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c
+++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c
@@ -64,6 +64,11 @@ SD_DEVICE mSdDeviceTemplate = {
     0,                         // IoAlign
     0                          // LastBlock
   },
+  {                            // EraseBlock
+    EFI_ERASE_BLOCK_PROTOCOL_REVISION,
+    1,
+    SdEraseBlocks
+  },
   {                            // Queue
     NULL,
     NULL
@@ -247,6 +252,12 @@ DiscoverUserArea (
   Device->BlockMedia.LogicalPartition = FALSE;
   Device->BlockMedia.LastBlock        = DivU64x32 (Capacity, 
Device->BlockMedia.BlockSize) - 1;
 
+  if (Csd->EraseBlkEn) {
+    Device->EraseBlock.EraseLengthGranularity = 1;
+  } else {
+    Device->EraseBlock.EraseLengthGranularity = (Csd->SectorSize + 1) * (1 << 
(Csd->WriteBlLen - 9));
+  }
+
   return Status;
 }
 
@@ -369,6 +380,8 @@ DiscoverSdDevice (
                   &Device->BlockIo,
                   &gEfiBlockIo2ProtocolGuid,
                   &Device->BlockIo2,
+                  &gEfiEraseBlockProtocolGuid,
+                  &Device->EraseBlock,
                   NULL
                   );
 
@@ -825,6 +838,8 @@ SdDxeDriverBindingStop (
                     &Device->BlockIo,
                     &gEfiBlockIo2ProtocolGuid,
                     &Device->BlockIo2,
+                    &gEfiEraseBlockProtocolGuid,
+                    &Device->EraseBlock,
                     NULL
                     );
     if (EFI_ERROR (Status)) {
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h 
b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h
index ca1609e..0ba72b7 100644
--- a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h
+++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h
@@ -4,7 +4,7 @@
   This file defines common data structures, macro definitions and some module
   internal function header files.
 
-  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
@@ -24,6 +24,7 @@
 #include <Protocol/SdMmcPassThru.h>
 #include <Protocol/BlockIo.h>
 #include <Protocol/BlockIo2.h>
+#include <Protocol/EraseBlock.h>
 
 #include <Protocol/DevicePath.h>
 
@@ -53,6 +54,9 @@ extern EFI_COMPONENT_NAME2_PROTOCOL     gSdDxeComponentName2;
 #define SD_DEVICE_DATA_FROM_BLKIO2(a) \
     CR(a, SD_DEVICE, BlockIo2, SD_DEVICE_SIGNATURE)
 
+#define SD_DEVICE_DATA_FROM_ERASEBLK(a) \
+    CR(a, SD_DEVICE, EraseBlock, SD_DEVICE_SIGNATURE)
+
 //
 // Take 2.5 seconds as generic time out value, 1 microsecond as unit.
 //
@@ -95,6 +99,7 @@ struct _SD_DEVICE {
   EFI_BLOCK_IO_PROTOCOL                 BlockIo;
   EFI_BLOCK_IO2_PROTOCOL                BlockIo2;
   EFI_BLOCK_IO_MEDIA                    BlockMedia;
+  EFI_ERASE_BLOCK_PROTOCOL              EraseBlock;
 
   LIST_ENTRY                            Queue;
 
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf 
b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
index b24b721..6f5e6ca 100644
--- a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
+++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
@@ -4,7 +4,7 @@
 #  It produces BlockIo and BlockIo2 protocols to allow upper layer
 #  access the SD memory card device.
 #
-#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
 #
 #  This program and the accompanying materials
 #  are licensed and made available under the terms and conditions of the BSD 
License
@@ -59,6 +59,7 @@
   gEfiSdMmcPassThruProtocolGuid                ## TO_START
   gEfiBlockIoProtocolGuid                      ## BY_START
   gEfiBlockIo2ProtocolGuid                     ## BY_START
+  gEfiEraseBlockProtocolGuid                   ## BY_START
   ## TO_START
   ## BY_START
   gEfiDevicePathProtocolGuid
-- 
2.7.1.windows.2

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

Reply via email to