public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Pete Batard <pete@akeo.ie>
To: edk2-devel@lists.01.org
Subject: [PATCH v3 edk2-platforms 07/23] Platform/Raspberry/Pi3: Add firmware driver
Date: Mon, 28 Jan 2019 12:44:29 +0000	[thread overview]
Message-ID: <20190128124445.9868-8-pete@akeo.ie> (raw)
In-Reply-To: <20190128124445.9868-1-pete@akeo.ie>

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Pete Batard <pete@akeo.ie>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 Platform/Raspberry/Pi3/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c   | 1084 ++++++++++++++++++++
 Platform/Raspberry/Pi3/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.inf |   49 +
 Platform/Raspberry/Pi3/Include/Protocol/RpiFirmware.h            |  131 +++
 3 files changed, 1264 insertions(+)

diff --git a/Platform/Raspberry/Pi3/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c b/Platform/Raspberry/Pi3/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c
new file mode 100644
index 000000000000..d330e45fdc4c
--- /dev/null
+++ b/Platform/Raspberry/Pi3/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c
@@ -0,0 +1,1084 @@
+/** @file
+ *
+ *  Copyright (c) 2017-2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *  Copyright (c) 2016, Linaro, Ltd. 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.
+ *
+ **/
+
+#include <PiDxe.h>
+
+#include <Library/ArmLib.h>
+#include <Library/DmaLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <IndustryStandard/Bcm2836.h>
+#include <IndustryStandard/RpiMbox.h>
+
+#include <Protocol/RpiFirmware.h>
+
+//
+// The number of statically allocated buffer pages
+//
+#define NUM_PAGES   1
+
+//
+// The number of iterations to perform when waiting for the mailbox
+// status to change
+//
+#define MAX_TRIES   0x100000
+
+STATIC VOID  *mDmaBuffer;
+STATIC VOID  *mDmaBufferMapping;
+STATIC UINTN mDmaBufferBusAddress;
+
+STATIC SPIN_LOCK mMailboxLock;
+
+STATIC
+BOOLEAN
+DrainMailbox (
+  VOID
+  )
+{
+  INTN    Tries;
+  UINT32  Val;
+
+  //
+  // Get rid of stale response data in the mailbox
+  //
+  Tries = 0;
+  do {
+    Val = MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_STATUS_OFFSET);
+    if (Val & (1U << BCM2836_MBOX_STATUS_EMPTY)) {
+      return TRUE;
+    }
+    ArmDataSynchronizationBarrier ();
+    MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_READ_OFFSET);
+  } while (++Tries < MAX_TRIES);
+
+  return FALSE;
+}
+
+STATIC
+BOOLEAN
+MailboxWaitForStatusCleared (
+  IN  UINTN   StatusMask
+  )
+{
+  INTN    Tries;
+  UINT32  Val;
+
+  //
+  // Get rid of stale response data in the mailbox
+  //
+  Tries = 0;
+  do {
+    Val = MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_STATUS_OFFSET);
+    if ((Val & StatusMask) == 0) {
+      return TRUE;
+    }
+    ArmDataSynchronizationBarrier ();
+  } while (++Tries < MAX_TRIES);
+
+  return FALSE;
+}
+
+STATIC
+EFI_STATUS
+MailboxTransaction (
+  IN    UINTN   Length,
+  IN    UINTN   Channel,
+  OUT   UINT32  *Result
+  )
+{
+  if (Channel >= BCM2836_MBOX_NUM_CHANNELS) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Get rid of stale response data in the mailbox
+  //
+  if (!DrainMailbox ()) {
+    DEBUG ((DEBUG_ERROR, "%a: timeout waiting for mailbox to drain\n",
+      __FUNCTION__));
+    return EFI_TIMEOUT;
+  }
+
+  //
+  // Wait for the 'output register full' bit to become clear
+  //
+  if (!MailboxWaitForStatusCleared (1U << BCM2836_MBOX_STATUS_FULL)) {
+    DEBUG ((DEBUG_ERROR, "%a: timeout waiting for outbox to become empty\n",
+      __FUNCTION__));
+    return EFI_TIMEOUT;
+  }
+
+  ArmDataSynchronizationBarrier ();
+
+  //
+  // Start the mailbox transaction
+  //
+  MmioWrite32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_WRITE_OFFSET,
+    (UINT32)((UINTN)mDmaBufferBusAddress | Channel));
+
+  ArmDataSynchronizationBarrier ();
+
+  //
+  // Wait for the 'input register empty' bit to clear
+  //
+  if (!MailboxWaitForStatusCleared (1U << BCM2836_MBOX_STATUS_EMPTY)) {
+    DEBUG ((DEBUG_ERROR, "%a: timeout waiting for inbox to become full\n",
+      __FUNCTION__));
+    return EFI_TIMEOUT;
+  }
+
+  //
+  // Read back the result
+  //
+  ArmDataSynchronizationBarrier ();
+  *Result = MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_READ_OFFSET);
+  ArmDataSynchronizationBarrier ();
+
+  return EFI_SUCCESS;
+}
+
+#pragma pack(1)
+typedef struct {
+  UINT32    BufferSize;
+  UINT32    Response;
+} RPI_FW_BUFFER_HEAD;
+
+typedef struct {
+  UINT32    TagId;
+  UINT32    TagSize;
+  UINT32    TagValueSize;
+} RPI_FW_TAG_HEAD;
+
+typedef struct {
+  UINT32                    DeviceId;
+  UINT32                    PowerState;
+} RPI_FW_POWER_STATE_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  RPI_FW_POWER_STATE_TAG    TagBody;
+  UINT32                    EndTag;
+} RPI_FW_SET_POWER_STATE_CMD;
+#pragma pack()
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareSetPowerState (
+  IN  UINT32    DeviceId,
+  IN  BOOLEAN   PowerState,
+  IN  BOOLEAN   Wait
+  )
+{
+  RPI_FW_SET_POWER_STATE_CMD  *Cmd;
+  EFI_STATUS                  Status;
+  UINT32                      Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_SET_POWER_STATE;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->TagBody.DeviceId       = DeviceId;
+  Cmd->TagBody.PowerState     = (PowerState ? RPI_MBOX_POWER_STATE_ENABLE : 0) |
+                                (Wait ? RPI_MBOX_POWER_STATE_WAIT : 0);
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if (!EFI_ERROR (Status) &&
+      PowerState ^ (Cmd->TagBody.PowerState & RPI_MBOX_POWER_STATE_ENABLE)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to %sable power for device %d\n",
+      __FUNCTION__, PowerState ? "en" : "dis", DeviceId));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  return Status;
+}
+
+#pragma pack()
+typedef struct {
+  UINT32                    Base;
+  UINT32                    Size;
+} RPI_FW_ARM_MEMORY_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  RPI_FW_ARM_MEMORY_TAG     TagBody;
+  UINT32                    EndTag;
+} RPI_FW_GET_ARM_MEMORY_CMD;
+#pragma pack()
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetArmMemory (
+  OUT   UINT32 *Base,
+  OUT   UINT32 *Size
+  )
+{
+  RPI_FW_GET_ARM_MEMORY_CMD   *Cmd;
+  EFI_STATUS                  Status;
+  UINT32                      Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_GET_ARM_MEMSIZE;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  *Base = Cmd->TagBody.Base;
+  *Size = Cmd->TagBody.Size;
+  return EFI_SUCCESS;
+}
+
+#pragma pack()
+typedef struct {
+  UINT8                     MacAddress[6];
+  UINT32                    Padding;
+} RPI_FW_MAC_ADDR_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  RPI_FW_MAC_ADDR_TAG       TagBody;
+  UINT32                    EndTag;
+} RPI_FW_GET_MAC_ADDR_CMD;
+#pragma pack()
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetMacAddress (
+  OUT   UINT8   MacAddress[6]
+  )
+{
+  RPI_FW_GET_MAC_ADDR_CMD     *Cmd;
+  EFI_STATUS                  Status;
+  UINT32                      Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_GET_MAC_ADDRESS;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  CopyMem (MacAddress, Cmd->TagBody.MacAddress, sizeof (Cmd->TagBody.MacAddress));
+  return EFI_SUCCESS;
+}
+
+#pragma pack()
+typedef struct {
+  UINT64                    Serial;
+} RPI_FW_SERIAL_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  RPI_FW_SERIAL_TAG         TagBody;
+  UINT32                    EndTag;
+} RPI_FW_GET_SERIAL_CMD;
+#pragma pack()
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetSerial (
+  OUT   UINT64 *Serial
+  )
+{
+  RPI_FW_GET_SERIAL_CMD       *Cmd;
+  EFI_STATUS                  Status;
+  UINT32                      Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_GET_BOARD_SERIAL;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  *Serial = Cmd->TagBody.Serial;
+  return EFI_SUCCESS;
+}
+
+#pragma pack()
+typedef struct {
+  UINT32                    Model;
+} RPI_FW_MODEL_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  RPI_FW_MODEL_TAG          TagBody;
+  UINT32                    EndTag;
+} RPI_FW_GET_MODEL_CMD;
+#pragma pack()
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetModel (
+  OUT   UINT32 *Model
+  )
+{
+  RPI_FW_GET_MODEL_CMD       *Cmd;
+  EFI_STATUS                  Status;
+  UINT32                      Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_GET_BOARD_MODEL;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  *Model = Cmd->TagBody.Model;
+  return EFI_SUCCESS;
+}
+
+#pragma pack()
+typedef struct {
+  UINT32                    Revision;
+} RPI_FW_MODEL_REVISION_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  RPI_FW_MODEL_REVISION_TAG TagBody;
+  UINT32                    EndTag;
+} RPI_FW_GET_MODEL_REVISION_CMD;
+#pragma pack()
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetModelRevision (
+  OUT   UINT32 *Revision
+  )
+{
+  RPI_FW_GET_MODEL_REVISION_CMD *Cmd;
+  EFI_STATUS                    Status;
+  UINT32                        Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_GET_BOARD_REVISION;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  *Revision = Cmd->TagBody.Revision;
+  return EFI_SUCCESS;
+}
+
+#pragma pack()
+typedef struct {
+  UINT32 Width;
+  UINT32 Height;
+} RPI_FW_FB_SIZE_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  RPI_FW_FB_SIZE_TAG        TagBody;
+  UINT32                    EndTag;
+} RPI_FW_GET_FB_SIZE_CMD;
+
+typedef struct {
+  UINT32 Depth;
+} RPI_FW_FB_DEPTH_TAG;
+
+typedef struct {
+  UINT32 Pitch;
+} RPI_FW_FB_PITCH_TAG;
+
+typedef struct {
+  UINT32 AlignmentBase;
+  UINT32 Size;
+} RPI_FW_FB_ALLOC_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           FreeFbTag;
+  UINT32                    EndTag;
+} RPI_FW_FREE_FB_CMD;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           PhysSizeTag;
+  RPI_FW_FB_SIZE_TAG        PhysSize;
+  RPI_FW_TAG_HEAD           VirtSizeTag;
+  RPI_FW_FB_SIZE_TAG        VirtSize;
+  RPI_FW_TAG_HEAD           DepthTag;
+  RPI_FW_FB_DEPTH_TAG       Depth;
+  RPI_FW_TAG_HEAD           AllocFbTag;
+  RPI_FW_FB_ALLOC_TAG       AllocFb;
+  RPI_FW_TAG_HEAD           PitchTag;
+  RPI_FW_FB_PITCH_TAG       Pitch;
+  UINT32                    EndTag;
+} RPI_FW_INIT_FB_CMD;
+#pragma pack()
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetFbSize (
+  OUT   UINT32 *Width,
+  OUT   UINT32 *Height
+  )
+{
+  RPI_FW_GET_FB_SIZE_CMD     *Cmd;
+  EFI_STATUS                  Status;
+  UINT32                      Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_GET_FB_GEOMETRY;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox  transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  *Width = Cmd->TagBody.Width;
+  *Height = Cmd->TagBody.Height;
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareFreeFb (VOID)
+{
+  RPI_FW_FREE_FB_CMD *Cmd;
+  EFI_STATUS         Status;
+  UINT32             Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize   = sizeof (*Cmd);
+  Cmd->BufferHead.Response     = 0;
+
+  Cmd->FreeFbTag.TagId         = RPI_MBOX_FREE_FB;
+  Cmd->FreeFbTag.TagSize       = 0;
+  Cmd->FreeFbTag.TagValueSize  = 0;
+  Cmd->EndTag                  = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareAllocFb (
+  IN  UINT32 Width,
+  IN  UINT32 Height,
+  IN  UINT32 Depth,
+  OUT EFI_PHYSICAL_ADDRESS *FbBase,
+  OUT UINTN *FbSize,
+  OUT UINTN *Pitch
+  )
+{
+  RPI_FW_INIT_FB_CMD *Cmd;
+  EFI_STATUS         Status;
+  UINT32             Result;
+
+  ASSERT (FbSize != NULL);
+  ASSERT (FbBase != NULL);
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+
+  Cmd->PhysSizeTag.TagId      = RPI_MBOX_SET_FB_PGEOM;
+  Cmd->PhysSizeTag.TagSize    = sizeof (Cmd->PhysSize);
+  Cmd->PhysSize.Width         = Width;
+  Cmd->PhysSize.Height        = Height;
+  Cmd->VirtSizeTag.TagId      = RPI_MBOX_SET_FB_VGEOM;
+  Cmd->VirtSizeTag.TagSize    = sizeof (Cmd->VirtSize);
+  Cmd->VirtSize.Width         = Width;
+  Cmd->VirtSize.Height        = Height;
+  Cmd->DepthTag.TagId         = RPI_MBOX_SET_FB_DEPTH;
+  Cmd->DepthTag.TagSize       = sizeof (Cmd->Depth);
+  Cmd->Depth.Depth            = Depth;
+  Cmd->AllocFbTag.TagId       = RPI_MBOX_ALLOC_FB;
+  Cmd->AllocFbTag.TagSize     = sizeof (Cmd->AllocFb);
+  Cmd->AllocFb.AlignmentBase  = 32;
+  Cmd->PitchTag.TagId         = RPI_MBOX_GET_FB_LINELENGTH;
+  Cmd->PitchTag.TagSize       = sizeof (Cmd->Pitch);
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  *Pitch = Cmd->Pitch.Pitch;
+  *FbBase = Cmd->AllocFb.AlignmentBase - BCM2836_DMA_DEVICE_OFFSET;
+  *FbSize = Cmd->AllocFb.Size;
+  return EFI_SUCCESS;
+}
+
+#pragma pack()
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  UINT8                     CommandLine[0];
+} RPI_FW_GET_COMMAND_LINE_CMD;
+#pragma pack()
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetCommmandLine (
+  IN  UINTN               BufferSize,
+  OUT CHAR8               CommandLine[]
+  )
+{
+  RPI_FW_GET_COMMAND_LINE_CMD  *Cmd;
+  EFI_STATUS                    Status;
+  UINT32                        Result;
+
+  if ((BufferSize % sizeof (UINT32)) != 0) {
+    DEBUG ((DEBUG_ERROR, "%a: BufferSize must be a multiple of 4\n",
+      __FUNCTION__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (sizeof (*Cmd) + BufferSize > EFI_PAGES_TO_SIZE (NUM_PAGES)) {
+    DEBUG ((DEBUG_ERROR, "%a: BufferSize exceeds size of DMA buffer\n",
+      __FUNCTION__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd) + BufferSize + sizeof (UINT32));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd) + BufferSize + sizeof (UINT32);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_GET_COMMAND_LINE;
+  Cmd->TagHead.TagSize        = BufferSize;
+  Cmd->TagHead.TagValueSize   = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd->TagHead.TagValueSize &= ~RPI_MBOX_VALUE_SIZE_RESPONSE_MASK;
+  if (Cmd->TagHead.TagValueSize >= BufferSize &&
+      Cmd->CommandLine[Cmd->TagHead.TagValueSize - 1] != '\0') {
+    DEBUG ((DEBUG_ERROR, "%a: insufficient buffer size\n", __FUNCTION__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  CopyMem (CommandLine, Cmd->CommandLine, Cmd->TagHead.TagValueSize);
+
+  if (CommandLine[Cmd->TagHead.TagValueSize - 1] != '\0') {
+    //
+    // Add a NUL terminator if required.
+    //
+    CommandLine[Cmd->TagHead.TagValueSize] = '\0';
+  }
+
+  return EFI_SUCCESS;
+}
+
+#pragma pack()
+typedef struct {
+  UINT32                    ClockId;
+  UINT32                    ClockRate;
+  UINT32                    SkipTurbo;
+} RPI_FW_SET_CLOCK_RATE_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  RPI_FW_SET_CLOCK_RATE_TAG TagBody;
+  UINT32                    EndTag;
+} RPI_FW_SET_CLOCK_RATE_CMD;
+#pragma pack()
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareSetClockRate (
+  IN  UINT32 ClockId,
+  IN  UINT32 ClockRate
+  )
+{
+  RPI_FW_SET_CLOCK_RATE_CMD   *Cmd;
+  EFI_STATUS                  Status;
+  UINT32                      Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_SET_CLOCK_RATE;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->TagBody.ClockId        = ClockId;
+  Cmd->TagBody.ClockRate      = ClockRate;
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+#pragma pack()
+typedef struct {
+  UINT32                    ClockId;
+  UINT32                    ClockRate;
+} RPI_FW_CLOCK_RATE_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  RPI_FW_CLOCK_RATE_TAG     TagBody;
+  UINT32                    EndTag;
+} RPI_FW_GET_CLOCK_RATE_CMD;
+#pragma pack()
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetClockRate (
+  IN  UINT32 ClockId,
+  IN  UINT32 ClockKind,
+  OUT UINT32 *ClockRate
+  )
+{
+  RPI_FW_GET_CLOCK_RATE_CMD   *Cmd;
+  EFI_STATUS                  Status;
+  UINT32                      Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = ClockKind;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->TagBody.ClockId        = ClockId;
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+    return EFI_DEVICE_ERROR;
+  }
+
+  *ClockRate = Cmd->TagBody.ClockRate;
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetCurrentClockRate (
+  IN  UINT32    ClockId,
+  OUT UINT32    *ClockRate
+  )
+{
+  return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_CLOCK_RATE, ClockRate);
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetMaxClockRate (
+  IN  UINT32    ClockId,
+  OUT UINT32    *ClockRate
+  )
+{
+  return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_MAX_CLOCK_RATE, ClockRate);
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetMinClockRate (
+  IN  UINT32    ClockId,
+  OUT UINT32    *ClockRate
+  )
+{
+  return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_MIN_CLOCK_RATE, ClockRate);
+}
+
+#pragma pack()
+typedef struct {
+  UINT32 Pin;
+  UINT32 State;
+} RPI_FW_SET_GPIO_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD        BufferHead;
+  RPI_FW_TAG_HEAD           TagHead;
+  RPI_FW_SET_GPIO_TAG       TagBody;
+  UINT32                    EndTag;
+} RPI_FW_SET_GPIO_CMD;
+#pragma pack()
+
+STATIC
+VOID
+RpiFirmwareSetLed (
+  IN  BOOLEAN On
+  )
+{
+  RPI_FW_SET_GPIO_CMD *Cmd;
+  EFI_STATUS          Status;
+  UINT32              Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
+    return;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_SET_GPIO;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  /*
+   * GPIO_PIN_2 = Activity LED
+   * GPIO_PIN_4 = HDMI Detect (Input / Active Low)
+   * GPIO_PIN_7 = Power LED (Input / Active Low)
+   *
+   * There's also a 128 pin offset.
+   */
+  Cmd->TagBody.Pin = 128 + 2;
+  Cmd->TagBody.State = On;
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox  transaction error: Status == %r, Response == 0x%x\n",
+      __FUNCTION__, Status, Cmd->BufferHead.Response));
+  }
+}
+
+STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL mRpiFirmwareProtocol = {
+  RpiFirmwareSetPowerState,
+  RpiFirmwareGetMacAddress,
+  RpiFirmwareGetCommmandLine,
+  RpiFirmwareGetCurrentClockRate,
+  RpiFirmwareGetMaxClockRate,
+  RpiFirmwareGetMinClockRate,
+  RpiFirmwareSetClockRate,
+  RpiFirmwareAllocFb,
+  RpiFirmwareFreeFb,
+  RpiFirmwareGetFbSize,
+  RpiFirmwareSetLed,
+  RpiFirmwareGetSerial,
+  RpiFirmwareGetModel,
+  RpiFirmwareGetModelRevision,
+  RpiFirmwareGetArmMemory
+};
+
+/**
+  Initialize the state information for the CPU Architectural Protocol
+
+  @param  ImageHandle   of the loaded driver
+  @param  SystemTable   Pointer to the System Table
+
+  @retval EFI_SUCCESS           Protocol registered
+  @retval EFI_OUT_OF_RESOURCES  Cannot allocate protocol data structure
+  @retval EFI_DEVICE_ERROR      Hardware problems
+
+**/
+EFI_STATUS
+RpiFirmwareDxeInitialize (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS      Status;
+  UINTN           BufferSize;
+
+  //
+  // We only need one of these
+  //
+  ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gRaspberryPiFirmwareProtocolGuid);
+
+  InitializeSpinLock (&mMailboxLock);
+
+  Status = DmaAllocateBuffer (EfiBootServicesData, NUM_PAGES, &mDmaBuffer);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to allocate DMA buffer (Status == %r)\n", __FUNCTION__));
+    return Status;
+  }
+
+  BufferSize = EFI_PAGES_TO_SIZE (NUM_PAGES);
+  Status = DmaMap (MapOperationBusMasterCommonBuffer, mDmaBuffer, &BufferSize,
+             &mDmaBufferBusAddress, &mDmaBufferMapping);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to map DMA buffer (Status == %r)\n", __FUNCTION__));
+    goto FreeBuffer;
+  }
+
+  //
+  // The channel index is encoded in the low bits of the bus address,
+  // so make sure these are cleared.
+  //
+  ASSERT (!(mDmaBufferBusAddress & (BCM2836_MBOX_NUM_CHANNELS - 1)));
+
+  Status = gBS->InstallProtocolInterface (&ImageHandle,
+                  &gRaspberryPiFirmwareProtocolGuid, EFI_NATIVE_INTERFACE,
+                  &mRpiFirmwareProtocol);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: failed to install RPI firmware protocol (Status == %r)\n",
+      __FUNCTION__, Status));
+    goto UnmapBuffer;
+  }
+
+  return EFI_SUCCESS;
+
+UnmapBuffer:
+  DmaUnmap (mDmaBufferMapping);
+FreeBuffer:
+  DmaFreeBuffer (NUM_PAGES, mDmaBuffer);
+
+  return Status;
+}
diff --git a/Platform/Raspberry/Pi3/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.inf b/Platform/Raspberry/Pi3/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.inf
new file mode 100644
index 000000000000..a12b5ece7100
--- /dev/null
+++ b/Platform/Raspberry/Pi3/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.inf
@@ -0,0 +1,49 @@
+#/** @file
+#
+#  Copyright (c) 2017-2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+#  Copyright (c) 2016, Linaro, Ltd. 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                    = 0x0001001A
+  BASE_NAME                      = RpiFirmwareDxe
+  FILE_GUID                      = 6d4628df-49a0-4b67-a325-d5af35c65745
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = RpiFirmwareDxeInitialize
+
+[Sources]
+  RpiFirmwareDxe.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Platform/Raspberry/Pi3/RPi3.dec
+
+[LibraryClasses]
+  ArmLib
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  DmaLib
+  IoLib
+  SynchronizationLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+
+[Protocols]
+  gRaspberryPiFirmwareProtocolGuid    ## PRODUCES
+
+[Depex]
+  TRUE
diff --git a/Platform/Raspberry/Pi3/Include/Protocol/RpiFirmware.h b/Platform/Raspberry/Pi3/Include/Protocol/RpiFirmware.h
new file mode 100644
index 000000000000..7583d7e1fcee
--- /dev/null
+++ b/Platform/Raspberry/Pi3/Include/Protocol/RpiFirmware.h
@@ -0,0 +1,131 @@
+/** @file
+ *
+ *  Copyright (c) 2016, Linaro Limited. 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.
+ *
+ **/
+
+#ifndef __RASPBERRY_PI_FIRMWARE_PROTOCOL_H__
+#define __RASPBERRY_PI_FIRMWARE_PROTOCOL_H__
+
+#define RASPBERRY_PI_FIRMWARE_PROTOL_GUID \
+  { 0x0ACA9535, 0x7AD0, 0x4286, { 0xB0, 0x2E, 0x87, 0xFA, 0x7E, 0x2A, 0x57, 0x11 } }
+
+typedef
+EFI_STATUS
+(EFIAPI *SET_POWER_STATE) (
+  IN  UINT32    DeviceId,
+  IN  BOOLEAN   PowerState,
+  IN  BOOLEAN   Wait
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_MAC_ADDRESS) (
+  OUT UINT8     MacAddress[6]
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_COMMAND_LINE) (
+  IN  UINTN     BufferSize,
+  OUT CHAR8     CommandLine[]
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_CLOCK_RATE) (
+  IN  UINT32    ClockId,
+  OUT UINT32    *ClockRate
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *SET_CLOCK_RATE) (
+  IN  UINT32    ClockId,
+  OUT UINT32    ClockRate
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_FB) (
+  IN  UINT32 Width,
+  IN  UINT32 Height,
+  IN  UINT32 Depth,
+  OUT EFI_PHYSICAL_ADDRESS *FbBase,
+  OUT UINTN *FbSize,
+  OUT UINTN *Pitch
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_FB_SIZE) (
+  OUT   UINT32 *Width,
+  OUT   UINT32 *Height
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *FREE_FB) (
+  VOID
+  );
+
+typedef
+VOID
+(EFIAPI *SET_LED) (
+  BOOLEAN On
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_SERIAL) (
+  UINT64 *Serial
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_MODEL) (
+  UINT32 *Model
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_MODEL_REVISION) (
+  UINT32 *Revision
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_ARM_MEM) (
+  UINT32 *Base,
+  UINT32 *Size
+  );
+
+typedef struct {
+  SET_POWER_STATE    SetPowerState;
+  GET_MAC_ADDRESS    GetMacAddress;
+  GET_COMMAND_LINE   GetCommandLine;
+  GET_CLOCK_RATE     GetClockRate;
+  GET_CLOCK_RATE     GetMaxClockRate;
+  GET_CLOCK_RATE     GetMinClockRate;
+  SET_CLOCK_RATE     SetClockRate;
+  GET_FB             GetFB;
+  FREE_FB            FreeFB;
+  GET_FB_SIZE        GetFBSize;
+  SET_LED            SetLed;
+  GET_SERIAL         GetSerial;
+  GET_MODEL          GetModel;
+  GET_MODEL_REVISION GetModelRevision;
+  GET_ARM_MEM        GetArmMem;
+} RASPBERRY_PI_FIRMWARE_PROTOCOL;
+
+extern EFI_GUID gRaspberryPiFirmwareProtocolGuid;
+
+#endif /* __RASPBERRY_PI_FIRMWARE_PROTOCOL_H__ */
-- 
2.17.0.windows.1



  parent reply	other threads:[~2019-01-28 12:45 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-28 12:44 [PATCH v3 edk2-platforms 00/23] Platform/Raspberry: Add Raspberry Pi 3 support Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 01/23] Silicon/Broadcom/Bcm282x: Add interrupt driver Pete Batard
