diff mbox series

[edk2,edk-platforms,v1,3/4] Platform/HiKey960: add fastboot platform driver

Message ID 1534761109-27037-4-git-send-email-haojian.zhuang@linaro.org
State New
Headers show
Series enable USB on HiKey960 | expand

Commit Message

Haojian Zhuang Aug. 20, 2018, 10:31 a.m. UTC
Implement the Android Fastboot protocol in HiKey960 platform.

Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>

---
 Platform/Hisilicon/HiKey960/HiKey960FastbootDxe/HiKey960FastbootDxe.inf |  63 ++
 Platform/Hisilicon/HiKey960/HiKey960FastbootDxe/HiKey960FastbootDxe.c   | 758 ++++++++++++++++++++
 2 files changed, 821 insertions(+)

-- 
2.7.4

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
diff mbox series

Patch

diff --git a/Platform/Hisilicon/HiKey960/HiKey960FastbootDxe/HiKey960FastbootDxe.inf b/Platform/Hisilicon/HiKey960/HiKey960FastbootDxe/HiKey960FastbootDxe.inf
new file mode 100644
index 000000000000..1771d41828d4
--- /dev/null
+++ b/Platform/Hisilicon/HiKey960/HiKey960FastbootDxe/HiKey960FastbootDxe.inf
@@ -0,0 +1,63 @@ 
+#/** @file
+#
+#  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+#  Copyright (c) 2018, Linaro. All rights reserved.
+#
+#  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
+#  http://opensource.org/licenses/bsd-license.php
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x00010019
+  BASE_NAME                      = HiKey960FastbootDxe
+  FILE_GUID                      = 80f046c6-d5ba-4916-a656-2e2b28d32304
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = HiKey960FastbootPlatformEntryPoint
+
+[Sources.common]
+  HiKey960FastbootDxe.c
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  CacheMaintenanceLib
+  DebugLib
+  DevicePathLib
+  IoLib
+  MemoryAllocationLib
+  PcdLib
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+  UefiDriverEntryPoint
+  UsbSerialNumberLib
+  TimerLib
+
+[Protocols]
+  gAndroidFastbootPlatformProtocolGuid
+  gEfiBlockIoProtocolGuid
+  gEfiDevicePathToTextProtocolGuid
+  gEfiDiskIoProtocolGuid
+  gEfiEraseBlockProtocolGuid
+  gEfiSimpleTextOutProtocolGuid
+
+[Packages]
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  ArmPkg/ArmPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  Platform/Hisilicon/HiKey960/HiKey960.dec
+  Platform/Hisilicon/Library/UsbSerialNumberLib/UsbSerialNumberLib.dec
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVendor
+  gHiKey960TokenSpaceGuid.PcdAndroidFastbootNvmDevicePath
+  gHiKey960TokenSpaceGuid.PcdArmFastbootFlashLimit
+  gHiKey960TokenSpaceGuid.PcdXloaderDevicePath
diff --git a/Platform/Hisilicon/HiKey960/HiKey960FastbootDxe/HiKey960FastbootDxe.c b/Platform/Hisilicon/HiKey960/HiKey960FastbootDxe/HiKey960FastbootDxe.c
new file mode 100644
index 000000000000..5e99a9f93ca4
--- /dev/null
+++ b/Platform/Hisilicon/HiKey960/HiKey960FastbootDxe/HiKey960FastbootDxe.c
@@ -0,0 +1,758 @@ 
+/** @file
+
+  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2018, Linaro. All rights reserved.
+
+  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
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+/*
+  Implementation of the Android Fastboot Platform protocol, to be used by the
+  Fastboot UEFI application, for Hisilicon HiKey960 platform.
+*/
+
+#include <Protocol/AndroidFastbootPlatform.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/EraseBlock.h>
+#include <Protocol/SimpleTextOut.h>
+
+#include <Protocol/DevicePathToText.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UsbSerialNumberLib.h>
+#include <Library/PrintLib.h>
+#include <Library/TimerLib.h>
+
+#define PARTITION_NAME_MAX_LENGTH        (72/2)
+
+#define SERIAL_NUMBER_LBA                20
+
+#define RANDOM_MAX                       0x7FFFFFFFFFFFFFFF
+#define RANDOM_MAGIC                     0x9A4DBEAF
+
+#define ADB_REBOOT_ADDRESS               0x32100000
+#define ADB_REBOOT_BOOTLOADER            0x77665500
+
+#define UFS_BLOCK_SIZE                   4096
+
+typedef struct _FASTBOOT_PARTITION_LIST {
+  LIST_ENTRY  Link;
+  CHAR16      PartitionName[PARTITION_NAME_MAX_LENGTH];
+  EFI_LBA     StartingLBA;
+  EFI_LBA     EndingLBA;
+} FASTBOOT_PARTITION_LIST;
+
+STATIC LIST_ENTRY                       mPartitionListHead;
+STATIC EFI_HANDLE                       mFlashHandle;
+STATIC EFI_BLOCK_IO_PROTOCOL           *mFlashBlockIo;
+STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut;
+
+/*
+  Helper to free the partition list
+*/
+STATIC
+VOID
+FreePartitionList (
+  VOID
+  )
+{
+  FASTBOOT_PARTITION_LIST *Entry;
+  FASTBOOT_PARTITION_LIST *NextEntry;
+
+  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead);
+  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
+    NextEntry = (FASTBOOT_PARTITION_LIST *) GetNextNode (
+                                              &mPartitionListHead,
+                                              &Entry->Link
+                                              );
+    RemoveEntryList (&Entry->Link);
+    FreePool (Entry);
+
+    Entry = NextEntry;
+  }
+}
+
+/*
+  Read the PartitionName fields from the GPT partition entries, putting them
+  into an allocated array that should later be freed.
+*/
+STATIC
+EFI_STATUS
+ReadPartitionEntries (
+  IN  EFI_BLOCK_IO_PROTOCOL *BlockIo,
+  OUT EFI_PARTITION_ENTRY  **PartitionEntries,
+  OUT UINTN                 *PartitionNumbers
+  )
+{
+  UINT32                      MediaId;
+  EFI_PARTITION_TABLE_HEADER *GptHeader;
+  EFI_PARTITION_ENTRY        *Entry;
+  EFI_STATUS                  Status;
+  VOID                       *Buffer;
+  UINTN                       PageCount;
+  UINTN                       BlockSize;
+  UINTN                       Count, EndLBA;
+
+  if ((PartitionEntries == NULL) || (PartitionNumbers == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+  MediaId = BlockIo->Media->MediaId;
+  BlockSize = BlockIo->Media->BlockSize;
+
+  //
+  // Read size of Partition entry and number of entries from GPT header
+  //
+
+  PageCount = EFI_SIZE_TO_PAGES (6 * BlockSize);
+  Buffer = AllocatePages (PageCount);
+  if (Buffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = BlockIo->ReadBlocks (
+                      BlockIo,
+                      MediaId,
+                      0,
+                      PageCount * EFI_PAGE_SIZE,
+                      Buffer
+                      );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  GptHeader = (EFI_PARTITION_TABLE_HEADER *)(Buffer + BlockSize);
+
+  //
+  // Check there is a GPT on the media
+  //
+  if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID ||
+      GptHeader->MyLBA != 1) {
+    DEBUG ((DEBUG_ERROR,
+      "Fastboot platform: No GPT on flash. "
+      "Fastboot on Versatile Express does not support MBR.\n"
+      ));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Entry = (EFI_PARTITION_ENTRY *)(Buffer + (2 * BlockSize));
+  EndLBA = GptHeader->FirstUsableLBA - 1;
+  Count = 0;
+  while (1) {
+    if ((Entry->StartingLBA > EndLBA) &&
+        (Entry->EndingLBA <= GptHeader->LastUsableLBA)) {
+      Count++;
+      EndLBA = Entry->EndingLBA;
+      Entry++;
+    } else {
+      break;
+    }
+  }
+  if (Count == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+  if (Count > GptHeader->NumberOfPartitionEntries) {
+    Count = GptHeader->NumberOfPartitionEntries;
+  }
+
+  *PartitionEntries = (EFI_PARTITION_ENTRY *)((UINTN)Buffer + (2 * BlockSize));
+  *PartitionNumbers = Count;
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LoadPtable (
+  VOID
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePathDup;
+  UINTN                               PartitionNumbers = 0;
+  UINTN                               LoopIndex;
+  EFI_PARTITION_ENTRY                *PartitionEntries = NULL;
+  FASTBOOT_PARTITION_LIST            *Entry;
+
+  InitializeListHead (&mPartitionListHead);
+
+  Status = gBS->LocateProtocol (
+                  &gEfiSimpleTextOutProtocolGuid,
+                  NULL,
+                  (VOID **) &mTextOut
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "Fastboot platform: Couldn't open Text Output Protocol: %r\n", Status
+      ));
+    return Status;
+  }
+
+  //
+  // Get EFI_HANDLES for all the partitions on the block devices pointed to by
+  // PcdFastbootFlashDevicePath, also saving their GPT partition labels.
+  // There's no way to find all of a device's children, so we get every handle
+  // in the system supporting EFI_BLOCK_IO_PROTOCOL and then filter out ones
+  // that don't represent partitions on the flash device.
+  //
+  FlashDevicePath = ConvertTextToDevicePath (
+                      (CHAR16*)FixedPcdGetPtr (PcdAndroidFastbootNvmDevicePath)
+                      );
+
+  //
+  // Create another device path pointer because LocateDevicePath will modify it.
+  //
+  FlashDevicePathDup = FlashDevicePath;
+  Status = gBS->LocateDevicePath (
+                  &gEfiBlockIoProtocolGuid,
+                  &FlashDevicePathDup,
+                  &mFlashHandle
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Warning: Couldn't locate Android NVM device (status: %r)\n",
+      Status
+      ));
+    //
+    // Failing to locate partitions should not prevent to do other Android
+    // FastBoot actions.
+    //
+    return EFI_SUCCESS;
+  }
+
+
+  Status = gBS->OpenProtocol (
+                  mFlashHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &mFlashBlockIo,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Fastboot platform: Couldn't open Android NVM device (status: %r)\n",
+      Status
+      ));
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Read the GPT partition entry array into memory so we can get the
+  // partition names.
+  //
+  Status = ReadPartitionEntries (
+             mFlashBlockIo,
+             &PartitionEntries,
+             &PartitionNumbers
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Warning: Failed to read partitions from Android NVM device (status: %r)\n",
+      Status
+      ));
+    //
+    // Failing to locate partitions should not prevent to do other Android
+    // FastBoot actions.
+    //
+    return EFI_SUCCESS;
+  }
+  for (LoopIndex = 0; LoopIndex < PartitionNumbers; LoopIndex++) {
+    //
+    // Create entry
+    //
+    Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
+    if (Entry == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      FreePartitionList ();
+      goto Exit;
+    }
+    StrnCpy (
+      Entry->PartitionName,
+      PartitionEntries[LoopIndex].PartitionName,
+      PARTITION_NAME_MAX_LENGTH
+      );
+    Entry->StartingLBA = PartitionEntries[LoopIndex].StartingLBA;
+    Entry->EndingLBA = PartitionEntries[LoopIndex].EndingLBA;
+    InsertTailList (&mPartitionListHead, &Entry->Link);
+  }
+Exit:
+  FreePages (
+    (VOID *)((UINTN)PartitionEntries - (2 * mFlashBlockIo->Media->BlockSize)),
+    EFI_SIZE_TO_PAGES (6 * mFlashBlockIo->Media->BlockSize)
+    );
+  return Status;
+}
+
+/*
+  Initialise: Open the Android NVM device and find the partitions on it. Save
+  them in a list along with the "PartitionName" fields for their GPT entries.
+  We will use these partition names as the key in
+  HiKey960FastbootPlatformFlashPartition.
+*/
+EFI_STATUS
+HiKey960FastbootPlatformInit (
+  VOID
+  )
+{
+  EFI_STATUS               Status;
+
+  Status = LoadPtable ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  return Status;
+}
+
+VOID
+HiKey960FastbootPlatformUnInit (
+  VOID
+  )
+{
+  FreePartitionList ();
+}
+
+EFI_STATUS
+HiKey960FlashPtable (
+  IN UINTN   Size,
+  IN VOID   *Image
+  )
+{
+  EFI_STATUS               Status;
+  Status = mFlashBlockIo->WriteBlocks (
+                            mFlashBlockIo,
+                            mFlashBlockIo->Media->MediaId,
+                            0,
+                            Size,
+                            Image
+                            );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to write (status:%r)\n", Status));
+    return Status;
+  }
+  FreePartitionList ();
+  Status = LoadPtable ();
+  return Status;
+}
+
+EFI_STATUS
+HiKey960ErasePtable (
+  VOID
+  )
+{
+  EFI_STATUS                  Status;
+
+  {
+    VOID         *DataPtr;
+    UINTN         Lba;
+
+    DataPtr = AllocatePages (1);
+    ZeroMem (DataPtr, EFI_PAGE_SIZE);
+    for (Lba = 0; Lba < 6; Lba++) {
+      Status = mFlashBlockIo->WriteBlocks (
+                          mFlashBlockIo,
+                          mFlashBlockIo->Media->MediaId,
+                          Lba,
+                          EFI_PAGE_SIZE,
+                          DataPtr
+                          );
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+    }
+Exit:
+    FreePages (DataPtr, 1);
+  }
+  FreePartitionList ();
+  return Status;
+}
+
+EFI_STATUS
+HiKey960FlashXloader (
+  IN UINTN   Size,
+  IN VOID   *Image
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_DEVICE_PATH_PROTOCOL         *DevicePath;
+  EFI_HANDLE                        Handle;
+  EFI_BLOCK_IO_PROTOCOL            *BlockIo;
+  EFI_DISK_IO_PROTOCOL             *DiskIo;
+
+  DevicePath = ConvertTextToDevicePath (
+                 (CHAR16*)FixedPcdGetPtr (PcdXloaderDevicePath)
+                 );
+
+  Status = gBS->LocateDevicePath (
+                  &gEfiBlockIoProtocolGuid,
+                  &DevicePath,
+                  &Handle
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Warning: Couldn't locate xloader device (status: %r)\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Status = gBS->OpenProtocol (
+                  Handle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Fastboot platform: Couldn't open xloader device (status: %r)\n",
+      Status
+      ));
+    return EFI_DEVICE_ERROR;
+  }
+  Status = gBS->OpenProtocol (
+                  Handle,
+                  &gEfiDiskIoProtocolGuid,
+                  (VOID **) &DiskIo,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = DiskIo->WriteDisk (
+                     DiskIo,
+                     BlockIo->Media->MediaId,
+                     0,
+                     Size,
+                     Image
+                     );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to write (status:%r)\n", Status));
+    return Status;
+  }
+  return Status;
+}
+
+EFI_STATUS
+HiKey960FastbootPlatformFlashPartition (
+  IN CHAR8  *PartitionName,
+  IN UINTN   Size,
+  IN VOID   *Image
+  )
+{
+  EFI_STATUS               Status;
+  UINTN                    PartitionSize;
+  FASTBOOT_PARTITION_LIST *Entry;
+  CHAR16                   PartitionNameUnicode[60];
+  BOOLEAN                  PartitionFound;
+  EFI_DISK_IO_PROTOCOL    *DiskIo;
+  UINTN                    BlockSize;
+
+  //
+  // Support the pseudo partition name, such as "ptable".
+  //
+  if (AsciiStrCmp (PartitionName, "ptable") == 0) {
+    return HiKey960FlashPtable (Size, Image);
+  } else if (AsciiStrCmp (PartitionName, "xloader") == 0) {
+    return HiKey960FlashXloader (Size, Image);
+  }
+
+  AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
+  PartitionFound = FALSE;
+  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
+  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
+    //
+    // Search the partition list for the partition named by PartitionName
+    //
+    if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
+      PartitionFound = TRUE;
+      break;
+    }
+
+   Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (
+                                         &mPartitionListHead,
+                                         &(Entry)->Link
+                                         );
+  }
+  if (!PartitionFound) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Check image will fit on device
+  //
+  BlockSize = mFlashBlockIo->Media->BlockSize;
+  PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) * BlockSize;
+  if (PartitionSize < Size) {
+    DEBUG ((DEBUG_ERROR, "Partition not big enough.\n"));
+    DEBUG ((
+      DEBUG_ERROR,
+      "Partition Size:\t%ld\nImage Size:\t%ld\n",
+      PartitionSize,
+      Size
+      ));
+    return EFI_VOLUME_FULL;
+  }
+
+  Status = gBS->OpenProtocol (
+                  mFlashHandle,
+                  &gEfiDiskIoProtocolGuid,
+                  (VOID **) &DiskIo,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = DiskIo->WriteDisk (
+                     DiskIo,
+                     mFlashBlockIo->Media->MediaId,
+                     Entry->StartingLBA * BlockSize,
+                     Size,
+                     Image
+                     );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Failed to write %d bytes into 0x%x, Status:%r\n",
+      Size,
+      Entry->StartingLBA * BlockSize,
+      Status
+      ));
+    return Status;
+  }
+
+  mFlashBlockIo->FlushBlocks(mFlashBlockIo);
+  MicroSecondDelay (50000);
+
+  return Status;
+}
+
+EFI_STATUS
+HiKey960FastbootPlatformErasePartition (
+  IN CHAR8 *PartitionName
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_ERASE_BLOCK_PROTOCOL   *EraseBlockProtocol;
+  UINTN                       Size;
+  BOOLEAN                     PartitionFound;
+  CHAR16                      PartitionNameUnicode[60];
+  FASTBOOT_PARTITION_LIST    *Entry;
+
+  AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
+
+  //
+  // Support the pseudo partition name, such as "ptable".
+  //
+  if (AsciiStrCmp (PartitionName, "ptable") == 0) {
+    return HiKey960ErasePtable ();
+  }
+
+  PartitionFound = FALSE;
+  Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead);
+  while (!IsNull (&mPartitionListHead, &Entry->Link)) {
+    //
+    // Search the partition list for the partition named by PartitionName
+    //
+    if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
+      PartitionFound = TRUE;
+      break;
+    }
+    Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link);
+  }
+  if (!PartitionFound) {
+    return EFI_NOT_FOUND;
+  }
+
+  Status = gBS->OpenProtocol (
+                  mFlashHandle,
+                  &gEfiEraseBlockProtocolGuid,
+                  (VOID **) &EraseBlockProtocol,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Size = (Entry->EndingLBA - Entry->StartingLBA + 1) * mFlashBlockIo->Media->BlockSize;
+  Status = EraseBlockProtocol->EraseBlocks (
+                                 EraseBlockProtocol,
+                                 mFlashBlockIo->Media->MediaId,
+                                 Entry->StartingLBA,
+                                 NULL,
+                                 Size
+                                 );
+  return Status;
+}
+
+EFI_STATUS
+HiKey960FastbootPlatformGetVar (
+  IN  CHAR8   *Name,
+  OUT CHAR8   *Value
+  )
+{
+  EFI_STATUS               Status = EFI_SUCCESS;
+  UINT64                   PartitionSize;
+  FASTBOOT_PARTITION_LIST *Entry;
+  CHAR16                   PartitionNameUnicode[60];
+  BOOLEAN                  PartitionFound;
+  CHAR16                   UnicodeSN[SERIAL_NUMBER_SIZE];
+
+  if (!AsciiStrCmp (Name, "max-download-size")) {
+    AsciiStrCpy (Value, FixedPcdGetPtr (PcdArmFastbootFlashLimit));
+  } else if (!AsciiStrCmp (Name, "product")) {
+    AsciiStrCpy (Value, FixedPcdGetPtr (PcdFirmwareVendor));
+  } else if (!AsciiStrCmp (Name, "serialno")) {
+    Status = LoadSNFromBlock (mFlashHandle, SERIAL_NUMBER_LBA, UnicodeSN);
+    UnicodeStrToAsciiStr (UnicodeSN, Value);
+  } else if ( !AsciiStrnCmp (Name, "partition-size", 14)) {
+    AsciiStrToUnicodeStr ((Name + 15), PartitionNameUnicode);
+    PartitionFound = FALSE;
+    Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
+    while (!IsNull (&mPartitionListHead, &Entry->Link)) {
+      //
+      // Search the partition list for the partition named by PartitionName
+      //
+      if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
+        PartitionFound = TRUE;
+        break;
+      }
+
+     Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (
+                                           &mPartitionListHead,
+                                           &(Entry)->Link
+                                           );
+    }
+    if (!PartitionFound) {
+      *Value = '\0';
+      return EFI_NOT_FOUND;
+    }
+
+    PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) *
+                    mFlashBlockIo->Media->BlockSize;
+    DEBUG ((
+      DEBUG_ERROR,
+      "Fastboot platform: check for partition-size:%a 0X%llx\n",
+      Name,
+      PartitionSize
+      ));
+    AsciiSPrint (Value, 12, "0x%llx", PartitionSize);
+  } else if ( !AsciiStrnCmp (Name, "partition-type", 14)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "Fastboot platform: check for partition-type:%a\n",
+        (Name + 15)
+        ));
+    if ( !AsciiStrnCmp  ( (Name + 15) , "system", 6) ||        \
+         !AsciiStrnCmp  ( (Name + 15) , "userdata", 8) ||      \
+         !AsciiStrnCmp  ( (Name + 15) , "cache", 5)) {
+      AsciiStrCpy (Value, "ext4");
+    } else {
+      AsciiStrCpy (Value, "raw");
+    }
+  } else if ( !AsciiStrCmp (Name, "erase-block-size")) {
+    AsciiSPrint (Value, 12, "0x%llx", UFS_BLOCK_SIZE);
+  } else if ( !AsciiStrCmp (Name, "logical-block-size")) {
+    AsciiSPrint (Value, 12, "0x%llx", UFS_BLOCK_SIZE);
+  } else {
+    *Value = '\0';
+  }
+  return Status;
+}
+
+EFI_STATUS
+HiKey960FastbootPlatformOemCommand (
+  IN  CHAR8   *Command
+  )
+{
+  EFI_STATUS   Status;
+  CHAR16       UnicodeSN[SERIAL_NUMBER_SIZE];
+  UINTN        Size;
+
+  Size = AsciiStrLen ("serialno");
+  if (AsciiStrCmp (Command, "Demonstrate") == 0) {
+    DEBUG ((DEBUG_ERROR, "ARM OEM Fastboot command 'Demonstrate' received.\n"));
+    return EFI_SUCCESS;
+  } else if (AsciiStrnCmp (Command, "serialno", Size) == 0) {
+    while (*(Command + Size) == ' ') {
+      Size++;
+    }
+    if (AsciiStrnCmp (Command + Size, "set", AsciiStrLen ("set")) == 0) {
+      Size += AsciiStrLen ("set");
+      while (*(Command + Size) == ' ') {
+        Size++;
+      }
+      Status = AssignUsbSN (Command + Size, UnicodeSN);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "Failed to set USB Serial Number.\n"));
+        return Status;
+      }
+    } else {
+      Status = GenerateUsbSN (UnicodeSN);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "Failed to generate USB Serial Number.\n"));
+        return Status;
+      }
+    }
+    Status = StoreSNToBlock (mFlashHandle, SERIAL_NUMBER_LBA, UnicodeSN);
+    return Status;
+  } else if (AsciiStrCmp (Command, "reboot-bootloader") == 0) {
+    MmioWrite32 (ADB_REBOOT_ADDRESS, ADB_REBOOT_BOOTLOADER);
+    WriteBackInvalidateDataCacheRange ((VOID *)ADB_REBOOT_ADDRESS, 4);
+    return EFI_SUCCESS;
+  } else {
+    DEBUG ((DEBUG_ERROR,
+      "HiKey960: Unrecognised Fastboot OEM command: %a\n",
+      Command
+      ));
+    return EFI_NOT_FOUND;
+  }
+}
+
+FASTBOOT_PLATFORM_PROTOCOL mPlatformProtocol = {
+  HiKey960FastbootPlatformInit,
+  HiKey960FastbootPlatformUnInit,
+  HiKey960FastbootPlatformFlashPartition,
+  HiKey960FastbootPlatformErasePartition,
+  HiKey960FastbootPlatformGetVar,
+  HiKey960FastbootPlatformOemCommand,
+};
+
+EFI_STATUS
+EFIAPI
+HiKey960FastbootPlatformEntryPoint (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+  )
+{
+  return gBS->InstallProtocolInterface (
+                &ImageHandle,
+                &gAndroidFastbootPlatformProtocolGuid,
+                EFI_NATIVE_INTERFACE,
+                &mPlatformProtocol
+                );
+}