2019-01-28 12:59   ` Ard Biesheuvel
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 02/23] Silicon/Broadcom/Bcm283x: Add GpioLib Pete Batard
2019-01-28 13:02   ` Ard Biesheuvel
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 03/23] Platform/Raspberry/Pi3: Add ACPI tables Pete Batard
2019-01-28 13:24   ` Ard Biesheuvel
2019-01-29 12:54     ` Pete Batard
2019-01-29 12:57       ` Ard Biesheuvel
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 04/23] Platform/Raspberry/Pi3: Add reset and memory init libraries Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 05/23] Platform/Raspberry/Pi3: Add platform library Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 06/23] Platform/Raspberry/Pi3: Add RTC library Pete Batard
2019-01-28 12:44 ` Pete Batard [this message]
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 08/23] Platform/Raspberry/Pi3: Add platform config driver Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 09/23] Platform/Raspberry/Pi3: Add SMBIOS driver Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 10/23] Platform/Raspberry/Pi3: Add display driver Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 11/23] Platform/Raspberry/Pi3: Add console driver Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 12/23] Platform/Raspberry/Pi3: Add NV storage driver Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 13/23] Platform/Raspberry/Pi3: Add Device Tree driver Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 14/23] Platform/Raspberry/Pi3: Add base MMC driver Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 15/23] Platform/Raspberry/Pi3: Add Arasan " Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 16/23] Platform/Raspberry/Pi3: Add SD Host driver Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 17/23] Platform/Raspberry/Pi3: Add platform boot manager and helper libraries Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 18/23] Platform/Raspberry/Pi3: Add USB host driver Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 19/23] Platform/Raspberry/Pi3: Add platform Pete Batard
2019-01-28 13:10   ` Ard Biesheuvel
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 20/23] Platform/Raspberry/Pi3: Add platform readme Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 21/23] Platform/Raspberry/Pi3 *NON-OSI*: Add ATF binaries Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 2/23] Platform/Raspberry/Pi3 *NON-OSI*: Add Device Tree binaries Pete Batard
2019-01-28 12:44 ` [PATCH v3 edk2-platforms 23/23] Platform/Raspberry/Pi3 *NON-OSI*: Add logo driver Pete Batard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190128124445.9868-8-pete@akeo.ie \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox