From: Pete Batard <pete@akeo.ie>
To: edk2-devel@lists.01.org
Subject: [PATCH v1 edk2-platfoms 1/2] Platform/Broadcom: Add Raspberry Pi 3 support
Date: Fri, 7 Dec 2018 12:05:10 +0000 [thread overview]
Message-ID: <20181207120511.8724-2-pete@akeo.ie> (raw)
In-Reply-To: <20181207120511.8724-1-pete@akeo.ie>
This commit contains the edk2-platform components that introduce
support for the Raspberry Pi 3 as a platform, based on the original
work by Ard Biesheuvel and Andrei Warkentin.
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Pete Batard <pete@akeo.ie>
---
Platform/Broadcom/Bcm283x/AcpiTables/AcpiTables.inf | 51 +
Platform/Broadcom/Bcm283x/AcpiTables/Csrt.aslc | 337 ++++
Platform/Broadcom/Bcm283x/AcpiTables/Dbg2.aslc | 32 +
Platform/Broadcom/Bcm283x/AcpiTables/Dsdt.asl | 523 ++++++
Platform/Broadcom/Bcm283x/AcpiTables/Fadt.aslc | 50 +
Platform/Broadcom/Bcm283x/AcpiTables/Gtdt.aslc | 31 +
Platform/Broadcom/Bcm283x/AcpiTables/Madt.aslc | 60 +
Platform/Broadcom/Bcm283x/AcpiTables/Pep.asl | 92 +
Platform/Broadcom/Bcm283x/AcpiTables/Pep.c | 84 +
Platform/Broadcom/Bcm283x/AcpiTables/Pep.h | 126 ++
Platform/Broadcom/Bcm283x/AcpiTables/Platform.h | 82 +
Platform/Broadcom/Bcm283x/AcpiTables/Rhpx.asl | 201 +++
Platform/Broadcom/Bcm283x/AcpiTables/Sdhc.asl | 105 ++
Platform/Broadcom/Bcm283x/AcpiTables/Spcr.asl | 53 +
Platform/Broadcom/Bcm283x/AcpiTables/Uart.asl | 155 ++
Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.c | 730 ++++++++
Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.h | 50 +
Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.inf | 53 +
Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.c | 367 ++++
Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.inf | 48 +
Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxe.c | 356 ++++
Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxe.inf | 81 +
Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeFormSetGuid.h | 23 +
Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeHii.uni | 100 ++
Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeHii.vfr | 306 ++++
Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/ComponentName.c | 222 +++
Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.c | 606 +++++++
Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.h | 43 +
Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.inf | 71 +
Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/Screenshot.c | 379 ++++
Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/ComponentName.c | 183 ++
Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsole.c | 1836 ++++++++++++++++++++
Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsole.h | 591 +++++++
Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxe.inf | 74 +
Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxe.uni | 19 +
| 20 +
Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/NewFont.c | 288 +++
Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/ComponentName.c | 163 ++
Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Diagnostics.c | 256 +++
Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Mmc.c | 458 +++++
Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Mmc.h | 533 ++++++
Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcBlockIo.c | 473 +++++
Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcDebug.c | 169 ++
Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcDxe.inf | 58 +
Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcIdentification.c | 993 +++++++++++
Platform/Broadcom/Bcm283x/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.c | 915 ++++++++++
Platform/Broadcom/Bcm283x/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf | 56 +
Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.c | 370 ++++
Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.inf | 53 +
Platform/Broadcom/Bcm283x/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c | 1085 ++++++++++++
Platform/Broadcom/Bcm283x/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.inf | 49 +
Platform/Broadcom/Bcm283x/Drivers/SdHostDxe/SdHostDxe.c | 830 +++++++++
Platform/Broadcom/Bcm283x/Drivers/SdHostDxe/SdHostDxe.inf | 54 +
Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FileIo.c | 196 +++
Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FvbInfo.c | 118 ++
Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.c | 984 +++++++++++
Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.h | 217 +++
Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c | 334 ++++
Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf | 93 +
Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836.h | 70 +
Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836MmcHs.h | 199 +++
Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836SdHost.h | 92 +
Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2837Gpio.h | 50 +
Platform/Broadcom/Bcm283x/Include/IndustryStandard/RpiFirmware.h | 93 +
Platform/Broadcom/Bcm283x/Include/Library/GpioLib.h | 33 +
Platform/Broadcom/Bcm283x/Include/Protocol/DwUsb.h | 53 +
Platform/Broadcom/Bcm283x/Include/Protocol/ExtendedTextOut.h | 36 +
Platform/Broadcom/Bcm283x/Include/Protocol/PiMmcHost.h | 187 ++
Platform/Broadcom/Bcm283x/Include/Protocol/RaspberryPiFirmware.h | 131 ++
Platform/Broadcom/Bcm283x/Include/Utils.h | 33 +
Platform/Broadcom/Bcm283x/Library/GpioLib/GpioLib.c | 79 +
Platform/Broadcom/Bcm283x/Library/GpioLib/GpioLib.inf | 39 +
Platform/Broadcom/Bcm283x/Library/MemoryInitPeiLib/MemoryInitPeiLib.c | 183 ++
Platform/Broadcom/Bcm283x/Library/MemoryInitPeiLib/MemoryInitPeiLib.inf | 51 +
Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBm.c | 831 +++++++++
Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBm.h | 60 +
Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf | 90 +
Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/AArch64/RaspberryPiHelper.S | 107 ++
Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPi.c | 99 ++
Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPiMem.c | 160 ++
Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPiPlatformLib.inf | 64 +
Platform/Broadcom/Bcm283x/Library/ResetLib/ResetLib.c | 104 ++
Platform/Broadcom/Bcm283x/Library/ResetLib/ResetLib.inf | 46 +
Platform/Broadcom/Bcm283x/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c | 222 +++
Platform/Broadcom/Bcm283x/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf | 43 +
Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec | 63 +
Platform/Broadcom/Bcm283x/RaspberryPiPkg.dsc | 636 +++++++
Platform/Broadcom/Bcm283x/RaspberryPiPkg.fdf | 450 +++++
Platform/Broadcom/Bcm283x/Readme.md | 263 +++
89 files changed, 21452 insertions(+)
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/AcpiTables.inf b/Platform/Broadcom/Bcm283x/AcpiTables/AcpiTables.inf
new file mode 100644
index 000000000000..db0270270cf9
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/AcpiTables.inf
@@ -0,0 +1,51 @@
+#/** @file
+#
+# ACPI table data and ASL sources required to boot the platform.
+#
+# Copyright (c) 2017, Andrey Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) Microsoft Corporation. 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 = 0x00010005
+ BASE_NAME = AcpiTables
+ FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD
+ MODULE_TYPE = USER_DEFINED
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = AARCH64
+#
+
+[Sources]
+ Platform.h
+ Madt.aslc
+ Fadt.aslc
+ Dbg2.aslc
+ Gtdt.aslc
+ Dsdt.asl
+ Csrt.aslc
+ Spcr.asl
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[FixedPcd]
+ gEmbeddedTokenSpaceGuid.PcdInterruptBaseAddress
+
+[BuildOptions]
+ # The default '-mcmodel=small' used with DEBUG produces a GenFw error when compiling CSRT.acpi:
+ # "AARCH64 small code model requires identical ELF and PE/COFF section offsets modulo 4 KB."
+ GCC:DEBUG_*_AARCH64_CC_FLAGS = -mcmodel=tiny
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Csrt.aslc b/Platform/Broadcom/Bcm283x/AcpiTables/Csrt.aslc
new file mode 100644
index 000000000000..926942ec8da3
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Csrt.aslc
@@ -0,0 +1,337 @@
+/** @file
+ *
+ * Core System Resource Table (CSRT)
+ *
+ * Copyright (c) Microsoft Corporation. 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 "Platform.h"
+
+#define DMA_MAX_REQ_LINES 32
+
+#pragma pack(push, 1)
+
+//------------------------------------------------------------------------
+// DMA Controller Vendor Data for RPi3
+//------------------------------------------------------------------------
+typedef struct
+{
+ UINT32 Length;
+ UINT32 Type;
+ UINT64 ChannelsBaseAddress;
+ UINT32 ChannelsBaseSize;
+ UINT64 ControllerBaseAddress;
+ UINT32 ControllerBaseSize;
+ UINT32 ChannelCount;
+ UINT32 ControllerInterrupt;
+ UINT32 MinimumRequestLine;
+ UINT32 MaximumRequestLine;
+ BOOLEAN CacheCoherent;
+} DMA_CONTROLLER_VENDOR_DATA;
+
+//------------------------------------------------------------------------
+// DMA Controller on RPi3
+//------------------------------------------------------------------------
+typedef struct
+{
+ EFI_ACPI_5_0_CSRT_RESOURCE_DESCRIPTOR_HEADER DmaControllerHeader;
+ DMA_CONTROLLER_VENDOR_DATA ControllerVendorData;
+} RD_DMA_CONTROLLER;
+
+//------------------------------------------------------------------------
+// DMA Channel Vendor Data for RPi3
+//------------------------------------------------------------------------
+typedef struct
+{
+ UINT32 ChannelNumber;
+ UINT32 ChannelInterrupt;
+ UINT16 IsReservedChannel;
+ UINT16 NoSrcNoDestAddrIncr;
+} DMA_CHANNEL_VENDOR_DATA;
+
+//------------------------------------------------------------------------
+// DMA Channel on RPi3
+//------------------------------------------------------------------------
+typedef struct
+{
+ EFI_ACPI_5_0_CSRT_RESOURCE_DESCRIPTOR_HEADER DmaChannelHeader;
+ DMA_CHANNEL_VENDOR_DATA ChannelVendorData;
+} RD_DMA_CHANNEL;
+
+//------------------------------------------------------------------------
+// DMA Resource Group on RPi3
+//------------------------------------------------------------------------
+
+typedef struct
+{
+ EFI_ACPI_5_0_CSRT_RESOURCE_GROUP_HEADER ResGroupHeader;
+ RD_DMA_CONTROLLER DmaController;
+ RD_DMA_CHANNEL DmaChannels[RPI3_DMA_CHANNEL_COUNT];
+} RG_DMA;
+
+//----------------------------------------------------------------------------
+// CSRT table structure for RPi3 platform - current revision only includes DMA
+//----------------------------------------------------------------------------
+typedef struct
+{
+// Standard ACPI Header
+ EFI_ACPI_DESCRIPTION_HEADER CsrtHeader;
+
+// DMA Resource Group
+ RG_DMA DmaResourceGroup;
+
+} EFI_ACPI_5_0_CSRT_TABLE;
+
+
+
+EFI_ACPI_5_0_CSRT_TABLE Csrt =
+{
+ //------------------------------------------------------------------------
+ // ACPI Table Header
+ //------------------------------------------------------------------------
+ {
+ EFI_ACPI_5_0_CORE_SYSTEM_RESOURCE_TABLE_SIGNATURE, // Signature "CSRT"
+ sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(RG_DMA), // Length
+ EFI_ACPI_5_0_CSRT_REVISION, // Revision
+ 0x00, // Checksum calculated at runtime.
+ EFI_ACPI_OEM_ID, // OEMID is a 6 bytes long field "BC2836"
+ EFI_ACPI_OEM_TABLE_ID, // OEM table identification(8 bytes long) "RPI3EDK2"
+ EFI_ACPI_OEM_REVISION, // OEM revision number.
+ EFI_ACPI_CREATOR_ID, // ASL compiler vendor ID.
+ EFI_ACPI_CREATOR_REVISION // ASL compiler revision number.
+ },
+
+ //------------------------------------------------------------------------
+ // DMA Resource Group
+ //------------------------------------------------------------------------
+ {
+
+ //------------------------------------------------------------------------
+ // DMA Resource Group Header
+ //------------------------------------------------------------------------
+ {
+ sizeof(RG_DMA), // Resource Group Length
+ EFI_ACPI_VENDOR_ID, // VendorId
+ 0, // SubvendorId
+ EFI_ACPI_CSRT_DEVICE_ID_DMA, // DeviceId 9
+ 0, // SubdeviceId
+ 0, // Revision
+ 0, // Reserved
+ 0 // SharedInfoLength
+ },
+
+
+ //-------------------------------------------------------------------------------
+ // Resource Descriptor - DMA Controller
+ //-------------------------------------------------------------------------------
+ {
+ {
+ sizeof(RD_DMA_CONTROLLER), // Length of this Resource Descriptor
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA, // Type for this resource 3=DMA
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CONTROLLER, // Subtype for this resource 1=DMA Controller
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+0, // ResourceId - 1st DMA controller
+ },
+ {
+ sizeof(DMA_CONTROLLER_VENDOR_DATA), // controller vendor data here
+ 1,
+ 0x3F007000, // Base address for channels
+ RPI3_DMA_CHANNEL_COUNT*0x100, // Base size = Number of channels x 0x100 size for each channel
+ 0x3F007FE0, // Base address for controller
+ 8, // Base size = two registers
+ RPI3_DMA_USED_CHANNEL_COUNT,
+ 0, // cannot use controller interrupt
+ 0, // Minimum Request Line
+ DMA_MAX_REQ_LINES-1, // Maximum Request Line
+ FALSE,
+ },
+ },
+
+ //------------------------------------------------------------------------
+ // Resource Descriptor(s) - DMA Channels 0 to n-1
+ //------------------------------------------------------------------------
+ {
+
+ // channel 0
+ {
+ {
+ sizeof(RD_DMA_CHANNEL), // Length of this Resource Descriptor
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA, // Type for this resource 3=DMA
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL, // Subtype for this resource 0=DMA Channel
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+1, // ResourceId
+ },
+ {
+ 0, // channel vendor data here
+ 0x30, // 16+32 dma_int[0]
+ 0,
+ 0
+ },
+ },
+
+ // channel 1 reserved
+ {
+ {
+ sizeof(RD_DMA_CHANNEL),
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA,
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL,
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+2, // ResourceId
+ },
+ {
+ 1, // channel vendor data here
+ 0x31, // 17+32 dma_int[1]
+ 1,
+ 0
+ },
+ },
+
+ // channel 2 - VC4 use only
+ {
+ {
+ sizeof(RD_DMA_CHANNEL),
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA,
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL,
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+3, // ResourceId
+ },
+ {
+ 2, // channel vendor data here
+ 0x32, // 18+32 dma_int[2]
+ 1,
+ 0
+ },
+ },
+
+ // channel 3 - VC4 use only
+ {
+ {
+ sizeof(RD_DMA_CHANNEL),
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA,
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL,
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+4,
+ },
+ {
+ 3, // channel vendor data here
+ 0x33, // 19+32 dma_int[3]
+ 1,
+ 0
+ },
+ },
+
+ // channel 4
+ {
+ {
+ sizeof(RD_DMA_CHANNEL),
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA,
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL,
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+5,
+ },
+ {
+ 4, // channel vendor data here
+ 0x34, // 20+32 dma_int[4]
+ 0,
+ 1 // SD host controller candidate
+ },
+ },
+
+ // channel 5
+ {
+ {
+ sizeof(RD_DMA_CHANNEL),
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA,
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL,
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+6,
+ },
+ {
+ 5, // channel vendor data here
+ 0x35, // 21+32 dma_int[5]
+ 0,
+ 0
+ },
+ },
+
+ // channel 6 is reserved
+ {
+ {
+ sizeof(RD_DMA_CHANNEL),
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA,
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL,
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+7,
+ },
+ {
+ 6, // channel vendor data here
+ 0x36, // 22+32 dma_int[6]
+ 1,
+ 0
+ },
+ },
+
+ // channel 7 is reserved
+ {
+ {
+ sizeof(RD_DMA_CHANNEL),
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA,
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL,
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+8,
+ },
+ {
+ 7, // channel vendor data here
+ 0x37, // 23+32 dma_int[7]
+ 1,
+ 0
+ },
+ },
+
+ // channel 8
+ {
+ {
+ sizeof(RD_DMA_CHANNEL),
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA,
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL,
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+9,
+ },
+ {
+ 8, // channel vendor data here
+ 0x38, // 24+32 dma_int[8]
+ 0,
+ 0
+ },
+ },
+
+ // channel 9
+ {
+ {
+ sizeof(RD_DMA_CHANNEL),
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA,
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL,
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP+10,
+ },
+ {
+ 9, // channel vendor data here
+ 0x39, // 25+32 dma_int[9]
+ 0,
+ 0
+ },
+ }
+
+ } // end DMA Channels 0 to 14
+
+ } // end DMA Resource group
+};
+
+#pragma pack(pop)
+
+VOID* ReferenceAcpiTable(VOID)
+{
+//
+// Reference the table being generated to prevent the optimizer from removing the
+// data structure from the exeutable
+//
+ return (VOID*)&Csrt;
+}
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Dbg2.aslc b/Platform/Broadcom/Bcm283x/AcpiTables/Dbg2.aslc
new file mode 100644
index 000000000000..b728a5f00cfb
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Dbg2.aslc
@@ -0,0 +1,32 @@
+/** @file
+ *
+ * Debug Port Table (DBG2)
+ *
+ * Copyright (c) Microsoft Corporation. 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.
+ *
+ **/
+
+char DBG2[92] = {
+ 0x44, 0x42, 0x47, 0x32, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4D, 0x53, 0x46, 0x54, 0x20, 0x20, 0x45, 0x44, 0x4B, 0x32,
+ 0x20, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0x00, 0x4D, 0x53,
+ 0x46, 0x54, 0x01, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x01, 0x0A, 0x00,
+ 0x26, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x80, 0x10, 0x00,
+ 0x00, 0x00, 0x16, 0x00, 0x22, 0x00, 0x00, 0x20, 0x00, 0x10,
+ 0x00, 0x50, 0x21, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x00,
+ 0x00, 0x00, '\\', '_', 'S', 'B', '.', 'U', 'R', 'T',
+ 'M', 0x00,
+};
+
+void * ReferenceAcpiTable(void) {
+ return (void *) &DBG2;
+}
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Dsdt.asl b/Platform/Broadcom/Bcm283x/AcpiTables/Dsdt.asl
new file mode 100644
index 000000000000..69897cb921f7
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Dsdt.asl
@@ -0,0 +1,523 @@
+/** @file
+ *
+ * Differentiated System Definition Table (DSDT)
+ *
+ * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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.
+ *
+ **/
+
+#define BCM_ALT0 0x4
+#define BCM_ALT1 0x5
+#define BCM_ALT2 0x6
+#define BCM_ALT3 0x7
+#define BCM_ALT4 0x3
+#define BCM_ALT5 0x2
+
+DefinitionBlock ("Dsdt.aml", "DSDT", 5, "MSFT", "EDK2", 2)
+{
+ Scope (\_SB_)
+ {
+ include("Sdhc.asl")
+ include("Pep.asl")
+
+ //
+ // Description: This is a Processor Device
+ //
+
+ Device (CPU0)
+ {
+ Name (_HID, "ACPI0007")
+ Name (_UID, 0x0)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ }
+
+ //
+ // Description: This is a Processor Device
+ //
+
+ Device (CPU1)
+ {
+ Name (_HID, "ACPI0007")
+ Name (_UID, 0x1)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ }
+
+ //
+ // Description: This is a Processor Device
+ //
+
+ Device (CPU2)
+ {
+ Name (_HID, "ACPI0007")
+ Name (_UID, 0x2)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ }
+
+ //
+ // Description: This is a Processor Device
+ //
+
+ Device (CPU3)
+ {
+ Name (_HID, "ACPI0007")
+ Name (_UID, 0x3)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ }
+
+ //
+ // Description: DWC OTG Controller
+ //
+
+ Device (USB0)
+ {
+ Name (_HID, "BCM2848")
+ Name (_CID, Package() { "DWC_OTG", "DWC2_OTG"})
+ Name (_UID, 0x0)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ MEMORY32FIXED(ReadWrite, 0x3F980000, 0x10000, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x29 }
+ })
+ Return(RBUF)
+ }
+ }
+
+ //
+ // Description: Video Core 4 GPU
+ //
+
+ Device (GPU0)
+ {
+ Name (_HID, "BCM2850")
+ Name (_CID, "VC4")
+ Name (_UID, 0x0)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ // Memory and interrupt for the GPU
+ MEMORY32FIXED(ReadWrite, 0x3FC00000, 0x1000, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x2A }
+
+ // HVS - Hardware Video Scalar
+ MEMORY32FIXED(ReadWrite, 0x3F400000, 0x6000, )
+ // The HVS interrupt is reserved by the VPU
+ // Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x41 }
+
+ // PixelValve0 - DSI0 or DPI
+ // MEMORY32FIXED(ReadWrite, 0x3F206000, 0x100, )
+ // Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x4D }
+
+ // PixelValve1 - DS1 or SMI
+ // MEMORY32FIXED(ReadWrite, 0x73F207000, 0x100, )
+ // Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x4E }
+
+ // PixelValve2 - HDMI output - connected to HVS display FIFO 1
+ MEMORY32FIXED(ReadWrite, 0x3F807000, 0x100, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x4A }
+
+ // HDMI registers
+ MEMORY32FIXED(ReadWrite, 0x3F902000, 0x600, ) // HDMI registers
+ MEMORY32FIXED(ReadWrite, 0x3F808000, 0x100, ) // HD registers
+ // hdmi_int[0]
+ // Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x48 }
+ // hdmi_int[1]
+ // Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x49 }
+
+ // HDMI DDC connection
+ I2CSerialBus(0x50,, 100000,, "\\_SB.I2C2",,,,) // EDID
+ I2CSerialBus(0x30,, 100000,, "\\_SB.I2C2",,,,) // E-DDC Segment Pointer
+ })
+ Return(RBUF)
+ }
+
+ // GPU Power Management Component Data
+ // Reference : https://github.com/Microsoft/graphics-driver-samples/wiki/Install-Driver-in-a-Windows-VM
+ Method(PMCD, 0, Serialized) {
+
+ Name(RBUF, Package() {
+ 1, // Version
+ 1, // Number of graphics power components
+
+ Package() { // Power components package
+
+ Package() { // GPU component package
+ 0, // Component Index
+ 0, // DXGK_POWER_COMPONENT_MAPPING.ComponentType (0 = DXGK_POWER_COMPONENT_ENGINE)
+ 0, // DXGK_POWER_COMPONENT_MAPPING.NodeIndex
+
+ Buffer() { // DXGK_POWER_RUNTIME_COMPONENT.ComponentGuid
+ // 9B2D1E26-1575-4747-8FC0-B9EB4BAA2D2B
+ 0x26, 0x1E, 0x2D, 0x9B, 0x75, 0x15, 0x47, 0x47,
+ 0x8f, 0xc0, 0xb9, 0xeb, 0x4b, 0xaa, 0x2d, 0x2b
+ },
+
+ "VC4_Engine_00",// DXGK_POWER_RUNTIME_COMPONENT.ComponentName
+ 2, // DXGK_POWER_RUNTIME_COMPONENT.StateCount
+
+ Package() { // DXGK_POWER_RUNTIME_COMPONENT.States[] package
+
+ Package() { // F0
+ 0, // DXGK_POWER_RUNTIME_STATE.TransitionLatency
+ 0, // DXGK_POWER_RUNTIME_STATE.ResidencyRequirement
+ 1210000, // DXGK_POWER_RUNTIME_STATE.NominalPower (microwatt)
+ },
+
+ Package() { // F1 - Placeholder
+ 10000, // DXGK_POWER_RUNTIME_STATE.TransitionLatency
+ 10000, // DXGK_POWER_RUNTIME_STATE.ResidencyRequirement
+ 4, // DXGK_POWER_RUNTIME_STATE.NominalPower
+ },
+ }
+ }
+ }
+ })
+ Return(RBUF)
+ }
+ }
+
+ //
+ // Description: PiQ Mailbox Driver
+ //
+
+ Device (RPIQ)
+ {
+ Name (_HID, "BCM2849")
+ Name (_CID, "RPIQ")
+ Name (_UID, 0)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ Memory32Fixed (ReadWrite, 0x3F00B880, 0x00000024, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x61 }
+ })
+ Return (RBUF)
+ }
+ }
+
+ //
+ // Description: VCHIQ Driver
+ //
+
+ Device (VCIQ)
+ {
+ Name (_HID, "BCM2835")
+ Name (_CID, "VCIQ")
+ Name (_UID, 0)
+ Name (_DEP, Package() { \_SB.RPIQ })
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ Memory32Fixed (ReadWrite, 0x3F00B840, 0x00000010, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x62 }
+ })
+ Return (RBUF)
+ }
+ }
+
+ //
+ // Description: VC Shared Memory Driver
+ //
+
+ Device (VCSM)
+ {
+ Name (_HID, "BCM2856")
+ Name (_CID, "VCSM")
+ Name (_UID, 0)
+ Name (_DEP, Package() { \_SB.VCIQ })
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ }
+
+ //
+ // Description: GPIO
+ //
+ Device (GPI0)
+ {
+ Name (_HID, "BCM2845")
+ Name (_CID, "BCMGPIO")
+ Name (_UID, 0x0)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ MEMORY32FIXED(ReadWrite, 0x3F200000, 0xB4, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) { 0x51 }
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) { 0x53 }
+ })
+ Return(RBUF)
+ }
+ }
+
+ //
+ // Description: I2C
+ //
+
+ Device (I2C1)
+ {
+ Name (_HID, "BCM2841")
+ Name (_CID, "BCMI2C")
+ Name (_UID, 0x1)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized)
+ {
+ Name (RBUF, ResourceTemplate()
+ {
+ Memory32Fixed(ReadWrite, 0x3F804000, 0x20)
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) {0x55}
+ //
+ // MsftFunctionConfig is encoded as the VendorLong.
+ //
+ // MsftFunctionConfig(Exclusive, PullUp, BCM_ALT0, "\\_SB.GPI0", 0, ResourceConsumer, ) {2, 3}
+ //
+ VendorLong () // Length = 0x31
+ {
+ /* 0000 */ 0x00, 0x60, 0x44, 0xD5, 0xF3, 0x1F, 0x11, 0x60, // .`D....`
+ /* 0008 */ 0x4A, 0xB8, 0xB0, 0x9C, 0x2D, 0x23, 0x30, 0xDD, // J...-#0.
+ /* 0010 */ 0x2F, 0x8D, 0x1D, 0x00, 0x01, 0x10, 0x00, 0x01, // /.......
+ /* 0018 */ 0x04, 0x00, 0x12, 0x00, 0x00, 0x16, 0x00, 0x20, // .......
+ /* 0020 */ 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x5C, // .......\
+ /* 0028 */ 0x5F, 0x53, 0x42, 0x2E, 0x47, 0x50, 0x49, 0x30, // _SB.GPI0
+ /* 0030 */ 0x00 // .
+ }
+
+ })
+ Return(RBUF)
+ }
+ }
+
+ //
+ // I2C2 is the HDMI DDC connection
+ //
+
+ Device (I2C2)
+ {
+ Name (_HID, "BCM2841")
+ Name (_CID, "BCMI2C")
+ Name (_UID, 0x2)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized)
+ {
+ Name (RBUF, ResourceTemplate()
+ {
+ Memory32Fixed(ReadWrite, 0x3F805000, 0x20)
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) {0x55}
+ })
+ Return(RBUF)
+ }
+ }
+
+ //
+ // Description: SPI
+ //
+
+ Device (SPI0)
+ {
+ Name (_HID, "BCM2838")
+ Name (_CID, "BCMSPI0")
+ Name (_UID, 0x0)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ MEMORY32FIXED(ReadWrite, 0x3F204000, 0x20, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) {0x56}
+
+ //
+ // MsftFunctionConfig is encoded as the VendorLong.
+ //
+ // MsftFunctionConfig(Exclusive, PullDown, BCM_ALT0, "\\_SB.GPI0", 0, ResourceConsumer, ) {9, 10, 11} // MISO, MOSI, SCLK
+ VendorLong () // Length = 0x33
+ {
+ /* 0000 */ 0x00, 0x60, 0x44, 0xD5, 0xF3, 0x1F, 0x11, 0x60, // .`D....`
+ /* 0008 */ 0x4A, 0xB8, 0xB0, 0x9C, 0x2D, 0x23, 0x30, 0xDD, // J...-#0.
+ /* 0010 */ 0x2F, 0x8D, 0x1F, 0x00, 0x01, 0x10, 0x00, 0x02, // /.......
+ /* 0018 */ 0x04, 0x00, 0x12, 0x00, 0x00, 0x18, 0x00, 0x22, // ......."
+ /* 0020 */ 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, // ........
+ /* 0028 */ 0x00, 0x5C, 0x5F, 0x53, 0x42, 0x2E, 0x47, 0x50, // .\_SB.GP
+ /* 0030 */ 0x49, 0x30, 0x00 // I0.
+ }
+
+ //
+ // MsftFunctionConfig is encoded as the VendorLong.
+ //
+ // MsftFunctionConfig(Exclusive, PullUp, BCM_ALT0, "\\_SB.GPI0", 0, ResourceConsumer, ) {8} // CE0
+ VendorLong () // Length = 0x2F
+ {
+ /* 0000 */ 0x00, 0x60, 0x44, 0xD5, 0xF3, 0x1F, 0x11, 0x60, // .`D....`
+ /* 0008 */ 0x4A, 0xB8, 0xB0, 0x9C, 0x2D, 0x23, 0x30, 0xDD, // J...-#0.
+ /* 0010 */ 0x2F, 0x8D, 0x1B, 0x00, 0x01, 0x10, 0x00, 0x01, // /.......
+ /* 0018 */ 0x04, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x1E, // ........
+ /* 0020 */ 0x00, 0x00, 0x00, 0x08, 0x00, 0x5C, 0x5F, 0x53, // .....\_S
+ /* 0028 */ 0x42, 0x2E, 0x47, 0x50, 0x49, 0x30, 0x00 // B.GPI0.
+ }
+
+ //
+ // MsftFunctionConfig is encoded as the VendorLong.
+ //
+ // MsftFunctionConfig(Exclusive, PullUp, BCM_ALT0, "\\_SB.GPI0", 0, ResourceConsumer, ) {7} // CE1
+ VendorLong () // Length = 0x2F
+ {
+ /* 0000 */ 0x00, 0x60, 0x44, 0xD5, 0xF3, 0x1F, 0x11, 0x60, // .`D....`
+ /* 0008 */ 0x4A, 0xB8, 0xB0, 0x9C, 0x2D, 0x23, 0x30, 0xDD, // J...-#0.
+ /* 0010 */ 0x2F, 0x8D, 0x1B, 0x00, 0x01, 0x10, 0x00, 0x01, // /.......
+ /* 0018 */ 0x04, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x1E, // ........
+ /* 0020 */ 0x00, 0x00, 0x00, 0x07, 0x00, 0x5C, 0x5F, 0x53, // .....\_S
+ /* 0028 */ 0x42, 0x2E, 0x47, 0x50, 0x49, 0x30, 0x00 // B.GPI0.
+ }
+ })
+ Return(RBUF)
+ }
+ }
+
+ Device (SPI1)
+ {
+ Name (_HID, "BCM2839")
+ Name (_CID, "BCMAUXSPI")
+ Name (_UID, 0x1)
+ Name (_DEP, Package() { \_SB.RPIQ })
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ MEMORY32FIXED(ReadWrite, 0x3F215080, 0x40,)
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared,) {0x3D}
+
+ //
+ // MsftFunctionConfig is encoded as the VendorLong.
+ //
+ // MsftFunctionConfig(Exclusive, PullDown, BCM_ALT4, "\\_SB.GPI0", 0, ResourceConsumer, ) {19, 20, 21} // MISO, MOSI, SCLK
+ VendorLong () // Length = 0x33
+ {
+ /* 0000 */ 0x00, 0x60, 0x44, 0xD5, 0xF3, 0x1F, 0x11, 0x60, // .`D....`
+ /* 0008 */ 0x4A, 0xB8, 0xB0, 0x9C, 0x2D, 0x23, 0x30, 0xDD, // J...-#0.
+ /* 0010 */ 0x2F, 0x8D, 0x1F, 0x00, 0x01, 0x10, 0x00, 0x02, // /.......
+ /* 0018 */ 0x03, 0x00, 0x12, 0x00, 0x00, 0x18, 0x00, 0x22, // ......."
+ /* 0020 */ 0x00, 0x00, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, // ........
+ /* 0028 */ 0x00, 0x5C, 0x5F, 0x53, 0x42, 0x2E, 0x47, 0x50, // .\_SB.GP
+ /* 0030 */ 0x49, 0x30, 0x00 // I0.
+ }
+
+ //
+ // MsftFunctionConfig is encoded as the VendorLong.
+ //
+ // MsftFunctionConfig(Exclusive, PullDown, BCM_ALT4, "\\_SB.GPI0", 0, ResourceConsumer, ) {16} // CE2
+ VendorLong () // Length = 0x2F
+ {
+ /* 0000 */ 0x00, 0x60, 0x44, 0xD5, 0xF3, 0x1F, 0x11, 0x60, // .`D....`
+ /* 0008 */ 0x4A, 0xB8, 0xB0, 0x9C, 0x2D, 0x23, 0x30, 0xDD, // J...-#0.
+ /* 0010 */ 0x2F, 0x8D, 0x1B, 0x00, 0x01, 0x10, 0x00, 0x02, // /.......
+ /* 0018 */ 0x03, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x1E, // ........
+ /* 0020 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x5C, 0x5F, 0x53, // .....\_S
+ /* 0028 */ 0x42, 0x2E, 0x47, 0x50, 0x49, 0x30, 0x00 // B.GPI0.
+ }
+ })
+ Return(RBUF)
+ }
+ }
+
+ // SPI2 has no pins on GPIO header
+ // Device (SPI2)
+ // {
+ // Name (_HID, "BCM2839")
+ // Name (_CID, "BCMAUXSPI")
+ // Name (_UID, 0x2)
+ // Name (_DEP, Package() { \_SB.RPIQ })
+ // Method (_STA)
+ // {
+ // Return(0xf) // Disabled
+ // }
+ // Method (_CRS, 0x0, Serialized) {
+ // Name (RBUF, ResourceTemplate () {
+ // MEMORY32FIXED(ReadWrite, 0x3F2150C0, 0x40,)
+ // Interrupt(ResourceConsumer, Level, ActiveHigh, Shared,) {0x3D}
+ // })
+ // Return(RBUF)
+ // }
+ // }
+
+ //
+ // Description: PWM Driver
+ //
+
+ Device (PWM0)
+ {
+ Name (_HID, "BCM2844")
+ Name (_CID, "BCM2844")
+ Name (_UID, 0)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ // DMA channel 11 control
+ Memory32Fixed (ReadWrite, 0x3F007B00, 0x00000100, )
+ // PWM control
+ Memory32Fixed (ReadWrite, 0x3F20C000, 0x00000028, )
+ // PWM control bus
+ Memory32Fixed (ReadWrite, 0x7E20C000, 0x00000028, )
+ // PWM control uncached
+ Memory32Fixed (ReadWrite, 0xFF20C000, 0x00000028, )
+ // PWM clock control
+ Memory32Fixed (ReadWrite, 0x3F1010A0, 0x00000008, )
+ // Interrupt DMA channel 11
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x3B }
+ // DMA channel 11, DREQ 5 for PWM
+ FixedDMA(5, 11, Width32Bit, )
+ })
+ Return (RBUF)
+ }
+ }
+
+ include("Uart.asl")
+ include("Rhpx.asl")
+ }
+}
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Fadt.aslc b/Platform/Broadcom/Bcm283x/AcpiTables/Fadt.aslc
new file mode 100644
index 000000000000..493a888d3699
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Fadt.aslc
@@ -0,0 +1,50 @@
+/** @file
+ *
+ * Fixed ACPI Description Table (FADT)
+ *
+ * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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.
+ *
+ **/
+
+char FACP[268] = {
+ 0x46, 0x41, 0x43, 0x50, 0x0C, 0x01, 0x00, 0x00, 0x05, 0x00, /* 0 */
+ 0x42, 0x43, 0x32, 0x38, 0x33, 0x36, 0x45, 0x44, 0x4B, 0x32, /* 10 */
+ 0x20, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0x00, 0x4D, 0x53, /* 20 */
+ 0x46, 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, /* 40 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 50 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 90 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, /* 100 */
+ 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, /* 110 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 120 */
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 130 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 140 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 150 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 160 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 170 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 180 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 190 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 200 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 210 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 220 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 230 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 240 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 250 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 268 */
+};
+
+void * ReferenceAcpiTable(void) {
+ return (void *) &FACP;
+}
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Gtdt.aslc b/Platform/Broadcom/Bcm283x/AcpiTables/Gtdt.aslc
new file mode 100644
index 000000000000..764cc6c09fe7
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Gtdt.aslc
@@ -0,0 +1,31 @@
+/** @file
+ *
+ * Generic Timer Description Table (GTDT)
+ * Automatically generated by AutoAcpi
+ *
+ * Copyright (c) Microsoft Corporation. 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.
+ *
+ **/
+
+char GTDT[80] = {
+ 0x47, 0x54, 0x44, 0x54, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x4D, 0x53, 0x46, 0x54, 0x20, 0x20, 0x45, 0x44, 0x4B, 0x32,
+ 0x20, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0x00, 0x4D, 0x53,
+ 0x46, 0x54, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+void * ReferenceAcpiTable(void) {
+ return (void *) >DT;
+}
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Madt.aslc b/Platform/Broadcom/Bcm283x/AcpiTables/Madt.aslc
new file mode 100644
index 000000000000..96f3ee469324
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Madt.aslc
@@ -0,0 +1,60 @@
+/** @file
+ *
+ * Multiple APIC Description Table (MADT)
+ *
+ * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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.
+ *
+ **/
+
+/*
+ * Even though the BCM2836 doesn't contain a GIC, these
+ * GICC definitions enable multi-core support (with PSCI).
+ *
+ * Mind the signatures in the header, they must be kept.
+ */
+char APIC[] = {
+ 0x41, 0x50, 0x49, 0x43, 0x6c, 0x01, 0x00, 0x00, 0x03, 0xaf, 0x42, 0x43,
+ 0x32, 0x38, 0x33, 0x36, 0x45, 0x44, 0x4b, 0x32, 0x20, 0x20, 0x20, 0x20,
+ 0x01, 0x00, 0x00, 0x00, 0x4d, 0x53, 0x46, 0x54, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x50, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x0b, 0x50, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0b, 0x50, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x50, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00
+};
+
+void * ReferenceAcpiTable(void) {
+ return (void *) &APIC;
+}
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Pep.asl b/Platform/Broadcom/Bcm283x/AcpiTables/Pep.asl
new file mode 100644
index 000000000000..c0e07c6eaf42
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Pep.asl
@@ -0,0 +1,92 @@
+/** @file
+ *
+ * Platform Extension Plugin (PEP).
+ *
+ * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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.
+ *
+ **/
+
+Device(PEPD)
+{
+ //
+ // RPI3 PEP virtual device.
+ //
+ Name(_HID, "BCM2854") // note: since pep on rpi3 is virtual device,
+ Name(_CID, "BCM2854") // its device id needs to be generated by Microsoft
+ Name(_UID, 0x0)
+ Name(_CRS, ResourceTemplate () {
+ // No hardware resources for PEP driver are needed.
+ })
+
+ //
+ // Processor info. PEP proprietary method to return
+ // PEP_PROCESSOR_TABLE_PLAT structure.
+ //
+ // See Pep.h and Pep.c.
+ //
+ Name(_GPI, Buffer() {
+ 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x5C,0x00,0x5F,0x00,0x53,
+ 0x00,0x42,0x00,0x2E,0x00,0x43,0x00,0x50,0x00,0x55,0x00,0x30,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ })
+
+ //
+ // Coordinated state info. PEP proprietary method to return
+ // PEP_COORDINATED_STATE_TABLE_PLAT structure.
+ //
+ // See Pep.h and Pep.c.
+ //
+ Name(_GCI, Buffer() {
+ 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x01,0x00,0x00,0x00
+ })
+
+ //
+ // Device info. PEP proprietary method to return
+ // PEP_DEVICE_TABLE_PLAT structure.
+ //
+ // See Pep.h and Pep.c.
+ //
+
+ Name(_GDI, Buffer() {
+ 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x5C,0x00,0x5F,0x00,0x53,
+ 0x00,0x42,0x00,0x2E,0x00,0x49,0x00,0x32,0x00,0x43,0x00,0x30,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,
+ 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ })
+}
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Pep.c b/Platform/Broadcom/Bcm283x/AcpiTables/Pep.c
new file mode 100644
index 000000000000..de457daaa547
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Pep.c
@@ -0,0 +1,84 @@
+/** @file
+ *
+ * PEP device tables
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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 "Pep.h"
+
+PEP_PROCESSOR_TABLE_PLAT RPI3Processors = {
+ 1, //Version
+ 1, //NumberProcessors
+ { //ProcessorInfo
+ { //[0]
+ L"\\_SB.CPU0", //DevicePath , wchar_t[16]
+ 0, //FeedbackCounterCount
+ 0x00000000, //Flags
+ 0, //NumberIdleStates
+ 0, //NumberPerfStates
+ { //IdleInfo
+ },
+ { // perfinfo
+ }
+ }
+ }
+};
+
+PEP_COORDINATED_STATE_TABLE_PLAT RPI3CoordinatedStates = {
+ 1, //Version
+ 1, //CoordinatedStateCount
+ { //CordinatedStates[]
+ { //[0]
+ { // DependencyInfo
+ { //[0]
+ 1, //ExpectedState
+ 0, //TargetProcessor
+ 0x0 | 0x2 | 0x4, //LooseDependency = FALSE, InitialState = TRUE, DependentState = TRUE
+ }
+ },
+ SOC_STATE_TYPE, //StateType
+ 0x1, //Flags
+ 0, //Latency
+ 0, //BreakEvenDuration
+ 1, //DependencyCount
+ 1, //MaximumDependencySize
+ }
+ }
+};
+
+PEP_DEVICE_TABLE_PLAT RPI3Devices = {
+ 1, //Version
+ 1, //NumberDevices
+ { //DeviceInfo
+ { //[1]
+ L"\\_SB.I2C0", //DevicePath , wchar_t[16]
+ 0x1 | (1 << 3), //DStateSupportMask (D0 and D3)
+ 1, //NumberCompoenents
+ { //DStateRequirement
+ { //[0]
+ PowerDeviceD3 //DState
+ }
+ },
+ { // FStateRequirement
+ { //[0]
+ { //FState
+ { //[0]
+ 0
+ }
+ }
+ }
+ }
+ }
+ }
+};
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Pep.h b/Platform/Broadcom/Bcm283x/AcpiTables/Pep.h
new file mode 100644
index 000000000000..16d8c460832e
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Pep.h
@@ -0,0 +1,126 @@
+/** @file
+ *
+ * PEP device defines
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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.
+ *
+ **/
+
+/*
+ * Note: Not everything is here. At least SOC_STATE_TYPE is missing.
+ */
+
+#ifndef _RPI3PEP_H_INCLUDED_
+#define _RPI3PEP_H_INCLUDED_
+
+#include <IndustryStandard/Acpi50.h>
+
+#define PEP_MAX_DEPENDENCIES_PER_STATE 16
+#define MAX_PROCESSOR_PATH_LENGTH 16
+#define MAX_DEVICE_PATH_LENGTH 32
+#define MAX_COMPONENT_COUNT 8
+#define P_NUMBER_PROCESSORS 1
+#define P_NUMBER_IDLE_STATES 1
+#define P_NUMBER_PERF_STATES 0
+#define P_NUMBER_DEVICES 1
+#define P_NUMBER_COORDINATED_STATS 1
+
+typedef struct _PEP_PROCESSOR_IDLE_STATE_INFO {
+ UINT32 Ulong;
+ UINT32 Latency;
+ UINT32 BreakEvenDuration;
+} PEP_PROCESSOR_IDLE_STATE_INFO, *PEP_PROCESSOR_IDLE_STATE_INFO;
+
+typedef struct _PEP_PROCESSOR_IDLE_INFO_PLAT {
+ //
+ // Processor idle states.
+ //
+ PEP_PROCESSOR_IDLE_STATE_INFO IdleStates[P_NUMBER_IDLE_STATES];
+} PEP_PROCESSOR_IDLE_INFO_PLAT, *PPEP_PROCESSOR_IDLE_INFO_PLAT;
+
+typedef struct COORDINATED_DEPENDENCY_INFO {
+ UINT32 ExpectedState;
+ UINT32 TargetProcessor;
+ UINT32 Ulong;
+} COORDINATED_DEPENDENCY_INFO, *PCOORDINATED_DEPENDENCY_INFO;
+
+typedef struct {
+ COORDINATED_DEPENDENCY_INFO DependencyInfo[PEP_MAX_DEPENDENCIES_PER_STATE];
+ UINT32 StateType;
+ UINT32 Ulong;
+ UINT32 Latency;
+ UINT32 BreakEvenDuration;
+ UINT32 DependencyCount;
+ UINT32 MaximumDependencySize;
+} COORDINATED_STATE_INFO;
+
+typedef struct {
+ UINT32 Unused;
+} PEP_PROCESSOR_PERF_INFO;
+
+typedef struct {
+ UINT32 FState[MAX_COMPONENT_COUNT];
+} COORDINATED_FSTATE_REQUIREMENT;
+
+typedef struct {
+ UINT32 DState;
+} COORDINATED_DSTATE_REQUIREMENT;
+
+//
+// Top level device table
+// *N.B. The exact length of the structure is determined by the NumberIdleStates/NumberPerfStates variables.
+//
+
+typedef struct _PEP_PROCESSOR_INFO_PLAT {
+ WCHAR DevicePath[MAX_PROCESSOR_PATH_LENGTH]; // Null-terminated ACPI name
+ ULONG FeedbackCounterCount;
+ ULONG Flags;
+
+ //
+ // We are putting the idle/perf state count here (instead
+ // of the PEP_PROCESSOR_xxx_INFO structure for the ease of parsing.
+ //
+ ULONG NumberIdleStates;
+ ULONG NumberPerfStates;
+
+ PEP_PROCESSOR_IDLE_INFO_PLAT IdleInfo;
+ PEP_PROCESSOR_PERF_INFO PerfInfo;
+} PEP_PROCESSOR_INFO_PLAT, *PPEP_PROCESSOR_INFO_PLAT;
+
+typedef struct _PEP_PROCESSOR_TABLE_PLAT {
+ UINT32 Version;
+ UINT32 NumberProcessors;
+ PEP_PROCESSOR_INFO_PLAT ProcessorInfo[P_NUMBER_PROCESSORS];
+} PEP_PROCESSOR_TABLE_PLAT;
+
+typedef struct _PEP_COORDINATED_STATE_TABLE_PLAT {
+ ULONG Version;
+ ULONG CoordinatedStateCount;
+ COORDINATED_STATE_INFO CoordinatedStates[P_NUMBER_COORDINATED_STATS];
+} PEP_COORDINATED_STATE_TABLE_PLAT, *PPEP_COORDINATED_STATE_TABLE_PLAT;
+
+typedef struct _PEP_DEVICE_INFO_PLAT {
+ WCHAR DevicePath[MAX_DEVICE_PATH_LENGTH]; // Null-terminated ACPI name
+ ULONG DStateSupportMask;
+ ULONG NumberComponents;
+
+ COORDINATED_DSTATE_REQUIREMENT DStateRequirement[P_NUMBER_COORDINATED_STATS];
+ COORDINATED_FSTATE_REQUIREMENT FStateRequirement[P_NUMBER_COORDINATED_STATS];
+} PEP_DEVICE_INFO_PLAT, *PPEP_DEVICE_INFO_PLAT;
+
+typedef struct _PEP_DEVICE_TABLE_PLAT {
+ ULONG Version;
+ ULONG NumberDevices;
+ PEP_DEVICE_INFO_PLAT DeviceInfo[P_NUMBER_DEVICES];
+} PEP_DEVICE_TABLE_PLAT, *PPEP_DEVICE_TABLE_PLAT;
+
+#endif
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Platform.h b/Platform/Broadcom/Bcm283x/AcpiTables/Platform.h
new file mode 100644
index 000000000000..826182698fd0
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Platform.h
@@ -0,0 +1,82 @@
+/** @file
+ *
+ * RPi3 Platform specific defines for constructing ACPI tables
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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 _Platform_H_INCLUDED_
+#define _Platform_H_INCLUDED_
+
+#include <IndustryStandard/Acpi50.h>
+
+#define EFI_ACPI_OEM_ID {'M','C','R','S','F','T'} // OEMID 6 bytes long
+#define EFI_ACPI_OEM_TABLE_ID SIGNATURE_64('R','P','I','3','E','D','K','2') // OEM table id 8 bytes long
+#define EFI_ACPI_OEM_REVISION 0x02000820
+#define EFI_ACPI_CREATOR_ID SIGNATURE_32('R','P','I','3')
+#define EFI_ACPI_CREATOR_REVISION 0x00000097
+
+#define EFI_ACPI_VENDOR_ID SIGNATURE_32('M','S','F','T')
+#define EFI_ACPI_CSRT_REVISION 0x00000005
+#define EFI_ACPI_CSRT_DEVICE_ID_DMA 0x00000009 // fixed id
+#define EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP 0x0 // count up from 0
+
+#define RPI3_DMA_CHANNEL_COUNT 10 // all 10 DMA channels are listed, including the reserved ones
+#define RPI3_DMA_USED_CHANNEL_COUNT 5 // use 5 DMA channels
+
+#define EFI_ACPI_5_0_CSRT_REVISION 0x00000000
+
+typedef enum
+{
+ EFI_ACPI_CSRT_RESOURCE_TYPE_RESERVED, // 0
+ EFI_ACPI_CSRT_RESOURCE_TYPE_INTERRUPT, // 1
+ EFI_ACPI_CSRT_RESOURCE_TYPE_TIMER, // 2
+ EFI_ACPI_CSRT_RESOURCE_TYPE_DMA, // 3
+ EFI_ACPI_CSRT_RESOURCE_TYPE_CACHE, // 4
+}
+CSRT_RESOURCE_TYPE;
+
+typedef enum
+{
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL, // 0
+ EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CONTROLLER // 1
+}
+CSRT_DMA_SUBTYPE;
+
+//------------------------------------------------------------------------
+// CSRT Resource Group header 24 bytes long
+//------------------------------------------------------------------------
+typedef struct
+{
+ UINT32 Length; // Length
+ UINT32 VendorID; // 4 bytes
+ UINT32 SubVendorId; // 4 bytes
+ UINT16 DeviceId; // 2 bytes
+ UINT16 SubdeviceId; // 2 bytes
+ UINT16 Revision; // 2 bytes
+ UINT16 Reserved; // 2 bytes
+ UINT32 SharedInfoLength; // 4 bytes
+} EFI_ACPI_5_0_CSRT_RESOURCE_GROUP_HEADER;
+
+//------------------------------------------------------------------------
+// CSRT Resource Descriptor 12 bytes total
+//------------------------------------------------------------------------
+typedef struct
+{
+ UINT32 Length; // 4 bytes
+ UINT16 ResourceType; // 2 bytes
+ UINT16 ResourceSubType; // 2 bytes
+ UINT32 UID; // 4 bytes
+} EFI_ACPI_5_0_CSRT_RESOURCE_DESCRIPTOR_HEADER;
+
+#endif // of _Platform_H_INCLUDED_
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Rhpx.asl b/Platform/Broadcom/Bcm283x/AcpiTables/Rhpx.asl
new file mode 100644
index 000000000000..b197aa53fed4
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Rhpx.asl
@@ -0,0 +1,201 @@
+/** @file
+ *
+ * [DSDT] RHProxy device to enable WinRT API (RHPX)
+ *
+ * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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.
+ *
+ **/
+
+Device(RHPX)
+{
+ Name(_HID, "MSFT8000")
+ Name(_CID, "MSFT8000")
+ Name(_UID, 1)
+
+ Name(_CRS, ResourceTemplate()
+ {
+ // Index 0
+ SPISerialBus( // SCKL - GPIO 11 - Pin 23
+ // MOSI - GPIO 10 - Pin 19
+ // MISO - GPIO 9 - Pin 21
+ // CE0 - GPIO 8 - Pin 24
+ 0, // Device selection (CE0)
+ PolarityLow, // Device selection polarity
+ FourWireMode, // wiremode
+ 8, // databit len
+ ControllerInitiated, // slave mode
+ 4000000, // connection speed
+ ClockPolarityLow, // clock polarity
+ ClockPhaseFirst, // clock phase
+ "\\_SB.SPI0", // ResourceSource: SPI bus controller name
+ 0, // ResourceSourceIndex
+ // Resource usage
+ // DescriptorName: creates name for offset of resource descriptor
+ ) // Vendor Data
+
+ // Index 1
+ SPISerialBus( // SCKL - GPIO 11 - Pin 23
+ // MOSI - GPIO 10 - Pin 19
+ // MISO - GPIO 9 - Pin 21
+ // CE1 - GPIO 7 - Pin 26
+ 1, // Device selection (CE1)
+ PolarityLow, // Device selection polarity
+ FourWireMode, // wiremode
+ 8, // databit len
+ ControllerInitiated, // slave mode
+ 4000000, // connection speed
+ ClockPolarityLow, // clock polarity
+ ClockPhaseFirst, // clock phase
+ "\\_SB.SPI0", // ResourceSource: SPI bus controller name
+ 0, // ResourceSourceIndex
+ // Resource usage
+ // DescriptorName: creates name for offset of resource descriptor
+ ) // Vendor Data
+
+ // Index 2
+ I2CSerialBus( // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1)
+ 0xFFFF, // SlaveAddress: placeholder
+ , // SlaveMode: default to ControllerInitiated
+ 0, // ConnectionSpeed: placeholder
+ , // Addressing Mode: default to 7 bit
+ "\\_SB.I2C1", // ResourceSource: I2C bus controller name
+ ,
+ ,
+ , // Descriptor Name: creates name for offset of resource descriptor
+ ) // VendorData
+
+ // Index 3
+ SPISerialBus( // SPI1_SCLK - GPIO21
+ // SPI1_MOSI - GPIO20
+ // SPI1_MISO - GPIO19
+ // SPI1_CE2_N - GPIO16
+ 2, // Device selection (CE2)
+ PolarityLow, // Device selection polarity
+ FourWireMode, // wiremode
+ 8, // databit len
+ ControllerInitiated, // slave mode
+ 4000000, // connection speed
+ ClockPolarityLow, // clock polarity
+ ClockPhaseFirst, // clock phase
+ "\\_SB.SPI1", // ResourceSource: SPI bus controller name
+ 0, // ResourceSourceIndex
+ // Resource usage
+ // DescriptorName: creates name for offset of resource descriptor
+ ) // Vendor Data
+
+ // GPIO 2
+ GpioIO(Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 2 }
+ GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 2 }
+ // GPIO 3
+ GpioIO(Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 3 }
+ GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 3 }
+ // GPIO 4
+ GpioIO(Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 4 }
+ GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 4 }
+ // GPIO 5
+ GpioIO(Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 5 }
+ GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 5 }
+ // GPIO 6
+ GpioIO(Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 6 }
+ GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 6 }
+ // GPIO 7
+ GpioIO(Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 7 }
+ GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 7 }
+ // GPIO 8
+ GpioIO(Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 8 }
+ GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 8 }
+ // GPIO 9
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 9 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 9 }
+ // GPIO 10
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 10 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 10 }
+ // GPIO 11
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 11 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 11 }
+ // GPIO 12
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 12 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 12 }
+ // GPIO 13
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 13 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 13 }
+ // NTRAID#MSFT-7141401-2016/04/7-jordanrh - disable UART muxing
+ // until a proper solution can be created for the dmap conflict
+ // GPIO 14 - UART TX
+ // GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 14 }
+ // GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 14 }
+ // GPIO 15 - UART RX
+ // GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 15 }
+ // GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 15 }
+ // GPIO 16
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 16 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 16 }
+ // GPIO 17
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 17 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 17 }
+ // GPIO 18
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 18 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 18 }
+ // GPIO 19
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 19 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 19 }
+ // GPIO 20
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 20 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 20 }
+ // GPIO 21
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 21 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 21 }
+ // GPIO 22
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 22 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 22 }
+ // GPIO 23
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 23 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 23 }
+ // GPIO 24
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 24 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 24 }
+ // GPIO 25
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 25 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 25 }
+ // GPIO 26
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 26 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 26 }
+ // GPIO 27
+ GpioIO(Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 27 }
+ GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 27 }
+ })
+
+ Name(_DSD, Package()
+ {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package()
+ {
+ // Reference http://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
+ // SPI 0
+ Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }}, // Index 0 & 1
+ Package(2) { "SPI0-MinClockInHz", 7629 }, // 7629 Hz
+ Package(2) { "SPI0-MaxClockInHz", 125000000 }, // 125 MHz
+ Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }}, // Data Bit Length
+ // I2C1
+ Package(2) { "bus-I2C-I2C1", Package() { 2 }},
+ // GPIO Pin Count and supported drive modes
+ Package (2) { "GPIO-PinCount", 54 },
+ Package (2) { "GPIO-UseDescriptorPinNumbers", 1 },
+ Package (2) { "GPIO-SupportedDriveModes", 0xf }, // InputHighImpedance, InputPullUp, InputPullDown, OutputCmos
+ // SPI 1
+ Package(2) { "bus-SPI-SPI1", Package() { 3 }}, // Index 3
+ Package(2) { "SPI1-MinClockInHz", 30511 }, // 30.5 kHz
+ Package(2) { "SPI1-MaxClockInHz", 20000000 }, // 20 MHz
+ Package(2) { "SPI1-SupportedDataBitLengths", Package() { 8 }}, // Data Bit Length
+ }
+ })
+}
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Sdhc.asl b/Platform/Broadcom/Bcm283x/AcpiTables/Sdhc.asl
new file mode 100644
index 000000000000..a39138ce5c5c
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Sdhc.asl
@@ -0,0 +1,105 @@
+/** @file
+ *
+ * [DSDT] SD controller/card definition (SDHC)
+ *
+ * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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.
+ *
+ **/
+
+//
+// Note: UEFI can use either SDHost or Arasan. We expose both to the OS.
+//
+
+//
+// Description: This is ArasanSD 3.0 SD Host Controller.
+//
+
+Device (SDC1)
+{
+ Name (_HID, "BCM2847")
+ Name (_CID, "ARASAN")
+ Name (_UID, 0x0)
+ Name (_S1D, 0x1)
+ Name (_S2D, 0x1)
+ Name (_S3D, 0x1)
+ Name (_S4D, 0x1)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ MEMORY32FIXED(ReadWrite, 0x3F300000, 0x100, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x5E }
+ })
+ Return(RBUF)
+ }
+
+ //
+ // A child device that represents the
+ // sd card, which is marked as non-removable.
+ //
+ Device (SDMM)
+ {
+ Method (_ADR)
+ {
+ Return (0)
+ }
+ Method (_RMV) // Is removable
+ {
+ Return (0) // 0 - fixed
+ }
+ }
+}
+
+
+//
+// Description: This is Broadcom SDHost 2.0 SD Host Controller
+//
+
+Device (SDC2)
+{
+ Name (_HID, "BCM2855")
+ Name (_CID, "SDHST")
+ Name (_UID, 0x0)
+ Name (_S1D, 0x1)
+ Name (_S2D, 0x1)
+ Name (_S3D, 0x1)
+ Name (_S4D, 0x1)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ MEMORY32FIXED(ReadWrite, 0x3F202000, 0x100, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x58 }
+ })
+ Return(RBUF)
+ }
+
+ //
+ // A child device that represents the
+ // sd card, which is marked as non-removable.
+ //
+ Device (SDMM)
+ {
+ Method (_ADR)
+ {
+ Return (0)
+ }
+ Method (_RMV) // Is removable
+ {
+ Return (0) // 0 - fixed
+ }
+ }
+}
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Spcr.asl b/Platform/Broadcom/Bcm283x/AcpiTables/Spcr.asl
new file mode 100644
index 000000000000..a6fbfd08e021
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Spcr.asl
@@ -0,0 +1,53 @@
+/** @file
+ *
+ * Serial Port Console Redirection Table (SPCR)
+ *
+ * Copyright (c) 2017-2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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.
+ *
+ **/
+
+[000h 0000 4] Signature : "SPCR" [Serial Port Console Redirection table]
+[004h 0004 4] Table Length : 00000050
+[008h 0008 1] Revision : 01
+[009h 0009 1] Checksum : 00
+[00Ah 0010 6] Oem ID : "RPiEFI"
+[010h 0016 8] Oem Table ID : "RPi3UEFI"
+[018h 0024 4] Oem Revision : 00000001
+[01Ch 0028 4] Asl Compiler ID : "----"
+[020h 0032 4] Asl Compiler Revision : 00000000
+
+[024h 0036 1] Interface Type : 10
+[025h 0037 3] Reserved : 000000
+
+[028h 0040 12] Serial Port Register : [Generic Address Structure]
+[028h 0040 1] Space ID : 00 [SystemMemory]
+[029h 0041 1] Bit Width : 20
+[02Ah 0042 1] Bit Offset : 00
+[02Bh 0043 1] Encoded Access Width : 02 [DWord Access:32]
+[02Ch 0044 8] Address : 000000003f215000
+
+[034h 0052 1] Interrupt Type : 0E
+[035h 0053 1] PCAT-compatible IRQ : 00
+[036h 0054 4] Interrupt : 3D
+[03Ah 0058 1] Baud Rate : 07
+[03Bh 0059 1] Parity : 00
+[03Ch 0060 1] Stop Bits : 01
+[03Dh 0061 1] Flow Control : 00
+[03Eh 0062 1] Terminal Type : 00
+[04Ch 0076 1] Reserved : 00
+[040h 0064 2] PCI Device ID : FFFF
+[042h 0066 2] PCI Vendor ID : FFFF
+[044h 0068 1] PCI Bus : 00
+[045h 0069 1] PCI Device : 00
+[046h 0070 1] PCI Function : 00
+[047h 0071 4] PCI Flags : 00000000
+[04Bh 0075 1] PCI Segment : 00
+[04Ch 0076 4] Reserved : 00000000
diff --git a/Platform/Broadcom/Bcm283x/AcpiTables/Uart.asl b/Platform/Broadcom/Bcm283x/AcpiTables/Uart.asl
new file mode 100644
index 000000000000..fa92cf24db91
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/AcpiTables/Uart.asl
@@ -0,0 +1,155 @@
+/** @file
+ *
+ * [DSDT] Serial devices (UART).
+ *
+ * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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.
+ *
+ **/
+
+//
+// Description: This is the PL011 based UART.
+//
+
+Device (URT0)
+{
+ Name (_HID, "BCM2837")
+ Name (_CID, "HID3123")
+ Name (_UID, 0x4)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ MEMORY32FIXED(ReadWrite, 0x3F201000, 0x1000, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 0x59 }
+ })
+ Return(RBUF)
+ }
+
+ Name (CLCK, 3000000)
+
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package (2) { "clock-frequency", CLCK },
+ }
+ })
+}
+
+//
+// Description: UART Mini.
+//
+// This device is referenced in the DBG2 table, which will cause the system to
+// not start the driver when the debugger is enabled and to mark the device
+// with problem code 53 (CM_PROB_USED_BY_DEBUGGER).
+//
+
+Device (URTM)
+{
+ Name (_HID, "BCM2836")
+ Name (_CID, "MINIUART")
+ Name (_UID, 0x0)
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ MEMORY32FIXED(ReadWrite, 0x3F215000, 0x70, )
+ Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) {0x3D}
+
+ // NTRAID#MSFT-7141401-2016/04/7-jordanrh - disable UART muxing
+ // until a proper solution can be created for the dmap conflict.
+ // When muxing is enabled, must consider DBG2 table conflict.
+ // The alternate function resource needs to be reserved when
+ // the kernel debugger is enabled to prevent another client
+ // from muxing the pins away.
+
+ //
+ // MsftFunctionConfig is encoded as the VendorLong.
+ //
+ // MsftFunctionConfig(Exclusive, PullDown, BCM_ALT5, "\\_SB.GPI0", 0, ResourceConsumer, ) {14, 15}
+ // VendorLong () // Length = 0x31
+ // {
+ // /* 0000 */ 0x00, 0x60, 0x44, 0xD5, 0xF3, 0x1F, 0x11, 0x60, // .`D....`
+ // /* 0008 */ 0x4A, 0xB8, 0xB0, 0x9C, 0x2D, 0x23, 0x30, 0xDD, // J...-#0.
+ // /* 0010 */ 0x2F, 0x8D, 0x1D, 0x00, 0x01, 0x10, 0x00, 0x02, // /.......
+ // /* 0018 */ 0x02, 0x00, 0x12, 0x00, 0x00, 0x16, 0x00, 0x20, // .......
+ // /* 0020 */ 0x00, 0x00, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x5C, // .......\
+ // /* 0028 */ 0x5F, 0x53, 0x42, 0x2E, 0x47, 0x50, 0x49, 0x30, // _SB.GPI0
+ // /* 0030 */ 0x00 // .
+ //}
+
+ })
+ Return(RBUF)
+ }
+}
+
+//
+// Multifunction serial bus device to support Bluetooth function.
+//
+
+Device(BTH0)
+{
+ Name (_HID, "BCM2EA6")
+ Name (_CID, "BCM2EA6")
+ Method (_STA)
+ {
+ Return(0xf)
+ }
+ Method (_CRS, 0x0, Serialized) {
+ Name (RBUF, ResourceTemplate () {
+ //
+ // BT UART: UART0 (PL011)
+ //
+ UARTSerialBus(
+ 115200, // InitialBaudRate: in BPS
+ , // BitsPerByte: default to 8 bits
+ , // StopBits: Defaults to one bit
+ 0x00, // LinesInUse: 8 1-bit flags to
+ // declare enabled control lines.
+ // Raspberry Pi does not exposed
+ // HW control signals -> not supported.
+ // Optional bits:
+ // - Bit 7 (0x80) Request To Send (RTS)
+ // - Bit 6 (0x40) Clear To Send (CTS)
+ // - Bit 5 (0x20) Data Terminal Ready (DTR)
+ // - Bit 4 (0x10) Data Set Ready (DSR)
+ // - Bit 3 (0x08) Ring Indicator (RI)
+ // - Bit 2 (0x04) Data Carrier Detect (DTD)
+ // - Bit 1 (0x02) Reserved. Must be 0.
+ // - Bit 0 (0x01) Reserved. Must be 0.
+ , // IsBigEndian:
+ // default to LittleEndian.
+ , // Parity: Defaults to no parity
+ , // FlowControl: Defaults to
+ // no flow control.
+ 16, // ReceiveBufferSize
+ 16, // TransmitBufferSize
+ "\\_SB.URT0", // ResourceSource:
+ // UART bus controller name
+ , // ResourceSourceIndex: assumed to be 0
+ , // ResourceUsage: assumed to be
+ // ResourceConsumer
+ UAR0, // DescriptorName: creates name
+ // for offset of resource descriptor
+ ) // Vendor data
+
+ //
+ // RPIQ connection for BT_ON/OFF
+ //
+ GpioIO(Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.RPIQ", 0, ResourceConsumer, , ) { 128 }
+ })
+ Return(RBUF)
+ }
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.c b/Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.c
new file mode 100644
index 000000000000..a070b6d5d8d9
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.c
@@ -0,0 +1,730 @@
+/** @file
+ *
+ * Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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 "ArasanMmcHostDxe.h"
+
+#define DEBUG_MMCHOST_SD DEBUG_VERBOSE
+
+BOOLEAN PreviousIsCardPresent = FALSE;
+UINT32 LastExecutedCommand = (UINT32) -1;
+
+STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol;
+
+/**
+ These SD commands are optional, according to the SD Spec
+**/
+BOOLEAN
+IgnoreCommand(
+ UINT32 Command
+ )
+{
+ switch (Command) {
+ case MMC_CMD20:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ Translates a generic SD command into the format used by the Arasan SD Host Controller
+**/
+UINT32
+TranslateCommand(
+ UINT32 Command,
+ UINT32 Argument
+ )
+{
+ UINT32 Translation = 0xffffffff;
+
+ if (LastExecutedCommand == CMD55) {
+ switch (Command) {
+ case MMC_CMD6:
+ Translation = ACMD6;
+ DEBUG((DEBUG_MMCHOST_SD, "ACMD6\n"));
+ break;
+ case MMC_ACMD22:
+ Translation = ACMD22;
+ DEBUG((DEBUG_MMCHOST_SD, "ACMD22\n"));
+ break;
+ case MMC_ACMD41:
+ Translation = ACMD41;
+ DEBUG((DEBUG_MMCHOST_SD, "ACMD41\n"));
+ break;
+ case MMC_ACMD51:
+ Translation = ACMD51;
+ DEBUG((DEBUG_MMCHOST_SD, "ACMD51\n"));
+ break;
+ default:
+ DEBUG((DEBUG_ERROR, "ArasanMMCHost: TranslateCommand(): Unrecognized App command: %d\n", Command));
+ }
+ } else {
+ switch (Command) {
+ case MMC_CMD0:
+ Translation = CMD0;
+ break;
+ case MMC_CMD1:
+ Translation = CMD1;
+ break;
+ case MMC_CMD2:
+ Translation = CMD2;
+ break;
+ case MMC_CMD3:
+ Translation = CMD3;
+ break;
+ case MMC_CMD5:
+ Translation = CMD5;
+ break;
+ case MMC_CMD6:
+ Translation = CMD6;
+ break;
+ case MMC_CMD7:
+ Translation = CMD7;
+ break;
+ case MMC_CMD8: {
+ if (Argument == CMD8_SD_ARG) {
+ Translation = CMD8_SD;
+ DEBUG((DEBUG_MMCHOST_SD, "Sending SD CMD8 variant\n"));
+ } else {
+ ASSERT (Argument == CMD8_MMC_ARG);
+ Translation = CMD8_MMC;
+ DEBUG((DEBUG_MMCHOST_SD, "Sending MMC CMD8 variant\n"));
+ }
+ break;
+ }
+ case MMC_CMD9:
+ Translation = CMD9;
+ break;
+ case MMC_CMD11:
+ Translation = CMD11;
+ break;
+ case MMC_CMD12:
+ Translation = CMD12;
+ break;
+ case MMC_CMD13:
+ Translation = CMD13;
+ break;
+ case MMC_CMD16:
+ Translation = CMD16;
+ break;
+ case MMC_CMD17:
+ Translation = CMD17;
+ break;
+ case MMC_CMD18:
+ Translation = CMD18;
+ break;
+ case MMC_CMD23:
+ Translation = CMD23;
+ break;
+ case MMC_CMD24:
+ Translation = CMD24;
+ break;
+ case MMC_CMD25:
+ Translation = CMD25;
+ break;
+ case MMC_CMD55:
+ Translation = CMD55;
+ break;
+ default:
+ DEBUG((DEBUG_ERROR, "ArasanMMCHost: TranslateCommand(): Unrecognized Command: %d\n", Command));
+ }
+ }
+
+ return Translation;
+}
+
+/**
+ Repeatedly polls a register until its value becomes correct, or until MAX_RETRY_COUNT polls is reached
+**/
+EFI_STATUS
+PollRegisterWithMask(
+ IN UINTN Register,
+ IN UINTN Mask,
+ IN UINTN ExpectedValue
+ )
+{
+ UINTN RetryCount = 0;
+
+ while (RetryCount < MAX_RETRY_COUNT) {
+ if ((MmioRead32(Register) & Mask) != ExpectedValue) {
+ RetryCount++;
+ gBS->Stall(STALL_AFTER_RETRY_US);
+ } else {
+ break;
+ }
+ }
+
+ if (RetryCount == MAX_RETRY_COUNT) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SoftReset(
+ IN UINT32 Mask
+ )
+{
+ MmioOr32(MMCHS_SYSCTL, Mask);
+ if (PollRegisterWithMask(MMCHS_SYSCTL, Mask, 0) == EFI_TIMEOUT) {
+ DEBUG((DEBUG_ERROR, "Failed to SoftReset with mask 0x%x\n", Mask));
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Calculate the clock divisor
+**/
+EFI_STATUS
+CalculateClockFrequencyDivisor(
+ IN UINTN TargetFrequency,
+ OUT UINT32 *DivisorValue,
+ OUT UINTN *ActualFrequency
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Divisor;
+ UINT32 BaseFrequency = 0;
+
+ Status = mFwProtocol->GetClockRate(RPI_FW_CLOCK_RATE_EMMC, &BaseFrequency);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Couldn't get RPI_FW_CLOCK_RATE_EMMC\n"));
+ return Status;
+ }
+
+ ASSERT (BaseFrequency != 0);
+ Divisor = BaseFrequency / TargetFrequency;
+
+ // Arasan controller is based on 3.0 spec so the div is multiple of 2
+ // Actual Frequency = BaseFequency/(Div*2)
+ Divisor /= 2;
+
+ if ((TargetFrequency < BaseFrequency) &&
+ (TargetFrequency * 2 * Divisor != BaseFrequency)) {
+ Divisor += 1;
+ }
+
+ if (Divisor > MAX_DIVISOR_VALUE) {
+ Divisor = MAX_DIVISOR_VALUE;
+ }
+
+ DEBUG((DEBUG_MMCHOST_SD, "ArasanMMCHost: BaseFrequency 0x%x Divisor 0x%x\n", BaseFrequency, Divisor));
+
+ *DivisorValue = (Divisor & 0xFF) << 8;
+ Divisor >>= 8;
+ *DivisorValue |= (Divisor & 0x03) << 6;
+
+ if (ActualFrequency) {
+ if (Divisor == 0) {
+ *ActualFrequency = BaseFrequency;
+ } else {
+ *ActualFrequency = BaseFrequency / Divisor;
+ *ActualFrequency >>= 1;
+ }
+ DEBUG((DEBUG_MMCHOST_SD, "ArasanMMCHost: *ActualFrequency 0x%x\n", *ActualFrequency));
+ }
+
+ DEBUG((DEBUG_MMCHOST_SD, "ArasanMMCHost: *DivisorValue 0x%x\n", *DivisorValue));
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+MMCIsCardPresent(
+ IN EFI_MMC_HOST_PROTOCOL *This
+ )
+{
+ return TRUE;
+}
+
+BOOLEAN
+MMCIsReadOnly(
+ IN EFI_MMC_HOST_PROTOCOL *This
+ )
+{
+ BOOLEAN IsReadOnly = !((MmioRead32(MMCHS_PRES_STATE) & WRITE_PROTECT_OFF) == WRITE_PROTECT_OFF);
+ DEBUG((DEBUG_MMCHOST_SD, "ArasanMMCHost: MMCIsReadOnly(): %d\n", IsReadOnly));
+ return IsReadOnly;
+}
+
+EFI_STATUS
+MMCBuildDevicePath(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
+ EFI_GUID DevicePathGuid = EFI_CALLER_ID_GUID;
+
+ DEBUG((DEBUG_MMCHOST_SD, "ArasanMMCHost: MMCBuildDevicePath()\n"));
+
+ NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof(VENDOR_DEVICE_PATH));
+ CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &DevicePathGuid);
+ *DevicePath = NewDevicePathNode;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MMCSendCommand(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_CMD MmcCmd,
+ IN UINT32 Argument
+ )
+{
+ UINTN MmcStatus;
+ UINTN RetryCount = 0;
+ UINTN CmdSendOKMask;
+ EFI_STATUS Status = EFI_SUCCESS;
+ BOOLEAN IsAppCmd = (LastExecutedCommand == CMD55);
+ BOOLEAN IsDATCmd = FALSE;
+ BOOLEAN IsADTCCmd = FALSE;
+
+ DEBUG((DEBUG_MMCHOST_SD, "ArasanMMCHost: MMCSendCommand(MmcCmd: %08x, Argument: %08x)\n", MmcCmd, Argument));
+
+ if (IgnoreCommand(MmcCmd)) {
+ return EFI_SUCCESS;
+ }
+
+ MmcCmd = TranslateCommand(MmcCmd, Argument);
+ if (MmcCmd == 0xffffffff) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((MmcCmd & CMD_R1_ADTC) == CMD_R1_ADTC) {
+ IsADTCCmd = TRUE;
+ }
+ if (((MmcCmd & CMD_R1B) == CMD_R1B &&
+ /*
+ * Abort commands don't get inhibited by DAT.
+ */
+ (MmcCmd & TYPE(CMD_TYPE_ABORT)) != TYPE(CMD_TYPE_ABORT)) ||
+ IsADTCCmd ||
+ /*
+ * We want to detect BRR/BWR change.
+ */
+ MmcCmd == CMD_SEND_STATUS) {
+ IsDATCmd = TRUE;
+ }
+
+ CmdSendOKMask = CMDI_MASK;
+ if (IsDATCmd) {
+ CmdSendOKMask |= DATI_MASK;
+ }
+
+ if (PollRegisterWithMask(MMCHS_PRES_STATE,
+ CmdSendOKMask, 0) == EFI_TIMEOUT) {
+ DEBUG((DEBUG_ERROR, "%a(%u): not ready for MMC_CMD%u PresState 0x%x MmcStatus 0x%x\n",
+ __FUNCTION__, __LINE__, MMC_CMD_NUM(MmcCmd),
+ MmioRead32(MMCHS_PRES_STATE),
+ MmioRead32(MMCHS_INT_STAT)));
+ Status = EFI_TIMEOUT;
+ goto out;
+ }
+
+ if (IsAppCmd && MmcCmd == ACMD22) {
+ MmioWrite32(MMCHS_BLK, 4);
+ } else if (IsAppCmd && MmcCmd == ACMD51) {
+ MmioWrite32(MMCHS_BLK, 8);
+ } else if (!IsAppCmd && MmcCmd == CMD6) {
+ MmioWrite32(MMCHS_BLK, 64);
+ } else if (IsADTCCmd) {
+ MmioWrite32(MMCHS_BLK, BLEN_512BYTES);
+ }
+
+ // Set Data timeout counter value to max value.
+ MmioAndThenOr32(MMCHS_SYSCTL, (UINT32) ~DTO_MASK, DTO_VAL);
+
+ //
+ // Clear Interrupt Status Register, but not the Card Inserted bit
+ // to avoid messing with card detection logic.
+ //
+ MmioWrite32(MMCHS_INT_STAT, ALL_EN & ~(CARD_INS));
+
+ // Set command argument register
+ MmioWrite32(MMCHS_ARG, Argument);
+
+ // Send the command
+ MmioWrite32(MMCHS_CMD, MmcCmd);
+
+ // Check for the command status.
+ while (RetryCount < MAX_RETRY_COUNT) {
+ MmcStatus = MmioRead32(MMCHS_INT_STAT);
+
+ // Read status of command response
+ if ((MmcStatus & ERRI) != 0) {
+ //
+ // CMD5 (CMD_IO_SEND_OP_COND) is only valid for SDIO
+ // cards and thus expected to fail.
+ //
+ if (MmcCmd != CMD_IO_SEND_OP_COND) {
+ DEBUG((DEBUG_ERROR, "%a(%u): MMC_CMD%u ERRI MmcStatus 0x%x\n",
+ __FUNCTION__, __LINE__, MMC_CMD_NUM(MmcCmd), MmcStatus));
+ }
+
+ SoftReset(SRC);
+
+ Status = EFI_DEVICE_ERROR;
+ goto out;
+ }
+
+ // Check if command is completed.
+ if ((MmcStatus & CC) == CC) {
+ MmioWrite32(MMCHS_INT_STAT, CC);
+ break;
+ }
+
+ RetryCount++;
+ gBS->Stall(STALL_AFTER_RETRY_US);
+ }
+
+ gBS->Stall(STALL_AFTER_SEND_CMD_US);
+
+ if (RetryCount == MAX_RETRY_COUNT) {
+ DEBUG((DEBUG_ERROR, "%a(%u): MMC_CMD%u completion TIMEOUT PresState 0x%x MmcStatus 0x%x\n",
+ __FUNCTION__, __LINE__, MMC_CMD_NUM(MmcCmd),
+ MmioRead32(MMCHS_PRES_STATE),
+ MmcStatus));
+ Status = EFI_TIMEOUT;
+ goto out;
+ }
+
+ out:
+ if (EFI_ERROR(Status)) {
+ LastExecutedCommand = (UINT32) -1;
+ } else {
+ LastExecutedCommand = MmcCmd;
+ }
+ return Status;
+}
+
+EFI_STATUS
+MMCNotifyState(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_STATE State
+ )
+{
+ DEBUG((DEBUG_MMCHOST_SD, "ArasanMMCHost: MMCNotifyState(State: %d)\n", State));
+
+ switch (State) {
+ case MmcHwInitializationState:
+ {
+ EFI_STATUS Status;
+ UINT32 Divisor;
+
+ Status = SoftReset(SRA);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ // Attempt to set the clock to 400Khz which is the expected initialization speed
+ Status = CalculateClockFrequencyDivisor(400000, &Divisor, NULL);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "ArasanMMCHost: MMCNotifyState(): Fail to initialize SD clock\n"));
+ return Status;
+ }
+
+ // Set Data Timeout Counter value, set clock frequency, enable internal clock
+ MmioOr32(MMCHS_SYSCTL, DTO_VAL | Divisor | CEN | ICS | ICE);
+
+ // Enable interrupts
+ MmioWrite32(MMCHS_IE, ALL_EN);
+ }
+ break;
+ case MmcIdleState:
+ break;
+ case MmcReadyState:
+ break;
+ case MmcIdentificationState:
+ break;
+ case MmcStandByState: {
+ EFI_STATUS Status;
+ UINTN ClockFrequency = 25000000;
+ UINT32 Divisor;
+
+ // First turn off the clock
+ MmioAnd32(MMCHS_SYSCTL, ~CEN);
+
+ Status = CalculateClockFrequencyDivisor(ClockFrequency, &Divisor, NULL);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "ArasanMMCHost: MmcStandByState(): Fail to initialize SD clock to %u Hz\n",
+ ClockFrequency));
+ return Status;
+ }
+
+ // Setup new divisor
+ MmioAndThenOr32(MMCHS_SYSCTL, (UINT32) ~CLKD_MASK, Divisor);
+
+ // Wait for the clock to stabilise
+ while ((MmioRead32(MMCHS_SYSCTL) & ICS_MASK) != ICS);
+
+ // Set Data Timeout Counter value, set clock frequency, enable internal clock
+ MmioOr32(MMCHS_SYSCTL, CEN);
+ }
+ break;
+ case MmcTransferState:
+ break;
+ case MmcSendingDataState:
+ break;
+ case MmcReceiveDataState:
+ break;
+ case MmcProgrammingState:
+ break;
+ case MmcDisconnectState:
+ case MmcInvalidState:
+ default:
+ DEBUG((DEBUG_ERROR, "ArasanMMCHost: MMCNotifyState(): Invalid State: %d\n", State));
+ ASSERT(0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MMCReceiveResponse(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_RESPONSE_TYPE Type,
+ IN UINT32* Buffer
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ if (Type == MMC_RESPONSE_TYPE_R2) {
+
+ // 16-byte response
+ Buffer[0] = MmioRead32(MMCHS_RSP10);
+ Buffer[1] = MmioRead32(MMCHS_RSP32);
+ Buffer[2] = MmioRead32(MMCHS_RSP54);
+ Buffer[3] = MmioRead32(MMCHS_RSP76);
+
+ Buffer[3] <<= 8;
+ Buffer[3] |= (Buffer[2] >> 24) & 0xFF;
+ Buffer[2] <<= 8;
+ Buffer[2] |= (Buffer[1] >> 24) & 0xFF;
+ Buffer[1] <<= 8;
+ Buffer[1] |= (Buffer[0] >> 24) & 0xFF;
+ Buffer[0] <<= 8;
+
+ DEBUG((
+ DEBUG_MMCHOST_SD,
+ "ArasanMMCHost: MMCReceiveResponse(Type: %x), Buffer[0-3]: %08x, %08x, %08x, %08x\n",
+ Type, Buffer[0], Buffer[1], Buffer[2], Buffer[3]));
+ } else {
+ // 4-byte response
+ Buffer[0] = MmioRead32(MMCHS_RSP10);
+ DEBUG((DEBUG_MMCHOST_SD, "ArasanMMCHost: MMCReceiveResponse(Type: %08x), Buffer[0]: %08x\n", Type, Buffer[0]));
+ }
+
+ gBS->Stall(STALL_AFTER_REC_RESP_US);
+ if (LastExecutedCommand == CMD_STOP_TRANSMISSION) {
+ DEBUG((DEBUG_MMCHOST_SD, "ArasanMMCHost: soft-resetting after CMD12\n"));
+ return SoftReset(SRC | SRD);
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MMCReadBlockData(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Length,
+ IN UINT32* Buffer
+ )
+{
+ UINTN MmcStatus;
+ UINTN RemLength;
+ UINTN Count;
+
+ DEBUG((DEBUG_VERBOSE, "%a(%u): LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n",
+ __FUNCTION__, __LINE__, Lba, Length, Buffer));
+
+ if (Buffer == NULL) {
+ DEBUG((DEBUG_ERROR, "%a(%u): NULL Buffer\n",
+ __FUNCTION__, __LINE__));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Length % sizeof(UINT32) != 0) {
+ DEBUG((DEBUG_ERROR, "%a(%u): bad Length %u\n",
+ __FUNCTION__, __LINE__, Length));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RemLength = Length;
+ while (RemLength != 0) {
+ UINTN RetryCount = 0;
+ UINT32 BlockLen = MIN(RemLength, BLEN_512BYTES);
+
+ while (RetryCount < MAX_RETRY_COUNT) {
+ MmcStatus = MmioRead32(MMCHS_INT_STAT);
+ if ((MmcStatus & BRR) != 0) {
+ MmioWrite32(MMCHS_INT_STAT, BRR);
+ /*
+ * Data is ready.
+ */
+ mFwProtocol->SetLed(TRUE);
+ for (Count = 0; Count < BlockLen; Count += 4, Buffer++) {
+ *Buffer = MmioRead32(MMCHS_DATA);
+ }
+
+ mFwProtocol->SetLed(FALSE);
+ break;
+ }
+
+ gBS->Stall(STALL_AFTER_RETRY_US);
+ RetryCount++;
+ }
+
+ if (RetryCount == MAX_RETRY_COUNT) {
+ DEBUG((DEBUG_ERROR, "%a(%u): %lu/%lu MMCHS_INT_STAT: %08x\n",
+ __FUNCTION__, __LINE__, Length - RemLength,
+ Length, MmcStatus));
+ return EFI_TIMEOUT;
+ }
+
+ RemLength -= BlockLen;
+ gBS->Stall(STALL_AFTER_READ_US);
+ }
+
+ MmioWrite32(MMCHS_INT_STAT, BRR);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MMCWriteBlockData(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Length,
+ IN UINT32* Buffer
+ )
+{
+ UINTN MmcStatus;
+ UINTN RemLength;
+ UINTN Count;
+
+ DEBUG((DEBUG_VERBOSE, "%a(%u): LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n",
+ __FUNCTION__, __LINE__, Lba, Length, Buffer));
+
+ if (Buffer == NULL) {
+ DEBUG((DEBUG_ERROR, "%a(%u): NULL Buffer\n",
+ __FUNCTION__, __LINE__));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Length % sizeof(UINT32) != 0) {
+ DEBUG((DEBUG_ERROR, "%a(%u): bad Length %u\n",
+ __FUNCTION__, __LINE__, Length));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RemLength = Length;
+ while (RemLength != 0) {
+ UINTN RetryCount = 0;
+ UINT32 BlockLen = MIN(RemLength, BLEN_512BYTES);
+
+ while (RetryCount < MAX_RETRY_COUNT) {
+ MmcStatus = MmioRead32(MMCHS_INT_STAT);
+ if ((MmcStatus & BWR) != 0) {
+ MmioWrite32(MMCHS_INT_STAT, BWR);
+ /*
+ * Can write data.
+ */
+ mFwProtocol->SetLed(TRUE);
+ for (Count = 0; Count < BlockLen; Count += 4, Buffer++) {
+ MmioWrite32(MMCHS_DATA, *Buffer);
+ }
+
+ mFwProtocol->SetLed(FALSE);
+ break;
+ }
+
+ gBS->Stall(STALL_AFTER_RETRY_US);
+ RetryCount++;
+ }
+
+ if (RetryCount == MAX_RETRY_COUNT) {
+ DEBUG((DEBUG_ERROR, "%a(%u): %lu/%lu MMCHS_INT_STAT: %08x\n",
+ __FUNCTION__, __LINE__, Length - RemLength,
+ Length, MmcStatus));
+ return EFI_TIMEOUT;
+ }
+
+ RemLength -= BlockLen;
+ gBS->Stall(STALL_AFTER_WRITE_US);
+ }
+
+ MmioWrite32(MMCHS_INT_STAT, BWR);
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+MMCIsMultiBlock (
+ IN EFI_MMC_HOST_PROTOCOL *This
+ )
+{
+ return TRUE;
+}
+
+EFI_MMC_HOST_PROTOCOL gMMCHost =
+ {
+ MMC_HOST_PROTOCOL_REVISION,
+ MMCIsCardPresent,
+ MMCIsReadOnly,
+ MMCBuildDevicePath,
+ MMCNotifyState,
+ MMCSendCommand,
+ MMCReceiveResponse,
+ MMCReadBlockData,
+ MMCWriteBlockData,
+ NULL,
+ MMCIsMultiBlock
+ };
+
+EFI_STATUS
+MMCInitialize(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle = NULL;
+
+ DEBUG((DEBUG_MMCHOST_SD, "ArasanMMCHost: MMCInitialize()\n"));
+
+ if (!PcdGet32 (PcdSdIsArasan)) {
+ DEBUG((DEBUG_INFO, "SD is not routed to Arasan\n"));
+ return EFI_REQUEST_UNLOAD_IMAGE;
+ }
+
+ Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid, NULL,
+ (VOID **)&mFwProtocol);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces(
+ &Handle,
+ &gRaspberryPiMmcHostProtocolGuid, &gMMCHost,
+ NULL
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ return Status;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.h b/Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.h
new file mode 100644
index 000000000000..6b4f0da4a425
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.h
@@ -0,0 +1,50 @@
+/** @file
+ *
+ * Copyright (c) Microsoft Corporation. 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 _MMC_HOST_DXE_H_
+#define _MMC_HOST_DXE_H_
+
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DmaLib.h>
+
+#include <Protocol/EmbeddedExternalDevice.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PiMmcHost.h>
+#include <Protocol/RaspberryPiFirmware.h>
+
+#include <IndustryStandard/Bcm2836.h>
+#include <IndustryStandard/Bcm2836MmcHs.h>
+#include <IndustryStandard/RpiFirmware.h>
+
+#define MAX_RETRY_COUNT (1000 * 20)
+
+#define STALL_AFTER_SEND_CMD_US (200) // in microseconds
+#define STALL_AFTER_REC_RESP_US (50)
+#define STALL_AFTER_WRITE_US (200)
+#define STALL_AFTER_READ_US (20)
+#define STALL_AFTER_RETRY_US (20)
+
+#define MAX_DIVISOR_VALUE 1023
+
+#endif
diff --git a/Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.inf
new file mode 100644
index 000000000000..4d70c1b72815
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.inf
@@ -0,0 +1,53 @@
+#/** @file
+#
+# Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) Microsoft Corporation. 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 = 0x00010005
+ BASE_NAME = ArasanMMCHost
+ FILE_GUID = 100c2cfa-b586-4198-9b4c-1683d195b1da
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = MMCInitialize
+
+
+[Sources.common]
+ ArasanMmcHostDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ PcdLib
+ UefiLib
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ IoLib
+ DmaLib
+ CacheMaintenanceLib
+
+[Guids]
+
+[Protocols]
+ gRaspberryPiMmcHostProtocolGuid ## PRODUCES
+ gRaspberryPiFirmwareProtocolGuid ## CONSUMES
+
+[Pcd]
+ gRaspberryPiTokenSpaceGuid.PcdSdIsArasan
+
+[Depex]
+ gRaspberryPiFirmwareProtocolGuid AND gRaspberryPiConfigAppliedProtocolGuid
diff --git a/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.c b/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.c
new file mode 100644
index 000000000000..dda61665031d
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.c
@@ -0,0 +1,367 @@
+/** @file
+ *
+ * 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/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <IndustryStandard/Bcm2836.h>
+
+#include <Protocol/Cpu.h>
+#include <Protocol/HardwareInterrupt.h>
+
+//
+// This currently only implements support for the architected timer interrupts
+// on the per-CPU interrupt controllers.
+//
+#define NUM_IRQS (4)
+
+#ifdef MDE_CPU_AARCH64
+#define ARM_ARCH_EXCEPTION_IRQ EXCEPT_AARCH64_IRQ
+#else
+#define ARM_ARCH_EXCEPTION_IRQ EXCEPT_ARM_IRQ
+#endif
+
+STATIC CONST
+EFI_PHYSICAL_ADDRESS RegBase = FixedPcdGet32 (PcdInterruptBaseAddress);
+
+//
+// Notifications
+//
+STATIC EFI_EVENT mExitBootServicesEvent;
+STATIC HARDWARE_INTERRUPT_HANDLER mRegisteredInterruptHandlers[NUM_IRQS];
+
+/**
+ Shutdown our hardware
+
+ DXE Core will disable interrupts and turn off the timer and disable interrupts
+ after all the event handlers have run.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+STATIC
+VOID
+EFIAPI
+ExitBootServicesEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ // Disable all interrupts
+ MmioWrite32 (RegBase + BCM2836_INTC_TIMER_CONTROL_OFFSET, 0);
+}
+
+/**
+ Enable interrupt source Source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+
+ @retval EFI_SUCCESS Source interrupt enabled.
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+EnableInterruptSource (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source
+ )
+{
+ if (Source >= NUM_IRQS) {
+ ASSERT(FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ MmioOr32 (RegBase + BCM2836_INTC_TIMER_CONTROL_OFFSET, 1 << Source);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Disable interrupt source Source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+
+ @retval EFI_SUCCESS Source interrupt disabled.
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+DisableInterruptSource (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source
+ )
+{
+ if (Source >= NUM_IRQS) {
+ ASSERT(FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ MmioAnd32 (RegBase + BCM2836_INTC_TIMER_CONTROL_OFFSET, ~(1 << Source));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register Handler for the specified interrupt source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+ @param Handler Callback for interrupt. NULL to unregister
+
+ @retval EFI_SUCCESS Source was updated to support Handler.
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+RegisterInterruptSource (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ IN HARDWARE_INTERRUPT_HANDLER Handler
+ )
+{
+ if (Source >= NUM_IRQS) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Handler == NULL && mRegisteredInterruptHandlers[Source] == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Handler != NULL && mRegisteredInterruptHandlers[Source] != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mRegisteredInterruptHandlers[Source] = Handler;
+ return EnableInterruptSource(This, Source);
+}
+
+
+/**
+ Return current state of interrupt source Source.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+ @param InterruptState TRUE: source enabled, FALSE: source disabled.
+
+ @retval EFI_SUCCESS InterruptState is valid
+ @retval EFI_DEVICE_ERROR InterruptState is not valid
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GetInterruptSourceState (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ IN BOOLEAN *InterruptState
+ )
+{
+ if (InterruptState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Source >= NUM_IRQS) {
+ ASSERT(FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ *InterruptState = (MmioRead32 (RegBase + BCM2836_INTC_TIMER_CONTROL_OFFSET) &
+ (1 << Source)) != 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Signal to the hardware that the End Of Intrrupt state
+ has been reached.
+
+ @param This Instance pointer for this protocol
+ @param Source Hardware source of the interrupt
+
+ @retval EFI_SUCCESS Source interrupt EOI'ed.
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+EndOfInterrupt (
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
+ IN HARDWARE_INTERRUPT_SOURCE Source
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
+
+ @param InterruptType Defines the type of interrupt or exception that
+ occurred on the processor.This parameter is processor
+ architecture specific.
+ @param SystemContext A pointer to the processor context when
+ the interrupt occurred on the processor.
+
+ @return None
+
+**/
+STATIC
+VOID
+EFIAPI
+IrqInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ HARDWARE_INTERRUPT_HANDLER InterruptHandler;
+ HARDWARE_INTERRUPT_SOURCE Source;
+ UINT32 RegVal;
+
+ RegVal = MmioRead32 (RegBase + BCM2836_INTC_TIMER_PENDING_OFFSET) &
+ ((1 << NUM_IRQS) - 1);
+ Source = HighBitSet32 (RegVal);
+ if (Source < 0) {
+ return;
+ }
+
+ InterruptHandler = mRegisteredInterruptHandlers [Source];
+ if (InterruptHandler != NULL) {
+ // Call the registered interrupt handler.
+ InterruptHandler (Source, SystemContext);
+ }
+}
+
+//
+// The protocol instance produced by this driver
+//
+STATIC EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {
+ RegisterInterruptSource,
+ EnableInterruptSource,
+ DisableInterruptSource,
+ GetInterruptSourceState,
+ EndOfInterrupt
+};
+
+STATIC VOID *mCpuArchProtocolNotifyEventRegistration;
+
+STATIC
+VOID
+EFIAPI
+CpuArchEventProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_CPU_ARCH_PROTOCOL *Cpu;
+ EFI_STATUS Status;
+
+ //
+ // Get the CPU protocol that this driver requires.
+ //
+ Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Unregister the default exception handler.
+ //
+ Status = Cpu->RegisterInterruptHandler(Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n",
+ __FUNCTION__, Status));
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // Register to receive interrupts
+ //
+ Status = Cpu->RegisterInterruptHandler(Cpu, ARM_ARCH_EXCEPTION_IRQ,
+ IrqInterruptHandler);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n",
+ __FUNCTION__, Status));
+ ASSERT (FALSE);
+ return;
+ }
+}
+
+
+/**
+ 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
+InterruptDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT CpuArchEvent;
+
+ // Make sure the Interrupt Controller Protocol is not already installed in the system.
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
+
+ Status = gBS->InstallMultipleProtocolInterfaces(
+ &ImageHandle,
+ &gHardwareInterruptProtocolGuid,
+ &gHardwareInterruptProtocol,
+ NULL);
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Install the interrupt handler as soon as the CPU arch protocol appears.
+ //
+ CpuArchEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiCpuArchProtocolGuid,
+ TPL_CALLBACK,
+ CpuArchEventProtocolNotify,
+ NULL,
+ &mCpuArchProtocolNotifyEventRegistration
+ );
+ ASSERT (CpuArchEvent != NULL);
+
+ // Register for an ExitBootServicesEvent
+ Status = gBS->CreateEvent(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY,
+ ExitBootServicesEvent, NULL, &mExitBootServicesEvent);
+
+ ASSERT_EFI_ERROR(Status);
+
+ return Status;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.inf
new file mode 100644
index 000000000000..831ae1bfeeab
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.inf
@@ -0,0 +1,48 @@
+#/** @file
+#
+# Copyright (c) 2017, 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 = 0x00010019
+ BASE_NAME = Bcm2836InterruptDxe
+ FILE_GUID = 3944f2d7-2e09-4fc0-9e98-008375641453
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InterruptDxeInitialize
+
+[Sources]
+ Bcm2836InterruptDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ IoLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gHardwareInterruptProtocolGuid ## PRODUCES
+ gEfiCpuArchProtocolGuid ## CONSUMES ## NOTIFY
+
+[FixedPcd]
+ gEmbeddedTokenSpaceGuid.PcdInterruptBaseAddress
+
+[Depex]
+ TRUE
diff --git a/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxe.c b/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxe.c
new file mode 100644
index 000000000000..4e3c68ca2994
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxe.c
@@ -0,0 +1,356 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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 <Uefi.h>
+#include <Library/HiiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/GpioLib.h>
+#include <Protocol/RaspberryPiFirmware.h>
+#include <IndustryStandard/RpiFirmware.h>
+#include "ConfigDxeFormSetGuid.h"
+
+extern UINT8 ConfigDxeHiiBin[];
+extern UINT8 ConfigDxeStrings[];
+
+STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol;
+
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+STATIC HII_VENDOR_DEVICE_PATH mVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ CONFIGDXE_FORM_SET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+
+STATIC EFI_STATUS
+InstallHiiPages (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+
+ DriverHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mVendorDevicePath,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HiiHandle = HiiAddPackages (&gConfigDxeFormSetGuid,
+ DriverHandle,
+ ConfigDxeStrings,
+ ConfigDxeHiiBin,
+ NULL);
+
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mVendorDevicePath,
+ NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ return EFI_SUCCESS;
+}
+
+
+STATIC EFI_STATUS
+SetupVariables (
+ VOID
+ )
+{
+ UINTN Size;
+ UINT32 Var32;
+ EFI_STATUS Status;
+
+ /*
+ * Create the vars with default value.
+ * If we don't, forms won't be able to update.
+ */
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"CpuClock",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdCpuClock, PcdGet32 (PcdCpuClock));
+ }
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"SdIsArasan",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdSdIsArasan, PcdGet32 (PcdSdIsArasan));
+ }
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"MmcDisableMulti",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdMmcDisableMulti, PcdGet32 (PcdMmcDisableMulti));
+ }
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"MmcForce1Bit",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdMmcForce1Bit, PcdGet32 (PcdMmcForce1Bit));
+ }
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"MmcForceDefaultSpeed",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdMmcForceDefaultSpeed, PcdGet32 (PcdMmcForceDefaultSpeed));
+ }
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"MmcSdDefaultSpeedMHz",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdMmcSdDefaultSpeedMHz, PcdGet32 (PcdMmcSdDefaultSpeedMHz));
+ }
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"MmcSdHighSpeedMHz",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdMmcSdHighSpeedMHz, PcdGet32 (PcdMmcSdHighSpeedMHz));
+ }
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"DebugEnableJTAG",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdDebugEnableJTAG, PcdGet32 (PcdDebugEnableJTAG));
+ }
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"DebugShowUEFIExit",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdDebugShowUEFIExit, PcdGet32 (PcdDebugShowUEFIExit));
+ }
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"DisplayEnableVModes",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdDisplayEnableVModes, PcdGet32 (PcdDisplayEnableVModes));
+ }
+
+ Size = sizeof (UINT32);
+ Status = gRT->GetVariable(L"DisplayEnableSShot",
+ &gConfigDxeFormSetGuid,
+ NULL, &Size, &Var32);
+ if (EFI_ERROR (Status)) {
+ PcdSet32 (PcdDisplayEnableSShot, PcdGet32 (PcdDisplayEnableSShot));
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+STATIC VOID
+ApplyVariables (
+ VOID
+ )
+{
+ UINTN Gpio34Group;
+ UINTN Gpio48Group;
+ EFI_STATUS Status;
+ UINT32 CpuClock = PcdGet32 (PcdCpuClock);
+ UINT32 Rate = 0;
+
+ if (CpuClock != 0) {
+ if (CpuClock == 2) {
+ /*
+ * Maximum: 1.2GHz on RPi 3, 1.4GHz on RPi 3B+, unless
+ * overridden with arm_freq=xxx in config.txt.
+ */
+ Status = mFwProtocol->GetMaxClockRate(RPI_FW_CLOCK_RATE_ARM, &Rate);
+ if (Status != EFI_SUCCESS) {
+ DEBUG((DEBUG_ERROR, "Couldn't get the max CPU speed, leaving as is: %r\n",
+ Status));
+ }
+ } else {
+ Rate = 600 * 1000000;
+ }
+ }
+
+ if (Rate != 0) {
+ DEBUG((DEBUG_INFO, "Setting CPU speed to %uHz\n", Rate));
+ Status = mFwProtocol->SetClockRate(RPI_FW_CLOCK_RATE_ARM, Rate);
+ if (Status != EFI_SUCCESS) {
+ DEBUG((DEBUG_ERROR, "Couldn't set the CPU speed: %r\n",
+ Status));
+ }
+ }
+
+ Status = mFwProtocol->GetClockRate(RPI_FW_CLOCK_RATE_ARM, &Rate);
+ if (Status != EFI_SUCCESS) {
+ DEBUG((DEBUG_ERROR, "Couldn't get the CPU speed: %r\n",
+ Status));
+ } else {
+ DEBUG((DEBUG_INFO, "Current CPU speed is %uHz\n", Rate));
+ }
+
+ /*
+ * Switching two groups around, so disable both first.
+ *
+ * No, I've not seen a problem, but having a group be
+ * routed to two sets of pins seems like asking for trouble.
+ */
+ GpioPinFuncSet(34, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(35, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(36, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(37, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(38, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(39, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(48, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(49, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(50, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(51, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(52, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(53, GPIO_FSEL_INPUT);
+ if (PcdGet32 (PcdSdIsArasan)) {
+ DEBUG((DEBUG_INFO, "Routing SD to Arasan\n"));
+ Gpio48Group = GPIO_FSEL_ALT3;
+ /*
+ * Route SDIO to SdHost.
+ */
+ Gpio34Group = GPIO_FSEL_ALT0;
+ } else {
+ DEBUG((DEBUG_INFO, "Routing SD to SdHost\n"));
+ Gpio48Group = GPIO_FSEL_ALT0;
+ /*
+ * Route SDIO to Arasan.
+ */
+ Gpio34Group = GPIO_FSEL_ALT3;
+ }
+ GpioPinFuncSet(34, Gpio34Group);
+ GpioPinFuncSet(35, Gpio34Group);
+ GpioPinFuncSet(36, Gpio34Group);
+ GpioPinFuncSet(37, Gpio34Group);
+ GpioPinFuncSet(38, Gpio34Group);
+ GpioPinFuncSet(39, Gpio34Group);
+ GpioPinFuncSet(48, Gpio48Group);
+ GpioPinFuncSet(49, Gpio48Group);
+ GpioPinFuncSet(50, Gpio48Group);
+ GpioPinFuncSet(51, Gpio48Group);
+ GpioPinFuncSet(52, Gpio48Group);
+ GpioPinFuncSet(53, Gpio48Group);
+
+ /*
+ * JTAG pin JTAG sig GPIO Mode Header pin
+ * 1 VREF N/A 1
+ * 3 nTRST GPIO22 ALT4 15
+ * 4 GND N/A 9
+ * 5 TDI GPIO4 ALT5 7
+ * 7 TMS GPIO27 ALT4 13
+ * 9 TCK GPIO25 ALT4 22
+ * 11 RTCK GPIO23 ALT4 16
+ * 13 TDO GPIO24 ALT4 18
+ */
+ if (PcdGet32 (PcdDebugEnableJTAG)) {
+ GpioPinFuncSet(22, GPIO_FSEL_ALT4);
+ GpioPinFuncSet(4, GPIO_FSEL_ALT5);
+ GpioPinFuncSet(27, GPIO_FSEL_ALT4);
+ GpioPinFuncSet(25, GPIO_FSEL_ALT4);
+ GpioPinFuncSet(23, GPIO_FSEL_ALT4);
+ GpioPinFuncSet(24, GPIO_FSEL_ALT4);
+ } else {
+ GpioPinFuncSet(22, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(4, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(27, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(25, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(23, GPIO_FSEL_INPUT);
+ GpioPinFuncSet(24, GPIO_FSEL_INPUT);
+ }
+}
+
+
+EFI_STATUS
+EFIAPI
+ConfigInitialize(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid,
+ NULL, (VOID **)&mFwProtocol);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SetupVariables();
+ if (Status != EFI_SUCCESS) {
+ DEBUG((DEBUG_ERROR, "Couldn't not setup NV vars: %r\n",
+ Status));
+ }
+
+ ApplyVariables();
+ Status = gBS->InstallProtocolInterface (&ImageHandle,
+ &gRaspberryPiConfigAppliedProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = InstallHiiPages();
+ if (Status != EFI_SUCCESS) {
+ DEBUG((DEBUG_ERROR, "Couldn't install ConfigDxe configuration pages: %r\n",
+ Status));
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxe.inf
new file mode 100644
index 000000000000..1eb429de1ae0
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxe.inf
@@ -0,0 +1,81 @@
+#/** @file
+#
+# Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+#
+# 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 = 0x00010005
+ BASE_NAME = ConfigDxe
+ FILE_GUID = 755cbac2-b23f-4b92-bc8e-fb01ce5907b7
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ConfigInitialize
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = AARCH64
+#
+
+[Sources]
+ ConfigDxe.c
+ ConfigDxeHii.vfr
+ ConfigDxeHii.uni
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ DxeServicesTableLib
+ PcdLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ HiiLib
+ GpioLib
+
+[Guids]
+ gConfigDxeFormSetGuid
+
+[Protocols]
+ gRaspberryPiFirmwareProtocolGuid ## CONSUMES
+ gRaspberryPiConfigAppliedProtocolGuid ## PRODUCES
+
+[Pcd]
+ gRaspberryPiTokenSpaceGuid.PcdHypEnable
+ gRaspberryPiTokenSpaceGuid.PcdHypLogMask
+ gRaspberryPiTokenSpaceGuid.PcdHypWindowsDebugHook
+ gRaspberryPiTokenSpaceGuid.PcdHypWin2000Mask
+ gRaspberryPiTokenSpaceGuid.PcdCpuClock
+ gRaspberryPiTokenSpaceGuid.PcdSdIsArasan
+ gRaspberryPiTokenSpaceGuid.PcdMmcForce1Bit
+ gRaspberryPiTokenSpaceGuid.PcdMmcForceDefaultSpeed
+ gRaspberryPiTokenSpaceGuid.PcdMmcSdDefaultSpeedMHz
+ gRaspberryPiTokenSpaceGuid.PcdMmcSdHighSpeedMHz
+ gRaspberryPiTokenSpaceGuid.PcdMmcDisableMulti
+ gRaspberryPiTokenSpaceGuid.PcdDebugEnableJTAG
+ gRaspberryPiTokenSpaceGuid.PcdDebugShowUEFIExit
+ gRaspberryPiTokenSpaceGuid.PcdDisplayEnableVModes
+ gRaspberryPiTokenSpaceGuid.PcdDisplayEnableSShot
+
+[FeaturePcd]
+
+[Depex]
+ gPcdProtocolGuid AND gRaspberryPiFirmwareProtocolGuid
diff --git a/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeFormSetGuid.h b/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeFormSetGuid.h
new file mode 100644
index 000000000000..b29ae3a42461
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeFormSetGuid.h
@@ -0,0 +1,23 @@
+/** @file
+ *
+ * Copyright (c) 2018 Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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 CONFIGDXE_FORM_SET_GUID_H
+#define CONFIGDXE_FORM_SET_GUID_H
+
+#define CONFIGDXE_FORM_SET_GUID \
+ {0xCD7CC258, 0x31DB, 0x22E6, {0x9F, 0x22, 0x63, 0xB0, 0xB8, 0xEE, 0xD6, 0xB5}}
+
+extern EFI_GUID gConfigDxeFormSetGuid;
+
+#endif /* CONFIGDXE_FORM_SET_GUID_H */
diff --git a/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeHii.uni b/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeHii.uni
new file mode 100644
index 000000000000..bf09261d5e4a
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeHii.uni
@@ -0,0 +1,100 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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.
+ *
+ **/
+
+#langdef en-US "English"
+
+#string STR_NULL_STRING #language en-US ""
+
+#string STR_FORM_SET_TITLE #language en-US "Raspberry Pi Configuration"
+#string STR_FORM_SET_TITLE_HELP #language en-US "Press <Enter> to configure system settings."
+
+/*
+ * Chipset config.
+ */
+
+#string STR_CHIPSET_FORM_TITLE #language en-US "Chipset Configuration"
+#string STR_CHIPSET_FORM_SUBTITLE #language en-US "Note: OS may override settings when booted."
+
+#string STR_CHIPSET_CLOCK_CPU_PROMPT #language en-US "CPU Clock"
+#string STR_CHIPSET_CLOCK_CPU_HELP #language en-US "CPU Speed"
+#string STR_CHIPSET_CLOCK_CPU_NA #language en-US "Don't Override"
+#string STR_CHIPSET_CLOCK_CPU_600MHZ #language en-US "Min (600MHz)"
+#string STR_CHIPSET_CLOCK_CPU_MAX #language en-US "Max"
+
+#string STR_CHIPSET_SD_PROMPT #language en-US "uSD Routing"
+#string STR_CHIPSET_SD_HELP #language en-US "Choose host controller to drive uSD slot"
+#string STR_CHIPSET_SD_SDHOST #language en-US "Broadcom SDHOST"
+#string STR_CHIPSET_SD_ARASAN #language en-US "Arasan SDHCI"
+
+/*
+ * MMC/SD configuration.
+ */
+
+#string STR_MMC_FORM_TITLE #language en-US "SD/MMC Tweaks"
+#string STR_MMC_FORM_SUBTITLE #language en-US "Note: UEFI only, OS will override settings when booted."
+
+#string STR_MMC_DISMULTI_PROMPT #language en-US "Multi-Block Support"
+#string STR_MMC_DISMULTI_HELP #language en-US "Use CMD18/CMD25 for transfers when possible"
+#string STR_MMC_DISMULTI_N #language en-US "Multi-block transfers"
+#string STR_MMC_DISMULTI_Y #language en-US "Single-block transfers"
+
+#string STR_MMC_FORCE1BIT_PROMPT #language en-US "uSD Max Bus Width"
+#string STR_MMC_FORCE1BIT_HELP #language en-US "Tweak for bad media"
+#string STR_MMC_FORCE1BIT_Y #language en-US "1 Bit Mode"
+#string STR_MMC_FORCE1BIT_N #language en-US "4 Bit Mode"
+
+#string STR_MMC_FORCEDS_PROMPT #language en-US "uSD Force Default Speed"
+#string STR_MMC_FORCEDS_HELP #language en-US "Tweak for bad media"
+#string STR_MMC_FORCEDS_Y #language en-US "Force Default Speed"
+#string STR_MMC_FORCEDS_N #language en-US "Allow High Speed"
+
+#string STR_MMC_SD_DS_PROMPT #language en-US "SD Default Speed (MHz)"
+#string STR_MMC_SD_DS_HELP #language en-US "Override default 25Mhz"
+
+#string STR_MMC_SD_HS_PROMPT #language en-US "SD High Speed (MHz)"
+#string STR_MMC_SD_HS_HELP #language en-US "Override default 50Mhz"
+
+
+/*
+ * Display settings.
+ */
+
+#string STR_DISPLAY_FORM_TITLE #language en-US "Display"
+#string STR_DISPLAY_FORM_SUBTITLE #language en-US "UEFI video driver settings"
+
+#string STR_DISPLAY_VMODES_PROMPT #language en-US "Resolutions"
+#string STR_DISPLAY_VMODES_HELP #language en-US "Support for non-native modes"
+#string STR_DISPLAY_VMODES_ENABLE #language en-US "Also support 640x480, 800x600, 1024x768, 720p and 1080p"
+#string STR_DISPLAY_VMODES_DISABLE #language en-US "Only native resolution"
+
+#string STR_DISPLAY_SSHOT_PROMPT #language en-US "Screenshot Support"
+#string STR_DISPLAY_SSHOT_HELP #language en-US "Save screen capture as a BMP on the first writable file system found"
+#string STR_DISPLAY_SSHOT_ENABLE #language en-US "Control-Alt-F12"
+#string STR_DISPLAY_SSHOT_DISABLE #language en-US "Not Enabled"
+
+/*
+ * Debugging settings go here.
+ */
+#string STR_DEBUG_FORM_TITLE #language en-US "Debugging"
+#string STR_DEBUG_FORM_SUBTITLE #language en-US "For UEFI/OS Developers"
+
+#string STR_DEBUG_JTAG_PROMPT #language en-US "JTAG Routing"
+#string STR_DEBUG_JTAG_HELP #language en-US "Signals (nTRST, TDI, TMS, TCK, RTCK, TDO) -> Header pins (15, 7, 13, 22, 16, 18)"
+#string STR_DEBUG_JTAG_ENABLE #language en-US "Enable JTAG via GPIO"
+#string STR_DEBUG_JTAG_DISABLE #language en-US "Disable JTAG"
+
+#string STR_DEBUG_EXIT_SHOW_PROMPT #language en-US "Verbose ExitBootServices"
+#string STR_DEBUG_EXIT_SHOW_HELP #language en-US "Show message when UEFI hands off to OS"
+#string STR_DEBUG_EXIT_SHOW_NO #language en-US "Do nothing"
+#string STR_DEBUG_EXIT_SHOW_YES #language en-US "Show farewell message"
diff --git a/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeHii.vfr b/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeHii.vfr
new file mode 100644
index 000000000000..d3d98acc2edf
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxeHii.vfr
@@ -0,0 +1,306 @@
+/** @file
+ *
+ * Copyright (c) 2018 Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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 <Guid/HiiPlatformSetupFormset.h>
+#include "ConfigDxeFormSetGuid.h"
+
+typedef struct {
+ /*
+ * 0 - One mode for the boot resolution.
+ * 1 - Adds additional "typical" resolutions like
+ * 640x480, 800x600, 1024 x 768, 720p and 1080p.
+ */
+ UINT32 Enable;
+} DISPLAY_ENABLE_VMODES_VARSTORE_DATA;
+
+typedef struct {
+ /*
+ * 0 - No screenshot support.
+ * 1 - Screenshot support via hotkey.
+ */
+ UINT32 Enable;
+} DISPLAY_ENABLE_SSHOT_VARSTORE_DATA;
+
+typedef struct {
+ /*
+ * 0 - No JTAG.
+ * 1 - JTAG mode.
+ */
+ UINT32 Enable;
+} DEBUG_ENABLE_JTAG_VARSTORE_DATA;
+
+typedef struct {
+ /*
+ * 0 - Don't show UEFI exit message.
+ * 1 - Show UEFI exit message.
+ */
+ UINT32 Show;
+} DEBUG_SHOW_UEFI_EXIT_VARSTORE_DATA;
+
+typedef struct {
+ /*
+ * 0 - don't change the clock rate.
+ * 1 - 600MHz.
+ * 2 - maximum.
+ */
+ UINT32 Clock;
+} CHIPSET_CPU_CLOCK_VARSTORE_DATA;
+
+typedef struct {
+ /*
+ * 0 - uSD slot routed to Broadcom SDHOST.
+ * 1 - uSD slot routed to Arasan SDHCI.
+ */
+ UINT32 Routing;
+} CHIPSET_SD_VARSTORE_DATA;
+
+typedef struct {
+ /*
+ * 0 - Don't disable multi-block.
+ * 1 - Disable multi-block commands.
+ */
+ UINT32 DisableMulti;
+} MMC_DISMULTI_VARSTORE_DATA;
+
+typedef struct {
+ /*
+ * 0 - Don't force 1 bit mode.
+ * 1 - Force 1 bit mode.
+ */
+ UINT32 Force1Bit;
+} MMC_FORCE1BIT_VARSTORE_DATA;
+
+typedef struct {
+ /*
+ * 0 - Don't force default speed.
+ * 1 - Force default speed.
+ */
+ UINT32 ForceDS;
+} MMC_FORCEDS_VARSTORE_DATA;
+
+typedef struct {
+ /*
+ * Default Speed MHz override (25MHz default).
+ */
+ UINT32 MHz;
+} MMC_SD_DS_MHZ_VARSTORE_DATA;
+
+typedef struct {
+ /*
+ * High Speed MHz override (50MHz default).
+ */
+ UINT32 MHz;
+} MMC_SD_HS_MHZ_VARSTORE_DATA;
+
+//
+// EFI Variable attributes
+//
+#define EFI_VARIABLE_NON_VOLATILE 0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
+#define EFI_VARIABLE_READ_ONLY 0x00000008
+
+formset
+ guid = CONFIGDXE_FORM_SET_GUID,
+ title = STRING_TOKEN(STR_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ efivarstore CHIPSET_CPU_CLOCK_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = CpuClock,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ efivarstore CHIPSET_SD_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = SdIsArasan,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ efivarstore MMC_DISMULTI_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = MmcDisableMulti,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ efivarstore MMC_FORCE1BIT_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = MmcForce1Bit,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ efivarstore MMC_FORCEDS_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = MmcForceDefaultSpeed,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ efivarstore MMC_SD_DS_MHZ_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = MmcSdDefaultSpeedMHz,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ efivarstore MMC_SD_HS_MHZ_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = MmcSdHighSpeedMHz,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ efivarstore DEBUG_ENABLE_JTAG_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = DebugEnableJTAG,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ efivarstore DEBUG_SHOW_UEFI_EXIT_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = DebugShowUEFIExit,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ efivarstore DISPLAY_ENABLE_VMODES_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = DisplayEnableVModes,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ efivarstore DISPLAY_ENABLE_SSHOT_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = DisplayEnableSShot,
+ guid = CONFIGDXE_FORM_SET_GUID;
+
+ form formid = 1,
+ title = STRING_TOKEN(STR_FORM_SET_TITLE);
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ goto 0x1002,
+ prompt = STRING_TOKEN(STR_CHIPSET_FORM_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING);
+
+ goto 0x1003,
+ prompt = STRING_TOKEN(STR_MMC_FORM_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING);
+
+ goto 0x1004,
+ prompt = STRING_TOKEN(STR_DISPLAY_FORM_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING);
+
+ goto 0x1005,
+ prompt = STRING_TOKEN(STR_DEBUG_FORM_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING);
+ endform;
+
+ form formid = 0x1002,
+ title = STRING_TOKEN(STR_CHIPSET_FORM_TITLE);
+ subtitle text = STRING_TOKEN(STR_CHIPSET_FORM_SUBTITLE);
+
+ oneof varid = CpuClock.Clock,
+ prompt = STRING_TOKEN(STR_CHIPSET_CLOCK_CPU_PROMPT),
+ help = STRING_TOKEN(STR_CHIPSET_CLOCK_CPU_HELP),
+ flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_CHIPSET_CLOCK_CPU_NA), value = 0, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_CHIPSET_CLOCK_CPU_600MHZ), value = 1, flags = 0;
+ option text = STRING_TOKEN(STR_CHIPSET_CLOCK_CPU_MAX), value = 2, flags = 0;
+ endoneof;
+
+ oneof varid = SdIsArasan.Routing,
+ prompt = STRING_TOKEN(STR_CHIPSET_SD_PROMPT),
+ help = STRING_TOKEN(STR_CHIPSET_SD_HELP),
+ flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_CHIPSET_SD_ARASAN), value = 1, flags = 0;
+ option text = STRING_TOKEN(STR_CHIPSET_SD_SDHOST), value = 0, flags = DEFAULT;
+ endoneof;
+ endform;
+
+ form formid = 0x1003,
+ title = STRING_TOKEN(STR_MMC_FORM_TITLE);
+ subtitle text = STRING_TOKEN(STR_MMC_FORM_SUBTITLE);
+
+ oneof varid = MmcDisableMulti.DisableMulti,
+ prompt = STRING_TOKEN(STR_MMC_DISMULTI_PROMPT),
+ help = STRING_TOKEN(STR_MMC_DISMULTI_HELP),
+ flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_MMC_DISMULTI_N), value = 0, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_MMC_DISMULTI_Y), value = 1, flags = 0;
+ endoneof;
+
+ oneof varid = MmcForce1Bit.Force1Bit,
+ prompt = STRING_TOKEN(STR_MMC_FORCE1BIT_PROMPT),
+ help = STRING_TOKEN(STR_MMC_FORCE1BIT_HELP),
+ flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_MMC_FORCE1BIT_N), value = 0, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_MMC_FORCE1BIT_Y), value = 1, flags = 0;
+ endoneof;
+
+ oneof varid = MmcForceDefaultSpeed.ForceDS,
+ prompt = STRING_TOKEN(STR_MMC_FORCEDS_PROMPT),
+ help = STRING_TOKEN(STR_MMC_FORCEDS_HELP),
+ flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_MMC_FORCEDS_N), value = 0, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_MMC_FORCEDS_Y), value = 1, flags = 0;
+ endoneof;
+
+ numeric varid = MmcSdDefaultSpeedMHz.MHz,
+ prompt = STRING_TOKEN(STR_MMC_SD_DS_PROMPT),
+ help = STRING_TOKEN(STR_MMC_SD_DS_HELP),
+ flags = DISPLAY_UINT_DEC | NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ minimum = 25,
+ maximum = 100,
+ default = 25,
+ endnumeric;
+
+ numeric varid = MmcSdHighSpeedMHz.MHz,
+ prompt = STRING_TOKEN(STR_MMC_SD_HS_PROMPT),
+ help = STRING_TOKEN(STR_MMC_SD_HS_HELP),
+ flags = DISPLAY_UINT_DEC | NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ minimum = 50,
+ maximum = 100,
+ default = 50,
+ endnumeric;
+ endform;
+
+ form formid = 0x1004,
+ title = STRING_TOKEN(STR_DISPLAY_FORM_TITLE);
+ subtitle text = STRING_TOKEN(STR_DISPLAY_FORM_SUBTITLE);
+
+ oneof varid = DisplayEnableVModes.Enable,
+ prompt = STRING_TOKEN(STR_DISPLAY_VMODES_PROMPT),
+ help = STRING_TOKEN(STR_DISPLAY_VMODES_HELP),
+ flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_DISPLAY_VMODES_ENABLE), value = 1, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_DISPLAY_VMODES_DISABLE), value = 0, flags = 0;
+ endoneof;
+
+ oneof varid = DisplayEnableSShot.Enable,
+ prompt = STRING_TOKEN(STR_DISPLAY_SSHOT_PROMPT),
+ help = STRING_TOKEN(STR_DISPLAY_SSHOT_HELP),
+ flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_DISPLAY_SSHOT_ENABLE), value = 1, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_DISPLAY_SSHOT_DISABLE), value = 0, flags = 0;
+ endoneof;
+ endform;
+
+ form formid = 0x1005,
+ title = STRING_TOKEN(STR_DEBUG_FORM_TITLE);
+ subtitle text = STRING_TOKEN(STR_DEBUG_FORM_SUBTITLE);
+
+ oneof varid = DebugEnableJTAG.Enable,
+ prompt = STRING_TOKEN(STR_DEBUG_JTAG_PROMPT),
+ help = STRING_TOKEN(STR_DEBUG_JTAG_HELP),
+ flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_DEBUG_JTAG_ENABLE), value = 1, flags = 0;
+ option text = STRING_TOKEN(STR_DEBUG_JTAG_DISABLE), value = 0, flags = DEFAULT;
+ endoneof;
+
+ oneof varid = DebugShowUEFIExit.Show,
+ prompt = STRING_TOKEN(STR_DEBUG_EXIT_SHOW_PROMPT),
+ help = STRING_TOKEN(STR_DEBUG_EXIT_SHOW_HELP),
+ flags = NUMERIC_SIZE_4 | INTERACTIVE,
+ option text = STRING_TOKEN(STR_DEBUG_EXIT_SHOW_NO), value = 0, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_DEBUG_EXIT_SHOW_YES), value = 1, flags = 0;
+ endoneof;
+ endform;
+endformset;
diff --git a/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/ComponentName.c b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/ComponentName.c
new file mode 100644
index 000000000000..e639826c60b1
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/ComponentName.c
@@ -0,0 +1,222 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2006-2016, Intel Corporation. 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 "DisplayDxe.h"
+
+STATIC
+EFI_STATUS
+EFIAPI
+ComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+);
+
+STATIC
+EFI_STATUS
+EFIAPI
+ComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
+ ComponentNameGetDriverName,
+ ComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) ComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) ComponentNameGetControllerName,
+ "en"
+};
+
+
+STATIC EFI_UNICODE_STRING_TABLE mDriverName[] = {
+ {
+ "eng;en",
+ (CHAR16 *)L"Raspberry Pi Display Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+STATIC EFI_UNICODE_STRING_TABLE mDeviceName[] = {
+ {
+ "eng;en",
+ (CHAR16 *)L"Raspberry Pi Framebuffer"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mDriverName,
+ DriverName,
+ (BOOLEAN)(This == &gComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mDeviceName,
+ ControllerName,
+ (BOOLEAN)(This == &gComponentName)
+ );
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.c b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.c
new file mode 100644
index 000000000000..e8b7f67c8870
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.c
@@ -0,0 +1,606 @@
+/** @file
+ *
+ * Copyright (c) 2017-2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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 "DisplayDxe.h"
+
+#define POS_TO_FB(posX, posY) ((UINT8 *) \
+ ((UINTN)This->Mode->FrameBufferBase + \
+ (posY) * This->Mode->Info->PixelsPerScanLine * \
+ PI3_BYTES_PER_PIXEL + \
+ (posX) * PI3_BYTES_PER_PIXEL))
+
+STATIC
+EFI_STATUS
+EFIAPI
+DriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+DriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+DriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+DisplayQueryMode(
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+DisplaySetMode(
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+DisplayBlt(
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta OPTIONAL
+ );
+
+STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
+ DriverSupported,
+ DriverStart,
+ DriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+typedef struct {
+ VENDOR_DEVICE_PATH DisplayDevicePath;
+ EFI_DEVICE_PATH EndDevicePath;
+} DISPLAY_DEVICE_PATH;
+
+typedef struct {
+ UINT32 Width;
+ UINT32 Height;
+} GOP_MODE_DATA;
+
+STATIC UINT32 mBootWidth;
+STATIC UINT32 mBootHeight;
+STATIC EFI_HANDLE mDevice;
+STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol;
+STATIC EFI_CPU_ARCH_PROTOCOL *mCpu;
+
+STATIC UINTN mLastMode;
+STATIC GOP_MODE_DATA mGopModeData[] = {
+ { 800, 600 }, /* Legacy */
+ { 640, 480 }, /* Legacy */
+ { 1024, 768 }, /* Legacy */
+ { 1280, 720 }, /* 720p */
+ { 1920, 1080 }, /* 1080p */
+ { 0, 0 }, /* Physical */
+};
+
+STATIC DISPLAY_DEVICE_PATH mDisplayProtoDevicePath =
+ {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(sizeof(VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
+ }
+ },
+ EFI_CALLER_ID_GUID,
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ sizeof(EFI_DEVICE_PATH_PROTOCOL),
+ 0
+ }
+ }
+ };
+
+#define PI3_BITS_PER_PIXEL (32)
+#define PI3_BYTES_PER_PIXEL (PI3_BITS_PER_PIXEL / 8)
+
+EFI_GRAPHICS_OUTPUT_PROTOCOL gDisplayProto = {
+ DisplayQueryMode,
+ DisplaySetMode,
+ DisplayBlt,
+ NULL
+};
+
+STATIC
+EFI_STATUS
+EFIAPI
+DisplayQueryMode(
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ )
+{
+ EFI_STATUS Status;
+ GOP_MODE_DATA *Mode;
+
+ if (ModeNumber > mLastMode) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->AllocatePool(
+ EfiBootServicesData,
+ sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
+ (VOID **)Info
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Mode = &mGopModeData[ModeNumber];
+
+ *SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+ (*Info)->Version = This->Mode->Info->Version;
+ (*Info)->HorizontalResolution = Mode->Width;
+ (*Info)->VerticalResolution = Mode->Height;
+ (*Info)->PixelFormat = This->Mode->Info->PixelFormat;
+ (*Info)->PixelsPerScanLine = Mode->Width;
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+ClearScreen(
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Fill;
+
+ Fill.Red = 0x00;
+ Fill.Green = 0x00;
+ Fill.Blue = 0x00;
+ This->Blt (This, &Fill, EfiBltVideoFill,
+ 0, 0, 0, 0, This->Mode->Info->HorizontalResolution,
+ This->Mode->Info->VerticalResolution,
+ This->Mode->Info->HorizontalResolution *
+ sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+DisplaySetMode(
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber
+ )
+{
+ UINTN FbSize;
+ UINTN FbPitch;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS FbBase;
+ GOP_MODE_DATA *Mode = &mGopModeData[ModeNumber];
+
+ if (ModeNumber > mLastMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUG((DEBUG_INFO, "Setting mode %u from %u: %u x %u\n",
+ ModeNumber, This->Mode->Mode, Mode->Width, Mode->Height));
+ Status = mFwProtocol->GetFB(Mode->Width, Mode->Height,
+ PI3_BITS_PER_PIXEL, &FbBase,
+ &FbSize, &FbPitch);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Could not set mode %u\n", ModeNumber));
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG((DEBUG_INFO, "Mode %u: %u x %u framebuffer is %u bytes at %p\n",
+ ModeNumber, Mode->Width, Mode->Height, FbSize, FbBase));
+
+ if (FbPitch / PI3_BYTES_PER_PIXEL != Mode->Width) {
+ DEBUG((DEBUG_ERROR, "Error: Expected width %u, got width %u\n",
+ Mode->Width, FbPitch / PI3_BYTES_PER_PIXEL));
+ return EFI_DEVICE_ERROR;
+ }
+
+ /*
+ * WT, because certain OS loaders access the frame buffer directly
+ * and we don't want to see corruption due to missing WB cache
+ * maintenance. Performance with WT is good.
+ */
+ Status = mCpu->SetMemoryAttributes(mCpu, FbBase,
+ ALIGN_VALUE(FbSize, EFI_PAGE_SIZE),
+ EFI_MEMORY_WT);
+ if (Status != EFI_SUCCESS) {
+ DEBUG((DEBUG_ERROR, "Couldn't set framebuffer attributes: %r\n", Status));
+ return Status;
+ }
+
+ This->Mode->Mode = ModeNumber;
+ This->Mode->Info->Version = 0;
+ This->Mode->Info->HorizontalResolution = Mode->Width;
+ This->Mode->Info->VerticalResolution = Mode->Height;
+ /*
+ * NOTE: Windows REQUIRES BGR in 32 or 24 bit format.
+ */
+ This->Mode->Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+ This->Mode->Info->PixelsPerScanLine = Mode->Width;
+ This->Mode->SizeOfInfo = sizeof(*This->Mode->Info);
+ This->Mode->FrameBufferBase = FbBase;
+ This->Mode->FrameBufferSize = FbSize;
+
+ ClearScreen(This);
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+DisplayBlt(
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta OPTIONAL
+ )
+{
+ UINT8 *VidBuf, *BltBuf, *VidBuf1;
+ UINTN i;
+
+ switch(BltOperation) {
+ case EfiBltVideoFill:
+ BltBuf = (UINT8 *)BltBuffer;
+
+ for (i = 0; i < Height; i++) {
+ VidBuf = POS_TO_FB(DestinationX, DestinationY + i);
+
+ SetMem32(VidBuf, Width * PI3_BYTES_PER_PIXEL, *(UINT32 *) BltBuf);
+ }
+ break;
+
+ case EfiBltVideoToBltBuffer:
+ if (Delta == 0) {
+ Delta = Width * PI3_BYTES_PER_PIXEL;
+ }
+
+ for (i = 0; i < Height; i++) {
+ VidBuf = POS_TO_FB(SourceX, SourceY + i);
+
+ BltBuf = (UINT8 *)((UINTN)BltBuffer + (DestinationY + i) * Delta +
+ DestinationX * PI3_BYTES_PER_PIXEL);
+
+ gBS->CopyMem((VOID *)BltBuf, (VOID *)VidBuf, PI3_BYTES_PER_PIXEL * Width);
+ }
+ break;
+
+ case EfiBltBufferToVideo:
+ if (Delta == 0) {
+ Delta = Width * PI3_BYTES_PER_PIXEL;
+ }
+
+ for (i = 0; i < Height; i++) {
+ VidBuf = POS_TO_FB(DestinationX, DestinationY + i);
+ BltBuf = (UINT8 *)((UINTN) BltBuffer + (SourceY + i) * Delta +
+ SourceX * PI3_BYTES_PER_PIXEL);
+
+ gBS->CopyMem((VOID *)VidBuf, (VOID *)BltBuf, Width * PI3_BYTES_PER_PIXEL);
+ }
+ break;
+
+ case EfiBltVideoToVideo:
+ for (i = 0; i < Height; i++) {
+ VidBuf = POS_TO_FB(SourceX, SourceY + i);
+ VidBuf1 = POS_TO_FB(DestinationX, DestinationY + i);
+
+ gBS->CopyMem((VOID *)VidBuf1, (VOID *)VidBuf, Width * PI3_BYTES_PER_PIXEL);
+ }
+ break;
+
+ default:
+ ASSERT_EFI_ERROR(EFI_SUCCESS);
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the state information for the Display Dxe
+
+ @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
+EFIAPI
+DisplayDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid, NULL,
+ (VOID **)&mFwProtocol);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL,
+ (VOID **) &mCpu);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Query the current display resolution from mailbox
+ Status = mFwProtocol->GetFBSize(&mBootWidth, &mBootHeight);
+ if(EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ DEBUG((DEBUG_INFO, "Display boot mode is %u x %u\n",
+ mBootWidth, mBootHeight));
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mDevice, &gEfiDevicePathProtocolGuid,
+ &mDisplayProtoDevicePath, &gEfiCallerIdGuid,
+ NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &mDriverBinding,
+ ImageHandle,
+ &gComponentName,
+ &gComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+DriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ VOID *Temp;
+
+ if (Controller != mDevice) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (gBS->HandleProtocol(Controller, &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &Temp) == EFI_SUCCESS) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+DriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ VOID *Dummy;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &Dummy,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gDisplayProto.Mode = AllocateZeroPool(sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
+ if (gDisplayProto.Mode == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto done;
+ }
+
+ gDisplayProto.Mode->Info = AllocateZeroPool(sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+ if (gDisplayProto.Mode->Info == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto done;
+ }
+
+
+ if (PcdGet32(PcdDisplayEnableVModes)) {
+ mLastMode = ELES(mGopModeData) - 1;
+ } else {
+ mLastMode = 0;
+ /*
+ * mBootWidth x mBootHeight may not be sensible,
+ * so clean it up, since we won't be adding
+ * any other extra vmodes.
+ */
+ if (mBootWidth < 640 ||
+ mBootHeight < 480) {
+ mBootWidth = 640;
+ mBootHeight = 480;
+ }
+ }
+
+ mGopModeData[mLastMode].Width = mBootWidth;
+ mGopModeData[mLastMode].Height = mBootHeight;
+
+ for (Index = 0; Index <= mLastMode; Index++) {
+ UINTN FbSize;
+ UINTN FbPitch;
+ EFI_PHYSICAL_ADDRESS FbBase;
+
+ GOP_MODE_DATA *Mode = &mGopModeData[Index];
+
+ Status = mFwProtocol->GetFB(Mode->Width, Mode->Height,
+ PI3_BITS_PER_PIXEL, &FbBase,
+ &FbSize, &FbPitch);
+ if (EFI_ERROR(Status)) {
+ goto done;
+ }
+
+ //
+ // There is no way to communicate pitch back to OS. OS and even UEFI
+ // expect a fully linear frame buffer. So the width should
+ // be based on the frame buffer's pitch value. In some cases VC
+ // firmware would allocate ao frame buffer with some padding
+ // presumably to be 8 byte align.
+ //
+ Mode->Width = FbPitch / PI3_BYTES_PER_PIXEL;
+
+ DEBUG((DEBUG_INFO, "Mode %u: %u x %u framebuffer is %u bytes at %p\n",
+ Index, Mode->Width, Mode->Height, FbSize, FbBase));
+
+ ASSERT (FbPitch != 0);
+ ASSERT (FbBase != 0);
+ ASSERT (FbSize != 0);
+ }
+
+ // Both set the mode and initialize current mode information.
+ gDisplayProto.Mode->MaxMode = mLastMode + 1;
+ DisplaySetMode(&gDisplayProto, 0);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller, &gEfiGraphicsOutputProtocolGuid,
+ &gDisplayProto, NULL);
+ if (EFI_ERROR (Status)) {
+ goto done;
+ }
+
+ if (PcdGet32(PcdDisplayEnableSShot)) {
+ RegisterScreenshotHandlers();
+ } else {
+ DEBUG((DEBUG_INFO, "Screenshot capture disabled\n"));
+ }
+
+done:
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "Could not start DisplayDxe: %r\n", Status));
+ if (gDisplayProto.Mode->Info != NULL) {
+ FreePool(gDisplayProto.Mode->Info);
+ gDisplayProto.Mode->Info = NULL;
+ }
+
+ if (gDisplayProto.Mode != NULL) {
+ FreePool(gDisplayProto.Mode);
+ gDisplayProto.Mode = NULL;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+DriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+
+ ClearScreen(&gDisplayProto);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller, &gEfiGraphicsOutputProtocolGuid,
+ &gDisplayProto, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FreePool(gDisplayProto.Mode->Info);
+ gDisplayProto.Mode->Info = NULL;
+ FreePool(gDisplayProto.Mode);
+ gDisplayProto.Mode = NULL;
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.h b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.h
new file mode 100644
index 000000000000..9fa3d4f6af83
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.h
@@ -0,0 +1,43 @@
+/** @file
+ *
+ * Copyright (c) 2017-2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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 _DISPLAY_H_
+#define _DISPLAY_H_
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/RaspberryPiFirmware.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/Cpu.h>
+#include <Utils.h>
+
+extern EFI_GRAPHICS_OUTPUT_PROTOCOL gDisplayProto;
+extern EFI_COMPONENT_NAME_PROTOCOL gComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gComponentName2;
+
+VOID
+RegisterScreenshotHandlers(
+ VOID
+ );
+
+#endif /* _DISPLAY_H_ */
diff --git a/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.inf
new file mode 100644
index 000000000000..1603edd4909d
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.inf
@@ -0,0 +1,71 @@
+#/** @file
+#
+# Component description file for Graphics Output module
+#
+# Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) Microsoft Corporation. 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 = 0x00010005
+ BASE_NAME = DisplayDxe
+ FILE_GUID = c5deae31-fad2-4030-841b-cfc9644d2c5b
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DisplayDxeInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# DRIVER_BINDING = gGraphicsConsoleDriverBinding
+# COMPONENT_NAME = gGraphicsConsoleComponentName
+# COMPONENT_NAME2 = gGraphicsConsoleComponentName2
+#
+
+[Sources]
+ DisplayDxe.c
+ Screenshot.c
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPkg/ArmPkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ UefiLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ IoLib
+ TimerLib
+ BmpSupportLib
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiGraphicsOutputProtocolGuid
+ gRaspberryPiFirmwareProtocolGuid
+ gEfiCpuArchProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiSimpleTextInputExProtocolGuid
+
+[Pcd]
+ gRaspberryPiTokenSpaceGuid.PcdDisplayEnableVModes
+ gRaspberryPiTokenSpaceGuid.PcdDisplayEnableSShot
+
+[Guids]
+
+[Depex]
+ gEfiCpuArchProtocolGuid AND gRaspberryPiFirmwareProtocolGuid
diff --git a/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/Screenshot.c b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/Screenshot.c
new file mode 100644
index 000000000000..a2feeba6084f
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/Screenshot.c
@@ -0,0 +1,379 @@
+/** @file
+ *
+ * Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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.
+ *
+ **/
+
+/*
+ * Loosely based on CrScreenShotDxe (https://github.com/LongSoft/CrScreenshotDxe).
+ *
+ * Copyright (c) 2016, Nikolaj Schlej, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "DisplayDxe.h"
+#include <Protocol/SimpleFileSystem.h>
+#include <Library/PrintLib.h>
+#include <Library/BmpSupportLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+/*
+ * ShowStatus defs.
+ */
+#define STATUS_SQUARE_SIDE 5
+#define STATUS_YELLOW 0xff, 0xff, 0x00
+#define STATUS_GREEN 0x00, 0xff, 0x00
+#define STATUS_BLUE 0x00, 0x00, 0xff
+#define STATUS_RED 0xff, 0x00, 0x00
+
+EFI_STATUS
+ShowStatus (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+ IN UINT8 Red,
+ IN UINT8 Green,
+ IN UINT8 Blue
+ )
+{
+ UINTN Index;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Square[STATUS_SQUARE_SIDE * STATUS_SQUARE_SIDE];
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Backup[STATUS_SQUARE_SIDE * STATUS_SQUARE_SIDE];
+
+ for (Index = 0 ; Index < STATUS_SQUARE_SIDE * STATUS_SQUARE_SIDE; Index++) {
+ Square[Index].Blue = Blue;
+ Square[Index].Green = Green;
+ Square[Index].Red = Red;
+ Square[Index].Reserved = 0x00;
+ }
+
+ // Backup current image.
+ GraphicsOutput->Blt(GraphicsOutput, Backup,
+ EfiBltVideoToBltBuffer, 0, 0, 0, 0,
+ STATUS_SQUARE_SIDE, STATUS_SQUARE_SIDE, 0);
+
+ // Draw the status square.
+ GraphicsOutput->Blt(GraphicsOutput, Square,
+ EfiBltBufferToVideo, 0, 0, 0, 0,
+ STATUS_SQUARE_SIDE, STATUS_SQUARE_SIDE, 0);
+
+ // Wait 500ms.
+ gBS->Stall(500*1000);
+
+ // Restore the backup.
+ GraphicsOutput->Blt(GraphicsOutput, Backup,
+ EfiBltBufferToVideo, 0, 0, 0, 0,
+ STATUS_SQUARE_SIDE, STATUS_SQUARE_SIDE, 0);
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FindWritableFs (
+ OUT EFI_FILE_PROTOCOL **WritableFs
+ )
+{
+ EFI_FILE_PROTOCOL *Fs = NULL;
+ EFI_HANDLE *HandleBuffer = NULL;
+ UINTN HandleCount;
+ UINTN Index;
+
+ EFI_STATUS Status = gBS->LocateHandleBuffer(ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL, &HandleCount, &HandleBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs = NULL;
+ EFI_FILE_PROTOCOL *File = NULL;
+
+ Status = gBS->HandleProtocol(HandleBuffer[Index],
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **) &SimpleFs);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ /*
+ * Not supposed to happen.
+ */
+ continue;
+ }
+
+ Status = SimpleFs->OpenVolume(SimpleFs, &Fs);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a OpenVolume[%u] returned %r\n", __FUNCTION__,
+ Index, Status));
+ continue;
+ }
+
+ Status = Fs->Open(Fs, &File, L"--------.---",
+ EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ |
+ EFI_FILE_MODE_WRITE, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a Open[%u] returned %r\n", __FUNCTION__,
+ Index, Status));
+ continue;
+ }
+
+ /*
+ * Okay, we have a writable filesystem!
+ */
+ Fs->Delete(File);
+ *WritableFs = Fs;
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ if (HandleBuffer) {
+ FreePool(HandleBuffer);
+ }
+
+ return Status;
+}
+
+STATIC
+VOID
+TakeScreenshot(
+ VOID
+ )
+{
+ VOID *BmpImage = NULL;
+ EFI_FILE_PROTOCOL *Fs = NULL;
+ EFI_FILE_PROTOCOL *File = NULL;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = &gDisplayProto;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Image = NULL;
+ EFI_STATUS Status;
+ CHAR16 FileName[8+1+3+1];
+ UINT32 ScreenWidth;
+ UINT32 ScreenHeight;
+ UINTN ImageSize;
+ UINTN BmpSize;
+ UINTN Index;
+ EFI_TIME Time;
+
+ Status = FindWritableFs(&Fs);
+ if (EFI_ERROR (Status)) {
+ ShowStatus(GraphicsOutput, STATUS_YELLOW);
+ }
+
+ ScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
+ ScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
+ ImageSize = ScreenWidth * ScreenHeight;
+
+ Status = gRT->GetTime(&Time, NULL);
+ if (!EFI_ERROR(Status)) {
+ UnicodeSPrint(FileName, sizeof(FileName), L"%02d%02d%02d%02d.bmp",
+ Time.Day, Time.Hour, Time.Minute, Time.Second);
+ } else {
+ UnicodeSPrint(FileName, sizeof(FileName), L"scrnshot.bmp");
+ }
+
+ Image = AllocatePool(ImageSize * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (Image == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ ShowStatus(GraphicsOutput, STATUS_RED);
+ goto done;
+ }
+
+ Status = GraphicsOutput->Blt(GraphicsOutput, Image,
+ EfiBltVideoToBltBuffer, 0, 0, 0, 0,
+ ScreenWidth, ScreenHeight, 0);
+ if (EFI_ERROR(Status)) {
+ ShowStatus(GraphicsOutput, STATUS_RED);
+ goto done;
+ }
+
+ for (Index = 0; Index < ImageSize; Index++) {
+ if (Image[Index].Red != 0x00 ||
+ Image[Index].Green != 0x00 ||
+ Image[Index].Blue != 0x00) {
+ break;
+ }
+ }
+
+ if (Index == ImageSize) {
+ ShowStatus(GraphicsOutput, STATUS_BLUE);
+ goto done;
+ }
+
+ Status = TranslateGopBltToBmp(Image, ScreenHeight, ScreenWidth,
+ &BmpImage, (UINT32 *) &BmpSize);
+ if (EFI_ERROR(Status)) {
+ ShowStatus(GraphicsOutput, STATUS_RED);
+ goto done;
+ }
+
+ Status = Fs->Open(Fs, &File, FileName, EFI_FILE_MODE_CREATE |
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
+ if (EFI_ERROR (Status)) {
+ ShowStatus(GraphicsOutput, STATUS_RED);
+ goto done;
+ }
+
+ Status = File->Write(File, &BmpSize, BmpImage);
+ File->Close(File);
+ if (EFI_ERROR (Status)) {
+ ShowStatus(GraphicsOutput, STATUS_RED);
+ goto done;
+ }
+
+ ShowStatus(GraphicsOutput, STATUS_GREEN);
+done:
+ if (BmpImage != NULL) {
+ FreePool (BmpImage);
+ }
+
+ if (Image != NULL) {
+ FreePool (Image);
+ }
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+ScreenshotKeyHandler (
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ TakeScreenshot();
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+ProcessScreenshotHandler(
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_KEY_DATA ScreenshotKey;
+
+ /*
+ * LCtrl+LAlt+F12
+ */
+ ScreenshotKey.Key.ScanCode = SCAN_F12;
+ ScreenshotKey.Key.UnicodeChar = 0;
+ ScreenshotKey.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID |
+ EFI_LEFT_CONTROL_PRESSED | EFI_LEFT_ALT_PRESSED;
+ ScreenshotKey.KeyState.KeyToggleState = 0;
+
+ Status = SimpleTextInEx->RegisterKeyNotify (
+ SimpleTextInEx,
+ &ScreenshotKey,
+ ScreenshotKeyHandler,
+ &Handle
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: couldn't register key notification: %r\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+ProcessScreenshotHandlers(
+ VOID
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx;
+
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextInputExProtocolGuid,
+ NULL, &HandleCount, &HandleBuffer);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index],
+ &gEfiSimpleTextInputExProtocolGuid,
+ (VOID **) &SimpleTextInEx);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ /*
+ * Not supposed to happen.
+ */
+ continue;
+ }
+
+ Status = ProcessScreenshotHandler(SimpleTextInEx);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ }
+}
+
+STATIC
+VOID
+EFIAPI
+OnTextInExInstall (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ ProcessScreenshotHandlers();
+}
+
+VOID
+RegisterScreenshotHandlers(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT TextInExInstallEvent;
+ VOID *TextInExInstallRegistration;
+
+ ProcessScreenshotHandlers();
+
+ Status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+ OnTextInExInstall, NULL,
+ &TextInExInstallEvent);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: couldn't create protocol install event: %r\n",
+ __FUNCTION__, Status));
+ return;
+ }
+
+ Status = gBS->RegisterProtocolNotify(&gEfiSimpleTextInputExProtocolGuid,
+ TextInExInstallEvent,
+ &TextInExInstallRegistration);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: couldn't register protocol install notify: %r\n",
+ __FUNCTION__, Status));
+ return;
+ }
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/ComponentName.c b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/ComponentName.c
new file mode 100644
index 000000000000..e5935b19a250
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/ComponentName.c
@@ -0,0 +1,183 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2006-2016, Intel Corporation. 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 "GraphicsConsole.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gGraphicsConsoleComponentName = {
+ GraphicsConsoleComponentNameGetDriverName,
+ GraphicsConsoleComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gGraphicsConsoleComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GraphicsConsoleComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GraphicsConsoleComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mGraphicsConsoleDriverNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *)L"Graphics Console Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mGraphicsConsoleDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gGraphicsConsoleComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsole.c b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsole.c
new file mode 100644
index 000000000000..4df5b37e5d4f
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsole.c
@@ -0,0 +1,1836 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2006-2016, Intel Corporation. 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 "GraphicsConsole.h"
+
+//
+// Graphics Console Device Private Data template
+//
+GRAPHICS_CONSOLE_DEV mGraphicsConsoleDevTemplate = {
+ GRAPHICS_CONSOLE_DEV_SIGNATURE,
+ (EFI_GRAPHICS_OUTPUT_PROTOCOL *) NULL,
+ {
+ GraphicsConsoleConOutReset,
+ GraphicsConsoleConOutOutputString,
+ GraphicsConsoleConOutTestString,
+ GraphicsConsoleConOutQueryMode,
+ GraphicsConsoleConOutSetMode,
+ GraphicsConsoleConOutSetAttribute,
+ GraphicsConsoleConOutClearScreen,
+ GraphicsConsoleConOutSetCursorPosition,
+ GraphicsConsoleConOutEnableCursor,
+ (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL
+ },
+ {
+ 0,
+ -1,
+ EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_BLACK),
+ 0,
+ 0,
+ TRUE
+ },
+ (GRAPHICS_CONSOLE_MODE_DATA *) NULL,
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) NULL,
+ {
+ (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *) NULL,
+ (EFI_GRAPHICS_OUTPUT_PROTOCOL *) NULL,
+ TRUE,
+ }
+};
+
+GRAPHICS_CONSOLE_MODE_DATA mGraphicsConsoleModeData[] = {
+ {100, 31},
+ //
+ // New modes can be added here.
+ // The last entry is specific for full screen mode.
+ //
+ {0, 0}
+};
+
+EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
+EFI_HII_FONT_PROTOCOL *mHiiFont;
+EFI_HII_HANDLE mHiiHandle;
+VOID *mHiiRegistration;
+
+EFI_GUID mFontPackageListGuid = {0xf5f219d3, 0x7006, 0x4648, {0xac, 0x8d, 0xd6, 0x1d, 0xfb, 0x7b, 0xc6, 0xad}};
+
+CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };
+
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL mGraphicsEfiColors[16] = {
+ //
+ // B G R reserved
+ //
+ {0x00, 0x00, 0x00, 0x00}, // BLACK
+ {0x98, 0x00, 0x00, 0x00}, // LIGHTBLUE
+ {0x00, 0x98, 0x00, 0x00}, // LIGHGREEN
+ {0x98, 0x98, 0x00, 0x00}, // LIGHCYAN
+ {0x00, 0x00, 0x98, 0x00}, // LIGHRED
+ {0x98, 0x00, 0x98, 0x00}, // MAGENTA
+ {0x00, 0x98, 0x98, 0x00}, // BROWN
+ {0x98, 0x98, 0x98, 0x00}, // LIGHTGRAY
+ {0x30, 0x30, 0x30, 0x00}, // DARKGRAY - BRIGHT BLACK
+ {0xff, 0x00, 0x00, 0x00}, // BLUE
+ {0x00, 0xff, 0x00, 0x00}, // LIME
+ {0xff, 0xff, 0x00, 0x00}, // CYAN
+ {0x00, 0x00, 0xff, 0x00}, // RED
+ {0xff, 0x00, 0xff, 0x00}, // FUCHSIA
+ {0x00, 0xff, 0xff, 0x00}, // YELLOW
+ {0xff, 0xff, 0xff, 0x00} // WHITE
+};
+
+EFI_NARROW_GLYPH mCursorGlyph = {
+ 0x0000,
+ 0x00,
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF }
+};
+
+CHAR16 SpaceStr[] = { NARROW_CHAR, ' ', 0 };
+
+EFI_DRIVER_BINDING_PROTOCOL gGraphicsConsoleDriverBinding = {
+ GraphicsConsoleControllerDriverSupported,
+ GraphicsConsoleControllerDriverStart,
+ GraphicsConsoleControllerDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Test to see if Graphics Console could be supported on the Controller.
+
+ Graphics Console could be supported if Graphics Output Protocol
+ exists on the Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ GraphicsOutput = NULL;
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &GraphicsOutput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (GraphicsOutput != NULL);
+
+ //
+ // We need to ensure that we do not layer on top of a virtual handle.
+ // We need to ensure that the handles produced by the conspliter do not
+ // get used.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ } else {
+ goto Error;
+ }
+
+ //
+ // Does Hii Exist? If not, we aren't ready to run
+ //
+ Status = EfiLocateHiiProtocol ();
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+Error:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+}
+
+/**
+ Initialize all the text modes which the graphics console supports.
+
+ It returns information for available text modes that the graphics can support.
+
+ @param[in] HorizontalResolution The size of video screen in pixels in the X dimension.
+ @param[in] VerticalResolution The size of video screen in pixels in the Y dimension.
+ @param[in] GopModeNumber The graphics mode number which graphis console is based on.
+ @param[out] TextModeCount The total number of text modes that graphics console supports.
+ @param[out] TextModeData The buffer to the text modes column and row information.
+ Caller is responsible to free it when it's non-NULL.
+
+ @retval EFI_SUCCESS The supporting mode information is returned.
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.
+
+**/
+EFI_STATUS
+InitializeGraphicsConsoleTextMode (
+ IN UINT32 HorizontalResolution,
+ IN UINT32 VerticalResolution,
+ IN UINT32 GopModeNumber,
+ OUT UINTN *TextModeCount,
+ OUT GRAPHICS_CONSOLE_MODE_DATA **TextModeData
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ GRAPHICS_CONSOLE_MODE_DATA *ModeBuffer;
+ GRAPHICS_CONSOLE_MODE_DATA *NewModeBuffer;
+ UINTN ValidCount;
+ UINTN ValidIndex;
+ UINTN MaxColumns;
+ UINTN MaxRows;
+
+ if ((TextModeCount == NULL) || (TextModeData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Count = sizeof (mGraphicsConsoleModeData) / sizeof (GRAPHICS_CONSOLE_MODE_DATA);
+
+ //
+ // Compute the maximum number of text Rows and Columns that this current graphics mode can support.
+ // To make graphics console work well, MaxColumns and MaxRows should not be zero.
+ //
+ MaxColumns = HorizontalResolution / EFI_GLYPH_WIDTH;
+ MaxRows = VerticalResolution / EFI_GLYPH_HEIGHT;
+
+ //
+ // According to UEFI spec, all output devices support at least 80x25 text mode.
+ //
+ ASSERT ((MaxColumns >= 80) && (MaxRows >= 25));
+
+ //
+ // Add full screen mode to the last entry.
+ //
+ mGraphicsConsoleModeData[Count - 1].Columns = MaxColumns;
+ mGraphicsConsoleModeData[Count - 1].Rows = MaxRows;
+
+ //
+ // Get defined mode buffer pointer.
+ //
+ ModeBuffer = mGraphicsConsoleModeData;
+
+ //
+ // Here we make sure that the final mode exposed does not include the duplicated modes,
+ // and does not include the invalid modes which exceed the max column and row.
+ // Reserve 2 modes for 80x25, 80x50 of graphics console.
+ //
+ NewModeBuffer = AllocateZeroPool (sizeof (GRAPHICS_CONSOLE_MODE_DATA) * (Count + 2));
+ ASSERT (NewModeBuffer != NULL);
+
+ //
+ // Mode 0 and mode 1 is for 80x25, 80x50 according to UEFI spec.
+ //
+ ValidCount = 0;
+
+ NewModeBuffer[ValidCount].Columns = 80;
+ NewModeBuffer[ValidCount].Rows = 25;
+ NewModeBuffer[ValidCount].GopWidth = HorizontalResolution;
+ NewModeBuffer[ValidCount].GopHeight = VerticalResolution;
+ NewModeBuffer[ValidCount].GopModeNumber = GopModeNumber;
+ NewModeBuffer[ValidCount].DeltaX = (HorizontalResolution - (NewModeBuffer[ValidCount].Columns * EFI_GLYPH_WIDTH)) >> 1;
+ NewModeBuffer[ValidCount].DeltaY = (VerticalResolution - (NewModeBuffer[ValidCount].Rows * EFI_GLYPH_HEIGHT)) >> 1;
+ ValidCount++;
+
+ if ((MaxColumns >= 80) && (MaxRows >= 50)) {
+ NewModeBuffer[ValidCount].Columns = 80;
+ NewModeBuffer[ValidCount].Rows = 50;
+ NewModeBuffer[ValidCount].DeltaX = (HorizontalResolution - (80 * EFI_GLYPH_WIDTH)) >> 1;
+ NewModeBuffer[ValidCount].DeltaY = (VerticalResolution - (50 * EFI_GLYPH_HEIGHT)) >> 1;
+ }
+ NewModeBuffer[ValidCount].GopWidth = HorizontalResolution;
+ NewModeBuffer[ValidCount].GopHeight = VerticalResolution;
+ NewModeBuffer[ValidCount].GopModeNumber = GopModeNumber;
+ ValidCount++;
+
+ //
+ // Start from mode 2 to put the valid mode other than 80x25 and 80x50 in the output mode buffer.
+ //
+ for (Index = 0; Index < Count; Index++) {
+ if ((ModeBuffer[Index].Columns == 0) || (ModeBuffer[Index].Rows == 0) ||
+ (ModeBuffer[Index].Columns > MaxColumns) || (ModeBuffer[Index].Rows > MaxRows)) {
+ //
+ // Skip the pre-defined mode which is invalid or exceeds the max column and row.
+ //
+ continue;
+ }
+ for (ValidIndex = 0; ValidIndex < ValidCount; ValidIndex++) {
+ if ((ModeBuffer[Index].Columns == NewModeBuffer[ValidIndex].Columns) &&
+ (ModeBuffer[Index].Rows == NewModeBuffer[ValidIndex].Rows)) {
+ //
+ // Skip the duplicated mode.
+ //
+ break;
+ }
+ }
+ if (ValidIndex == ValidCount) {
+ NewModeBuffer[ValidCount].Columns = ModeBuffer[Index].Columns;
+ NewModeBuffer[ValidCount].Rows = ModeBuffer[Index].Rows;
+ NewModeBuffer[ValidCount].GopWidth = HorizontalResolution;
+ NewModeBuffer[ValidCount].GopHeight = VerticalResolution;
+ NewModeBuffer[ValidCount].GopModeNumber = GopModeNumber;
+ NewModeBuffer[ValidCount].DeltaX = (HorizontalResolution - (NewModeBuffer[ValidCount].Columns * EFI_GLYPH_WIDTH)) >> 1;
+ NewModeBuffer[ValidCount].DeltaY = (VerticalResolution - (NewModeBuffer[ValidCount].Rows * EFI_GLYPH_HEIGHT)) >> 1;
+ ValidCount++;
+ }
+ }
+
+ DEBUG_CODE (
+ for (Index = 0; Index < ValidCount; Index++) {
+ DEBUG ((DEBUG_INFO, "Graphics - Mode %d, Column = %d, Row = %d\n",
+ Index, NewModeBuffer[Index].Columns, NewModeBuffer[Index].Rows));
+ }
+ );
+
+ //
+ // Return valid mode count and mode information buffer.
+ //
+ *TextModeCount = ValidCount;
+ *TextModeData = NewModeBuffer;
+ return EFI_SUCCESS;
+}
+
+/**
+ Start this driver on Controller by opening Graphics Output Protocol,
+ and installing Simple Text Out protocol on Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to Controller.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ GRAPHICS_CONSOLE_DEV *Private;
+ UINT32 HorizontalResolution;
+ UINT32 VerticalResolution;
+ UINT32 ModeIndex;
+ UINTN MaxMode;
+ UINT32 ModeNumber;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+
+ ModeNumber = 0;
+
+ //
+ // Initialize the Graphics Console device instance
+ //
+ Private = AllocateCopyPool (
+ sizeof (GRAPHICS_CONSOLE_DEV),
+ &mGraphicsConsoleDevTemplate
+ );
+ if (Private == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->SimpleTextOutput.Mode = &(Private->SimpleTextOutputMode);
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &Private->GraphicsOutput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Private->ExtendedTextOutput.TextOut = &(Private->SimpleTextOutput);
+ Private->ExtendedTextOutput.GraphicsOutput = Private->GraphicsOutput;
+
+ HorizontalResolution = PcdGet32 (PcdVideoHorizontalResolution);
+ VerticalResolution = PcdGet32 (PcdVideoVerticalResolution);
+
+ ASSERT (Private->GraphicsOutput != NULL);
+ //
+ // The console is build on top of Graphics Output Protocol, find the mode number
+ // for the user-defined mode; if there are multiple video devices,
+ // graphic console driver will set all the video devices to the same mode.
+ //
+ if ((HorizontalResolution == 0x0) || (VerticalResolution == 0x0)) {
+ //
+ // Find the highest resolution which GOP supports.
+ //
+ MaxMode = Private->GraphicsOutput->Mode->MaxMode;
+
+ for (ModeIndex = 0; ModeIndex < MaxMode; ModeIndex++) {
+ Status = Private->GraphicsOutput->QueryMode (
+ Private->GraphicsOutput,
+ ModeIndex,
+ &SizeOfInfo,
+ &Info
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Info->HorizontalResolution > HorizontalResolution) ||
+ ((Info->HorizontalResolution == HorizontalResolution) && (Info->VerticalResolution > VerticalResolution))) {
+ HorizontalResolution = Info->HorizontalResolution;
+ VerticalResolution = Info->VerticalResolution;
+ ModeNumber = ModeIndex;
+ }
+ FreePool (Info);
+ }
+ }
+ if ((HorizontalResolution == 0x0) || (VerticalResolution == 0x0)) {
+ Status = EFI_UNSUPPORTED;
+ goto Error;
+ }
+ } else {
+ //
+ // Use user-defined resolution
+ //
+ Status = CheckModeSupported (
+ Private->GraphicsOutput,
+ HorizontalResolution,
+ VerticalResolution,
+ &ModeNumber
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if not supporting current mode, try 800x600 which is required by UEFI/EFI spec.
+ //
+ HorizontalResolution = 800;
+ VerticalResolution = 600;
+ Status = CheckModeSupported (
+ Private->GraphicsOutput,
+ HorizontalResolution,
+ VerticalResolution,
+ &ModeNumber
+ );
+ Mode = Private->GraphicsOutput->Mode;
+ if (EFI_ERROR (Status) && Mode->MaxMode != 0) {
+ //
+ // Set default mode failed or device don't support default mode, then get the current mode information.
+ //
+ HorizontalResolution = Mode->Info->HorizontalResolution;
+ VerticalResolution = Mode->Info->VerticalResolution;
+ ModeNumber = Mode->Mode;
+ }
+ }
+ }
+ if (ModeNumber != Private->GraphicsOutput->Mode->Mode) {
+ //
+ // Current graphics mode is not set or is not set to the mode which we has found,
+ // set the new graphic mode.
+ //
+ Status = Private->GraphicsOutput->SetMode (Private->GraphicsOutput, ModeNumber);
+ if (EFI_ERROR (Status)) {
+ //
+ // The mode set operation failed
+ //
+ goto Error;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "GraphicsConsole video resolution %d x %d\n", HorizontalResolution, VerticalResolution));
+
+ //
+ // Initialize the mode which GraphicsConsole supports.
+ //
+ Status = InitializeGraphicsConsoleTextMode (
+ HorizontalResolution,
+ VerticalResolution,
+ ModeNumber,
+ &MaxMode,
+ &Private->ModeData
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // Update the maximum number of modes
+ //
+ Private->SimpleTextOutputMode.MaxMode = (INT32) MaxMode;
+
+ DEBUG_CODE_BEGIN ();
+ Status = GraphicsConsoleConOutSetMode (&Private->SimpleTextOutput, 0);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ Status = GraphicsConsoleConOutOutputString (&Private->SimpleTextOutput, (CHAR16 *)L"Graphics Console Started\n\r");
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Install protocol interfaces for the Graphics Console device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSimpleTextOutProtocolGuid,
+ &Private->SimpleTextOutput,
+ &gExtendedTextOutputProtocolGuid,
+ &Private->ExtendedTextOutput,
+ NULL
+ );
+
+Error:
+ if (EFI_ERROR (Status)) {
+ //
+ // Close GOP.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (Private->LineBuffer != NULL) {
+ FreePool (Private->LineBuffer);
+ }
+
+ if (Private->ModeData != NULL) {
+ FreePool (Private->ModeData);
+ }
+
+ //
+ // Free private data
+ //
+ FreePool (Private);
+ }
+
+ return Status;
+}
+
+/**
+ Stop this driver on Controller by removing Simple Text Out protocol
+ and closing the Graphics Output Protocol on Controller.
+
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval EFI_NOT_STARTED Simple Text Out protocol could not be found the
+ Controller.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;
+ GRAPHICS_CONSOLE_DEV *Private;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &SimpleTextOutput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiSimpleTextOutProtocolGuid,
+ &Private->SimpleTextOutput,
+ &gExtendedTextOutputProtocolGuid,
+ &Private->ExtendedTextOutput,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Close GOP.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (Private->LineBuffer != NULL) {
+ FreePool (Private->LineBuffer);
+ }
+
+ if (Private->ModeData != NULL) {
+ FreePool (Private->ModeData);
+ }
+
+ //
+ // Free our instance data
+ //
+ FreePool (Private);
+ }
+
+ return Status;
+}
+
+/**
+ Check if the current specific mode supported the user defined resolution
+ for the Graphics Console device based on Graphics Output Protocol.
+
+ If yes, set the graphic devcice's current mode to this specific mode.
+
+ @param GraphicsOutput Graphics Output Protocol instance pointer.
+ @param HorizontalResolution User defined horizontal resolution
+ @param VerticalResolution User defined vertical resolution.
+ @param CurrentModeNumber Current specific mode to be check.
+
+ @retval EFI_SUCCESS The mode is supported.
+ @retval EFI_UNSUPPORTED The specific mode is out of range of graphics
+ device supported.
+ @retval other The specific mode does not support user defined
+ resolution or failed to set the current mode to the
+ specific mode on graphics device.
+
+**/
+EFI_STATUS
+CheckModeSupported (
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+ IN UINT32 HorizontalResolution,
+ IN UINT32 VerticalResolution,
+ OUT UINT32 *CurrentModeNumber
+ )
+{
+ UINT32 ModeNumber;
+ EFI_STATUS Status;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ UINT32 MaxMode;
+
+ Status = EFI_SUCCESS;
+ MaxMode = GraphicsOutput->Mode->MaxMode;
+
+ for (ModeNumber = 0; ModeNumber < MaxMode; ModeNumber++) {
+ Status = GraphicsOutput->QueryMode (
+ GraphicsOutput,
+ ModeNumber,
+ &SizeOfInfo,
+ &Info
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Info->HorizontalResolution == HorizontalResolution) &&
+ (Info->VerticalResolution == VerticalResolution)) {
+ if ((GraphicsOutput->Mode->Info->HorizontalResolution == HorizontalResolution) &&
+ (GraphicsOutput->Mode->Info->VerticalResolution == VerticalResolution)) {
+ //
+ // If video device has been set to this mode, we do not need to SetMode again
+ //
+ FreePool (Info);
+ break;
+ } else {
+ Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
+ if (!EFI_ERROR (Status)) {
+ FreePool (Info);
+ break;
+ }
+ }
+ }
+ FreePool (Info);
+ }
+ }
+
+ if (ModeNumber == GraphicsOutput->Mode->MaxMode) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ *CurrentModeNumber = ModeNumber;
+ return Status;
+}
+
+
+/**
+ Locate HII Database protocol and HII Font protocol.
+
+ @retval EFI_SUCCESS HII Database protocol and HII Font protocol
+ are located successfully.
+ @return other Failed to locate HII Database protocol or
+ HII Font protocol.
+
+**/
+EFI_STATUS
+EfiLocateHiiProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &mHiiDatabase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **) &mHiiFont);
+ return Status;
+}
+
+//
+// Body of the STO functions
+//
+
+/**
+ Reset the text output device hardware and optionally run diagnostics.
+
+ Implements SIMPLE_TEXT_OUTPUT.Reset().
+ If ExtendeVerification is TRUE, then perform dependent Graphics Console
+ device reset, and set display mode to mode 0.
+ If ExtendedVerification is FALSE, only set display mode to mode 0.
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The text output device was reset.
+ @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and
+ could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ Status = This->SetMode (This, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK));
+ return Status;
+}
+
+
+/**
+ Write a Unicode string to the output device.
+
+ Implements SIMPLE_TEXT_OUTPUT.OutputString().
+ The Unicode string will be converted to Glyphs and will be
+ sent to the Graphics Console.
+
+ @param This Protocol instance pointer.
+ @param WString The NULL-terminated Unicode string to be displayed
+ on the output device(s). All output devices must
+ also support the Unicode drawing defined in this file.
+
+ @retval EFI_SUCCESS The string was output to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
+ the text.
+ @retval EFI_UNSUPPORTED The output device's mode is not currently in a
+ defined text mode.
+ @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
+ characters in the Unicode string could not be
+ rendered and were skipped.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ )
+{
+ GRAPHICS_CONSOLE_DEV *Private;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ INTN Mode;
+ UINTN MaxColumn;
+ UINTN MaxRow;
+ UINTN Width;
+ UINTN Height;
+ UINTN Delta;
+ EFI_STATUS Status;
+ BOOLEAN Warning;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ UINTN DeltaX;
+ UINTN DeltaY;
+ UINTN Count;
+ UINTN Index;
+ INT32 OriginAttribute;
+ EFI_TPL OldTpl;
+
+ if (This->Mode->Mode == -1) {
+ //
+ // If current mode is not valid, return error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ //
+ // Current mode
+ //
+ Mode = This->Mode->Mode;
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ GraphicsOutput = Private->GraphicsOutput;
+
+ MaxColumn = Private->ModeData[Mode].Columns;
+ MaxRow = Private->ModeData[Mode].Rows;
+ DeltaX = (UINTN) Private->ModeData[Mode].DeltaX;
+ DeltaY = (UINTN) Private->ModeData[Mode].DeltaY;
+ Width = MaxColumn * EFI_GLYPH_WIDTH;
+ Height = (MaxRow - 1) * EFI_GLYPH_HEIGHT;
+ Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+
+ //
+ // The Attributes won't change when during the time OutputString is called
+ //
+ GetTextColors (This, &Foreground, &Background);
+
+ FlushCursor (This);
+
+ Warning = FALSE;
+
+ //
+ // Backup attribute
+ //
+ OriginAttribute = This->Mode->Attribute;
+
+ while (*WString != L'\0') {
+
+ if (*WString == CHAR_BACKSPACE) {
+ //
+ // If the cursor is at the left edge of the display, then move the cursor
+ // one row up.
+ //
+ if (This->Mode->CursorColumn == 0 && This->Mode->CursorRow > 0) {
+ This->Mode->CursorRow--;
+ This->Mode->CursorColumn = (INT32) (MaxColumn - 1);
+ This->OutputString (This, SpaceStr);
+ FlushCursor (This);
+ This->Mode->CursorRow--;
+ This->Mode->CursorColumn = (INT32) (MaxColumn - 1);
+ } else if (This->Mode->CursorColumn > 0) {
+ //
+ // If the cursor is not at the left edge of the display, then move the cursor
+ // left one column.
+ //
+ This->Mode->CursorColumn--;
+ This->OutputString (This, SpaceStr);
+ FlushCursor (This);
+ This->Mode->CursorColumn--;
+ }
+
+ WString++;
+
+ } else if (*WString == CHAR_LINEFEED) {
+ //
+ // If the cursor is at the bottom of the display, then scroll the display one
+ // row, and do not update the cursor position. Otherwise, move the cursor
+ // down one row.
+ //
+ if (This->Mode->CursorRow == (INT32) (MaxRow - 1)) {
+ //
+ // Scroll Screen Up One Row
+ //
+ GraphicsOutput->Blt (
+ GraphicsOutput,
+ NULL,
+ EfiBltVideoToVideo,
+ DeltaX,
+ DeltaY + EFI_GLYPH_HEIGHT,
+ DeltaX,
+ DeltaY,
+ Width,
+ Height,
+ Delta
+ );
+
+ //
+ // Print Blank Line at last line
+ //
+ GraphicsOutput->Blt (
+ GraphicsOutput,
+ &Background,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ DeltaX,
+ DeltaY + Height,
+ Width,
+ EFI_GLYPH_HEIGHT,
+ Delta
+ );
+ } else {
+ This->Mode->CursorRow++;
+ }
+
+ WString++;
+
+ } else if (*WString == CHAR_CARRIAGE_RETURN) {
+ //
+ // Move the cursor to the beginning of the current row.
+ //
+ This->Mode->CursorColumn = 0;
+ WString++;
+
+ } else if (*WString == WIDE_CHAR) {
+
+ This->Mode->Attribute |= EFI_WIDE_ATTRIBUTE;
+ WString++;
+
+ } else if (*WString == NARROW_CHAR) {
+
+ This->Mode->Attribute &= (~ (UINT32) EFI_WIDE_ATTRIBUTE);
+ WString++;
+
+ } else {
+ //
+ // Print the character at the current cursor position and move the cursor
+ // right one column. If this moves the cursor past the right edge of the
+ // display, then the line should wrap to the beginning of the next line. This
+ // is equivalent to inserting a CR and an LF. Note that if the cursor is at the
+ // bottom of the display, and the line wraps, then the display will be scrolled
+ // one line.
+ // If wide char is going to be displayed, need to display one character at a time
+ // Or, need to know the display length of a certain string.
+ //
+ // Index is used to determine how many character width units (wide = 2, narrow = 1)
+ // Count is used to determine how many characters are used regardless of their attributes
+ //
+ for (Count = 0, Index = 0; (This->Mode->CursorColumn + Index) < MaxColumn; Count++, Index++) {
+ if (WString[Count] == CHAR_NULL ||
+ WString[Count] == CHAR_BACKSPACE ||
+ WString[Count] == CHAR_LINEFEED ||
+ WString[Count] == CHAR_CARRIAGE_RETURN ||
+ WString[Count] == WIDE_CHAR ||
+ WString[Count] == NARROW_CHAR) {
+ break;
+ }
+ //
+ // Is the wide attribute on?
+ //
+ if ((This->Mode->Attribute & EFI_WIDE_ATTRIBUTE) != 0) {
+ //
+ // If wide, add one more width unit than normal since we are going to increment at the end of the for loop
+ //
+ Index++;
+ //
+ // This is the end-case where if we are at column 79 and about to print a wide character
+ // We should prevent this from happening because we will wrap inappropriately. We should
+ // not print this character until the next line.
+ //
+ if ((This->Mode->CursorColumn + Index + 1) > MaxColumn) {
+ Index++;
+ break;
+ }
+ }
+ }
+
+ Status = DrawUnicodeWeightAtCursorN (This, WString, Count);
+ if (EFI_ERROR (Status)) {
+ Warning = TRUE;
+ }
+ //
+ // At the end of line, output carriage return and line feed
+ //
+ WString += Count;
+ This->Mode->CursorColumn += (INT32) Index;
+ if (This->Mode->CursorColumn > (INT32) MaxColumn) {
+ This->Mode->CursorColumn -= 2;
+ This->OutputString (This, SpaceStr);
+ }
+
+ if (This->Mode->CursorColumn >= (INT32) MaxColumn) {
+ FlushCursor (This);
+ if (!Private->ExtendedTextOutput.AutoWrap) {
+ This->Mode->CursorColumn = MaxColumn - 1;
+ } else {
+ This->OutputString (This, mCrLfString);
+ }
+ FlushCursor (This);
+ }
+ }
+ }
+
+ This->Mode->Attribute = OriginAttribute;
+
+ FlushCursor (This);
+
+ if (Warning) {
+ Status = EFI_WARN_UNKNOWN_GLYPH;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+
+}
+
+/**
+ Verifies that all characters in a Unicode string can be output to the
+ target device.
+
+ Implements SIMPLE_TEXT_OUTPUT.TestString().
+ If one of the characters in the *Wstring is neither valid valid Unicode
+ drawing characters, not ASCII code, then this function will return
+ EFI_UNSUPPORTED
+
+ @param This Protocol instance pointer.
+ @param WString The NULL-terminated Unicode string to be examined for the output
+ device(s).
+
+ @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
+ @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be
+ rendered by one or more of the output devices mapped
+ by the EFI handle.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Count;
+
+ EFI_IMAGE_OUTPUT *Blt;
+
+ Blt = NULL;
+ Count = 0;
+
+ while (WString[Count] != 0) {
+ Status = mHiiFont->GetGlyph (
+ mHiiFont,
+ WString[Count],
+ NULL,
+ &Blt,
+ NULL
+ );
+ if (Blt != NULL) {
+ FreePool (Blt);
+ Blt = NULL;
+ }
+ Count++;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Returns information for an available text mode that the output device(s)
+ supports
+
+ Implements SIMPLE_TEXT_OUTPUT.QueryMode().
+ It returnes information for an available text mode that the Graphics Console supports.
+ In this driver,we only support text mode 80x25, which is defined as mode 0.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param Columns The returned columns of the requested mode.
+ @param Rows The returned rows of the requested mode.
+
+ @retval EFI_SUCCESS The requested mode information is returned.
+ @retval EFI_UNSUPPORTED The mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutQueryMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ )
+{
+ GRAPHICS_CONSOLE_DEV *Private;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ Status = EFI_SUCCESS;
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+
+ *Columns = Private->ModeData[ModeNumber].Columns;
+ *Rows = Private->ModeData[ModeNumber].Rows;
+
+ if (*Columns <= 0 || *Rows <= 0) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Sets the output device(s) to a specified mode.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetMode().
+ Set the Graphics Console to a specified mode. In this driver, we only support mode 0.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The text mode to set.
+
+ @retval EFI_SUCCESS The requested text mode is set.
+ @retval EFI_DEVICE_ERROR The requested text mode cannot be set because of
+ Graphics Console device error.
+ @retval EFI_UNSUPPORTED The text mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ )
+{
+ EFI_STATUS Status;
+ GRAPHICS_CONSOLE_DEV *Private;
+ GRAPHICS_CONSOLE_MODE_DATA *ModeData;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *NewLineBuffer;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ GraphicsOutput = Private->GraphicsOutput;
+
+ //
+ // Make sure the requested mode number is supported
+ //
+ if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ ModeData = &(Private->ModeData[ModeNumber]);
+
+ if (ModeData->Columns <= 0 && ModeData->Rows <= 0) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ //
+ // If the mode has been set at least one other time, then LineBuffer will not be NULL
+ //
+ if (Private->LineBuffer != NULL) {
+ //
+ // If the new mode is the same as the old mode, then just return EFI_SUCCESS
+ //
+ if ((INT32) ModeNumber == This->Mode->Mode) {
+ //
+ // Clear the current text window on the current graphics console
+ //
+ This->ClearScreen (This);
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ //
+ // Otherwise, the size of the text console and/or the GOP mode will
+ // be changed, so erase the cursor, and free the LineBuffer for the
+ // current mode
+ //
+ FlushCursor (This);
+
+ FreePool (Private->LineBuffer);
+ }
+
+ //
+ // Attempt to allocate a line buffer for the requested mode number
+ //
+ NewLineBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * ModeData->Columns * EFI_GLYPH_WIDTH * EFI_GLYPH_HEIGHT);
+
+ if (NewLineBuffer == NULL) {
+ //
+ // The new line buffer could not be allocated, so return an error.
+ // No changes to the state of the current console have been made, so the current console is still valid
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Assign the current line buffer to the newly allocated line buffer
+ //
+ Private->LineBuffer = NewLineBuffer;
+
+ if (ModeData->GopModeNumber != GraphicsOutput->Mode->Mode) {
+ //
+ // Either no graphics mode is currently set, or it is set
+ // to the wrong resolution, so set the new graphics mode
+ //
+ Status = GraphicsOutput->SetMode (GraphicsOutput, ModeData->GopModeNumber);
+ if (EFI_ERROR (Status)) {
+ //
+ // The mode set operation failed
+ //
+ goto Done;
+ }
+ } else {
+ //
+ // The current graphics mode is correct, so simply clear the entire display
+ //
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ &mGraphicsEfiColors[0],
+ EfiBltVideoFill,
+ 0,
+ 0,
+ 0,
+ 0,
+ ModeData->GopWidth,
+ ModeData->GopHeight,
+ 0
+ );
+ }
+
+ //
+ // The new mode is valid, so commit the mode change
+ //
+ This->Mode->Mode = (INT32) ModeNumber;
+
+ //
+ // Move the text cursor to the upper left hand corner of the display and flush it
+ //
+ This->Mode->CursorColumn = 0;
+ This->Mode->CursorRow = 0;
+
+ FlushCursor (This);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Sets the background and foreground colors for the OutputString () and
+ ClearScreen () functions.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetAttribute().
+
+ @param This Protocol instance pointer.
+ @param Attribute The attribute to set. Bits 0..3 are the foreground
+ color, and bits 4..6 are the background color.
+ All other bits are undefined and must be zero.
+
+ @retval EFI_SUCCESS The requested attribute is set.
+ @retval EFI_DEVICE_ERROR The requested attribute cannot be set due to Graphics Console port error.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ )
+{
+ EFI_TPL OldTpl;
+
+ if ((Attribute | 0x7F) != 0x7F) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((INT32) Attribute == This->Mode->Attribute) {
+ return EFI_SUCCESS;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ FlushCursor (This);
+
+ This->Mode->Attribute = (INT32) Attribute;
+
+ FlushCursor (This);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Clears the output device(s) display to the currently selected background
+ color.
+
+ Implements SIMPLE_TEXT_OUTPUT.ClearScreen().
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ GRAPHICS_CONSOLE_DEV *Private;
+ GRAPHICS_CONSOLE_MODE_DATA *ModeData;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ EFI_TPL OldTpl;
+
+ if (This->Mode->Mode == -1) {
+ //
+ // If current mode is not valid, return error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ GraphicsOutput = Private->GraphicsOutput;
+ ModeData = &(Private->ModeData[This->Mode->Mode]);
+
+ GetTextColors (This, &Foreground, &Background);
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ &Background,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ 0,
+ 0,
+ ModeData->GopWidth,
+ ModeData->GopHeight,
+ 0
+ );
+
+ This->Mode->CursorColumn = 0;
+ This->Mode->CursorRow = 0;
+
+ FlushCursor (This);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Sets the current coordinates of the cursor position.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetCursorPosition().
+
+ @param This Protocol instance pointer.
+ @param Column The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+ @param Row The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the
+ cursor position is invalid for the current mode.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ )
+{
+ GRAPHICS_CONSOLE_DEV *Private;
+ GRAPHICS_CONSOLE_MODE_DATA *ModeData;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (This->Mode->Mode == -1) {
+ //
+ // If current mode is not valid, return error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ ModeData = &(Private->ModeData[This->Mode->Mode]);
+
+ if ((Column >= ModeData->Columns) || (Row >= ModeData->Rows)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if ((This->Mode->CursorColumn == (INT32) Column) && (This->Mode->CursorRow == (INT32) Row)) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ FlushCursor (This);
+
+ This->Mode->CursorColumn = (INT32) Column;
+ This->Mode->CursorRow = (INT32) Row;
+
+ FlushCursor (This);
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Makes the cursor visible or invisible.
+
+ Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
+
+ @param This Protocol instance pointer.
+ @param Visible If TRUE, the cursor is set to be visible, If FALSE,
+ the cursor is set to be invisible.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_UNSUPPORTED The output device's mode is not currently in a
+ defined text mode.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ )
+{
+ EFI_TPL OldTpl;
+
+ if (This->Mode->Mode == -1) {
+ //
+ // If current mode is not valid, return error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ FlushCursor (This);
+
+ This->Mode->CursorVisible = Visible;
+
+ FlushCursor (This);
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets Graphics Console devcie's foreground color and background color.
+
+ @param This Protocol instance pointer.
+ @param Foreground Returned text foreground color.
+ @param Background Returned text background color.
+
+ @retval EFI_SUCCESS It returned always.
+
+**/
+EFI_STATUS
+GetTextColors (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Foreground,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background
+ )
+{
+ INTN Attribute;
+
+ Attribute = This->Mode->Attribute & 0x7F;
+
+ *Foreground = mGraphicsEfiColors[Attribute & 0x0f];
+ *Background = mGraphicsEfiColors[Attribute >> 4];
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Draw Unicode string on the Graphics Console device's screen.
+
+ @param This Protocol instance pointer.
+ @param UnicodeWeight One Unicode string to be displayed.
+ @param Count The count of Unicode string.
+
+ @retval EFI_OUT_OF_RESOURCES If no memory resource to use.
+ @retval EFI_UNSUPPORTED If no Graphics Output Protocol exists.
+ @retval EFI_SUCCESS Drawing Unicode string implemented successfully.
+
+**/
+EFI_STATUS
+DrawUnicodeWeightAtCursorN (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *UnicodeWeight,
+ IN UINTN Count
+ )
+{
+ EFI_STATUS Status;
+ GRAPHICS_CONSOLE_DEV *Private;
+ EFI_IMAGE_OUTPUT *Blt;
+ EFI_STRING String;
+ EFI_FONT_DISPLAY_INFO *FontInfo;
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ Blt = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+ if (Blt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Blt->Width = (UINT16) (Private->ModeData[This->Mode->Mode].GopWidth);
+ Blt->Height = (UINT16) (Private->ModeData[This->Mode->Mode].GopHeight);
+
+ String = AllocateCopyPool ((Count + 1) * sizeof (CHAR16), UnicodeWeight);
+ if (String == NULL) {
+ FreePool (Blt);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Set the end character
+ //
+ *(String + Count) = L'\0';
+
+ FontInfo = (EFI_FONT_DISPLAY_INFO *) AllocateZeroPool (sizeof (EFI_FONT_DISPLAY_INFO));
+ if (FontInfo == NULL) {
+ FreePool (Blt);
+ FreePool (String);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get current foreground and background colors.
+ //
+ GetTextColors (This, &FontInfo->ForegroundColor, &FontInfo->BackgroundColor);
+
+ //
+ // If Graphics Output protocol exists, using HII Font protocol to draw.
+ //
+ Blt->Image.Screen = Private->GraphicsOutput;
+
+ Status = mHiiFont->StringToImage (
+ mHiiFont,
+ EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_DIRECT_TO_SCREEN | EFI_HII_IGNORE_LINE_BREAK,
+ String,
+ FontInfo,
+ &Blt,
+ This->Mode->CursorColumn * EFI_GLYPH_WIDTH + Private->ModeData[This->Mode->Mode].DeltaX,
+ This->Mode->CursorRow * EFI_GLYPH_HEIGHT + Private->ModeData[This->Mode->Mode].DeltaY,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (Blt != NULL) {
+ FreePool (Blt);
+ }
+ if (String != NULL) {
+ FreePool (String);
+ }
+ if (FontInfo != NULL) {
+ FreePool (FontInfo);
+ }
+ return Status;
+}
+
+/**
+ Flush the cursor on the screen.
+
+ If CursorVisible is FALSE, nothing to do and return directly.
+ If CursorVisible is TRUE,
+ i) If the cursor shows on screen, it will be erased.
+ ii) If the cursor does not show on screen, it will be shown.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The cursor is erased successfully.
+
+**/
+EFI_STATUS
+FlushCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ )
+{
+ GRAPHICS_CONSOLE_DEV *Private;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE *CurrentMode;
+ INTN GlyphX;
+ INTN GlyphY;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Background;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION BltChar[EFI_GLYPH_HEIGHT][EFI_GLYPH_WIDTH];
+ UINTN PosX;
+ UINTN PosY;
+
+ CurrentMode = This->Mode;
+
+ if (!CurrentMode->CursorVisible) {
+ return EFI_SUCCESS;
+ }
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ GraphicsOutput = Private->GraphicsOutput;
+
+ //
+ // In this driver, only narrow character was supported.
+ //
+ //
+ // Blt a character to the screen
+ //
+ GlyphX = (CurrentMode->CursorColumn * EFI_GLYPH_WIDTH) + Private->ModeData[CurrentMode->Mode].DeltaX;
+ GlyphY = (CurrentMode->CursorRow * EFI_GLYPH_HEIGHT) + Private->ModeData[CurrentMode->Mode].DeltaY;
+
+ GraphicsOutput->Blt (
+ GraphicsOutput,
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltChar,
+ EfiBltVideoToBltBuffer,
+ GlyphX,
+ GlyphY,
+ 0,
+ 0,
+ EFI_GLYPH_WIDTH,
+ EFI_GLYPH_HEIGHT,
+ EFI_GLYPH_WIDTH * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+
+ GetTextColors (This, &Foreground.Pixel, &Background.Pixel);
+
+ //
+ // Convert Monochrome bitmap of the Glyph to BltBuffer structure
+ //
+ for (PosY = 0; PosY < EFI_GLYPH_HEIGHT; PosY++) {
+ for (PosX = 0; PosX < EFI_GLYPH_WIDTH; PosX++) {
+ if ((mCursorGlyph.GlyphCol1[PosY] & (BIT0 << PosX)) != 0) {
+ BltChar[PosY][EFI_GLYPH_WIDTH - PosX - 1].Raw ^= Foreground.Raw;
+ }
+ }
+ }
+
+ GraphicsOutput->Blt (
+ GraphicsOutput,
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltChar,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ GlyphX,
+ GlyphY,
+ EFI_GLYPH_WIDTH,
+ EFI_GLYPH_HEIGHT,
+ EFI_GLYPH_WIDTH * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ HII Database Protocol notification event handler.
+
+ Register font package when HII Database Protocol has been installed.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+RegisterFontPackage (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_SIMPLE_FONT_PACKAGE_HDR *SimplifiedFont;
+ UINT32 PackageLength;
+ UINT8 *Package;
+ UINT8 *Location;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+
+ //
+ // Locate HII Database Protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID **) &HiiDatabase
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Add 4 bytes to the header for entire length for HiiAddPackages use only.
+ //
+ // +--------------------------------+ <-- Package
+ // | |
+ // | PackageLength(4 bytes) |
+ // | |
+ // |--------------------------------| <-- SimplifiedFont
+ // | |
+ // |EFI_HII_SIMPLE_FONT_PACKAGE_HDR |
+ // | |
+ // |--------------------------------| <-- Location
+ // | |
+ // | gUsStdNarrowGlyphData |
+ // | |
+ // +--------------------------------+
+
+ PackageLength = sizeof (EFI_HII_SIMPLE_FONT_PACKAGE_HDR) + mNarrowFontSize + 4;
+ Package = AllocateZeroPool (PackageLength);
+ ASSERT (Package != NULL);
+
+ WriteUnaligned32((UINT32 *) Package,PackageLength);
+ SimplifiedFont = (EFI_HII_SIMPLE_FONT_PACKAGE_HDR *) (Package + 4);
+ SimplifiedFont->Header.Length = (UINT32) (PackageLength - 4);
+ SimplifiedFont->Header.Type = EFI_HII_PACKAGE_SIMPLE_FONTS;
+ SimplifiedFont->NumberOfNarrowGlyphs = (UINT16) (mNarrowFontSize / sizeof (EFI_NARROW_GLYPH));
+
+ Location = (UINT8 *) (&SimplifiedFont->NumberOfWideGlyphs + 1);
+ CopyMem (Location, gUsStdNarrowGlyphData, mNarrowFontSize);
+
+ //
+ // Add this simplified font package to a package list then install it.
+ //
+ mHiiHandle = HiiAddPackages (
+ &mFontPackageListGuid,
+ NULL,
+ Package,
+ NULL
+ );
+ ASSERT (mHiiHandle != NULL);
+ FreePool (Package);
+}
+
+/**
+ The user Entry Point for module GraphicsConsole. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @return other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeGraphicsConsole (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Register notify function on HII Database Protocol to add font package.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiHiiDatabaseProtocolGuid,
+ TPL_CALLBACK,
+ RegisterFontPackage,
+ NULL,
+ &mHiiRegistration
+ );
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gGraphicsConsoleDriverBinding,
+ ImageHandle,
+ &gGraphicsConsoleComponentName,
+ &gGraphicsConsoleComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsole.h b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsole.h
new file mode 100644
index 000000000000..ba93cab86bf3
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsole.h
@@ -0,0 +1,591 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2006-2016, Intel Corporation. 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 _GRAPHICS_CONSOLE_H_
+#define _GRAPHICS_CONSOLE_H_
+
+#include <Uefi.h>
+#include <Protocol/ExtendedTextOut.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiDatabase.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HiiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Guid/MdeModuleHii.h>
+
+extern EFI_COMPONENT_NAME_PROTOCOL gGraphicsConsoleComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gGraphicsConsoleComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gGraphicsConsoleDriverBinding;
+extern EFI_NARROW_GLYPH gUsStdNarrowGlyphData[];
+
+extern UINT32 mNarrowFontSize;
+
+typedef union {
+ EFI_NARROW_GLYPH NarrowGlyph;
+ EFI_WIDE_GLYPH WideGlyph;
+} GLYPH_UNION;
+
+//
+// Device Structure
+//
+#define GRAPHICS_CONSOLE_DEV_SIGNATURE SIGNATURE_32 ('g', 's', 't', 'o')
+
+typedef struct {
+ UINTN Columns;
+ UINTN Rows;
+ INTN DeltaX;
+ INTN DeltaY;
+ UINT32 GopWidth;
+ UINT32 GopHeight;
+ UINT32 GopModeNumber;
+} GRAPHICS_CONSOLE_MODE_DATA;
+
+typedef struct {
+ UINTN Signature;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SimpleTextOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutputMode;
+ GRAPHICS_CONSOLE_MODE_DATA *ModeData;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LineBuffer;
+ EXTENDED_TEXT_OUTPUT_PROTOCOL ExtendedTextOutput;
+} GRAPHICS_CONSOLE_DEV;
+
+#define GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS(a) \
+ CR (a, GRAPHICS_CONSOLE_DEV, SimpleTextOutput, GRAPHICS_CONSOLE_DEV_SIGNATURE)
+
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+/**
+ Reset the text output device hardware and optionally run diagnostics.
+
+ Implements SIMPLE_TEXT_OUTPUT.Reset().
+ If ExtendeVerification is TRUE, then perform dependent Graphics Console
+ device reset, and set display mode to mode 0.
+ If ExtendedVerification is FALSE, only set display mode to mode 0.
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The text output device was reset.
+ @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and
+ could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Write a Unicode string to the output device.
+
+ Implements SIMPLE_TEXT_OUTPUT.OutputString().
+ The Unicode string will be converted to Glyphs and will be
+ sent to the Graphics Console.
+
+ @param This Protocol instance pointer.
+ @param WString The NULL-terminated Unicode string to be displayed
+ on the output device(s). All output devices must
+ also support the Unicode drawing defined in this file.
+
+ @retval EFI_SUCCESS The string was output to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
+ the text.
+ @retval EFI_UNSUPPORTED The output device's mode is not currently in a
+ defined text mode.
+ @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
+ characters in the Unicode string could not be
+ rendered and were skipped.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ );
+
+/**
+ Verifies that all characters in a Unicode string can be output to the
+ target device.
+
+ Implements SIMPLE_TEXT_OUTPUT.TestString().
+ If one of the characters in the *Wstring is neither valid valid Unicode
+ drawing characters, not ASCII code, then this function will return
+ EFI_UNSUPPORTED
+
+ @param This Protocol instance pointer.
+ @param WString The NULL-terminated Unicode string to be examined for the output
+ device(s).
+
+ @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
+ @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be
+ rendered by one or more of the output devices mapped
+ by the EFI handle.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *WString
+ );
+
+/**
+ Returns information for an available text mode that the output device(s)
+ supports
+
+ Implements SIMPLE_TEXT_OUTPUT.QueryMode().
+ It returnes information for an available text mode that the Graphics Console supports.
+ In this driver,we only support text mode 80x25, which is defined as mode 0.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param Columns The returned columns of the requested mode.
+ @param Rows The returned rows of the requested mode.
+
+ @retval EFI_SUCCESS The requested mode information is returned.
+ @retval EFI_UNSUPPORTED The mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutQueryMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ );
+
+
+/**
+ Sets the output device(s) to a specified mode.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetMode().
+ Set the Graphics Console to a specified mode. In this driver, we only support mode 0.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The text mode to set.
+
+ @retval EFI_SUCCESS The requested text mode is set.
+ @retval EFI_DEVICE_ERROR The requested text mode cannot be set because of
+ Graphics Console device error.
+ @retval EFI_UNSUPPORTED The text mode number is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+/**
+ Sets the background and foreground colors for the OutputString () and
+ ClearScreen () functions.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetAttribute().
+
+ @param This Protocol instance pointer.
+ @param Attribute The attribute to set. Bits 0..3 are the foreground
+ color, and bits 4..6 are the background color.
+ All other bits are undefined and must be zero.
+
+ @retval EFI_SUCCESS The requested attribute is set.
+ @retval EFI_DEVICE_ERROR The requested attribute cannot be set due to Graphics Console port error.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ );
+
+/**
+ Clears the output device(s) display to the currently selected background
+ color.
+
+ Implements SIMPLE_TEXT_OUTPUT.ClearScreen().
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ );
+
+/**
+ Sets the current coordinates of the cursor position.
+
+ Implements SIMPLE_TEXT_OUTPUT.SetCursorPosition().
+
+ @param This Protocol instance pointer.
+ @param Column The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+ @param Row The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the
+ cursor position is invalid for the current mode.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ );
+
+
+/**
+ Makes the cursor visible or invisible.
+
+ Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
+
+ @param This Protocol instance pointer.
+ @param Visible If TRUE, the cursor is set to be visible, If FALSE,
+ the cursor is set to be invisible.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleConOutEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ );
+
+/**
+ Test to see if Graphics Console could be supported on the Controller.
+
+ Graphics Console could be supported if Graphics Output Protocol exists
+ on the Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+/**
+ Start this driver on Controller by opening the Graphics Output Protocol,
+ and installing Simple Text Out protocol on Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to Controller.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on Controller by removing Simple Text Out protocol
+ and closing the Graphics Output Protocol on Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval EFI_NOT_STARTED Simple Text Out protocol could not be found the
+ Controller.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+GraphicsConsoleControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+
+/**
+ Locate HII Database protocol and HII Font protocol.
+
+ @retval EFI_SUCCESS HII Database protocol and HII Font protocol
+ are located successfully.
+ @return other Failed to locate HII Database protocol or
+ HII Font protocol.
+
+**/
+EFI_STATUS
+EfiLocateHiiProtocol (
+ VOID
+ );
+
+
+/**
+ Gets Graphics Console devcie's foreground color and background color.
+
+ @param This Protocol instance pointer.
+ @param Foreground Returned text foreground color.
+ @param Background Returned text background color.
+
+ @retval EFI_SUCCESS It returned always.
+
+**/
+EFI_STATUS
+GetTextColors (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Foreground,
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background
+ );
+
+/**
+ Draw Unicode string on the Graphics Console device's screen.
+
+ @param This Protocol instance pointer.
+ @param UnicodeWeight One Unicode string to be displayed.
+ @param Count The count of Unicode string.
+
+ @retval EFI_OUT_OF_RESOURCES If no memory resource to use.
+ @retval EFI_UNSUPPORTED If no Graphics Output Protocol exists.
+ @retval EFI_SUCCESS Drawing Unicode string implemented successfully.
+
+**/
+EFI_STATUS
+DrawUnicodeWeightAtCursorN (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *UnicodeWeight,
+ IN UINTN Count
+ );
+
+/**
+ Flush the cursor on the screen.
+
+ If CursorVisible is FALSE, nothing to do and return directly.
+ If CursorVisible is TRUE,
+ i) If the cursor shows on screen, it will be erased.
+ ii) If the cursor does not show on screen, it will be shown.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The cursor is erased successfully.
+
+**/
+EFI_STATUS
+FlushCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ );
+
+/**
+ Check if the current specific mode supported the user defined resolution
+ for the Graphics Console device based on Graphics Output Protocol.
+
+ If yes, set the graphic device's current mode to this specific mode.
+
+ @param GraphicsOutput Graphics Output Protocol instance pointer.
+ @param HorizontalResolution User defined horizontal resolution
+ @param VerticalResolution User defined vertical resolution.
+ @param CurrentModeNumber Current specific mode to be check.
+
+ @retval EFI_SUCCESS The mode is supported.
+ @retval EFI_UNSUPPORTED The specific mode is out of range of graphics
+ device supported.
+ @retval other The specific mode does not support user defined
+ resolution or failed to set the current mode to the
+ specific mode on graphics device.
+
+**/
+EFI_STATUS
+CheckModeSupported (
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+ IN UINT32 HorizontalResolution,
+ IN UINT32 VerticalResolution,
+ OUT UINT32 *CurrentModeNumber
+ );
+
+#endif
diff --git a/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
new file mode 100644
index 000000000000..cf359b414682
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
@@ -0,0 +1,74 @@
+#/** @file
+#
+# Copyright (c) 2006-2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+#
+# 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 = 0x00010005
+ BASE_NAME = GraphicsConsoleDxe
+ MODULE_UNI_FILE = GraphicsConsoleDxe.uni
+ FILE_GUID = CCCB0C28-4B24-11d5-9A5A-0090273FC14D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.1
+ ENTRY_POINT = InitializeGraphicsConsole
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC AARCH64
+#
+# DRIVER_BINDING = gGraphicsConsoleDriverBinding
+# COMPONENT_NAME = gGraphicsConsoleComponentName
+# COMPONENT_NAME2 = gGraphicsConsoleComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ NewFont.c
+ GraphicsConsole.c
+ GraphicsConsole.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ MemoryAllocationLib
+ BmpSupportLib
+ BaseMemoryLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ HiiLib
+ PcdLib
+
+[Protocols]
+ gEfiDevicePathProtocolGuid
+ gEfiSimpleTextOutProtocolGuid
+ gEfiGraphicsOutputProtocolGuid
+ gEfiHiiFontProtocolGuid
+ gEfiHiiDatabaseProtocolGuid
+ gExtendedTextOutputProtocolGuid
+
+[FeaturePcd]
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ GraphicsConsoleDxeExtra.uni
diff --git a/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxe.uni b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxe.uni
new file mode 100644
index 000000000000..09336b5cae36
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxe.uni
@@ -0,0 +1,19 @@
+/** @file
+ *
+ * Copyright (c) 2006-2014, Intel Corporation. All rights reserved.
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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.
+ *
+ **/
+
+#string STR_MODULE_ABSTRACT #language en-US "Console support on graphic devices"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Install SimpleTextOutputProtocol on GraphicsOutputProtocol devices\n"
+
--git a/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxeExtra.uni b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxeExtra.uni
new file mode 100644
index 000000000000..cb8a6e0dbb5e
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxeExtra.uni
@@ -0,0 +1,20 @@
+/** @file
+ *
+ * Copyright (c) 2006-2014, Intel Corporation. All rights reserved.
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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.
+ *
+ **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Graphics Console DXE Driver"
+
+
diff --git a/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/NewFont.c b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/NewFont.c
new file mode 100644
index 000000000000..6331b89b10dd
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/NewFont.c
@@ -0,0 +1,288 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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.
+ *
+ **/
+
+/*
+ * Based on ftp://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT and
+ * https://en.wikipedia.org/wiki/Code_page_437 for the cp437 Unicode equivalents
+ * and the cp437 8x19 font from that_editor.
+ *
+ * https://github.com/bisqwit/that_editor/blob/master/8x19.inc
+ * https://github.com/bisqwit/that_editor/blob/master/sourcematerial/vga8x19.bdf
+ * https://github.com/stsp/dosemu2/blob/master/COPYING.DOSEMU
+ */
+
+#include "GraphicsConsole.h"
+
+EFI_NARROW_GLYPH gUsStdNarrowGlyphData[] = {
+ { 0x263a, 0x00, {0x00,0x00,0x7E,0x81,0xA5,0xA5,0x81,0x81,0xA5,0xA5,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x263b, 0x00, {0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xFF,0xDB,0xE7,0xFF,0xFF,0xFF,0x7E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2665, 0x00, {0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2666, 0x00, {0x00,0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2663, 0x00, {0x00,0x00,0x00,0x18,0x3C,0x3C,0xFF,0xE7,0xE7,0xE7,0xFF,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2660, 0x00, {0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0xFF,0x7E,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2022, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x25d8, 0x00, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}},
+ { 0x25cb, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x66,0x42,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x25d9, 0x00, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDB,0x99,0xBD,0xBD,0x99,0xDB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}},
+ { 0x2642, 0x00, {0x00,0x00,0x1E,0x06,0x0E,0x0A,0x1A,0x78,0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2640, 0x00, {0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x266a, 0x00, {0x00,0x00,0x3F,0x33,0x33,0x3F,0x30,0x30,0x30,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00}},
+ { 0x266b, 0x00, {0x00,0x00,0x7F,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00,0x00}},
+ { 0x263c, 0x00, {0x00,0x00,0x00,0x18,0x18,0xDB,0xFF,0x3C,0xE7,0x3C,0xFF,0xDB,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x25ba, 0x00, {0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00}},
+ { 0x25c4, 0x00, {0x00,0x02,0x06,0x0E,0x1E,0x3E,0x7E,0xFE,0x7E,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2195, 0x00, {0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x203c, 0x00, {0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b6, 0x00, {0x00,0x00,0x7F,0xDB,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00a7, 0x00, {0x00,0x00,0x7C,0xC6,0x62,0x30,0x78,0x4C,0x64,0x3C,0x18,0x8C,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x25ac, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00}},
+ { 0x21a8, 0x00, {0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2191, 0x00, {0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2193, 0x00, {0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2192, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2190, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x221f, 0x00, {0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2194, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x25b2, 0x00, {0x00,0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x25bc, 0x00, {0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0020, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0021, 0x00, {0x00,0x00,0x18,0x3C,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0022, 0x00, {0x66,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0023, 0x00, {0x00,0x00,0x00,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0024, 0x00, {0x10,0x10,0x7C,0xD6,0xD6,0xD2,0x70,0x38,0x1C,0x16,0x96,0xD6,0xD6,0x7C,0x10,0x10,0x00,0x00,0x00}},
+ { 0x0025, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0026, 0x00, {0x00,0x00,0x38,0x6C,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0027, 0x00, {0x30,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0028, 0x00, {0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0029, 0x00, {0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,0x00}},
+ { 0x002a, 0x00, {0x00,0x00,0x00,0x00,0x00,0x66,0x24,0x3C,0xFF,0x3C,0x24,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x002b, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x002c, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x30,0x00,0x00,0x00,0x00}},
+ { 0x002d, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x002e, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x002f, 0x00, {0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0030, 0x00, {0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0031, 0x00, {0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0032, 0x00, {0x00,0x00,0x7C,0xC6,0x06,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0033, 0x00, {0x00,0x00,0x7C,0xC6,0x06,0x06,0x06,0x3C,0x06,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0034, 0x00, {0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0035, 0x00, {0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0036, 0x00, {0x00,0x00,0x38,0x60,0xC0,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0037, 0x00, {0x00,0x00,0xFE,0xC6,0x06,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0038, 0x00, {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0039, 0x00, {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00,0x00}},
+ { 0x003a, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x003b, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,0x00}},
+ { 0x003c, 0x00, {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,0x00}},
+ { 0x003d, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x003e, 0x00, {0x00,0x00,0x00,0xC0,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0xC0,0x00,0x00,0x00,0x00,0x00}},
+ { 0x003f, 0x00, {0x00,0x00,0x7C,0xC6,0x86,0x06,0x0C,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0040, 0x00, {0x00,0x00,0x00,0x7C,0xC6,0xC6,0xCE,0xDE,0xDE,0xDE,0xDE,0xCC,0xC0,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0041, 0x00, {0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0042, 0x00, {0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0043, 0x00, {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0044, 0x00, {0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0045, 0x00, {0x00,0x00,0xFE,0x66,0x62,0x62,0x68,0x78,0x68,0x60,0x62,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0046, 0x00, {0x00,0x00,0xFE,0x66,0x62,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0047, 0x00, {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0048, 0x00, {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0049, 0x00, {0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x004a, 0x00, {0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,0x00}},
+ { 0x004b, 0x00, {0x00,0x00,0xE6,0x66,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x004c, 0x00, {0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,0x00}},
+ { 0x004d, 0x00, {0x00,0x00,0xC6,0xEE,0xFE,0xD6,0xD6,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x004e, 0x00, {0x00,0x00,0xC6,0xE6,0xF6,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x004f, 0x00, {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0050, 0x00, {0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0051, 0x00, {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00,0x00}},
+ { 0x0052, 0x00, {0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0053, 0x00, {0x00,0x00,0x7C,0xC6,0xC6,0xC2,0x60,0x38,0x0C,0x06,0x86,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0054, 0x00, {0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0055, 0x00, {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0056, 0x00, {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0057, 0x00, {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0058, 0x00, {0x00,0x00,0xC6,0xC6,0x6C,0x6C,0x38,0x38,0x38,0x38,0x6C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0059, 0x00, {0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x005a, 0x00, {0x00,0x00,0xFE,0xC6,0x86,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00}},
+ { 0x005b, 0x00, {0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x005c, 0x00, {0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x005d, 0x00, {0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x005e, 0x00, {0x00,0x10,0x38,0x6C,0xC6,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x005f, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00}},
+ { 0x0060, 0x00, {0x30,0x30,0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0061, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0062, 0x00, {0x00,0x00,0xE0,0x60,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0063, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0064, 0x00, {0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0065, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0066, 0x00, {0x00,0x00,0x1C,0x36,0x32,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0067, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0xCC,0x78,0x00}},
+ { 0x0068, 0x00, {0x00,0x00,0xE0,0x60,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0069, 0x00, {0x00,0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x006a, 0x00, {0x00,0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00}},
+ { 0x006b, 0x00, {0x00,0x00,0xE0,0x60,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x006c, 0x00, {0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x006d, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0xD6,0xD6,0xD6,0xD6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x006e, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00}},
+ { 0x006f, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0070, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0xF0,0x00}},
+ { 0x0071, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x0C,0x1E,0x00}},
+ { 0x0072, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0073, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC2,0x78,0x0C,0x86,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0074, 0x00, {0x00,0x00,0x10,0x30,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0075, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0076, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0077, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0078, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x10,0x38,0x6C,0xC6,0x82,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0079, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x0C,0xF8,0x00}},
+ { 0x007a, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00}},
+ { 0x007b, 0x00, {0x00,0x00,0x0E,0x18,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x007c, 0x00, {0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x007d, 0x00, {0x00,0x00,0x70,0x18,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,0x00}},
+ { 0x007e, 0x00, {0x00,0x76,0xD4,0x9C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2302, 0x00, {0x00,0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00c7, 0x00, {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00,0x00}},
+ { 0x00fc, 0x00, {0x00,0x00,0x00,0xCC,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00e9, 0x00, {0x00,0x0C,0x18,0x30,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00e2, 0x00, {0x00,0x10,0x38,0x6C,0x00,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00e4, 0x00, {0x00,0x00,0x00,0xCC,0xCC,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00e0, 0x00, {0x00,0x60,0x30,0x18,0x0C,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00e5, 0x00, {0x00,0x38,0x6C,0x6C,0x38,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00e7, 0x00, {0x00,0x00,0x00,0x00,0x3C,0x66,0x62,0x60,0x60,0x66,0x64,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00,0x00}},
+ { 0x00ea, 0x00, {0x00,0x10,0x38,0x6C,0x44,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00eb, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00e8, 0x00, {0x00,0x60,0x30,0x18,0x0C,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ef, 0x00, {0x00,0x00,0x00,0x66,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ee, 0x00, {0x00,0x18,0x3C,0x66,0x42,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ec, 0x00, {0x00,0x60,0x30,0x18,0x08,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00c4, 0x00, {0xC6,0xC6,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00c5, 0x00, {0x38,0x28,0x38,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00c9, 0x00, {0x18,0x30,0x60,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00e6, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xCC,0x76,0x36,0x36,0x7E,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00c6, 0x00, {0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00f4, 0x00, {0x00,0x10,0x38,0x6C,0x44,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00f6, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00f2, 0x00, {0x00,0x60,0x30,0x18,0x0C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00fb, 0x00, {0x00,0x30,0x78,0xCC,0x84,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00f9, 0x00, {0x00,0x60,0x30,0x18,0x0C,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ff, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x0C,0x78,0x00}},
+ { 0x00d6, 0x00, {0xC6,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00dc, 0x00, {0xC6,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00a2, 0x00, {0x08,0x08,0x3C,0x6E,0xCA,0xC8,0xC8,0xC8,0xC8,0xC8,0xC8,0xCA,0x6E,0x3C,0x08,0x08,0x00,0x00,0x00}},
+ { 0x00a3, 0x00, {0x00,0x38,0x6C,0x64,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0x62,0xE6,0xFC,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00a5, 0x00, {0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x20a7, 0x00, {0x00,0xF8,0xCC,0xCC,0xFC,0xF8,0xC4,0xCC,0xDE,0xCC,0xCC,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0192, 0x00, {0x00,0x0E,0x1B,0x19,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0x98,0xD8,0x70,0x00,0x00,0x00}},
+ { 0x00e1, 0x00, {0x00,0x18,0x30,0x60,0xC0,0x00,0x78,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ed, 0x00, {0x00,0x0C,0x18,0x30,0x20,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00f3, 0x00, {0x00,0x18,0x30,0x60,0x40,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00fa, 0x00, {0x00,0x18,0x30,0x60,0x40,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00f1, 0x00, {0x00,0x00,0x36,0xD4,0x88,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00d1, 0x00, {0x36,0xCC,0x00,0xC6,0xE6,0xF6,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00aa, 0x00, {0x00,0x3C,0x6C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ba, 0x00, {0x00,0x38,0x6C,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00bf, 0x00, {0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x30,0x60,0xC0,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2310, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ac, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00bd, 0x00, {0x00,0xC0,0xC0,0xC0,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC0,0x9C,0x06,0x0C,0x18,0x3E,0x00,0x00,0x00}},
+ { 0x00bc, 0x00, {0x00,0xC0,0xC0,0xC0,0xC2,0xC6,0x0C,0x18,0x30,0x66,0xCE,0x9A,0x32,0x3E,0x06,0x06,0x00,0x00,0x00}},
+ { 0x00a1, 0x00, {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00ab, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00bb, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2591, 0x00, {0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11}},
+ { 0x2592, 0x00, {0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55}},
+ { 0x2593, 0x00, {0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD}},
+ { 0x2502, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2524, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2561, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2562, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x2556, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x2555, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2563, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x2551, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x2557, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x255d, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x255c, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x255b, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2510, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2514, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2534, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x252c, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x251c, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2500, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x253c, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x255e, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x255f, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x255a, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2554, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x2569, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2566, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x2560, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x2550, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x256c, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x2567, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2568, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2564, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2565, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x2559, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2558, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2552, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2553, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x256b, 0x00, {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36}},
+ { 0x256a, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2518, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x250c, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2588, 0x00, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}},
+ { 0x2584, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}},
+ { 0x258c, 0x00, {0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0}},
+ { 0x2590, 0x00, {0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F}},
+ { 0x2580, 0x00, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x03b1, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00df, 0x00, {0x00,0x00,0x78,0xCC,0xCC,0xCC,0xCC,0xD8,0xCC,0xC6,0xC6,0xC6,0xC6,0xCC,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0393, 0x00, {0x00,0x00,0xFE,0xC6,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00}},
+ { 0x03c0, 0x00, {0x00,0x00,0x00,0x00,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x03a3, 0x00, {0x00,0x00,0x00,0xFE,0xC6,0xC2,0x60,0x30,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00}},
+ { 0x03c3, 0x00, {0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b5, 0x00, {0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xC0,0x00,0x00,0x00,0x00}},
+ { 0x03c4, 0x00, {0x00,0x00,0x00,0x00,0x76,0xDC,0x98,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}},
+ { 0x03a6, 0x00, {0x00,0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0398, 0x00, {0x00,0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,0x00}},
+ { 0x03a9, 0x00, {0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00,0x00}},
+ { 0x03b4, 0x00, {0x00,0x00,0x1E,0x20,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x221e, 0x00, {0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x03c6, 0x00, {0x00,0x00,0x00,0x03,0x06,0x7E,0xDB,0xDB,0xDB,0xDB,0xD3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00,0x00}},
+ { 0x03b5, 0x00, {0x00,0x00,0x1C,0x30,0x60,0x60,0x60,0x7C,0x60,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2229, 0x00, {0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2261, 0x00, {0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b1, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2265, 0x00, {0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x7E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2264, 0x00, {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x7E,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2320, 0x00, {0x00,0x00,0x0E,0x1B,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
+ { 0x2321, 0x00, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00}},
+ { 0x00f7, 0x00, {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2248, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b0, 0x00, {0x00,0x38,0x6C,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x2219, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b7, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x221a, 0x00, {0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00,0x00}},
+ { 0x207f, 0x00, {0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00b2, 0x00, {0x00,0x70,0xD8,0x10,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x25a0, 0x00, {0x00,0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x00a0, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ { 0x0000, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} //EOL
+};
+
+// Get available Unicode glyphs narrow fonts(8*19 pixels) size.
+UINT32 mNarrowFontSize = sizeof (gUsStdNarrowGlyphData);
+
diff --git a/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/ComponentName.c b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/ComponentName.c
new file mode 100644
index 000000000000..80eb4ff9a870
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/ComponentName.c
@@ -0,0 +1,163 @@
+/** @file
+ *
+ * Component Name Protocol implementation for the MMC DXE driver
+ *
+ * Copyright (c) 2011, ARM 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.
+ *
+ **/
+
+#include "Mmc.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gMmcComponentName = {
+ MmcGetDriverName,
+ MmcGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gMmcComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) MmcGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) MmcGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
+mMmcDriverNameTable[] = {
+ {"eng;en", L"MMC/SD Card Interface Driver"},
+ {NULL, NULL}
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+ @param DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mMmcDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gMmcComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+ @param ChildHandle The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+ @param ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Diagnostics.c b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Diagnostics.c
new file mode 100644
index 000000000000..f0ff16708b67
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Diagnostics.c
@@ -0,0 +1,256 @@
+/** @file
+ *
+ * Diagnostics Protocol implementation for the MMC DXE driver
+ *
+ * Copyright (c) 2011-2014, ARM 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.
+ *
+ **/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+
+#include "Mmc.h"
+
+#define DIAGNOSTIC_LOGBUFFER_MAXCHAR 1024
+
+CHAR16* mLogBuffer = NULL;
+UINTN mLogRemainChar = 0;
+
+CHAR16*
+DiagnosticInitLog (
+ UINTN MaxBufferChar
+ )
+{
+ mLogRemainChar = MaxBufferChar;
+ mLogBuffer = AllocatePool ((UINTN)MaxBufferChar * sizeof (CHAR16));
+ return mLogBuffer;
+}
+
+UINTN
+DiagnosticLog (
+ CONST CHAR16* Str
+ )
+{
+ UINTN len = StrLen (Str);
+ if (len < mLogRemainChar) {
+ StrCpyS (mLogBuffer, mLogRemainChar, Str);
+ mLogRemainChar -= len;
+ mLogBuffer += len;
+ return len;
+ } else {
+ return 0;
+ }
+}
+
+VOID
+GenerateRandomBuffer (
+ VOID* Buffer,
+ UINTN BufferSize
+ )
+{
+ UINT64 i;
+ UINT64* Buffer64 = (UINT64*)Buffer;
+
+ for (i = 0; i < (BufferSize >> 3); i++) {
+ *Buffer64 = i | (~i << 32);
+ Buffer64++;
+ }
+}
+
+BOOLEAN
+CompareBuffer (
+ VOID *BufferA,
+ VOID *BufferB,
+ UINTN BufferSize
+ )
+{
+ UINTN i;
+ UINT64* BufferA64 = (UINT64*)BufferA;
+ UINT64* BufferB64 = (UINT64*)BufferB;
+
+ for (i = 0; i < (BufferSize >> 3); i++) {
+ if (*BufferA64 != *BufferB64) {
+ DEBUG ((DEBUG_ERROR, "CompareBuffer: Error at %i", i));
+ DEBUG ((DEBUG_ERROR, "(0x%lX) != (0x%lX)\n", *BufferA64, *BufferB64));
+ return FALSE;
+ }
+ BufferA64++;
+ BufferB64++;
+ }
+ return TRUE;
+}
+
+EFI_STATUS
+MmcReadWriteDataTest (
+ MMC_HOST_INSTANCE *MmcHostInstance,
+ EFI_LBA Lba,
+ UINTN BufferSize
+ )
+{
+ VOID *BackBuffer;
+ VOID *WriteBuffer;
+ VOID *ReadBuffer;
+ EFI_STATUS Status;
+
+ // Check if a Media is Present
+ if (!MmcHostInstance->BlockIo.Media->MediaPresent) {
+ DiagnosticLog (L"ERROR: No Media Present\n");
+ return EFI_NO_MEDIA;
+ }
+
+ if (MmcHostInstance->State != MmcTransferState) {
+ DiagnosticLog (L"ERROR: Not ready for Transfer state\n");
+ return EFI_NOT_READY;
+ }
+
+ BackBuffer = AllocatePool (BufferSize);
+ WriteBuffer = AllocatePool (BufferSize);
+ ReadBuffer = AllocatePool (BufferSize);
+
+ // Read (and save) buffer at a specific location
+ Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer);
+ if (Status != EFI_SUCCESS) {
+ DiagnosticLog (L"ERROR: Fail to Read Block (1)\n");
+ return Status;
+ }
+
+ // Write buffer at the same location
+ GenerateRandomBuffer (WriteBuffer,BufferSize);
+ Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,WriteBuffer);
+ if (Status != EFI_SUCCESS) {
+ DiagnosticLog (L"ERROR: Fail to Write Block (1)\n");
+ return Status;
+ }
+
+ // Read the buffer at the same location
+ Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer);
+ if (Status != EFI_SUCCESS) {
+ DiagnosticLog (L"ERROR: Fail to Read Block (2)\n");
+ return Status;
+ }
+
+ // Check that is conform
+ if (!CompareBuffer (ReadBuffer,WriteBuffer,BufferSize)) {
+ DiagnosticLog (L"ERROR: Fail to Read/Write Block (1)\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Restore content at the original location
+ Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer);
+ if (Status != EFI_SUCCESS) {
+ DiagnosticLog (L"ERROR: Fail to Write Block (2)\n");
+ return Status;
+ }
+
+ // Read the restored content
+ Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer);
+ if (Status != EFI_SUCCESS) {
+ DiagnosticLog (L"ERROR: Fail to Read Block (3)\n");
+ return Status;
+ }
+
+ // Check the content is correct
+ if (!CompareBuffer (ReadBuffer,BackBuffer,BufferSize)) {
+ DiagnosticLog (L"ERROR: Fail to Read/Write Block (2)\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MmcDriverDiagnosticsRunDiagnostics (
+ IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
+ IN CHAR8 *Language,
+ OUT EFI_GUID **ErrorType,
+ OUT UINTN *BufferSize,
+ OUT CHAR16 **Buffer
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ MMC_HOST_INSTANCE *MmcHostInstance;
+ EFI_STATUS Status;
+
+ if ((Language == NULL) ||
+ (ErrorType == NULL) ||
+ (Buffer == NULL) ||
+ (ControllerHandle == NULL) ||
+ (BufferSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check Language is supported (i.e. is "en-*" - only English is supported)
+ if (AsciiStrnCmp (Language, "en", 2) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+ *ErrorType = NULL;
+ *BufferSize = DIAGNOSTIC_LOGBUFFER_MAXCHAR;
+ *Buffer = DiagnosticInitLog (DIAGNOSTIC_LOGBUFFER_MAXCHAR);
+
+ DiagnosticLog (L"MMC Driver Diagnostics\n");
+
+ // Find the MMC Host instance on which we have been asked to run diagnostics
+ MmcHostInstance = NULL;
+ CurrentLink = mMmcHostPool.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {
+ MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
+ ASSERT(MmcHostInstance != NULL);
+ if (MmcHostInstance->MmcHandle == ControllerHandle) {
+ break;
+ }
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ // If we didn't find the controller, return EFI_UNSUPPORTED
+ if ((MmcHostInstance == NULL)
+ || (MmcHostInstance->MmcHandle != ControllerHandle)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ // LBA=1 Size=BlockSize
+ DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block\n");
+ Status = MmcReadWriteDataTest (MmcHostInstance, 1, MmcHostInstance->BlockIo.Media->BlockSize);
+
+ // LBA=2 Size=BlockSize
+ DiagnosticLog (L"MMC Driver Diagnostics - Test: Second Block\n");
+ Status = MmcReadWriteDataTest (MmcHostInstance, 2, MmcHostInstance->BlockIo.Media->BlockSize);
+
+ // LBA=10 Size=BlockSize
+ DiagnosticLog (L"MMC Driver Diagnostics - Test: Any Block\n");
+ Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock >> 1, MmcHostInstance->BlockIo.Media->BlockSize);
+
+ // LBA=LastBlock Size=BlockSize
+ DiagnosticLog (L"MMC Driver Diagnostics - Test: Last Block\n");
+ Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock, MmcHostInstance->BlockIo.Media->BlockSize);
+
+ // LBA=1 Size=2*BlockSize
+ DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block / 2 BlockSSize\n");
+ Status = MmcReadWriteDataTest (MmcHostInstance, 1, 2 * MmcHostInstance->BlockIo.Media->BlockSize);
+
+ return Status;
+}
+
+//
+// EFI Driver Diagnostics 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2 = {
+ (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) MmcDriverDiagnosticsRunDiagnostics,
+ "en"
+};
diff --git a/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Mmc.c b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Mmc.c
new file mode 100644
index 000000000000..d90cf3018251
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Mmc.c
@@ -0,0 +1,458 @@
+/** @file
+ *
+ * Main file of the MMC Dxe driver. The driver entrypoint is defined into this file.
+ *
+ * Copyright (c) 2011-2013, ARM 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.
+ *
+ **/
+
+#include <Protocol/DevicePath.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "Mmc.h"
+
+EFI_BLOCK_IO_MEDIA mMmcMediaTemplate = {
+ SIGNATURE_32('m','m','c','o'), // MediaId
+ TRUE, // RemovableMedia
+ FALSE, // MediaPresent
+ FALSE, // LogicalPartition
+ FALSE, // ReadOnly
+ FALSE, // WriteCaching
+ 512, // BlockSize
+ 4, // IoAlign
+ 0, // Pad
+ 0 // LastBlock
+};
+
+//
+// This device structure is serviced as a header.
+// Its next field points to the first root bridge device node.
+//
+LIST_ENTRY mMmcHostPool;
+
+/**
+ Event triggered by the timer to check if any cards have been removed
+ or if new ones have been plugged in
+**/
+
+EFI_EVENT gCheckCardsEvent;
+
+/**
+ Initialize the MMC Host Pool to support multiple MMC devices
+**/
+VOID
+InitializeMmcHostPool (
+ VOID
+ )
+{
+ InitializeListHead (&mMmcHostPool);
+}
+
+/**
+ Insert a new Mmc Host controller to the pool
+**/
+VOID
+InsertMmcHost (
+ IN MMC_HOST_INSTANCE *MmcHostInstance
+ )
+{
+ InsertTailList (&mMmcHostPool, &(MmcHostInstance->Link));
+}
+
+/*
+ Remove a new Mmc Host controller to the pool
+*/
+VOID
+RemoveMmcHost (
+ IN MMC_HOST_INSTANCE *MmcHostInstance
+ )
+{
+ RemoveEntryList (&(MmcHostInstance->Link));
+}
+
+MMC_HOST_INSTANCE* CreateMmcHostInstance (
+ IN EFI_MMC_HOST_PROTOCOL* MmcHost
+ )
+{
+ EFI_STATUS Status;
+ MMC_HOST_INSTANCE* MmcHostInstance;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ MmcHostInstance = AllocateZeroPool (sizeof (MMC_HOST_INSTANCE));
+ if (MmcHostInstance == NULL) {
+ return NULL;
+ }
+
+ MmcHostInstance->Signature = MMC_HOST_INSTANCE_SIGNATURE;
+
+ MmcHostInstance->State = MmcHwInitializationState;
+
+ MmcHostInstance->BlockIo.Media = AllocateCopyPool (sizeof(EFI_BLOCK_IO_MEDIA), &mMmcMediaTemplate);
+ if (MmcHostInstance->BlockIo.Media == NULL) {
+ goto FREE_INSTANCE;
+ }
+
+ MmcHostInstance->BlockIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION;
+ MmcHostInstance->BlockIo.Reset = MmcReset;
+ MmcHostInstance->BlockIo.ReadBlocks = MmcReadBlocks;
+ MmcHostInstance->BlockIo.WriteBlocks = MmcWriteBlocks;
+ MmcHostInstance->BlockIo.FlushBlocks = MmcFlushBlocks;
+
+ MmcHostInstance->MmcHost = MmcHost;
+
+ // Create DevicePath for the new MMC Host
+ Status = MmcHost->BuildDevicePath (MmcHost, &NewDevicePathNode);
+ if (EFI_ERROR (Status)) {
+ goto FREE_MEDIA;
+ }
+
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);
+ if (DevicePath == NULL) {
+ goto FREE_MEDIA;
+ }
+
+ SetDevicePathEndNode (DevicePath);
+ MmcHostInstance->DevicePath = AppendDevicePathNode (DevicePath, NewDevicePathNode);
+
+ // Publish BlockIO protocol interface
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &MmcHostInstance->MmcHandle,
+ &gEfiBlockIoProtocolGuid,&MmcHostInstance->BlockIo,
+ &gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR(Status)) {
+ goto FREE_DEVICE_PATH;
+ }
+
+ return MmcHostInstance;
+
+FREE_DEVICE_PATH:
+ FreePool(DevicePath);
+
+FREE_MEDIA:
+ FreePool(MmcHostInstance->BlockIo.Media);
+
+FREE_INSTANCE:
+ FreePool(MmcHostInstance);
+
+ return NULL;
+}
+
+EFI_STATUS DestroyMmcHostInstance (
+ IN MMC_HOST_INSTANCE* MmcHostInstance
+ )
+{
+ EFI_STATUS Status;
+
+ // Uninstall Protocol Interfaces
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ MmcHostInstance->MmcHandle,
+ &gEfiBlockIoProtocolGuid,&(MmcHostInstance->BlockIo),
+ &gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ // Free Memory allocated for the instance
+ if (MmcHostInstance->BlockIo.Media) {
+ FreePool(MmcHostInstance->BlockIo.Media);
+ }
+ if (MmcHostInstance->CardInfo.ECSDData) {
+ FreePages (MmcHostInstance->CardInfo.ECSDData, EFI_SIZE_TO_PAGES (sizeof (ECSD)));
+ }
+ FreePool (MmcHostInstance);
+
+ return Status;
+}
+
+/**
+ This function checks if the controller implement the Mmc Host and the Device Path Protocols
+**/
+EFI_STATUS
+EFIAPI
+MmcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ //EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_MMC_HOST_PROTOCOL *MmcHost;
+ EFI_DEV_PATH_PTR Node;
+
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, go on checking other conditions
+ //
+ if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ Node.DevPath = RemainingDevicePath;
+ if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
+ Node.DevPath->SubType != HW_VENDOR_DP ||
+ DevicePathNodeLength(Node.DevPath) != sizeof(VENDOR_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // Check if Mmc Host protocol is installed by platform
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gRaspberryPiMmcHostProtocolGuid,
+ (VOID **) &MmcHost,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the Mmc Host used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gRaspberryPiMmcHostProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+**/
+EFI_STATUS
+EFIAPI
+MmcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ MMC_HOST_INSTANCE *MmcHostInstance;
+ EFI_MMC_HOST_PROTOCOL *MmcHost;
+
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS
+ //
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Get the Mmc Host protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gRaspberryPiMmcHostProtocolGuid,
+ (VOID **) &MmcHost,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+ return Status;
+ }
+
+ MmcHostInstance = CreateMmcHostInstance(MmcHost);
+ if (MmcHostInstance != NULL) {
+ // Add the handle to the pool
+ InsertMmcHost (MmcHostInstance);
+
+ MmcHostInstance->Initialized = FALSE;
+
+ // Detect card presence now
+ CheckCardsCallback (NULL, NULL);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+**/
+EFI_STATUS
+EFIAPI
+MmcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ LIST_ENTRY *CurrentLink;
+ MMC_HOST_INSTANCE *MmcHostInstance;
+
+ MMC_TRACE("MmcDriverBindingStop()");
+
+ // For each MMC instance
+ CurrentLink = mMmcHostPool.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {
+ MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
+ ASSERT(MmcHostInstance != NULL);
+
+ // Close gRaspberryPiMmcHostProtocolGuid
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gRaspberryPiMmcHostProtocolGuid,(VOID **) &MmcHostInstance->MmcHost,
+ This->DriverBindingHandle
+ );
+
+ // Remove MMC Host Instance from the pool
+ RemoveMmcHost (MmcHostInstance);
+
+ // Destroy MmcHostInstance
+ DestroyMmcHostInstance (MmcHostInstance);
+ }
+
+ return Status;
+}
+
+VOID
+EFIAPI
+CheckCardsCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ MMC_HOST_INSTANCE *MmcHostInstance;
+ EFI_STATUS Status;
+
+ CurrentLink = mMmcHostPool.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &mMmcHostPool) {
+ MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
+ ASSERT(MmcHostInstance != NULL);
+
+ if (MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost) == !MmcHostInstance->Initialized) {
+ MmcHostInstance->State = MmcHwInitializationState;
+ MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized;
+ MmcHostInstance->Initialized = !MmcHostInstance->Initialized;
+
+ if (MmcHostInstance->BlockIo.Media->MediaPresent) {
+ InitializeMmcDevice (MmcHostInstance);
+ }
+
+ Status = gBS->ReinstallProtocolInterface (
+ (MmcHostInstance->MmcHandle),
+ &gEfiBlockIoProtocolGuid,
+ &(MmcHostInstance->BlockIo),
+ &(MmcHostInstance->BlockIo)
+ );
+
+ if (EFI_ERROR(Status)) {
+ Print(L"MMC Card: Error reinstalling BlockIo interface\n");
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+}
+
+
+EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding = {
+ MmcDriverBindingSupported,
+ MmcDriverBindingStart,
+ MmcDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+
+**/
+EFI_STATUS
+EFIAPI
+MmcDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Initializes MMC Host pool
+ //
+ InitializeMmcHostPool ();
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gMmcDriverBinding,
+ ImageHandle,
+ &gMmcComponentName,
+ &gMmcComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ // Install driver diagnostics
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDriverDiagnostics2ProtocolGuid,&gMmcDriverDiagnostics2,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ // Use a timer to detect if a card has been plugged in or removed
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL | EVT_TIMER,
+ TPL_CALLBACK,
+ CheckCardsCallback,
+ NULL,
+ &gCheckCardsEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->SetTimer(
+ gCheckCardsEvent,
+ TimerPeriodic,
+ (UINT64)(10*1000*200)); // 200 ms
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Mmc.h b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Mmc.h
new file mode 100644
index 000000000000..a18f4a82d903
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/Mmc.h
@@ -0,0 +1,533 @@
+/** @file
+ *
+ * Main Header file for the MMC DXE driver
+ *
+ * Copyright (c) 2011-2015, ARM 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 __MMC_H
+#define __MMC_H
+
+#include <Uefi.h>
+
+#include <Protocol/DiskIo.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PiMmcHost.h>
+
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define MMC_TRACE(txt) DEBUG((DEBUG_BLKIO, "MMC: " txt "\n"))
+
+#define MMC_IOBLOCKS_READ 0
+#define MMC_IOBLOCKS_WRITE 1
+
+#define MMC_OCR_POWERUP 0x80000000
+
+#define MMC_OCR_ACCESS_MASK 0x3 /* bit[30-29] */
+#define MMC_OCR_ACCESS_BYTE 0x1 /* bit[29] */
+#define MMC_OCR_ACCESS_SECTOR 0x2 /* bit[30] */
+
+#define MMC_CSD_GET_CCC(Response) (Response[2] >> 20)
+#define MMC_CSD_GET_TRANSPEED(Response) (Response[3] & 0xFF)
+#define MMC_CSD_GET_READBLLEN(Response) ((Response[2] >> 16) & 0xF)
+#define MMC_CSD_GET_WRITEBLLEN(Response) ((Response[0] >> 22) & 0xF)
+#define MMC_CSD_GET_FILEFORMAT(Response) ((Response[0] >> 10) & 0x3)
+#define MMC_CSD_GET_FILEFORMATGRP(Response) ((Response[0] >> 15) & 0x1)
+#define MMC_CSD_GET_DEVICESIZE(csd) (((Response[1] >> 30) & 0x3) | ((Response[2] & 0x3FF) << 2))
+#define HC_MMC_CSD_GET_DEVICESIZE(Response) ((Response[1] >> 16) | ((Response[2] & 0x3F) << 16));
+#define MMC_CSD_GET_DEVICESIZEMULT(csd) ((Response[1] >> 15) & 0x7)
+
+#define MMC_R0_READY_FOR_DATA (1 << 8)
+
+#define MMC_R0_CURRENTSTATE(Response) ((Response[0] >> 9) & 0xF)
+
+#define MMC_R0_STATE_IDLE 0
+#define MMC_R0_STATE_READY 1
+#define MMC_R0_STATE_IDENT 2
+#define MMC_R0_STATE_STDBY 3
+#define MMC_R0_STATE_TRAN 4
+#define MMC_R0_STATE_DATA 5
+#define MMC_R0_STATE_RECV 6
+#define MMC_R0_STATE_PROG 7
+#define MMC_R0_STATE_DIS 8
+
+
+#define EMMC_CMD6_ARG_ACCESS(x) (((x) & 0x3) << 24)
+#define EMMC_CMD6_ARG_INDEX(x) (((x) & 0xFF) << 16)
+#define EMMC_CMD6_ARG_VALUE(x) (((x) & 0xFF) << 8)
+#define EMMC_CMD6_ARG_CMD_SET(x) (((x) & 0x7) << 0)
+
+#define SWITCH_CMD_DATA_LENGTH 64
+#define SD_HIGH_SPEED_SUPPORTED 0x200
+#define SD_DEFAULT_SPEED 25000000
+#define SD_HIGH_SPEED 50000000
+#define SWITCH_CMD_SUCCESS_MASK 0xf
+
+#define BUSWIDTH_4 4
+
+typedef enum {
+ UNKNOWN_CARD,
+ MMC_CARD, //MMC card
+ MMC_CARD_HIGH, //MMC Card with High capacity
+ EMMC_CARD, //eMMC 4.41 card
+ SD_CARD, //SD 1.1 card
+ SD_CARD_2, //SD 2.0 or above standard card
+ SD_CARD_2_HIGH //SD 2.0 or above high capacity card
+} CARD_TYPE;
+
+typedef struct {
+ UINT32 Reserved0: 7; // 0
+ UINT32 V170_V195: 1; // 1.70V - 1.95V
+ UINT32 V200_V260: 7; // 2.00V - 2.60V
+ UINT32 V270_V360: 9; // 2.70V - 3.60V
+ UINT32 RESERVED_1: 5; // Reserved
+ UINT32 AccessMode: 2; // 00b (byte mode), 10b (sector mode)
+ UINT32 PowerUp: 1; // This bit is set to LOW if the card has not finished the power up routine
+} OCR;
+
+typedef struct {
+ UINT8 SD_SPEC: 4; // SD Memory Card - Spec. Version [59:56]
+ UINT8 SCR_STRUCTURE: 4; // SCR Structure [63:60]
+ UINT8 SD_BUS_WIDTHS: 4; // DAT Bus widths supported [51:48]
+ UINT8 DATA_STAT_AFTER_ERASE: 1; // Data Status after erases [55]
+ UINT8 SD_SECURITY: 3; // CPRM Security Support [54:52]
+ UINT8 EX_SECURITY_1: 1; // Extended Security Support [43]
+ UINT8 SD_SPEC4: 1; // Spec. Version 4.00 or higher [42]
+ UINT8 RESERVED_1: 2; // Reserved [41:40]
+ UINT8 SD_SPEC3: 1; // Spec. Version 3.00 or higher [47]
+ UINT8 EX_SECURITY_2: 3; // Extended Security Support [46:44]
+ UINT8 CMD_SUPPORT: 4; // Command Support bits [35:32]
+ UINT8 RESERVED_2: 4; // Reserved [39:36]
+ UINT32 RESERVED_3; // Manufacturer Usage [31:0]
+} SCR;
+
+typedef struct {
+ UINT32 NOT_USED; // 1 [0:0]
+ UINT32 CRC; // CRC7 checksum [7:1]
+
+ UINT32 MDT; // Manufacturing date [19:8]
+ UINT32 RESERVED_1; // Reserved [23:20]
+ UINT32 PSN; // Product serial number [55:24]
+ UINT8 PRV; // Product revision [63:56]
+ UINT8 PNM[5]; // Product name [64:103]
+ UINT16 OID; // OEM/Application ID [119:104]
+ UINT8 MID; // Manufacturer ID [127:120]
+} CID;
+
+typedef struct {
+ UINT8 NOT_USED: 1; // Not used, always 1 [0:0]
+ UINT8 CRC: 7; // CRC [7:1]
+
+ UINT8 RESERVED_1: 2; // Reserved [9:8]
+ UINT8 FILE_FORMAT: 2; // File format [11:10]
+ UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12]
+ UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13]
+ UINT8 COPY: 1; // Copy flag (OTP) [14:14]
+ UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15]
+
+ UINT16 RESERVED_2: 5; // Reserved [20:16]
+ UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21]
+ UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22]
+ UINT16 R2W_FACTOR: 3; // Write speed factor [28:26]
+ UINT16 RESERVED_3: 2; // Reserved [30:29]
+ UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31]
+
+ UINT32 WP_GRP_SIZE: 7; // Write protect group size [38:32]
+ UINT32 SECTOR_SIZE: 7; // Erase sector size [45:39]
+ UINT32 ERASE_BLK_EN: 1; // Erase single block enable [46:46]
+ UINT32 C_SIZE_MULT: 3; // Device size multiplier [49:47]
+ UINT32 VDD_W_CURR_MAX: 3; // Max. write current @ VDD max [52:50]
+ UINT32 VDD_W_CURR_MIN: 3; // Max. write current @ VDD min [55:53]
+ UINT32 VDD_R_CURR_MAX: 3; // Max. read current @ VDD max [58:56]
+ UINT32 VDD_R_CURR_MIN: 3; // Max. read current @ VDD min [61:59]
+ UINT32 C_SIZELow2: 2; // Device size [63:62]
+
+ UINT32 C_SIZEHigh10: 10;// Device size [73:64]
+ UINT32 RESERVED_4: 2; // Reserved [75:74]
+ UINT32 DSR_IMP: 1; // DSR implemented [76:76]
+ UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77]
+ UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78]
+ UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79]
+ UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80]
+ UINT32 CCC: 12;// Card command classes [95:84]
+
+ UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96]
+ UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+ UINT8 TAAC ; // Data read access-time 1 [119:112]
+
+ UINT8 RESERVED_5: 2; // Reserved [121:120]
+ UINT8 SPEC_VERS: 4; // System specification version [125:122]
+ UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126]
+} CSD;
+
+typedef struct {
+ UINT8 RESERVED_1[16]; // Reserved [15:0]
+ UINT8 SECURE_REMOVAL_TYPE; // Secure Removal Type [16:16]
+ UINT8 PRODUCT_STATE_AWARENESS_ENABLEMENT; // Product state awareness enablement [17:17]
+ UINT8 MAX_PRE_LOADING_DATA_SIZE[4]; // MAX pre loading data size [21:18]
+ UINT8 PRE_LOADING_DATA_SIZE[4]; // Pre loading data size [25:22]
+ UINT8 FFU_STATUS; // FFU Status [26:26]
+ UINT8 RESERVED_2[2]; // Reserved [28:27]
+ UINT8 MODE_OPERATION_CODES; // Mode operation codes [29:29]
+ UINT8 MODE_CONFIG; // Mode config [30:30]
+ UINT8 RESERVED_3; // Reserved [31:31]
+ UINT8 FLUSH_CACHE; // Flushing of the cache [32:32]
+ UINT8 CACHE_CTRL; // Control to turn the cache ON/OFF [33:33]
+ UINT8 POWER_OFF_NOTIFICATION; // Power Off Notification [34:34]
+ UINT8 PACKED_FAILURE_INDEX; // Packed command failure index [35:35]
+ UINT8 PACKED_COMMAND_STATUS; // Packed command status [36:36]
+ UINT8 CONTEXT_CONF[15]; // Context configuration [51:37]
+ UINT8 EXT_PARTITIONS_ATTRIBUTE[2]; // Extended partitions attribute [53:52]
+ UINT8 EXCEPTION_EVENTS_STATUS[2]; // Exception events status [55:54]
+ UINT8 EXCEPTION_EVENTS_CTRL[2]; // Exception events control [57:56]
+ UINT8 DYNCAP_NEEDED; // Number of addressed group to be released [58:58]
+ UINT8 CLASS_6_CTRL; // Class 6 commands control [59:59]
+ UINT8 INI_TIMEOUT_EMU; // 1st initialization after disabling sector size emulation [60:60]
+ UINT8 DATA_SECTOR_SIZE; // Sector size [61:61]
+ UINT8 USE_NATIVE_SECTOR; // Sector size emulation [62:62]
+ UINT8 NATIVE_SECTOR_SIZE; // Native sector size [63:63]
+ UINT8 VENDOR_SPECIFIC_FIELD[64]; // Vendor specific fields [127:64]
+ UINT8 RESERVED_4[2]; // Reserved [129:128]
+ UINT8 PROGRAM_CID_CSD_DDR_SUPPORT; // Program CID/CSD in DDR mode support [130:130]
+ UINT8 PERIODIC_WAKEUP; // Periodic wake-up [131:131]
+ UINT8 TCASE_SUPPORT; // Package case temperature is controlled [132:132]
+ UINT8 PRODUCTION_STATE_AWARENESS; // Production state awareness [133:133]
+ UINT8 SECTOR_BAD_BLK_MGMNT; // Bad block management mode [134:134]
+ UINT8 RESERVED_5; // Reserved [135:135]
+ UINT8 ENH_START_ADDR[4]; // Enhanced user data start address [139:136]
+ UINT8 ENH_SIZE_MULT[3]; // Enhanced user data area size [142:140]
+ UINT8 GP_SIZE_MULT[12]; // General purpose partition size [154:143]
+ UINT8 PARTITION_SETTING_COMPLETED; // Partitioning setting [155:155]
+ UINT8 PARTITIONS_ATTRIBUTE; // Partitions attribute [156:156]
+ UINT8 MAX_ENH_SIZE_MULT[3]; // Max enhanced area size [159:157]
+ UINT8 PARTITIONING_SUPPORT; // Partitioning [160:160]
+ UINT8 HPI_MGMT; // HPI management [161:161]
+ UINT8 RST_N_FUNCTION; // H/W reset function [162:162]
+ UINT8 BKOPS_EN; // Enable background operations handshake [163:163]
+ UINT8 BKOPS_START; // Manually start background operations [164:164]
+ UINT8 SANITIZE_START; // Start sanitize operation [165:165]
+ UINT8 WR_REL_PARAM; // Write reliability parameter register [166:166]
+ UINT8 WR_REL_SET; // Write reliability setting register [167:167]
+ UINT8 RPMB_SIZE_MULT; // RPMB size [168:168]
+ UINT8 FW_CONFIG; // FW configuration [169:169]
+ UINT8 RESERVED_6; // Reserved [170:170]
+ UINT8 USER_WP; // User area write protection register [171:171]
+ UINT8 RESERVED_7; // Reserved [172:172]
+ UINT8 BOOT_WP; // Boot area write protection register [173:173]
+ UINT8 BOOT_WP_STATUS; // Boot write protection register [174:174]
+ UINT8 ERASE_GROUP_DEF; // High-density erase group definition [175:175]
+ UINT8 RESERVED_8; // Reserved [176:176]
+ UINT8 BOOT_BUS_CONDITIONS; // Boot bus conditions [177:177]
+ UINT8 BOOT_CONFIG_PROT; // Boot config protection [178:178]
+ UINT8 PARTITION_CONFIG; // Partition config [179:179]
+ UINT8 RESERVED_9; // Reserved [180:180]
+ UINT8 ERASED_MEM_CONT; // Erased memory content [181:181]
+ UINT8 RESERVED_10; // Reserved [182:182]
+ UINT8 BUS_WIDTH; // Bus width mode [183:183]
+ UINT8 RESERVED_11; // Reserved [184:184]
+ UINT8 HS_TIMING; // High-speed interface timing [185:185]
+ UINT8 RESERVED_12; // Reserved [186:186]
+ UINT8 POWER_CLASS; // Power class [187:187]
+ UINT8 RESERVED_13; // Reserved [188:188]
+ UINT8 CMD_SET_REV; // Command set revision [189:189]
+ UINT8 RESERVED_14; // Reserved [190:190]
+ UINT8 CMD_SET; // Command set [191:191]
+ UINT8 EXT_CSD_REV; // Extended CSD revision [192:192]
+ UINT8 RESERVED_15; // Reserved [193:193]
+ UINT8 CSD_STRUCTURE; // CSD Structure [194:194]
+ UINT8 RESERVED_16; // Reserved [195:195]
+ UINT8 DEVICE_TYPE; // Device type [196:196]
+ UINT8 DRIVER_STRENGTH; // I/O Driver strength [197:197]
+ UINT8 OUT_OF_INTERRUPT_TIME; // Out-of-interrupt busy timing [198:198]
+ UINT8 PARTITION_SWITCH_TIME; // Partition switching timing [199:199]
+ UINT8 PWR_CL_52_195; // Power class for 52MHz at 1.95V 1 R [200:200]
+ UINT8 PWR_CL_26_195; // Power class for 26MHz at 1.95V 1 R [201:201]
+ UINT8 PWR_CL_52_360; // Power class for 52MHz at 3.6V 1 R [202:202]
+ UINT8 PWR_CL_26_360; // Power class for 26MHz at 3.6V 1 R [203:203]
+ UINT8 RESERVED_17; // Reserved [204:204]
+ UINT8 MIN_PERF_R_4_26; // Minimum read performance for 4bit at 26MHz [205:205]
+ UINT8 MIN_PERF_W_4_26; // Minimum write performance for 4bit at 26MHz [206:206]
+ UINT8 MIN_PERF_R_8_26_4_52; // Minimum read performance for 8bit at 26MHz, for 4bit at 52MHz [207:207]
+ UINT8 MIN_PERF_W_8_26_4_52; // Minimum write performance for 8bit at 26MHz, for 4bit at 52MHz [208:208]
+ UINT8 MIN_PERF_R_8_52; // Minimum read performance for 8bit at 52MHz [209:209]
+ UINT8 MIN_PERF_W_8_52; // Minimum write performance for 8bit at 52MHz [210:210]
+ UINT8 RESERVED_18; // Reserved [211:211]
+ UINT32 SECTOR_COUNT; // Sector count [215:212]
+ UINT8 SLEEP_NOTIFICATION_TIME; // Sleep notification timout [216:216]
+ UINT8 S_A_TIMEOUT; // Sleep/awake timeout [217:217]
+ UINT8 PRODUCTION_STATE_AWARENESS_TIMEOUT; // Production state awareness timeout [218:218]
+ UINT8 S_C_VCCQ; // Sleep current (VCCQ) [219:219]
+ UINT8 S_C_VCC; // Sleep current (VCC) [220:220]
+ UINT8 HC_WP_GRP_SIZE; // High-capacity write protect group size [221:221]
+ UINT8 REL_WR_SECTOR_C; // Reliable write sector count [222:222]
+ UINT8 ERASE_TIMEOUT_MULT; // High-capacity erase timeout [223:223]
+ UINT8 HC_ERASE_GRP_SIZE; // High-capacity erase unit size [224:224]
+ UINT8 ACC_SIZE; // Access size [225:225]
+ UINT8 BOOT_SIZE_MULTI; // Boot partition size [226:226]
+ UINT8 RESERVED_19; // Reserved [227:227]
+ UINT8 BOOT_INFO; // Boot information [228:228]
+ UINT8 SECURE_TRIM_MULT; // Secure TRIM Multiplier [229:229]
+ UINT8 SECURE_ERASE_MULT; // Secure Erase Multiplier [230:230]
+ UINT8 SECURE_FEATURE_SUPPORT; // Secure Feature Support [231:231]
+ UINT8 TRIM_MULT; // TRIM Multiplier [232:232]
+ UINT8 RESERVED_20; // Reserved [233:233]
+ UINT8 MIN_PREF_DDR_R_8_52; // Minimum read performance for 8bit at 52MHz in DDR mode [234:234]
+ UINT8 MIN_PREF_DDR_W_8_52; // Minimum write performance for 8bit at 52MHz in DDR mode [235:235]
+ UINT8 PWR_CL_200_130; // Power class for 200MHz at VCCQ=1.3V, VCC=3.6V [236:236]
+ UINT8 PWR_CL_200_195; // Power class for 200MHz at VCCQ=1.95V, VCC=3.6V [237:237]
+ UINT8 PWR_CL_DDR_52_195; // Power class for 52MHz, DDR at 1.95V [238:238]
+ UINT8 PWR_CL_DDR_52_360; // Power class for 52Mhz, DDR at 3.6V [239:239]
+ UINT8 RESERVED_21; // Reserved [240:240]
+ UINT8 INI_TIMEOUT_AP; // 1st initialization time after partitioning [241:241]
+ UINT8 CORRECTLY_PRG_SECTORS_NUM[4]; // Number of correctly programmed sectors [245:242]
+ UINT8 BKOPS_STATUS; // Background operations status [246:246]
+ UINT8 POWER_OFF_LONG_TIME; // Power off notification (long) timeout [247:247]
+ UINT8 GENERIC_CMD6_TIME; // Generic CMD6 timeout [248:248]
+ UINT8 CACHE_SIZE[4]; // Cache size [252:249]
+ UINT8 PWR_CL_DDR_200_360; // Power class for 200MHz, DDR at VCC=3.6V [253:253]
+ UINT8 FIRMWARE_VERSION[8]; // Firmware version [261:254]
+ UINT8 DEVICE_VERSION[2]; // Device version [263:262]
+ UINT8 OPTIMAL_TRIM_UNIT_SIZE; // Optimal trim unit size [264:264]
+ UINT8 OPTIMAL_WRITE_SIZE; // Optimal write size [265:265]
+ UINT8 OPTIMAL_READ_SIZE; // Optimal read size [266:266]
+ UINT8 PRE_EOL_INFO; // Pre EOL information [267:267]
+ UINT8 DEVICE_LIFE_TIME_EST_TYP_A; // Device life time estimation type A [268:268]
+ UINT8 DEVICE_LIFE_TIME_EST_TYP_B; // Device life time estimation type B [269:269]
+ UINT8 VENDOR_PROPRIETARY_HEALTH_REPORT[32]; // Vendor proprietary health report [301:270]
+ UINT8 NUMBER_OF_FW_SECTORS_CORRECTLY_PROGRAMMED[4]; // Number of FW sectors correctly programmed [305:302]
+ UINT8 RESERVED_22[181]; // Reserved [486:306]
+ UINT8 FFU_ARG[4]; // FFU argument [490:487]
+ UINT8 OPERATION_CODE_TIMEOUT; // Operation codes timeout [491:491]
+ UINT8 FFU_FEATURES; // FFU features [492:492]
+ UINT8 SUPPORTED_MODES; // Supported modes [493:493]
+ UINT8 EXT_SUPPORT; // Extended partitions attribute support [494:494]
+ UINT8 LARGE_UNIT_SIZE_M1; // Large unit size [495:495]
+ UINT8 CONTEXT_CAPABILITIES; // Context management capabilities [496:496]
+ UINT8 TAG_RES_SIZE; // Tag resource size [497:497]
+ UINT8 TAG_UNIT_SIZE; // Tag unit size [498:498]
+ UINT8 DATA_TAG_SUPPORT; // Data tag support [499:499]
+ UINT8 MAX_PACKED_WRITES; // Max packed write commands [500:500]
+ UINT8 MAX_PACKED_READS; // Max packed read commands [501:501]
+ UINT8 BKOPS_SUPPORT; // Background operations support [502:502]
+ UINT8 HPI_FEATURES; // HPI features [503:503]
+ UINT8 S_CMD_SET; // Supported command sets [504:504]
+ UINT8 EXT_SECURITY_ERR; // Extended security commands error [505:505]
+ UINT8 RESERVED_23[6]; // Reserved [511:506]
+} ECSD;
+
+typedef struct {
+ UINT16 RCA;
+ CARD_TYPE CardType;
+ OCR OCRData;
+ CID CIDData;
+ CSD CSDData;
+ ECSD *ECSDData; // MMC V4 extended card specific
+} CARD_INFO;
+
+typedef struct _MMC_HOST_INSTANCE {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_HANDLE MmcHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ MMC_STATE State;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ CARD_INFO CardInfo;
+ EFI_MMC_HOST_PROTOCOL *MmcHost;
+
+ BOOLEAN Initialized;
+} MMC_HOST_INSTANCE;
+
+#define MMC_HOST_INSTANCE_SIGNATURE SIGNATURE_32('m', 'm', 'c', 'h')
+#define MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS(a) CR (a, MMC_HOST_INSTANCE, BlockIo, MMC_HOST_INSTANCE_SIGNATURE)
+#define MMC_HOST_INSTANCE_FROM_LINK(a) CR (a, MMC_HOST_INSTANCE, Link, MMC_HOST_INSTANCE_SIGNATURE)
+
+
+EFI_STATUS
+EFIAPI
+MmcGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+EFIAPI
+MmcGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+extern EFI_COMPONENT_NAME_PROTOCOL gMmcComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gMmcComponentName2;
+
+extern EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2;
+
+extern LIST_ENTRY mMmcHostPool;
+
+/**
+ Reset the block device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
+ It resets the block device hardware.
+ ExtendedVerification is ignored in this implementation.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The block device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the requested number of blocks from the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
+ It reads the requested number of blocks from the device.
+ All the blocks are read, or an error is returned.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the read request is for.
+ @param Lba The starting logical block address to read from on the device.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a specified number of blocks to the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
+ It writes a specified number of blocks to the device.
+ All blocks are written, or an error is returned.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer Pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data were written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic
+ block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flushes all modified data to a physical block device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data were written correctly to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+EFI_STATUS
+MmcNotifyState (
+ IN MMC_HOST_INSTANCE *MmcHostInstance,
+ IN MMC_STATE State
+ );
+
+EFI_STATUS
+InitializeMmcDevice (
+ IN MMC_HOST_INSTANCE *MmcHost
+ );
+
+VOID
+EFIAPI
+CheckCardsCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+VOID
+PrintCSD (
+ IN UINT32* Csd
+ );
+
+VOID
+PrintRCA (
+ IN UINT32 Rca
+ );
+
+VOID
+PrintOCR (
+ IN UINT32 Ocr
+ );
+
+VOID
+PrintResponseR1 (
+ IN UINT32 Response
+ );
+
+VOID
+PrintCID (
+ IN UINT32* Cid
+ );
+
+#endif
diff --git a/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcBlockIo.c b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcBlockIo.c
new file mode 100644
index 000000000000..54cdbde95292
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcBlockIo.c
@@ -0,0 +1,473 @@
+/** @file
+ *
+ * Copyright (c) 2011-2015, ARM 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.
+ *
+ **/
+
+#include <Library/BaseMemoryLib.h>
+
+#include "Mmc.h"
+
+#define MMCI0_BLOCKLEN 512
+#define MMCI0_TIMEOUT 1000
+
+STATIC
+EFI_STATUS
+R1TranAndReady(UINT32 *Response)
+{
+ if ((*Response & MMC_R0_READY_FOR_DATA) != 0 &&
+ MMC_R0_CURRENTSTATE(Response) == MMC_R0_STATE_TRAN) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
+STATIC
+EFI_STATUS
+ValidateWrittenBlockCount(
+ IN MMC_HOST_INSTANCE *MmcHostInstance,
+ IN UINTN Count,
+ OUT UINTN *TransferredBlocks
+ )
+{
+ UINT32 R1;
+ UINT8 Data[4];
+ EFI_STATUS Status;
+ UINT32 BlocksWritten;
+ EFI_MMC_HOST_PROTOCOL *MmcHost = MmcHostInstance->MmcHost;
+
+ if (MmcHostInstance->CardInfo.CardType == MMC_CARD ||
+ MmcHostInstance->CardInfo.CardType == MMC_CARD_HIGH ||
+ MmcHostInstance->CardInfo.CardType == EMMC_CARD) {
+ /*
+ * Not on MMC.
+ */
+ return EFI_SUCCESS;
+ }
+
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD55,
+ MmcHostInstance->CardInfo.RCA << 16);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n",
+ __FUNCTION__, __LINE__, Status));
+ return Status;
+ }
+
+ Status = MmcHost->SendCommand (MmcHost, MMC_ACMD22, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n",
+ __FUNCTION__, __LINE__, Status));
+ return Status;
+ }
+
+ MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, &R1);
+ Status = R1TranAndReady(&R1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Read Data
+ Status = MmcHost->ReadBlockData (MmcHost, 0, sizeof(Data),
+ (VOID *) Data);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n",
+ __FUNCTION__, __LINE__, Status));
+ return Status;
+ }
+
+ /*
+ * Big Endian.
+ */
+ BlocksWritten = ((UINT32) Data[0] << 24) |
+ ((UINT32) Data[1] << 16) |
+ ((UINT32) Data[2] << 8) |
+ ((UINT32) Data[3] << 0);
+ if (BlocksWritten != Count) {
+ DEBUG ((DEBUG_ERROR, "%a(%u): expected %u != gotten %u\n",
+ __FUNCTION__, __LINE__, Count, BlocksWritten));
+ if (BlocksWritten == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ *TransferredBlocks = BlocksWritten;
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+WaitUntilTran(
+ IN MMC_HOST_INSTANCE *MmcHostInstance
+ )
+{
+ INTN Timeout;
+ UINT32 Response[1];
+ EFI_STATUS Status = EFI_SUCCESS;
+ EFI_MMC_HOST_PROTOCOL *MmcHost = MmcHostInstance->MmcHost;
+
+ Timeout = MMCI0_TIMEOUT;
+ while(Timeout--) {
+ /*
+ * We expect CMD13 to timeout while card is programming,
+ * because the card holds DAT0 low (busy).
+ */
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD13,
+ MmcHostInstance->CardInfo.RCA << 16);
+ if (EFI_ERROR(Status) && Status != EFI_TIMEOUT) {
+ DEBUG ((DEBUG_ERROR, "%a(%u) CMD13 failed: %r\n",
+ __FUNCTION__, __LINE__, Status));
+ break;
+ }
+
+ if (Status == EFI_SUCCESS) {
+ MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);
+ Status = R1TranAndReady(Response);
+ if (!EFI_ERROR(Status)) {
+ break;
+ }
+ }
+
+ gBS->Stall(1000);
+ }
+
+ if (0 == Timeout) {
+ DEBUG ((DEBUG_ERROR, "%a(%u) card is busy\n", __FUNCTION__, __LINE__));
+ return EFI_NOT_READY;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+MmcNotifyState (
+ IN MMC_HOST_INSTANCE *MmcHostInstance,
+ IN MMC_STATE State
+ )
+{
+ MmcHostInstance->State = State;
+ return MmcHostInstance->MmcHost->NotifyState (MmcHostInstance->MmcHost, State);
+}
+
+EFI_STATUS
+EFIAPI
+MmcReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ MMC_HOST_INSTANCE *MmcHostInstance;
+
+ MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);
+
+ if (MmcHostInstance->MmcHost == NULL) {
+ // Nothing to do
+ return EFI_SUCCESS;
+ }
+
+ // If a card is not present then clear all media settings
+ if (!MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost)) {
+ MmcHostInstance->BlockIo.Media->MediaPresent = FALSE;
+ MmcHostInstance->BlockIo.Media->LastBlock = 0;
+ MmcHostInstance->BlockIo.Media->BlockSize = 512; // Should be zero but there is a bug in DiskIo
+ MmcHostInstance->BlockIo.Media->ReadOnly = FALSE;
+
+ // Indicate that the driver requires initialization
+ MmcHostInstance->State = MmcHwInitializationState;
+
+ return EFI_SUCCESS;
+ }
+
+ // Implement me. Either send a CMD0 (could not work for some MMC host) or just turn off/turn
+ // on power and restart Identification mode
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MmcDetectCard (
+ EFI_MMC_HOST_PROTOCOL *MmcHost
+ )
+{
+ if (!MmcHost->IsCardPresent (MmcHost)) {
+ return EFI_NO_MEDIA;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+EFI_STATUS
+MmcStopTransmission (
+ EFI_MMC_HOST_PROTOCOL *MmcHost
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Response[4];
+ // Command 12 - Stop transmission (ends read or write)
+ // Normally only needed for streaming transfers or after error.
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);
+ if (!EFI_ERROR (Status)) {
+ MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response);
+ }
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+MmcTransferBlock (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINTN Cmd,
+ IN UINTN Transfer,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer,
+ OUT UINTN *TransferredSize
+ )
+{
+ EFI_STATUS Status;
+ MMC_HOST_INSTANCE *MmcHostInstance;
+ EFI_MMC_HOST_PROTOCOL *MmcHost;
+ UINTN CmdArg;
+
+ MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);
+ MmcHost = MmcHostInstance->MmcHost;
+
+ //Set command argument based on the card access mode (Byte mode or Block mode)
+ if ((MmcHostInstance->CardInfo.OCRData.AccessMode & MMC_OCR_ACCESS_MASK) ==
+ MMC_OCR_ACCESS_SECTOR) {
+ CmdArg = Lba;
+ } else {
+ CmdArg = Lba * This->Media->BlockSize;
+ }
+
+ Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(MMC_CMD%d): Error %r\n", __func__,
+ MMC_INDX(Cmd), Status));
+ return Status;
+ }
+
+ if (Transfer == MMC_IOBLOCKS_READ) {
+ Status = MmcHost->ReadBlockData (MmcHost, Lba, BufferSize, Buffer);
+ } else {
+ Status = MmcHost->WriteBlockData (MmcHost, Lba, BufferSize, Buffer);
+ if (!EFI_ERROR (Status)) {
+ Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a() : Error MmcProgrammingState\n", __func__));
+ return Status;
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status) ||
+ BufferSize > This->Media->BlockSize) {
+ /*
+ * CMD12 needs to be set for multiblock (to transition from
+ * RECV to PROG) or for errors.
+ */
+ EFI_STATUS Status2 = MmcStopTransmission (MmcHost);
+ if (EFI_ERROR (Status2)) {
+ DEBUG ((DEBUG_ERROR, "MmcIoBlocks() : CMD12 error on Status %r: %r\n",
+ Status, Status2));
+ return Status2;
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_BLKIO, "%a(): Error %a Block Data and Status = %r\n",
+ __func__, Transfer == MMC_IOBLOCKS_READ ? "Read" : "Write",
+ Status));
+ return Status;
+ }
+
+ ASSERT (Cmd == MMC_CMD25 || Cmd == MMC_CMD18);
+ }
+
+ //
+ // For reads, should be already in TRAN. For writes, wait
+ // until programming finishes.
+ //
+ Status = WaitUntilTran(MmcHostInstance);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "WaitUntilTran after write failed\n"));
+ return Status;
+ }
+
+ Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));
+ return Status;
+ }
+
+ if (Transfer != MMC_IOBLOCKS_READ) {
+ UINTN BlocksWritten = 0;
+
+ Status = ValidateWrittenBlockCount (MmcHostInstance,
+ BufferSize /
+ This->Media->BlockSize,
+ &BlocksWritten);
+ *TransferredSize = BlocksWritten *
+ This->Media->BlockSize;
+ } else {
+ *TransferredSize = BufferSize;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+MmcIoBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINTN Transfer,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Cmd;
+ MMC_HOST_INSTANCE *MmcHostInstance;
+ EFI_MMC_HOST_PROTOCOL *MmcHost;
+ UINTN BytesRemainingToBeTransfered;
+ UINTN BlockCount;
+ UINTN ConsumeSize;
+
+ BlockCount = 1;
+ MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);
+ ASSERT (MmcHostInstance != NULL);
+ MmcHost = MmcHostInstance->MmcHost;
+ ASSERT (MmcHost);
+
+ if (This->Media->MediaId != MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if ((MmcHost == NULL) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check if a Card is Present
+ if (!MmcHostInstance->BlockIo.Media->MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (PcdGet32(PcdMmcDisableMulti) == 0 &&
+ MMC_HOST_HAS_ISMULTIBLOCK(MmcHost) &&
+ MmcHost->IsMultiBlock(MmcHost)) {
+ BlockCount = (BufferSize + This->Media->BlockSize - 1) / This->Media->BlockSize;
+ }
+
+ // All blocks must be within the device
+ if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ // Reading 0 Byte is valid
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ // The buffer size must be an exact multiple of the block size
+ if ((BufferSize % This->Media->BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // Check the alignment
+ if ((This->Media->IoAlign > 2) && (((UINTN)Buffer & (This->Media->IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BytesRemainingToBeTransfered = BufferSize;
+ while (BytesRemainingToBeTransfered > 0) {
+ Status = WaitUntilTran(MmcHostInstance);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "WaitUntilTran before IO failed"));
+ return Status;
+ }
+
+ if (Transfer == MMC_IOBLOCKS_READ) {
+ if (BlockCount == 1) {
+ // Read a single block
+ Cmd = MMC_CMD17;
+ } else {
+ // Read multiple blocks
+ Cmd = MMC_CMD18;
+ }
+ } else {
+ if (BlockCount == 1) {
+ // Write a single block
+ Cmd = MMC_CMD24;
+ } else {
+ // Write multiple blocks
+ Cmd = MMC_CMD25;
+ }
+ }
+
+ ConsumeSize = BlockCount * This->Media->BlockSize;
+ if (BytesRemainingToBeTransfered < ConsumeSize) {
+ ConsumeSize = BytesRemainingToBeTransfered;
+ }
+
+ Status = MmcTransferBlock (This, Cmd, Transfer, MediaId, Lba, ConsumeSize, Buffer, &ConsumeSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Failed to transfer block and Status:%r\n", __func__, Status));
+ return Status;
+ }
+
+ BytesRemainingToBeTransfered -= ConsumeSize;
+ if (BytesRemainingToBeTransfered > 0) {
+ Lba += BlockCount;
+ Buffer = (UINT8 *)Buffer + ConsumeSize;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MmcReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+MmcWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+MmcFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcDebug.c b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcDebug.c
new file mode 100644
index 000000000000..ea53700caaf8
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcDebug.c
@@ -0,0 +1,169 @@
+/** @file
+ *
+ * Copyright (c) 2011-2013, ARM 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.
+ *
+ **/
+
+#include "Mmc.h"
+
+#if !defined(MDEPKG_NDEBUG)
+CONST CHAR8* mStrUnit[] = { "100kbit/s", "1Mbit/s", "10Mbit/s", "100MBit/s",
+ "Unknown", "Unknown", "Unknown", "Unknown" };
+CONST CHAR8* mStrValue[] = { "1.0", "1.2", "1.3", "1.5", "2.0", "2.5",
+ "3.0", "3.5", "4.0", "4.5", "5.0", "5.5",
+ "6.0", "7.0", "8.0" };
+#endif
+
+VOID
+PrintCID (
+ IN UINT32* Cid
+ )
+{
+ DEBUG ((DEBUG_ERROR, "- PrintCID\n"));
+ DEBUG ((DEBUG_ERROR, "\t- Manufacturing date: %d/%d\n", (Cid[0] >> 8) & 0xF, (Cid[0] >> 12) & 0xFF));
+ DEBUG ((DEBUG_ERROR, "\t- Product serial number: 0x%X%X\n", Cid[1] & 0xFFFFFF, (Cid[0] >> 24) & 0xFF));
+ DEBUG ((DEBUG_ERROR, "\t- Product revision: %d\n", Cid[1] >> 24));
+ //DEBUG ((DEBUG_ERROR, "\t- Product name: %s\n", (char*)(Cid + 2)));
+ DEBUG ((DEBUG_ERROR, "\t- OEM ID: %c%c\n", (Cid[3] >> 8) & 0xFF, (Cid[3] >> 16) & 0xFF));
+}
+
+
+VOID
+PrintCSD (
+ IN UINT32* Csd
+ )
+{
+ UINTN Value;
+
+ if (((Csd[2] >> 30) & 0x3) == 0) {
+ DEBUG ((DEBUG_ERROR, "- PrintCSD Version 1.01-1.10/Version 2.00/Standard Capacity\n"));
+ } else if (((Csd[2] >> 30) & 0x3) == 1) {
+ DEBUG ((DEBUG_ERROR, "- PrintCSD Version 2.00/High Capacity\n"));
+ } else {
+ DEBUG ((DEBUG_ERROR, "- PrintCSD Version Higher than v3.3\n"));
+ }
+
+ DEBUG ((DEBUG_ERROR, "\t- Supported card command class: 0x%X\n", MMC_CSD_GET_CCC (Csd)));
+ DEBUG ((DEBUG_ERROR, "\t- Max Speed: %a * %a\n",mStrValue[(MMC_CSD_GET_TRANSPEED (Csd) >> 3) & 0xF],mStrUnit[MMC_CSD_GET_TRANSPEED (Csd) & 7]));
+ DEBUG ((DEBUG_ERROR, "\t- Maximum Read Data Block: %d\n",2 << (MMC_CSD_GET_READBLLEN (Csd)-1)));
+ DEBUG ((DEBUG_ERROR, "\t- Maximum Write Data Block: %d\n",2 << (MMC_CSD_GET_WRITEBLLEN (Csd)-1)));
+
+ if (!MMC_CSD_GET_FILEFORMATGRP (Csd)) {
+ Value = MMC_CSD_GET_FILEFORMAT (Csd);
+ if (Value == 0) {
+ DEBUG ((DEBUG_ERROR, "\t- Format (0): Hard disk-like file system with partition table\n"));
+ } else if (Value == 1) {
+ DEBUG ((DEBUG_ERROR, "\t- Format (1): DOS FAT (floppy-like) with boot sector only (no partition table)\n"));
+ } else if (Value == 2) {
+ DEBUG ((DEBUG_ERROR, "\t- Format (2): Universal File Format\n"));
+ } else {
+ DEBUG ((DEBUG_ERROR, "\t- Format (3): Others/Unknown\n"));
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "\t- Format: Reserved\n"));
+ }
+}
+
+VOID
+PrintRCA (
+ IN UINT32 Rca
+ )
+{
+ DEBUG ((DEBUG_ERROR, "- PrintRCA: 0x%X\n", Rca));
+ DEBUG ((DEBUG_ERROR, "\t- Status: 0x%X\n", Rca & 0xFFFF));
+ DEBUG ((DEBUG_ERROR, "\t- RCA: 0x%X\n", (Rca >> 16) & 0xFFFF));
+}
+
+VOID
+PrintOCR (
+ IN UINT32 Ocr
+ )
+{
+ UINTN MinV;
+ UINTN MaxV;
+ UINTN Volts;
+ UINTN Loop;
+
+ MinV = 36; // 3.6
+ MaxV = 20; // 2.0
+ Volts = 20; // 2.0
+
+ // The MMC register bits [23:8] indicate the working range of the card
+ for (Loop = 8; Loop < 24; Loop++) {
+ if (Ocr & (1 << Loop)) {
+ if (MinV > Volts) {
+ MinV = Volts;
+ }
+ if (MaxV < Volts) {
+ MaxV = Volts + 1;
+ }
+ }
+ Volts++;
+ }
+
+ DEBUG ((DEBUG_ERROR, "- PrintOCR Ocr (0x%X)\n",Ocr));
+ DEBUG ((DEBUG_ERROR, "\t- Card operating voltage: %d.%d to %d.%d\n", MinV/10, MinV % 10, MaxV/10, MaxV % 10));
+ if (((Ocr >> 29) & 3) == 0) {
+ DEBUG ((DEBUG_ERROR, "\t- AccessMode: Byte Mode\n"));
+ } else {
+ DEBUG ((DEBUG_ERROR, "\t- AccessMode: Block Mode (0x%X)\n", ((Ocr >> 29) & 3)));
+ }
+
+ if (Ocr & MMC_OCR_POWERUP) {
+ DEBUG ((DEBUG_ERROR, "\t- PowerUp\n"));
+ } else {
+ DEBUG ((DEBUG_ERROR, "\t- Voltage Not Supported\n"));
+ }
+}
+
+VOID
+PrintResponseR1 (
+ IN UINT32 Response
+ )
+{
+ DEBUG ((DEBUG_INFO, "Response: 0x%X\n", Response));
+ if (Response & MMC_R0_READY_FOR_DATA) {
+ DEBUG ((DEBUG_INFO, "\t- READY_FOR_DATA\n"));
+ }
+
+ switch ((Response >> 9) & 0xF) {
+ case 0:
+ DEBUG ((DEBUG_INFO, "\t- State: Idle\n"));
+ break;
+ case 1:
+ DEBUG ((DEBUG_INFO, "\t- State: Ready\n"));
+ break;
+ case 2:
+ DEBUG ((DEBUG_INFO, "\t- State: Ident\n"));
+ break;
+ case 3:
+ DEBUG ((DEBUG_INFO, "\t- State: StandBy\n"));
+ break;
+ case 4:
+ DEBUG ((DEBUG_INFO, "\t- State: Tran\n"));
+ break;
+ case 5:
+ DEBUG ((DEBUG_INFO, "\t- State: Data\n"));
+ break;
+ case 6:
+ DEBUG ((DEBUG_INFO, "\t- State: Rcv\n"));
+ break;
+ case 7:
+ DEBUG ((DEBUG_INFO, "\t- State: Prg\n"));
+ break;
+ case 8:
+ DEBUG ((DEBUG_INFO, "\t- State: Dis\n"));
+ break;
+ default:
+ DEBUG ((DEBUG_INFO, "\t- State: Reserved\n"));
+ break;
+ }
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcDxe.inf
new file mode 100644
index 000000000000..fd91f47aeaf0
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcDxe.inf
@@ -0,0 +1,58 @@
+#/** @file
+#
+# Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) 2011-2015, ARM 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.
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PiMmcDxe
+ FILE_GUID = b6f44cc0-9e45-11df-be21-0002a5f5f51b
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = MmcDxeInitialize
+
+[Sources.common]
+ ComponentName.c
+ Mmc.c
+ MmcBlockIo.c
+ MmcIdentification.c
+ MmcDebug.c
+ Diagnostics.c
+
+[Packages]
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+
+[Protocols]
+ gEfiDiskIoProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiDriverDiagnostics2ProtocolGuid
+ gRaspberryPiMmcHostProtocolGuid
+
+[Pcd]
+ gRaspberryPiTokenSpaceGuid.PcdMmcForce1Bit
+ gRaspberryPiTokenSpaceGuid.PcdMmcForceDefaultSpeed
+ gRaspberryPiTokenSpaceGuid.PcdMmcSdDefaultSpeedMHz
+ gRaspberryPiTokenSpaceGuid.PcdMmcSdHighSpeedMHz
+ gRaspberryPiTokenSpaceGuid.PcdMmcDisableMulti
+
+[Depex]
+ TRUE
diff --git a/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcIdentification.c b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcIdentification.c
new file mode 100644
index 000000000000..ef819fb753c6
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcIdentification.c
@@ -0,0 +1,993 @@
+/** @file
+ *
+ * Copyright (c) 2011-2015, ARM 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.
+ *
+ **/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/TimerLib.h>
+
+#include "Mmc.h"
+
+typedef union {
+ UINT32 Raw;
+ OCR Ocr;
+} OCR_RESPONSE;
+
+#define MAX_RETRY_COUNT 1000
+#define CMD_RETRY_COUNT 20
+#define RCA_SHIFT_OFFSET 16
+#define EMMC_CARD_SIZE 512
+#define EMMC_ECSD_SIZE_OFFSET 53
+
+#define EXTCSD_BUS_WIDTH 183
+#define EXTCSD_HS_TIMING 185
+
+#define EMMC_TIMING_BACKWARD 0
+#define EMMC_TIMING_HS 1
+#define EMMC_TIMING_HS200 2
+#define EMMC_TIMING_HS400 3
+
+#define EMMC_BUS_WIDTH_1BIT 0
+#define EMMC_BUS_WIDTH_4BIT 1
+#define EMMC_BUS_WIDTH_8BIT 2
+#define EMMC_BUS_WIDTH_DDR_4BIT 5
+#define EMMC_BUS_WIDTH_DDR_8BIT 6
+
+#define EMMC_SWITCH_ERROR (1 << 7)
+
+#define SD_BUS_WIDTH_1BIT (1 << 0)
+#define SD_BUS_WIDTH_4BIT (1 << 2)
+
+#define SD_CCC_SWITCH (1 << 10)
+
+#define DEVICE_STATE(x) (((x) >> 9) & 0xf)
+typedef enum _EMMC_DEVICE_STATE {
+ EMMC_IDLE_STATE = 0,
+ EMMC_READY_STATE,
+ EMMC_IDENT_STATE,
+ EMMC_STBY_STATE,
+ EMMC_TRAN_STATE,
+ EMMC_DATA_STATE,
+ EMMC_RCV_STATE,
+ EMMC_PRG_STATE,
+ EMMC_DIS_STATE,
+ EMMC_BTST_STATE,
+ EMMC_SLP_STATE
+} EMMC_DEVICE_STATE;
+
+UINT32 mEmmcRcaCount = 0;
+
+STATIC
+EFI_STATUS
+EFIAPI
+EmmcGetDeviceState (
+ IN MMC_HOST_INSTANCE *MmcHostInstance,
+ OUT EMMC_DEVICE_STATE *State
+ )
+{
+ EFI_MMC_HOST_PROTOCOL *Host;
+ EFI_STATUS Status;
+ UINT32 Data, RCA;
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Host = MmcHostInstance->MmcHost;
+ RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET;
+ Status = Host->SendCommand (Host, MMC_CMD13, RCA);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcGetDeviceState(): Failed to get card status, Status=%r.\n", Status));
+ return Status;
+ }
+ Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R1, &Data);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcGetDeviceState(): Failed to get response of CMD13, Status=%r.\n", Status));
+ return Status;
+ }
+ if (Data & EMMC_SWITCH_ERROR) {
+ DEBUG ((DEBUG_ERROR, "EmmcGetDeviceState(): Failed to switch expected mode, Status=%r.\n", Status));
+ return EFI_DEVICE_ERROR;
+ }
+ *State = DEVICE_STATE(Data);
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+EmmcSetEXTCSD (
+ IN MMC_HOST_INSTANCE *MmcHostInstance,
+ UINT32 ExtCmdIndex,
+ UINT32 Value
+ )
+{
+ EFI_MMC_HOST_PROTOCOL *Host;
+ EMMC_DEVICE_STATE State;
+ EFI_STATUS Status;
+ UINT32 Argument;
+
+ Host = MmcHostInstance->MmcHost;
+ Argument = EMMC_CMD6_ARG_ACCESS(3) | EMMC_CMD6_ARG_INDEX(ExtCmdIndex) |
+ EMMC_CMD6_ARG_VALUE(Value) | EMMC_CMD6_ARG_CMD_SET(1);
+ Status = Host->SendCommand (Host, MMC_CMD6, Argument);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetEXTCSD(): Failed to send CMD6, Status=%r.\n", Status));
+ return Status;
+ }
+ // Make sure device exiting prog mode
+ do {
+ Status = EmmcGetDeviceState (MmcHostInstance, &State);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetEXTCSD(): Failed to get device state, Status=%r.\n", Status));
+ return Status;
+ }
+ } while (State == EMMC_PRG_STATE);
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+EmmcIdentificationMode (
+ IN MMC_HOST_INSTANCE *MmcHostInstance,
+ IN OCR_RESPONSE Response
+ )
+{
+ EFI_MMC_HOST_PROTOCOL *Host;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ EMMC_DEVICE_STATE State;
+ UINT32 RCA;
+
+ Host = MmcHostInstance->MmcHost;
+ Media = MmcHostInstance->BlockIo.Media;
+
+ // Fetch card identity register
+ Status = Host->SendCommand (Host, MMC_CMD2, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): Failed to send CMD2, Status=%r.\n", Status));
+ return Status;
+ }
+
+ Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CIDData));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): CID retrieval error, Status=%r.\n", Status));
+ return Status;
+ }
+
+ // Assign a relative address value to the card
+ MmcHostInstance->CardInfo.RCA = ++mEmmcRcaCount; // TODO: might need a more sophisticated way of doing this
+ RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET;
+ Status = Host->SendCommand (Host, MMC_CMD3, RCA);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): RCA set error, Status=%r.\n", Status));
+ return Status;
+ }
+
+ // Fetch card specific data
+ Status = Host->SendCommand (Host, MMC_CMD9, RCA);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): Failed to send CMD9, Status=%r.\n", Status));
+ return Status;
+ }
+
+ Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CSDData));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): CSD retrieval error, Status=%r.\n", Status));
+ return Status;
+ }
+
+ // Select the card
+ Status = Host->SendCommand (Host, MMC_CMD7, RCA);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status));
+ }
+
+ if (MMC_HOST_HAS_SETIOS(Host)) {
+ // Set 1-bit bus width
+ Status = Host->SetIos (Host, 0, 1, EMMCBACKWARD);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): Set 1-bit bus width error, Status=%r.\n", Status));
+ return Status;
+ }
+
+ // Set 1-bit bus width for EXTCSD
+ Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_1BIT);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): Set extcsd bus width error, Status=%r.\n", Status));
+ return Status;
+ }
+ }
+
+ // Fetch ECSD
+ MmcHostInstance->CardInfo.ECSDData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (ECSD)));
+ if (MmcHostInstance->CardInfo.ECSDData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = Host->SendCommand (Host, MMC_CMD8, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status));
+ }
+
+ Status = Host->ReadBlockData (Host, 0, 512, (UINT32 *)MmcHostInstance->CardInfo.ECSDData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): ECSD read error, Status=%r.\n", Status));
+ goto FreePageExit;
+ }
+
+ // Make sure device exiting data mode
+ do {
+ Status = EmmcGetDeviceState (MmcHostInstance, &State);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentificationMode(): Failed to get device state, Status=%r.\n", Status));
+ goto FreePageExit;
+ }
+ } while (State == EMMC_DATA_STATE);
+
+ // Set up media
+ Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards
+ Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN;
+ Media->ReadOnly = MmcHostInstance->CardInfo.CSDData.PERM_WRITE_PROTECT;
+ Media->LogicalBlocksPerPhysicalBlock = 1;
+ Media->IoAlign = 4;
+ // Compute last block using bits [215:212] of the ECSD
+ Media->LastBlock = MmcHostInstance->CardInfo.ECSDData->SECTOR_COUNT - 1; // eMMC isn't supposed to report this for
+ // Cards <2GB in size, but the model does.
+
+ // Setup card type
+ MmcHostInstance->CardInfo.CardType = EMMC_CARD;
+ return EFI_SUCCESS;
+
+FreePageExit:
+ FreePages (MmcHostInstance->CardInfo.ECSDData, EFI_SIZE_TO_PAGES (sizeof (ECSD)));
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+InitializeEmmcDevice (
+ IN MMC_HOST_INSTANCE *MmcHostInstance
+ )
+{
+ EFI_MMC_HOST_PROTOCOL *Host;
+ EFI_STATUS Status = EFI_SUCCESS;
+ ECSD *ECSDData;
+ UINT32 BusClockFreq, Idx, BusMode;
+ UINT32 BusWidth = 8;
+ UINT32 TimingMode[4] = {EMMCHS52DDR1V2, EMMCHS52DDR1V8, EMMCHS52, EMMCHS26};
+
+ Host = MmcHostInstance->MmcHost;
+ ECSDData = MmcHostInstance->CardInfo.ECSDData;
+ if (ECSDData->DEVICE_TYPE == EMMCBACKWARD){
+ return EFI_SUCCESS;
+ }
+
+ if (PcdGet32(PcdMmcForceDefaultSpeed)) {
+ DEBUG((DEBUG_WARN, "Forcing default speed mode\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (PcdGet32(PcdMmcForce1Bit)) {
+ DEBUG((DEBUG_WARN, "Forcing 1 bit mode\n"));
+ BusWidth = 1;
+ }
+
+ if (!MMC_HOST_HAS_SETIOS(Host)) {
+ DEBUG((DEBUG_ERROR, "Controller doesn't support speed / bus width change\n"));
+ return EFI_SUCCESS;
+ }
+
+ Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_HS_TIMING, EMMC_TIMING_HS);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to switch high speed mode, Status:%r.\n", Status));
+ return Status;
+ }
+
+ for (Idx = 0; Idx < 4; Idx++) {
+ switch (TimingMode[Idx]) {
+ case EMMCHS52DDR1V2:
+ case EMMCHS52DDR1V8:
+ case EMMCHS52:
+ BusClockFreq = 52000000;
+ break;
+ case EMMCHS26:
+ BusClockFreq = 26000000;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ Status = Host->SetIos (Host, BusClockFreq, BusWidth, TimingMode[Idx]);
+ if (!EFI_ERROR (Status)) {
+ switch (TimingMode[Idx]) {
+ case EMMCHS52DDR1V2:
+ case EMMCHS52DDR1V8:
+ BusMode = EMMC_BUS_WIDTH_DDR_8BIT;
+ break;
+ case EMMCHS52:
+ case EMMCHS26:
+ BusMode = EMMC_BUS_WIDTH_8BIT;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, BusMode);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to set EXTCSD bus width, Status:%r\n", Status));
+ }
+ return Status;
+ }
+ }
+ return Status;
+}
+
+STATIC
+UINT32
+SdSwitchCmdArgument (
+ IN UINT32 AccessMode,
+ IN UINT32 CommandSystem,
+ IN UINT32 DriveStrength,
+ IN UINT32 PowerLimit,
+ IN BOOLEAN Mode
+ )
+{
+ return (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \
+ ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \
+ (Mode ? BIT31 : 0);
+}
+
+STATIC
+EFI_STATUS
+SdSelect (
+ IN MMC_HOST_INSTANCE *MmcHostInstance
+ )
+{
+ /*
+ * Moves a card from standby to transfer state.
+ */
+ EFI_STATUS Status;
+ EFI_MMC_HOST_PROTOCOL *MmcHost = MmcHostInstance->MmcHost;
+
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD7,
+ MmcHostInstance->CardInfo.RCA << 16);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a: error: %r\n",
+ __FUNCTION__, Status));
+ }
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+SdDeselect (
+ IN MMC_HOST_INSTANCE *MmcHostInstance
+ )
+{
+ /*
+ * Moves a card from transfer to standby.
+ */
+ EFI_STATUS Status;
+ EFI_MMC_HOST_PROTOCOL *MmcHost = MmcHostInstance->MmcHost;
+
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a: error: %r\n",
+ __FUNCTION__, Status));
+ }
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+SdGetCsd(
+ IN MMC_HOST_INSTANCE *MmcHostInstance,
+ IN UINT32 *Response,
+ IN BOOLEAN Print
+ )
+{
+ EFI_STATUS Status;
+ EFI_MMC_HOST_PROTOCOL *MmcHost = MmcHostInstance->MmcHost;
+
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD9,
+ MmcHostInstance->CardInfo.RCA << 16);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(%u): error: %r\n", __FUNCTION__,
+ __LINE__, Status));
+ return Status;
+ }
+
+ Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD,
+ Response);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(%u): error %r\n", __FUNCTION__,
+ __LINE__, Status));
+ return Status;
+ }
+
+ if (Print) {
+ PrintCSD (Response);
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SdSet4Bit(
+ IN MMC_HOST_INSTANCE *MmcHostInstance
+ )
+{
+ UINT32 CmdArg;
+ EFI_STATUS Status;
+ EFI_MMC_HOST_PROTOCOL *MmcHost = MmcHostInstance->MmcHost;
+
+ if (PcdGet32(PcdMmcForce1Bit)) {
+ DEBUG((DEBUG_WARN, "Forcing 1 bit mode\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (!MMC_HOST_HAS_SETIOS(MmcHost)) {
+ DEBUG((DEBUG_WARN, "Controller doesn't support bus width change\n"));
+ return EFI_SUCCESS;
+ }
+
+ CmdArg = MmcHostInstance->CardInfo.RCA << 16;
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n",
+ __FUNCTION__, __LINE__, Status));
+ return Status;
+ }
+
+ /* Width: 4 */
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, 2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(%u): error %r\n",
+ __FUNCTION__, __LINE__, Status));
+ return Status;
+ }
+
+ Status = MmcHost->SetIos (MmcHost, 0, BUSWIDTH_4, EMMCBACKWARD);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n",
+ __FUNCTION__, __LINE__, Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SdSetSpeed(
+ IN MMC_HOST_INSTANCE *MmcHostInstance,
+ IN BOOLEAN CccSwitch
+ )
+{
+ UINT32 Speed;
+ UINT32 CmdArg;
+ EFI_STATUS Status;
+ UINT32 Buffer[16];
+ UINT32 Response[4];
+ EFI_MMC_HOST_PROTOCOL *MmcHost = MmcHostInstance->MmcHost;
+
+ if (!MMC_HOST_HAS_SETIOS(MmcHost)) {
+ DEBUG((DEBUG_WARN, "Controller doesn't support speed change\n"));
+ return EFI_SUCCESS;
+ }
+
+ Speed = PcdGet32(PcdMmcSdDefaultSpeedMHz) * 1000000;
+ if (Speed == 0) {
+ Speed = SD_DEFAULT_SPEED;
+ } else {
+ DEBUG((DEBUG_INFO, "Using default speed override %u Hz\n",
+ Speed));
+ }
+
+ /*
+ * First set base speed. We'll then try HS.
+ */
+ Status = MmcHost->SetIos (MmcHost, Speed, 0, EMMCBACKWARD);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a: error setting speed %u: %r\n",
+ __FUNCTION__, Speed, Status));
+ return Status;
+ }
+
+ if (PcdGet32(PcdMmcForceDefaultSpeed)) {
+ DEBUG((DEBUG_WARN, "Forcing default speed mode\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (!CccSwitch) {
+ return EFI_SUCCESS;
+ }
+
+ /* Query. */
+ CmdArg = SdSwitchCmdArgument(0xf, 0xf, 0xf, 0xf, FALSE);
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, CmdArg);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(%u): error: %r\n",
+ __FUNCTION__, __LINE__, Status));
+ return Status;
+ } else {
+ Status = MmcHost->ReadBlockData (MmcHost, 0, SWITCH_CMD_DATA_LENGTH,
+ Buffer);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(%u): error: %r\n",
+ __FUNCTION__, __LINE__, Status));
+ return Status;
+ }
+ }
+
+ if (!(Buffer[3] & SD_HIGH_SPEED_SUPPORTED)) {
+ DEBUG((DEBUG_ERROR, "%a: High Speed not supported by Card\n"));
+ return EFI_SUCCESS;
+ }
+
+ /* Switch to high speed. */
+ CmdArg = SdSwitchCmdArgument(1, 0xf, 0xf, 0xf, TRUE);
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, CmdArg);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(%u): error: %r\n",
+ __FUNCTION__, __LINE__, Status));
+ return Status;
+ } else {
+ Status = MmcHost->ReadBlockData (MmcHost, 0,
+ SWITCH_CMD_DATA_LENGTH, Buffer);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(%u): error: %r\n",
+ __FUNCTION__, __LINE__, Status));
+ return Status;
+ }
+
+ if ((Buffer[4] & SWITCH_CMD_SUCCESS_MASK) != 0x1) {
+ DEBUG((DEBUG_ERROR, "Problem switching SD card into HS mode\n"));
+ DEBUG((DEBUG_ERROR, "%08x %08x %08x %08x\n",
+ Buffer[0], Buffer[1], Buffer[2], Buffer[3]));
+ DEBUG((DEBUG_ERROR, "%08x %08x %08x %08x\n",
+ Buffer[4], Buffer[5], Buffer[6], Buffer[8]));
+ return Status;
+ }
+ }
+
+ DEBUG((DEBUG_ERROR, "Dumping CSD after high-speed switch\n"));
+ SdDeselect(MmcHostInstance);
+ SdGetCsd(MmcHostInstance, Response, TRUE);
+ SdSelect(MmcHostInstance);
+
+ Speed = PcdGet32(PcdMmcSdHighSpeedMHz) * 1000000;
+ if (Speed == 0) {
+ Speed = SD_HIGH_SPEED;
+ } else {
+ DEBUG((DEBUG_INFO, "Using high speed override %u Hz\n",
+ Speed));
+ }
+
+ Status = MmcHost->SetIos (MmcHost, Speed, 0, EMMCBACKWARD);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a: error setting speed %u: %r\n",
+ __FUNCTION__, Speed, Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+InitializeSdMmcDevice (
+ IN MMC_HOST_INSTANCE *MmcHostInstance
+ )
+{
+ UINT32 Response[4];
+ UINT32 Buffer[128];
+ UINTN BlockSize;
+ UINTN CardSize;
+ UINTN NumBlocks;
+ BOOLEAN CccSwitch;
+ SCR Scr;
+ EFI_STATUS Status;
+ EFI_MMC_HOST_PROTOCOL *MmcHost = MmcHostInstance->MmcHost;
+
+ Status = SdGetCsd (MmcHostInstance, Response, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (MMC_CSD_GET_CCC(Response) & SD_CCC_SWITCH) {
+ CccSwitch = TRUE;
+ } else {
+ CccSwitch = FALSE;
+ }
+
+ if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {
+ CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);
+ NumBlocks = ((CardSize + 1) * 1024);
+ BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);
+ } else {
+ CardSize = MMC_CSD_GET_DEVICESIZE (Response);
+ NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));
+ BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);
+ }
+
+ // For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.
+ if (BlockSize > 512) {
+ NumBlocks = MultU64x32 (NumBlocks, BlockSize / 512);
+ BlockSize = 512;
+ }
+
+ MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1);
+ MmcHostInstance->BlockIo.Media->BlockSize = BlockSize;
+ MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost);
+ MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;
+ MmcHostInstance->BlockIo.Media->MediaId++;
+
+ Status = SdSelect(MmcHostInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD55,
+ MmcHostInstance->CardInfo.RCA << 16);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a (MMC_CMD55): Error and Status = %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+ Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a (MMC_CMD55): Error and Status = %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+ if ((Response[0] & MMC_STATUS_APP_CMD) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ /* SCR */
+ Status = MmcHost->SendCommand (MmcHost, MMC_ACMD51, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(MMC_ACMD51): Error and Status = %r\n", __func__, Status));
+ return Status;
+ } else {
+ Status = MmcHost->ReadBlockData (MmcHost, 0, 8, Buffer);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(MMC_ACMD51): ReadBlockData Error and Status = %r\n", __func__, Status));
+ return Status;
+ }
+ CopyMem (&Scr, Buffer, 8);
+ if (Scr.SD_SPEC == 2) {
+ if (Scr.SD_SPEC3 == 1) {
+ if (Scr.SD_SPEC4 == 1) {
+ DEBUG ((DEBUG_INFO, "Found SD Card for Spec Version 4.xx\n"));
+ } else {
+ DEBUG ((DEBUG_INFO, "Found SD Card for Spec Version 3.0x\n"));
+ }
+ } else {
+ if (Scr.SD_SPEC4 == 0) {
+ DEBUG ((DEBUG_INFO, "Found SD Card for Spec Version 2.0\n"));
+ } else {
+ DEBUG ((DEBUG_ERROR, "Found invalid SD Card\n"));
+ }
+ }
+ } else {
+ if ((Scr.SD_SPEC3 == 0) && (Scr.SD_SPEC4 == 0)) {
+ if (Scr.SD_SPEC == 1) {
+ DEBUG ((DEBUG_INFO, "Found SD Card for Spec Version 1.10\n"));
+ } else {
+ DEBUG ((DEBUG_INFO, "Found SD Card for Spec Version 1.0\n"));
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "Found invalid SD Card\n"));
+ }
+ }
+ }
+
+ Status = SdSetSpeed(MmcHostInstance, CccSwitch);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (Scr.SD_BUS_WIDTHS & SD_BUS_WIDTH_4BIT) {
+ Status = SdSet4Bit(MmcHostInstance);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+MmcIdentificationMode (
+ IN MMC_HOST_INSTANCE *MmcHostInstance
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Response[4];
+ UINTN Timeout;
+ UINTN CmdArg;
+ BOOLEAN IsHCS;
+ EFI_MMC_HOST_PROTOCOL *MmcHost;
+ OCR_RESPONSE OcrResponse;
+
+ MmcHost = MmcHostInstance->MmcHost;
+ CmdArg = 0;
+ IsHCS = FALSE;
+
+ if (MmcHost == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // We can get into this function if we restart the identification mode
+ if (MmcHostInstance->State == MmcHwInitializationState) {
+ // Initialize the MMC Host HW
+ Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState, Status=%r.\n", Status));
+ return Status;
+ }
+ }
+
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode(MMC_CMD0): Error, Status=%r.\n", Status));
+ return Status;
+ }
+ Status = MmcNotifyState (MmcHostInstance, MmcIdleState);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Error MmcIdleState, Status=%r.\n", Status));
+ return Status;
+ }
+
+ // Send CMD1 to get OCR (MMC)
+ // This command only valid for MMC and eMMC
+ Timeout = MAX_RETRY_COUNT;
+ do {
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, EMMC_CMD1_CAPACITY_GREATER_THAN_2GB);
+ if (EFI_ERROR (Status))
+ break;
+ Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, (UINT32 *)&OcrResponse);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));
+ return Status;
+ }
+ Timeout--;
+ } while (!OcrResponse.Ocr.PowerUp && (Timeout > 0));
+ if (Status == EFI_SUCCESS) {
+ if (!OcrResponse.Ocr.PowerUp) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode(MMC_CMD1): Card initialisation failure, Status=%r.\n", Status));
+ return EFI_DEVICE_ERROR;
+ }
+ OcrResponse.Ocr.PowerUp = 0;
+ if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB) {
+ MmcHostInstance->CardInfo.OCRData.AccessMode = BIT1;
+ }
+ else {
+ MmcHostInstance->CardInfo.OCRData.AccessMode = 0x0;
+ }
+ // Check whether MMC or eMMC
+ if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB ||
+ OcrResponse.Raw == EMMC_CMD1_CAPACITY_LESS_THAN_2GB) {
+ return EmmcIdentificationMode (MmcHostInstance, OcrResponse);
+ }
+ }
+
+ // Are we using SDIO ?
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);
+ if (Status == EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported, Status=%r.\n", Status));
+ return EFI_UNSUPPORTED;
+ }
+
+ // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)
+ CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);
+ if (Status == EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Card is SD2.0 => Supports high capacity\n"));
+ IsHCS = TRUE;
+ Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Failed to receive response to CMD8, Status=%r.\n", Status));
+ return Status;
+ }
+ PrintResponseR1 (Response[0]);
+ // Check if it is valid response
+ if (Response[0] != CmdArg) {
+ DEBUG ((DEBUG_ERROR, "The Card is not usable\n"));
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "Not a SD2.0 Card\n"));
+ }
+
+ // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)
+ Timeout = MAX_RETRY_COUNT;
+ while (Timeout > 0) {
+ // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);
+ if (Status == EFI_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "Card should be SD\n"));
+ if (IsHCS) {
+ MmcHostInstance->CardInfo.CardType = SD_CARD_2;
+ } else {
+ MmcHostInstance->CardInfo.CardType = SD_CARD;
+ }
+
+ // Note: The first time CmdArg will be zero
+ CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];
+ if (IsHCS) {
+ CmdArg |= BIT30;
+ }
+ Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);
+ if (!EFI_ERROR (Status)) {
+ Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));
+ return Status;
+ }
+ ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "Card should be MMC\n"));
+ MmcHostInstance->CardInfo.CardType = MMC_CARD;
+
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);
+ if (!EFI_ERROR (Status)) {
+ Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));
+ return Status;
+ }
+ ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {
+ gBS->Stall (1);
+ Timeout--;
+ } else {
+ if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {
+ MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;
+ DEBUG ((DEBUG_ERROR, "High capacity card.\n"));
+ }
+ break; // The MMC/SD card is ready. Continue the Identification Mode
+ }
+ } else {
+ gBS->Stall (1);
+ Timeout--;
+ }
+ }
+
+ if (Timeout == 0) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode(): No Card\n"));
+ return EFI_NO_MEDIA;
+ } else {
+ PrintOCR (Response[0]);
+ }
+
+ Status = MmcNotifyState (MmcHostInstance, MmcReadyState);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));
+ return Status;
+ }
+
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));
+ return Status;
+ }
+ Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Failed to receive CID, Status=%r.\n", Status));
+ return Status;
+ }
+
+ PrintCID (Response);
+
+ Status = MmcHost->NotifyState (MmcHost, MmcIdentificationState);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));
+ return Status;
+ }
+
+ //
+ // Note, SD specifications say that "if the command execution causes a state change, it
+ // will be visible to the host in the response to the next command"
+ // The status returned for this CMD3 will be 2 - identification
+ //
+ CmdArg = 1;
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));
+ return Status;
+ }
+
+ Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Failed to receive RCA, Status=%r.\n", Status));
+ return Status;
+ }
+ PrintRCA (Response[0]);
+
+ // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card
+ if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {
+ MmcHostInstance->CardInfo.RCA = Response[0] >> 16;
+ } else {
+ MmcHostInstance->CardInfo.RCA = CmdArg;
+ }
+ Status = MmcNotifyState (MmcHostInstance, MmcStandByState);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InitializeMmcDevice (
+ IN MMC_HOST_INSTANCE *MmcHostInstance
+ )
+{
+ EFI_STATUS Status;
+ EFI_MMC_HOST_PROTOCOL *MmcHost;
+ UINTN BlockCount;
+
+ BlockCount = 1;
+ MmcHost = MmcHostInstance->MmcHost;
+
+ Status = MmcIdentificationMode (MmcHostInstance);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "InitializeMmcDevice(): Error in Identification Mode, Status=%r\n", Status));
+ return Status;
+ }
+
+ Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "InitializeMmcDevice(): Error MmcTransferState, Status=%r\n", Status));
+ return Status;
+ }
+
+ if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {
+ Status = InitializeSdMmcDevice (MmcHostInstance);
+ } else {
+ Status = InitializeEmmcDevice (MmcHostInstance);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Set Block Length
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",
+ MmcHostInstance->BlockIo.Media->BlockSize, Status));
+ return Status;
+ }
+
+ // Block Count (not used). Could return an error for SD card
+ if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "InitializeMmcDevice(MMC_CMD23): Error, Status=%r\n", Status));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.c b/Platform/Broadcom/Bcm283x/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.c
new file mode 100644
index 000000000000..36b953d9c5f4
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.c
@@ -0,0 +1,915 @@
+/** @file
+ *
+ * Static SMBIOS Table for ARM platform
+ * Derived from EmulatorPkg package
+ *
+ * Note SMBIOS 2.7.1 Required structures:
+ * BIOS Information (Type 0)
+ * System Information (Type 1)
+ * Board Information (Type 2)
+ * System Enclosure (Type 3)
+ * Processor Information (Type 4) - CPU Driver
+ * Cache Information (Type 7) - For cache that is external to processor
+ * System Slots (Type 9) - If system has slots
+ * Physical Memory Array (Type 16)
+ * Memory Device (Type 17) - For each socketed system-memory Device
+ * Memory Array Mapped Address (Type 19) - One per contiguous block per Physical Memroy Array
+ * System Boot Information (Type 32)
+ *
+ * Copyright (c) 2017-2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2013, Linaro.org
+ * Copyright (c) 2012, Apple Inc. All rights reserved.<BR>
+ * Copyright (c) Microsoft Corporation. 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 <Base.h>
+#include <Protocol/Smbios.h>
+#include <Protocol/RaspberryPiFirmware.h>
+#include <IndustryStandard/SmBios.h>
+#include <IndustryStandard/RpiFirmware.h>
+#include <Guid/SmBios.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PrintLib.h>
+#include <Utils.h>
+
+STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol;
+
+/***********************************************************************
+ SMBIOS data definition TYPE0 BIOS Information
+************************************************************************/
+SMBIOS_TABLE_TYPE0 mBIOSInfoType0 = {
+ { EFI_SMBIOS_TYPE_BIOS_INFORMATION, sizeof (SMBIOS_TABLE_TYPE0), 0 },
+ 1, // Vendor String
+ 2, // BiosVersion String
+ 0x0, // BiosSegment
+ 3, // BiosReleaseDate String
+ 0x1F, // BiosSize
+ { // BiosCharacteristics
+ 0, // Reserved :2; ///< Bits 0-1.
+ 0, // Unknown :1;
+ 0, // BiosCharacteristicsNotSupported :1;
+ 0, // IsaIsSupported :1;
+ 0, // McaIsSupported :1;
+ 0, // EisaIsSupported :1;
+ 0, // PciIsSupported :1;
+ 0, // PcmciaIsSupported :1;
+ 0, // PlugAndPlayIsSupported :1;
+ 0, // ApmIsSupported :1;
+ 0, // BiosIsUpgradable :1;
+ 0, // BiosShadowingAllowed :1;
+ 0, // VlVesaIsSupported :1;
+ 0, // EscdSupportIsAvailable :1;
+ 0, // BootFromCdIsSupported :1;
+ 1, // SelectableBootIsSupported :1;
+ 0, // RomBiosIsSocketed :1;
+ 0, // BootFromPcmciaIsSupported :1;
+ 0, // EDDSpecificationIsSupported :1;
+ 0, // JapaneseNecFloppyIsSupported :1;
+ 0, // JapaneseToshibaFloppyIsSupported :1;
+ 0, // Floppy525_360IsSupported :1;
+ 0, // Floppy525_12IsSupported :1;
+ 0, // Floppy35_720IsSupported :1;
+ 0, // Floppy35_288IsSupported :1;
+ 0, // PrintScreenIsSupported :1;
+ 0, // Keyboard8042IsSupported :1;
+ 0, // SerialIsSupported :1;
+ 0, // PrinterIsSupported :1;
+ 0, // CgaMonoIsSupported :1;
+ 0, // NecPc98 :1;
+ 0 // ReservedForVendor :32; ///< Bits 32-63. Bits 32-47 reserved for BIOS vendor
+ ///< and bits 48-63 reserved for System Vendor.
+ },
+ { // BIOSCharacteristicsExtensionBytes[]
+ 0x01, // AcpiIsSupported :1;
+ // UsbLegacyIsSupported :1;
+ // AgpIsSupported :1;
+ // I2OBootIsSupported :1;
+ // Ls120BootIsSupported :1;
+ // AtapiZipDriveBootIsSupported :1;
+ // Boot1394IsSupported :1;
+ // SmartBatteryIsSupported :1;
+ // BIOSCharacteristicsExtensionBytes[1]
+ 0x0e, // BiosBootSpecIsSupported :1;
+ // FunctionKeyNetworkBootIsSupported :1;
+ // TargetContentDistributionEnabled :1;
+ // UefiSpecificationSupported :1;
+ // VirtualMachineSupported :1;
+ // ExtensionByte2Reserved :3;
+ },
+ 0xFF, // SystemBiosMajorRelease
+ 0xFF, // SystemBiosMinorRelease
+ 0xFF, // EmbeddedControllerFirmwareMajorRelease
+ 0xFF, // EmbeddedControllerFirmwareMinorRelease
+};
+
+CHAR8 *mBIOSInfoType0Strings[] = {
+ "https://github.com/andreiw/RaspberryPiPkg", // Vendor String
+ "Raspberry Pi 64-bit UEFI (" __DATE__ " " __TIME__ ")", // BiosVersion String
+ __DATE__,
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE1 System Information
+************************************************************************/
+SMBIOS_TABLE_TYPE1 mSysInfoType1 = {
+ { EFI_SMBIOS_TYPE_SYSTEM_INFORMATION, sizeof (SMBIOS_TABLE_TYPE1), 0 },
+ 1, // Manufacturer String
+ 2, // ProductName String
+ 3, // Version String
+ 4, // SerialNumber String
+ { 0x25EF0280, 0xEC82, 0x42B0, { 0x8F, 0xB6, 0x10, 0xAD, 0xCC, 0xC6, 0x7C, 0x02 } },
+ SystemWakeupTypePowerSwitch,
+ 5, // SKUNumber String
+ 6, // Family String
+};
+
+#define PROD_BASE 8
+#define PROD_KNOWN 13
+#define PROD_UNKNOWN 11
+CHAR8 *ProductNames[] = {
+ /* 8 */ "3",
+ /* 9 */ "Zero",
+ /* 10 */ "CM3",
+ /* 11 */ "???",
+ /* 12 */ "Zero W",
+ /* 13 */ "3B+"
+};
+
+#define MANU_UNKNOWN 0
+#define MANU_KNOWN 4
+#define MANU_BASE 1
+CHAR8 *ManufNames[] = {
+ "???",
+ /* 0 */ "Sony",
+ /* 1 */ "Egoman",
+ /* 2 */ "Embest",
+ /* 3 */ "Sony Japan",
+ /* 4 */ "Embest"
+};
+
+CHAR8 mSysInfoManufName[sizeof("Sony Japan")];
+CHAR8 mSysInfoProductName[sizeof("64-bit Raspberry Pi XXXXXX (rev. xxxxxxxx)")];
+CHAR8 mSysInfoSerial[sizeof(UINT64) * 2 + 1];
+CHAR8 mSysInfoSKU[sizeof(UINT64) * 2 + 1];
+
+CHAR8 *mSysInfoType1Strings[] = {
+ mSysInfoManufName,
+ mSysInfoProductName,
+ mSysInfoProductName,
+ mSysInfoSerial,
+ mSysInfoSKU,
+ "edk2",
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE2 Board Information
+************************************************************************/
+SMBIOS_TABLE_TYPE2 mBoardInfoType2 = {
+ { EFI_SMBIOS_TYPE_BASEBOARD_INFORMATION, sizeof (SMBIOS_TABLE_TYPE2), 0 },
+ 1, // Manufacturer String
+ 2, // ProductName String
+ 3, // Version String
+ 4, // SerialNumber String
+ 5, // AssetTag String
+ { // FeatureFlag
+ 1, // Motherboard :1;
+ 0, // RequiresDaughterCard :1;
+ 0, // Removable :1;
+ 0, // Replaceable :1;
+ 0, // HotSwappable :1;
+ 0, // Reserved :3;
+ },
+ 6, // LocationInChassis String
+ 0, // ChassisHandle;
+ BaseBoardTypeMotherBoard, // BoardType;
+ 0, // NumberOfContainedObjectHandles;
+ { 0 } // ContainedObjectHandles[1];
+};
+CHAR8 *mBoardInfoType2Strings[] = {
+ mSysInfoManufName,
+ mSysInfoProductName,
+ mSysInfoProductName,
+ mSysInfoSerial,
+ "None",
+ mSysInfoSKU,
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE3 Enclosure Information
+************************************************************************/
+SMBIOS_TABLE_TYPE3 mEnclosureInfoType3 = {
+ { EFI_SMBIOS_TYPE_SYSTEM_ENCLOSURE, sizeof (SMBIOS_TABLE_TYPE3), 0 },
+ 1, // Manufacturer String
+ MiscChassisEmbeddedPc, // Type;
+ 2, // Version String
+ 3, // SerialNumber String
+ 4, // AssetTag String
+ ChassisStateSafe, // BootupState;
+ ChassisStateSafe, // PowerSupplyState;
+ ChassisStateSafe, // ThermalState;
+ ChassisSecurityStatusNone,// SecurityStatus;
+ { 0, 0, 0, 0 }, // OemDefined[4];
+ 0, // Height;
+ 0, // NumberofPowerCords;
+ 0, // ContainedElementCount;
+ 0, // ContainedElementRecordLength;
+ { { 0 } }, // ContainedElements[1];
+};
+CHAR8 *mEnclosureInfoType3Strings[] = {
+ mSysInfoManufName,
+ mSysInfoProductName,
+ mSysInfoSerial,
+ "None",
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE4 Processor Information
+************************************************************************/
+SMBIOS_TABLE_TYPE4 mProcessorInfoType4 = {
+ { EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION, sizeof (SMBIOS_TABLE_TYPE4), 0},
+ 1, // Socket String
+ CentralProcessor, // ProcessorType; ///< The enumeration value from PROCESSOR_TYPE_DATA.
+ ProcessorFamilyIndicatorFamily2, // ProcessorFamily; ///< The enumeration value from PROCESSOR_FAMILY2_DATA.
+ 2, // ProcessorManufacture String;
+ { // ProcessorId;
+ { // PROCESSOR_SIGNATURE
+ 0, // ProcessorSteppingId:4;
+ 0, // ProcessorModel: 4;
+ 0, // ProcessorFamily: 4;
+ 0, // ProcessorType: 2;
+ 0, // ProcessorReserved1: 2;
+ 0, // ProcessorXModel: 4;
+ 0, // ProcessorXFamily: 8;
+ 0, // ProcessorReserved2: 4;
+ },
+
+ { // PROCESSOR_FEATURE_FLAGS
+ 0, // ProcessorFpu :1;
+ 0, // ProcessorVme :1;
+ 0, // ProcessorDe :1;
+ 0, // ProcessorPse :1;
+ 0, // ProcessorTsc :1;
+ 0, // ProcessorMsr :1;
+ 0, // ProcessorPae :1;
+ 0, // ProcessorMce :1;
+ 0, // ProcessorCx8 :1;
+ 0, // ProcessorApic :1;
+ 0, // ProcessorReserved1 :1;
+ 0, // ProcessorSep :1;
+ 0, // ProcessorMtrr :1;
+ 0, // ProcessorPge :1;
+ 0, // ProcessorMca :1;
+ 0, // ProcessorCmov :1;
+ 0, // ProcessorPat :1;
+ 0, // ProcessorPse36 :1;
+ 0, // ProcessorPsn :1;
+ 0, // ProcessorClfsh :1;
+ 0, // ProcessorReserved2 :1;
+ 0, // ProcessorDs :1;
+ 0, // ProcessorAcpi :1;
+ 0, // ProcessorMmx :1;
+ 0, // ProcessorFxsr :1;
+ 0, // ProcessorSse :1;
+ 0, // ProcessorSse2 :1;
+ 0, // ProcessorSs :1;
+ 0, // ProcessorReserved3 :1;
+ 0, // ProcessorTm :1;
+ 0, // ProcessorReserved4 :2;
+ }
+ },
+ 3, // ProcessorVersion String;
+ { // Voltage;
+ 1, // ProcessorVoltageCapability5V :1;
+ 1, // ProcessorVoltageCapability3_3V :1;
+ 1, // ProcessorVoltageCapability2_9V :1;
+ 0, // ProcessorVoltageCapabilityReserved :1; ///< Bit 3, must be zero.
+ 0, // ProcessorVoltageReserved :3; ///< Bits 4-6, must be zero.
+ 0 // ProcessorVoltageIndicateLegacy :1;
+ },
+ 0, // ExternalClock;
+ 0, // MaxSpeed;
+ 0, // CurrentSpeed;
+ 0x41, // Status;
+ ProcessorUpgradeOther, // ProcessorUpgrade; ///< The enumeration value from PROCESSOR_UPGRADE.
+ 0, // L1CacheHandle;
+ 0, // L2CacheHandle;
+ 0, // L3CacheHandle;
+ 4, // SerialNumber;
+ 5, // AssetTag;
+ 6, // PartNumber;
+ 4, // CoreCount;
+ 4, // EnabledCoreCount;
+ 4, // ThreadCount;
+ 0x6C, // ProcessorCharacteristics;
+ ProcessorFamilyARM, // ARM Processor Family;
+};
+
+CHAR8 *mProcessorInfoType4Strings[] = {
+ "Socket",
+ "ARM",
+ "BCM2837 ARMv8",
+ "1.0",
+ "1.0",
+ "1.0",
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE7 Cache Information
+************************************************************************/
+SMBIOS_TABLE_TYPE7 mCacheInfoType7 = {
+ { EFI_SMBIOS_TYPE_CACHE_INFORMATION, sizeof (SMBIOS_TABLE_TYPE7), 0 },
+ 1, // SocketDesignation String
+ 0x018A, // Cache Configuration
+ 0x00FF, // Maximum Size 256k
+ 0x00FF, // Install Size 256k
+ { // Supported SRAM Type
+ 0, //Other :1
+ 0, //Unknown :1
+ 0, //NonBurst :1
+ 1, //Burst :1
+ 0, //PiplelineBurst :1
+ 1, //Synchronous :1
+ 0, //Asynchronous :1
+ 0 //Reserved :9
+ },
+ { // Current SRAM Type
+ 0, //Other :1
+ 0, //Unknown :1
+ 0, //NonBurst :1
+ 1, //Burst :1
+ 0, //PiplelineBurst :1
+ 1, //Synchronous :1
+ 0, //Asynchronous :1
+ 0 //Reserved :9
+ },
+ 0, // Cache Speed unknown
+ CacheErrorMultiBit, // Error Correction Multi
+ CacheTypeUnknown, // System Cache Type
+ CacheAssociativity2Way // Associativity
+};
+CHAR8 *mCacheInfoType7Strings[] = {
+ "Cache1",
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE9 System Slot Information
+************************************************************************/
+SMBIOS_TABLE_TYPE9 mSysSlotInfoType9 = {
+ { EFI_SMBIOS_TYPE_SYSTEM_SLOTS, sizeof (SMBIOS_TABLE_TYPE9), 0 },
+ 1, // SlotDesignation String
+ SlotTypeOther, // SlotType; ///< The enumeration value from MISC_SLOT_TYPE.
+ SlotDataBusWidthOther, // SlotDataBusWidth; ///< The enumeration value from MISC_SLOT_DATA_BUS_WIDTH.
+ SlotUsageAvailable, // CurrentUsage; ///< The enumeration value from MISC_SLOT_USAGE.
+ SlotLengthOther, // SlotLength; ///< The enumeration value from MISC_SLOT_LENGTH.
+ 0, // SlotID;
+ { // SlotCharacteristics1;
+ 1, // CharacteristicsUnknown :1;
+ 0, // Provides50Volts :1;
+ 0, // Provides33Volts :1;
+ 0, // SharedSlot :1;
+ 0, // PcCard16Supported :1;
+ 0, // CardBusSupported :1;
+ 0, // ZoomVideoSupported :1;
+ 0, // ModemRingResumeSupported:1;
+ },
+ { // SlotCharacteristics2;
+ 0, // PmeSignalSupported :1;
+ 0, // HotPlugDevicesSupported :1;
+ 0, // SmbusSignalSupported :1;
+ 0, // Reserved :5; ///< Set to 0.
+ },
+ 0, // SegmentGroupNum;
+ 0, // BusNum;
+ 0, // DevFuncNum;
+};
+CHAR8 *mSysSlotInfoType9Strings[] = {
+ "SD Card",
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE16 Physical Memory ArrayInformation
+************************************************************************/
+SMBIOS_TABLE_TYPE16 mPhyMemArrayInfoType16 = {
+ { EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY, sizeof (SMBIOS_TABLE_TYPE16), 0 },
+ MemoryArrayLocationSystemBoard, // Location; ///< The enumeration value from MEMORY_ARRAY_LOCATION.
+ MemoryArrayUseSystemMemory, // Use; ///< The enumeration value from MEMORY_ARRAY_USE.
+ MemoryErrorCorrectionUnknown, // MemoryErrorCorrection; ///< The enumeration value from MEMORY_ERROR_CORRECTION.
+ 0x40000000, // MaximumCapacity;
+ 0xFFFE, // MemoryErrorInformationHandle;
+ 1, // NumberOfMemoryDevices;
+ 0x40000000ULL, // ExtendedMaximumCapacity;
+};
+CHAR8 *mPhyMemArrayInfoType16Strings[] = {
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE17 Memory Device Information
+************************************************************************/
+SMBIOS_TABLE_TYPE17 mMemDevInfoType17 = {
+ { EFI_SMBIOS_TYPE_MEMORY_DEVICE, sizeof (SMBIOS_TABLE_TYPE17), 0 },
+ 0, // MemoryArrayHandle; // Should match SMBIOS_TABLE_TYPE16.Handle, initialized at runtime, refer to PhyMemArrayInfoUpdateSmbiosType16()
+ 0xFFFE, // MemoryErrorInformationHandle;
+ 0xFFFF, // TotalWidth;
+ 0xFFFF, // DataWidth;
+ 0x0400, // Size; // When bit 15 is 0: Size in MB
+ // When bit 15 is 1: Size in KB, and continues in ExtendedSize
+ MemoryFormFactorUnknown, // FormFactor; ///< The enumeration value from MEMORY_FORM_FACTOR.
+ 0xff, // DeviceSet;
+ 1, // DeviceLocator String
+ 2, // BankLocator String
+ MemoryTypeDram, // MemoryType; ///< The enumeration value from MEMORY_DEVICE_TYPE.
+ { // TypeDetail;
+ 0, // Reserved :1;
+ 0, // Other :1;
+ 1, // Unknown :1;
+ 0, // FastPaged :1;
+ 0, // StaticColumn :1;
+ 0, // PseudoStatic :1;
+ 0, // Rambus :1;
+ 0, // Synchronous :1;
+ 0, // Cmos :1;
+ 0, // Edo :1;
+ 0, // WindowDram :1;
+ 0, // CacheDram :1;
+ 0, // Nonvolatile :1;
+ 0, // Registered :1;
+ 0, // Unbuffered :1;
+ 0, // Reserved1 :1;
+ },
+ 0, // Speed;
+ 3, // Manufacturer String
+ 0, // SerialNumber String
+ 0, // AssetTag String
+ 0, // PartNumber String
+ 0, // Attributes;
+ 0, // ExtendedSize;
+ 0, // ConfiguredMemoryClockSpeed;
+};
+CHAR8 *mMemDevInfoType17Strings[] = {
+ "OS Virtual Memory",
+ "malloc",
+ "OSV",
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE19 Memory Array Mapped Address Information
+************************************************************************/
+SMBIOS_TABLE_TYPE19 mMemArrMapInfoType19 = {
+ { EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS, sizeof (SMBIOS_TABLE_TYPE19), 0 },
+ 0x00000000, // StartingAddress;
+ 0x00000000, // EndingAddress;
+ 0, // MemoryArrayHandle;
+ 1, // PartitionWidth;
+ 0, // ExtendedStartingAddress;
+ 0, // ExtendedEndingAddress;
+};
+CHAR8 *mMemArrMapInfoType19Strings[] = {
+ NULL
+};
+
+/***********************************************************************
+ SMBIOS data definition TYPE32 Boot Information
+************************************************************************/
+SMBIOS_TABLE_TYPE32 mBootInfoType32 = {
+ { EFI_SMBIOS_TYPE_SYSTEM_BOOT_INFORMATION, sizeof (SMBIOS_TABLE_TYPE32), 0 },
+ { 0, 0, 0, 0, 0, 0 }, // Reserved[6];
+ BootInformationStatusNoError // BootStatus
+};
+
+CHAR8 *mBootInfoType32Strings[] = {
+ NULL
+};
+
+
+/**
+
+ Create SMBIOS record.
+
+ Converts a fixed SMBIOS structure and an array of pointers to strings into
+ an SMBIOS record where the strings are cat'ed on the end of the fixed record
+ and terminated via a double NULL and add to SMBIOS table.
+
+ SMBIOS_TABLE_TYPE32 gSmbiosType12 = {
+ { EFI_SMBIOS_TYPE_SYSTEM_CONFIGURATION_OPTIONS, sizeof (SMBIOS_TABLE_TYPE12), 0 },
+ 1 // StringCount
+ };
+
+ CHAR8 *gSmbiosType12Strings[] = {
+ "Not Found",
+ NULL
+ };
+
+ ...
+
+ LogSmbiosData (
+ (EFI_SMBIOS_TABLE_HEADER*)&gSmbiosType12,
+ gSmbiosType12Strings
+ );
+
+ @param Template Fixed SMBIOS structure, required.
+ @param StringPack Array of strings to convert to an SMBIOS string pack.
+ NULL is OK.
+ @param DataSmbiosHande The new SMBIOS record handle .
+ NULL is OK.
+**/
+
+EFI_STATUS
+EFIAPI
+LogSmbiosData (
+ IN EFI_SMBIOS_TABLE_HEADER *Template,
+ IN CHAR8 **StringPack,
+ OUT EFI_SMBIOS_HANDLE *DataSmbiosHande
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMBIOS_PROTOCOL *Smbios;
+ EFI_SMBIOS_HANDLE SmbiosHandle;
+ EFI_SMBIOS_TABLE_HEADER *Record;
+ UINTN Index;
+ UINTN StringSize;
+ UINTN Size;
+ CHAR8 *Str;
+
+ //
+ // Locate Smbios protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Calculate the size of the fixed record and optional string pack
+
+ Size = Template->Length;
+ if (StringPack == NULL) {
+ // At least a double null is required
+ Size += 2;
+ } else {
+ for (Index = 0; StringPack[Index] != NULL; Index++) {
+ StringSize = AsciiStrSize (StringPack[Index]);
+ Size += StringSize;
+ }
+ if (StringPack[0] == NULL) {
+ // At least a double null is required
+ Size += 1;
+ }
+
+ // Don't forget the terminating double null
+ Size += 1;
+ }
+
+ // Copy over Template
+ Record = (EFI_SMBIOS_TABLE_HEADER *)AllocateZeroPool (Size);
+ if (Record == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (Record, Template, Template->Length);
+
+ // Append string pack
+ Str = ((CHAR8 *)Record) + Record->Length;
+
+ for (Index = 0; StringPack[Index] != NULL; Index++) {
+ StringSize = AsciiStrSize (StringPack[Index]);
+ CopyMem (Str, StringPack[Index], StringSize);
+ Str += StringSize;
+ }
+
+ *Str = 0;
+ SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+ Status = Smbios->Add (
+ Smbios,
+ gImageHandle,
+ &SmbiosHandle,
+ Record
+ );
+
+ if ((Status == EFI_SUCCESS) && (DataSmbiosHande != NULL)) {
+ *DataSmbiosHande = SmbiosHandle;
+ }
+
+ ASSERT_EFI_ERROR (Status);
+ FreePool (Record);
+ return Status;
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE0 BIOS Information
+************************************************************************/
+VOID
+BIOSInfoUpdateSmbiosType0 (
+ VOID
+ )
+{
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mBIOSInfoType0, mBIOSInfoType0Strings, NULL);
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE1 System Information
+************************************************************************/
+VOID
+I64ToHexString(
+ IN OUT CHAR8* TargetStringSz,
+ IN UINT32 TargetStringSize,
+ IN UINT64 Value
+ )
+{
+ static CHAR8 ItoH[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
+ UINT8 StringInx;
+ INT8 NibbleInx;
+
+ ZeroMem((void*)TargetStringSz, TargetStringSize);
+
+ //
+ // Convert each nibble to hex string, starting from
+ // the highest non-zero nibble.
+ //
+ StringInx = 0;
+ for (NibbleInx = sizeof(UINT64) * 2; NibbleInx > 0; --NibbleInx) {
+ UINT64 NibbleMask = (((UINT64)0xF) << ((NibbleInx - 1) * 4));
+ UINT8 Nibble = (UINT8)((Value & NibbleMask) >> ((NibbleInx - 1) * 4));
+
+ ASSERT(Nibble <= 0xF);
+
+ if (StringInx < (TargetStringSize-1)) {
+ TargetStringSz[StringInx++] = ItoH[Nibble];
+ } else {
+ break;
+ }
+ }
+}
+
+VOID
+SysInfoUpdateSmbiosType1 (
+ VOID
+ )
+{
+ UINT32 BoardRevision = 0;
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT64 BoardSerial = 0;
+ UINTN Prod = PROD_UNKNOWN;
+ UINTN Manu = MANU_UNKNOWN;
+
+ Status = mFwProtocol->GetModelRevision(&BoardRevision);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "Failed to get board model: %r\n",
+ Status));
+ } else {
+ Prod = X(BoardRevision, 4, 11);
+ }
+
+ if (Prod > PROD_KNOWN) {
+ Prod = PROD_UNKNOWN;
+ }
+ Prod -= PROD_BASE;
+ AsciiSPrint(mSysInfoProductName,
+ sizeof(mSysInfoProductName),
+ "64-bit Raspberry Pi %a (rev. %x)",
+ ProductNames[Prod], BoardRevision);
+
+ Manu = X(BoardRevision, 16, 19);
+ if (Manu > MANU_KNOWN) {
+ Manu = MANU_UNKNOWN;
+ } else {
+ Manu += MANU_BASE;
+ }
+ AsciiSPrint(mSysInfoManufName,
+ sizeof(mSysInfoManufName),
+ "%a", ManufNames[Manu]);
+
+ I64ToHexString(mSysInfoSKU,
+ sizeof(mSysInfoSKU),
+ BoardRevision);
+
+ Status = mFwProtocol->GetSerial(&BoardSerial);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "Failed to get board serial: %r\n",
+ Status));
+ }
+
+ I64ToHexString(mSysInfoSerial,
+ sizeof(mSysInfoSerial),
+ BoardSerial);
+
+ DEBUG ((DEBUG_ERROR, "Board Serial Number: %a\n", mSysInfoSerial));
+
+ mSysInfoType1.Uuid.Data1= *(UINT32 *)"RPi3";
+ mSysInfoType1.Uuid.Data2=0x0;
+ mSysInfoType1.Uuid.Data3=0x0;
+ CopyMem(mSysInfoType1.Uuid.Data4,
+ &BoardSerial, sizeof(BoardSerial));
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mSysInfoType1, mSysInfoType1Strings, NULL);
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE2 Board Information
+************************************************************************/
+VOID
+BoardInfoUpdateSmbiosType2 (
+ VOID
+ )
+{
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mBoardInfoType2, mBoardInfoType2Strings, NULL);
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE3 Enclosure Information
+************************************************************************/
+VOID
+EnclosureInfoUpdateSmbiosType3 (
+ VOID
+ )
+{
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mEnclosureInfoType3, mEnclosureInfoType3Strings, NULL);
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE4 Processor Information
+************************************************************************/
+VOID
+ProcessorInfoUpdateSmbiosType4 (
+ IN UINTN MaxCpus
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Rate;
+
+ mProcessorInfoType4.CoreCount = (UINT8) MaxCpus;
+ mProcessorInfoType4.EnabledCoreCount = (UINT8) MaxCpus;
+ mProcessorInfoType4.ThreadCount = (UINT8) MaxCpus;
+
+ Status = mFwProtocol->GetMaxClockRate(RPI_FW_CLOCK_RATE_ARM, &Rate);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Couldn't get the max CPU speed: %r\n", Status));
+ } else {
+ mProcessorInfoType4.MaxSpeed = Rate / 1000000;
+ DEBUG ((DEBUG_INFO, "Max CPU speed: %uHz\n", Rate));
+ }
+
+ Status = mFwProtocol->GetClockRate(RPI_FW_CLOCK_RATE_ARM, &Rate);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Couldn't get the current CPU speed: %r\n", Status));
+ } else {
+ mProcessorInfoType4.CurrentSpeed = Rate / 1000000;
+ DEBUG ((DEBUG_INFO, "Current CPU speed: %uHz\n", Rate));
+ }
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mProcessorInfoType4, mProcessorInfoType4Strings, NULL);
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE7 Cache Information
+************************************************************************/
+VOID
+CacheInfoUpdateSmbiosType7 (
+ VOID
+ )
+{
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mCacheInfoType7, mCacheInfoType7Strings, NULL);
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE9 System Slot Information
+************************************************************************/
+VOID
+SysSlotInfoUpdateSmbiosType9 (
+ VOID
+ )
+{
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mSysSlotInfoType9, mSysSlotInfoType9Strings, NULL);
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE16 Physical Memory Array Information
+************************************************************************/
+VOID
+PhyMemArrayInfoUpdateSmbiosType16 (
+ VOID
+ )
+{
+ EFI_SMBIOS_HANDLE MemArraySmbiosHande;
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mPhyMemArrayInfoType16, mPhyMemArrayInfoType16Strings, &MemArraySmbiosHande);
+
+ //
+ // Update the memory device information
+ //
+ mMemDevInfoType17.MemoryArrayHandle = MemArraySmbiosHande;
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE17 Memory Device Information
+************************************************************************/
+VOID
+MemDevInfoUpdateSmbiosType17 (
+ VOID
+ )
+{
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mMemDevInfoType17, mMemDevInfoType17Strings, NULL);
+}
+
+/***********************************************************************
+ SMBIOS data update TYPE19 Memory Array Map Information
+************************************************************************/
+VOID
+MemArrMapInfoUpdateSmbiosType19 (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Base;
+ UINT32 Size;
+
+ Status = mFwProtocol->GetArmMem(&Base, &Size);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Couldn't get the ARM memory size: %r\n", Status));
+ } else {
+ mMemArrMapInfoType19.StartingAddress = Base / 1024;
+ mMemArrMapInfoType19.EndingAddress = (Base + Size - 1) / 1024;
+ }
+
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mMemArrMapInfoType19, mMemArrMapInfoType19Strings, NULL);
+}
+
+
+/***********************************************************************
+ SMBIOS data update TYPE32 Boot Information
+************************************************************************/
+VOID
+BootInfoUpdateSmbiosType32 (
+ VOID
+ )
+{
+ LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mBootInfoType32, mBootInfoType32Strings, NULL);
+}
+
+/***********************************************************************
+ Driver Entry
+************************************************************************/
+EFI_STATUS
+EFIAPI
+PlatformSmbiosDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid, NULL,
+ (VOID **)&mFwProtocol);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BIOSInfoUpdateSmbiosType0();
+
+ SysInfoUpdateSmbiosType1();
+
+ BoardInfoUpdateSmbiosType2();
+
+ EnclosureInfoUpdateSmbiosType3();
+
+ ProcessorInfoUpdateSmbiosType4 (4); //One example for creating and updating
+
+ CacheInfoUpdateSmbiosType7();
+
+ SysSlotInfoUpdateSmbiosType9();
+
+ PhyMemArrayInfoUpdateSmbiosType16();
+
+ MemDevInfoUpdateSmbiosType17();
+
+ MemArrMapInfoUpdateSmbiosType19();
+
+ BootInfoUpdateSmbiosType32();
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf
new file mode 100644
index 000000000000..ada4c3fc228d
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf
@@ -0,0 +1,56 @@
+#/** @file
+#
+# SMBIOS Table for ARM platform
+#
+# Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Copyright (c) 2013 Linaro.org
+#
+# 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 = 0x00010005
+ BASE_NAME = PlatformSmbiosDxe
+ FILE_GUID = BAD0554E-22E9-4D83-9AFD-CC87727A1A45
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PlatformSmbiosDriverEntryPoint
+
+[Sources]
+ PlatformSmbiosDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ ArmPkg/ArmPkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PrintLib
+
+[Protocols]
+ gEfiSmbiosProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+ gRaspberryPiFirmwareProtocolGuid ## CONSUMES
+[Guids]
+
+[Depex]
+ gEfiSmbiosProtocolGuid AND gRaspberryPiFirmwareProtocolGuid
+
+[Pcd]
+ gArmTokenSpaceGuid.PcdSystemMemorySize
diff --git a/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.c b/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.c
new file mode 100644
index 000000000000..f2b0117629fd
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.c
@@ -0,0 +1,370 @@
+/** @file
+ *
+ * Copyright (c) 2017, Andrey 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/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <libfdt.h>
+
+#include <Protocol/RaspberryPiFirmware.h>
+
+#include <Guid/Fdt.h>
+
+STATIC VOID *mFdtImage;
+
+STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol;
+
+STATIC
+VOID
+UpdateMacAddress (
+ VOID
+ )
+{
+ INTN Node;
+ INTN Retval;
+ EFI_STATUS Status;
+ UINT8 MacAddress[6];
+
+ //
+ // Locate the node that the 'ethernet' alias refers to
+ //
+ Node = fdt_path_offset(mFdtImage, "ethernet");
+ if (Node < 0) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to locate 'ethernet' alias\n",
+ __FUNCTION__));
+ return;
+ }
+
+ //
+ // Get the MAC address from the firmware
+ //
+ Status = mFwProtocol->GetMacAddress (MacAddress);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to retrieve MAC address\n", __FUNCTION__));
+ return;
+ }
+
+ Retval = fdt_setprop (mFdtImage, Node, "mac-address", MacAddress,
+ sizeof MacAddress);
+ if (Retval != 0) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to create 'mac-address' property (%d)\n",
+ __FUNCTION__, Retval));
+ return;
+ }
+
+ DEBUG ((DEBUG_INFO,
+ "%a: setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n",
+ __FUNCTION__, MacAddress[0], MacAddress[1], MacAddress[2], MacAddress[3],
+ MacAddress[4], MacAddress[5]));
+}
+
+STATIC
+VOID
+CleanMemoryNodes (
+ VOID
+ )
+{
+ INTN Node;
+ INT32 Retval;
+
+ Node = fdt_path_offset(mFdtImage, "/memory");
+ if (Node < 0) {
+ return;
+ }
+
+ /*
+ * Remove bogus memory nodes which can make the booted
+ * OS go crazy and ignore the UEFI map.
+ */
+ DEBUG ((DEBUG_INFO, "Removing bogus /memory\n"));
+ Retval = fdt_del_node(mFdtImage, Node);
+ if (Retval != 0) {
+ DEBUG ((DEBUG_ERROR, "Failed to remove /memory\n"));
+ }
+}
+
+STATIC
+VOID
+SanitizePSCI (
+ VOID
+ )
+{
+ INTN Node;
+ INTN Root;
+ INT32 Retval;
+
+ Root = fdt_path_offset(mFdtImage, "/");
+ ASSERT (Root >= 0);
+ if (Root < 0) {
+ return;
+ }
+
+ Node = fdt_path_offset(mFdtImage, "/psci");
+ if (Node < 0) {
+ Node = fdt_add_subnode(mFdtImage, Root, "psci");
+ }
+
+ ASSERT (Node >= 0);
+ if (Node < 0) {
+ DEBUG ((DEBUG_ERROR, "Couldn't find/create /psci\n"));
+ return;
+ }
+
+ Retval = fdt_setprop_string(mFdtImage, Node, "compatible",
+ "arm,psci-1.0");
+ if (Retval != 0) {
+ DEBUG ((DEBUG_ERROR, "Couldn't set /psci compatible property\n"));
+ return;
+ }
+
+ Retval = fdt_setprop_string(mFdtImage, Node, "method", "smc");
+ if (Retval != 0) {
+ DEBUG ((DEBUG_ERROR, "Couldn't set /psci method property\n"));
+ return;
+ }
+
+ Root = fdt_path_offset(mFdtImage, "/cpus");
+ if (Root < 0) {
+ DEBUG ((DEBUG_ERROR, "No CPUs to update with PSCI enable-method?\n"));
+ return;
+ }
+
+ Node = fdt_first_subnode(mFdtImage, Root);
+ while (Node >= 0) {
+ if (fdt_setprop_string(mFdtImage, Node, "enable-method", "psci") != 0) {
+ DEBUG ((DEBUG_ERROR, "Failed to update enable-method for a CPU\n"));
+ return;
+ }
+
+ fdt_delprop(mFdtImage, Node, "cpu-release-addr");
+ Node = fdt_next_subnode(mFdtImage, Node);
+ }
+}
+
+STATIC
+VOID
+CleanSimpleFramebuffer (
+ VOID
+ )
+{
+ INTN Node;
+ INT32 Retval;
+
+ /*
+ * Should look for nodes by kind and remove aliases
+ * by matching against device.
+ */
+ Node = fdt_path_offset(mFdtImage, "display0");
+ if (Node < 0) {
+ return;
+ }
+
+ /*
+ * Remove bogus GPU-injected simple-framebuffer, which
+ * doesn't reflect the framebuffer built by UEFI.
+ */
+ DEBUG ((DEBUG_INFO, "Removing bogus display0\n"));
+ Retval = fdt_del_node(mFdtImage, Node);
+ if (Retval != 0) {
+ DEBUG ((DEBUG_ERROR, "Failed to remove display0\n"));
+ return;
+ }
+
+ Node = fdt_path_offset(mFdtImage, "/aliases");
+ if (Node < 0) {
+ DEBUG ((DEBUG_ERROR, "Couldn't find /aliases to remove display0\n"));
+ return;
+ }
+
+ Retval = fdt_delprop(mFdtImage, Node, "display0");
+ if (Retval != 0) {
+ DEBUG ((DEBUG_ERROR, "Failed to remove display0 alias\n"));
+ }
+}
+
+#define MAX_CMDLINE_SIZE 512
+
+STATIC
+VOID
+UpdateBootArgs (
+ VOID
+ )
+{
+ INTN Node;
+ INTN Retval;
+ EFI_STATUS Status;
+ CHAR8 *CommandLine;
+
+ //
+ // Locate the /chosen node
+ //
+ Node = fdt_path_offset(mFdtImage, "/chosen");
+ if (Node < 0) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to locate /chosen node\n",
+ __FUNCTION__));
+ return;
+ }
+
+ //
+ // If /chosen/bootargs already exists, we want to add a space character
+ // before adding the firmware supplied arguments. However, the RpiFirmware
+ // protocol expects a 32-bit aligned buffer. So let's allocate 4 bytes of
+ // slack, and skip the first 3 when passing this buffer into libfdt.
+ //
+ CommandLine = AllocatePool (MAX_CMDLINE_SIZE) + 4;
+ if (!CommandLine) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to allocate memory\n", __FUNCTION__));
+ return;
+ }
+
+ //
+ // Get the command line from the firmware
+ //
+ Status = mFwProtocol->GetCommandLine (MAX_CMDLINE_SIZE, CommandLine + 4);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to retrieve command line\n",
+ __FUNCTION__));
+ return;
+ }
+
+ if (AsciiStrLen (CommandLine + 4) == 0) {
+ DEBUG ((DEBUG_INFO, "%a: empty command line received\n", __FUNCTION__));
+ return;
+ }
+
+ CommandLine[3] = ' ';
+
+ Retval = fdt_appendprop_string (mFdtImage, Node, "bootargs", &CommandLine[3]);
+ if (Retval != 0) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to set /chosen/bootargs property (%d)\n",
+ __FUNCTION__, Retval));
+ }
+
+ DEBUG_CODE_BEGIN ();
+ CONST CHAR8 *Prop;
+ INT32 Length;
+ INT32 Index;
+
+ Node = fdt_path_offset (mFdtImage, "/chosen");
+ ASSERT (Node >= 0);
+
+ Prop = fdt_getprop (mFdtImage, Node, "bootargs", &Length);
+ ASSERT (Prop != NULL);
+
+ DEBUG ((DEBUG_INFO, "Command line set from firmware (length %d):\n'", Length));
+
+ for (Index = 0; Index < Length; Index++, Prop++) {
+ if (*Prop == '\0') {
+ continue;
+ }
+ DEBUG ((DEBUG_INFO, "%c", *Prop));
+ }
+
+ DEBUG ((DEBUG_INFO, "'\n"));
+ DEBUG_CODE_END ();
+
+ FreePool (CommandLine - 4);
+}
+
+
+/**
+ @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
+EFIAPI
+RpiFdtDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ VOID *FdtImage;
+ UINTN FdtSize;
+ INT32 Retval;
+ BOOLEAN Internal;
+
+ Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid, NULL,
+ (VOID **)&mFwProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ Internal = FALSE;
+ FdtImage = (VOID *) (UINTN) PcdGet32(PcdFdtBaseAddress);
+ Retval = fdt_check_header (FdtImage);
+ if (Retval == 0) {
+ /*
+ * Have FDT passed via config.txt.
+ */
+ FdtSize = fdt_totalsize (FdtImage);
+ DEBUG ((DEBUG_INFO, "DTB passed via config.txt of 0x%lx bytes\n", FdtSize));
+ Status = EFI_SUCCESS;
+ } else {
+ Internal = TRUE;
+ DEBUG ((DEBUG_INFO, "No/bad FDT at %p (%a), trying internal DTB...\n",
+ FdtImage, fdt_strerror (Retval)));
+ Status = GetSectionFromAnyFv (&gRaspberryPiFdtFileGuid, EFI_SECTION_RAW, 0,
+ &FdtImage, &FdtSize);
+ if (Status == EFI_SUCCESS) {
+ if (fdt_check_header (FdtImage) != 0) {
+ Status = EFI_INCOMPATIBLE_VERSION;
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to locate device tree: %r\n", Status));
+ return Status;
+ }
+
+ /*
+ * Probably overkill.
+ */
+ FdtSize += EFI_PAGE_SIZE * 2;
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES(FdtSize),
+ (EFI_PHYSICAL_ADDRESS *) &mFdtImage);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to allocate new device tree: %r\n", Status));
+ return Status;
+ }
+
+ Retval = fdt_open_into (FdtImage, mFdtImage, FdtSize);
+ ASSERT (Retval == 0);
+
+ SanitizePSCI ();
+ CleanMemoryNodes ();
+ CleanSimpleFramebuffer ();
+ UpdateMacAddress ();
+ if (Internal) {
+ /*
+ * A GPU-provided DTB already has the full command line.
+ */
+ UpdateBootArgs ();
+ }
+
+ DEBUG ((DEBUG_INFO, "Installed FDT is at %p\n", mFdtImage));
+ Status = gBS->InstallConfigurationTable (&gFdtTableGuid, mFdtImage);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.inf
new file mode 100644
index 000000000000..a79e9ddcdc8a
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.inf
@@ -0,0 +1,53 @@
+#/** @file
+#
+# Copyright (c) 2017, 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 = 0x00010019
+ BASE_NAME = RpiFdtDxe
+ FILE_GUID = 8505280f-109e-437e-9fe4-1aa09c7074d9
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = RpiFdtDxeInitialize
+
+[Sources]
+ RpiFdtDxe.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ DxeServicesLib
+ FdtLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Guids]
+ gFdtTableGuid
+ gRaspberryPiFdtFileGuid
+
+[Protocols]
+ gRaspberryPiFirmwareProtocolGuid ## CONSUMES
+
+[Depex]
+ gRaspberryPiFirmwareProtocolGuid
+
+[FixedPcd]
+ gRaspberryPiTokenSpaceGuid.PcdFdtBaseAddress
diff --git a/Platform/Broadcom/Bcm283x/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c b/Platform/Broadcom/Bcm283x/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c
new file mode 100644
index 000000000000..50f3ed3f1e36
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c
@@ -0,0 +1,1085 @@
+/** @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/RpiFirmware.h>
+
+#include <Protocol/RaspberryPiFirmware.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_FW_SET_POWER_STATE;
+ Cmd->TagHead.TagSize = sizeof Cmd->TagBody;
+ Cmd->TagHead.TagValueSize = 0;
+ Cmd->TagBody.DeviceId = DeviceId;
+ Cmd->TagBody.PowerState = (PowerState ? RPI_FW_POWER_STATE_ENABLE : 0) |
+ (Wait ? RPI_FW_POWER_STATE_WAIT : 0);
+ Cmd->EndTag = 0;
+
+ Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_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_FW_GET_ARM_MEMSIZE;
+ Cmd->TagHead.TagSize = sizeof Cmd->TagBody;
+ Cmd->TagHead.TagValueSize = 0;
+ Cmd->EndTag = 0;
+
+ Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_GET_MAC_ADDRESS;
+ Cmd->TagHead.TagSize = sizeof Cmd->TagBody;
+ Cmd->TagHead.TagValueSize = 0;
+ Cmd->EndTag = 0;
+
+ Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_GET_BOARD_SERIAL;
+ Cmd->TagHead.TagSize = sizeof Cmd->TagBody;
+ Cmd->TagHead.TagValueSize = 0;
+ Cmd->EndTag = 0;
+
+ Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_GET_BOARD_MODEL;
+ Cmd->TagHead.TagSize = sizeof Cmd->TagBody;
+ Cmd->TagHead.TagValueSize = 0;
+ Cmd->EndTag = 0;
+
+ Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_GET_BOARD_REVISION;
+ Cmd->TagHead.TagSize = sizeof Cmd->TagBody;
+ Cmd->TagHead.TagValueSize = 0;
+ Cmd->EndTag = 0;
+
+ Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_GET_FB_GEOMETRY;
+ Cmd->TagHead.TagSize = sizeof Cmd->TagBody;
+ Cmd->TagHead.TagValueSize = 0;
+ Cmd->EndTag = 0;
+
+ Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_FREE_FB;
+ Cmd->FreeFbTag.TagSize = 0;
+ Cmd->FreeFbTag.TagValueSize = 0;
+ Cmd->EndTag = 0;
+
+ Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_FW_MBOX_CHANNEL, &Result);
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_SET_FB_PGEOM;
+ Cmd->PhysSizeTag.TagSize = sizeof Cmd->PhysSize;
+ Cmd->PhysSize.Width = Width;
+ Cmd->PhysSize.Height = Height;
+ Cmd->VirtSizeTag.TagId = RPI_FW_SET_FB_VGEOM;
+ Cmd->VirtSizeTag.TagSize = sizeof Cmd->VirtSize;
+ Cmd->VirtSize.Width = Width;
+ Cmd->VirtSize.Height = Height;
+ Cmd->DepthTag.TagId = RPI_FW_SET_FB_DEPTH;
+ Cmd->DepthTag.TagSize = sizeof Cmd->Depth;
+ Cmd->Depth.Depth = Depth;
+ Cmd->AllocFbTag.TagId = RPI_FW_ALLOC_FB;
+ Cmd->AllocFbTag.TagSize = sizeof Cmd->AllocFb;
+ Cmd->AllocFb.AlignmentBase = 32;
+ Cmd->PitchTag.TagId = RPI_FW_GET_FB_LINELENGTH;
+ Cmd->PitchTag.TagSize = sizeof Cmd->Pitch;
+ Cmd->EndTag = 0;
+
+ Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_GET_COMMAND_LINE;
+ Cmd->TagHead.TagSize = BufferSize;
+ Cmd->TagHead.TagValueSize = 0;
+
+ Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_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_FW_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_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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_FW_GET_CLOCK_RATE, ClockRate);
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetMaxClockRate (
+ IN UINT32 ClockId,
+ OUT UINT32 *ClockRate
+ )
+{
+ return RpiFirmwareGetClockRate(ClockId, RPI_FW_GET_MAX_CLOCK_RATE, ClockRate);
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareGetMinClockRate (
+ IN UINT32 ClockId,
+ OUT UINT32 *ClockRate
+ )
+{
+ return RpiFirmwareGetClockRate(ClockId, RPI_FW_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
+RpiFirmwareLedSet (
+ 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_FW_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_FW_MBOX_CHANNEL, &Result);
+
+ ReleaseSpinLock (&mMailboxLock);
+
+ if (EFI_ERROR (Status) ||
+ Cmd->BufferHead.Response != RPI_FW_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,
+ RpiFirmwareLedSet,
+ 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/Broadcom/Bcm283x/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.inf
new file mode 100644
index 000000000000..2ab57bbf54f0
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/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 = 0x00010019
+ 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/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ ArmLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DmaLib
+ IoLib
+ SynchronizationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gRaspberryPiFirmwareProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
diff --git a/Platform/Broadcom/Bcm283x/Drivers/SdHostDxe/SdHostDxe.c b/Platform/Broadcom/Bcm283x/Drivers/SdHostDxe/SdHostDxe.c
new file mode 100644
index 000000000000..7dd76098c8a1
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/SdHostDxe/SdHostDxe.c
@@ -0,0 +1,830 @@
+/** @file
+ *
+ * Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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 <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DmaLib.h>
+#include <Library/TimerLib.h>
+
+#include <Protocol/EmbeddedExternalDevice.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PiMmcHost.h>
+#include <Protocol/RaspberryPiFirmware.h>
+
+#include <IndustryStandard/Bcm2836.h>
+#include <IndustryStandard/RpiFirmware.h>
+#include <IndustryStandard/Bcm2836SdHost.h>
+
+#define SDHOST_BLOCK_BYTE_LENGTH 512
+
+// Driver Timing Parameters
+#define CMD_STALL_AFTER_POLL_US 1
+#define CMD_MIN_POLL_TOTAL_TIME_US 100000 // 100ms
+#define CMD_MAX_POLL_COUNT (CMD_MIN_POLL_TOTAL_TIME_US / CMD_STALL_AFTER_POLL_US)
+#define CMD_MAX_RETRY_COUNT 3
+#define CMD_STALL_AFTER_RETRY_US 20 // 20us
+#define FIFO_MAX_POLL_COUNT 1000000
+#define STALL_TO_STABILIZE_US 10000 // 10ms
+
+#define IDENT_MODE_SD_CLOCK_FREQ_HZ 400000 // 400KHz
+
+// Macros adopted from MmcDxe internal header
+#define SDHOST_R0_READY_FOR_DATA BIT8
+#define SDHOST_R0_CURRENTSTATE(Response) ((Response >> 9) & 0xF)
+
+#define DEBUG_MMCHOST_SD DEBUG_VERBOSE
+#define DEBUG_MMCHOST_SD_INFO DEBUG_INFO
+#define DEBUG_MMCHOST_SD_ERROR DEBUG_ERROR
+
+STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol;
+
+// Per Physical Layer Simplified Specs
+#ifndef NDEBUG
+STATIC CONST CHAR8* mStrSdState[] = { "idle", "ready", "ident", "stby",
+ "tran", "data", "rcv", "prg", "dis",
+ "ina" };
+STATIC CONST CHAR8 *mFsmState[] = { "identmode", "datamode", "readdata",
+ "writedata", "readwait", "readcrc",
+ "writecrc", "writewait1", "powerdown",
+ "powerup", "writestart1", "writestart2",
+ "genpulses", "writewait2", "?",
+ "startpowdown" };
+#endif /* NDEBUG */
+STATIC UINT32 mLastGoodCmd = MMC_GET_INDX(MMC_CMD0);
+
+STATIC inline BOOLEAN
+IsAppCmd(
+ VOID
+ )
+{
+ return mLastGoodCmd == MMC_CMD55;
+}
+
+STATIC BOOLEAN
+IsBusyCmd(
+ IN UINT32 MmcCmd
+ )
+{
+ if (IsAppCmd()) {
+ return FALSE;
+ }
+
+ return MmcCmd == MMC_CMD7 || MmcCmd == MMC_CMD12;
+}
+
+STATIC BOOLEAN
+IsWriteCmd(
+ IN UINT32 MmcCmd
+ )
+{
+ if (IsAppCmd()) {
+ return FALSE;
+ }
+
+ return MmcCmd == MMC_CMD24 || MmcCmd == MMC_CMD25;
+}
+
+STATIC BOOLEAN
+IsReadCmd(
+ IN UINT32 MmcCmd,
+ IN UINT32 Argument
+ )
+{
+ if (MmcCmd == MMC_CMD8 && !IsAppCmd()) {
+ if (Argument == CMD8_MMC_ARG) {
+ DEBUG((DEBUG_MMCHOST_SD, "Sending MMC CMD8 variant\n"));
+ return TRUE;
+ } else {
+ ASSERT (Argument == CMD8_SD_ARG);
+ DEBUG((DEBUG_MMCHOST_SD, "Sending SD CMD8 variant\n"));
+ return FALSE;
+ }
+ }
+
+ return
+ (MmcCmd == MMC_CMD6 && !IsAppCmd()) ||
+ (MmcCmd == MMC_CMD17 && !IsAppCmd()) ||
+ (MmcCmd == MMC_CMD18 && !IsAppCmd()) ||
+ (MmcCmd == MMC_CMD13 && IsAppCmd()) ||
+ (MmcCmd == MMC_ACMD22 && IsAppCmd()) ||
+ (MmcCmd == MMC_ACMD51 && IsAppCmd());
+}
+
+STATIC VOID
+SdHostDumpRegisters(
+ VOID
+ )
+{
+ DEBUG((DEBUG_MMCHOST_SD, "SdHost: Registers Dump:\n"));
+ DEBUG((DEBUG_MMCHOST_SD, " CMD: 0x%8.8X\n", MmioRead32(SDHOST_CMD)));
+ DEBUG((DEBUG_MMCHOST_SD, " ARG: 0x%8.8X\n", MmioRead32(SDHOST_ARG)));
+ DEBUG((DEBUG_MMCHOST_SD, " TOUT: 0x%8.8X\n", MmioRead32(SDHOST_TOUT)));
+ DEBUG((DEBUG_MMCHOST_SD, " CDIV: 0x%8.8X\n", MmioRead32(SDHOST_CDIV)));
+ DEBUG((DEBUG_MMCHOST_SD, " RSP0: 0x%8.8X\n", MmioRead32(SDHOST_RSP0)));
+ DEBUG((DEBUG_MMCHOST_SD, " RSP1: 0x%8.8X\n", MmioRead32(SDHOST_RSP1)));
+ DEBUG((DEBUG_MMCHOST_SD, " RSP2: 0x%8.8X\n", MmioRead32(SDHOST_RSP2)));
+ DEBUG((DEBUG_MMCHOST_SD, " RSP3: 0x%8.8X\n", MmioRead32(SDHOST_RSP3)));
+ DEBUG((DEBUG_MMCHOST_SD, " HSTS: 0x%8.8X\n", MmioRead32(SDHOST_HSTS)));
+ DEBUG((DEBUG_MMCHOST_SD, " VDD: 0x%8.8X\n", MmioRead32(SDHOST_VDD)));
+ DEBUG((DEBUG_MMCHOST_SD, " EDM: 0x%8.8X\n", MmioRead32(SDHOST_EDM)));
+ DEBUG((DEBUG_MMCHOST_SD, " HCFG: 0x%8.8X\n", MmioRead32(SDHOST_HCFG)));
+ DEBUG((DEBUG_MMCHOST_SD, " HBCT: 0x%8.8X\n", MmioRead32(SDHOST_HBCT)));
+ DEBUG((DEBUG_MMCHOST_SD, " HBLC: 0x%8.8X\n\n", MmioRead32(SDHOST_HBLC)));
+}
+
+#ifndef NDEBUG
+STATIC EFI_STATUS
+SdHostGetSdStatus(
+ UINT32* SdStatus
+ )
+{
+ ASSERT(SdStatus != NULL);
+
+ // On command completion with R1 or R1b response type
+ // the SDCard status will be in RSP0
+ UINT32 Rsp0 = MmioRead32(SDHOST_RSP0);
+ if (Rsp0 != 0xFFFFFFFF) {
+ *SdStatus = Rsp0;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NO_RESPONSE;
+}
+#endif /* NDEBUG */
+
+STATIC VOID
+SdHostDumpSdCardStatus(
+ VOID
+ )
+{
+#ifndef NDEBUG
+ UINT32 SdCardStatus;
+ EFI_STATUS Status = SdHostGetSdStatus(&SdCardStatus);
+ if (!EFI_ERROR(Status)) {
+ UINT32 CurrState = SDHOST_R0_CURRENTSTATE(SdCardStatus);
+ DEBUG((
+ DEBUG_MMCHOST_SD,
+ "SdHost: SdCardStatus 0x%8.8X: ReadyForData?%d, State[%d]: %a\n",
+ SdCardStatus,
+ ((SdCardStatus & SDHOST_R0_READY_FOR_DATA) ? 1 : 0),
+ CurrState,
+ ((CurrState < (sizeof(mStrSdState) / sizeof(*mStrSdState))) ?
+ mStrSdState[CurrState] : "UNDEF")));
+ }
+#endif /* NDEBUG */
+}
+
+STATIC VOID
+SdHostDumpStatus(
+ VOID
+ )
+{
+ SdHostDumpRegisters();
+
+#ifndef NDEBUG
+ UINT32 Hsts = MmioRead32(SDHOST_HSTS);
+
+ if (Hsts & SDHOST_HSTS_ERROR) {
+ DEBUG((DEBUG_MMCHOST_SD_ERROR,
+ "SdHost: Diagnose HSTS: 0x%8.8X\n", Hsts));
+
+ DEBUG((DEBUG_MMCHOST_SD_ERROR, "SdHost: Last Good CMD = %u\n",
+ MMC_GET_INDX(mLastGoodCmd)));
+ if (Hsts & SDHOST_HSTS_FIFO_ERROR)
+ DEBUG((DEBUG_MMCHOST_SD_ERROR, " - Fifo Error\n"));
+ if (Hsts & SDHOST_HSTS_CRC7_ERROR)
+ DEBUG((DEBUG_MMCHOST_SD_ERROR, " - CRC7 Error\n"));
+ if (Hsts & SDHOST_HSTS_CRC16_ERROR)
+ DEBUG((DEBUG_MMCHOST_SD_ERROR, " - CRC16 Error\n"));
+ if (Hsts & SDHOST_HSTS_CMD_TIME_OUT)
+ DEBUG((DEBUG_MMCHOST_SD_ERROR, " - CMD Timeout (TOUT %x)\n",
+ MmioRead32(SDHOST_TOUT)));
+ if (Hsts & SDHOST_HSTS_REW_TIME_OUT)
+ DEBUG((DEBUG_MMCHOST_SD_ERROR, " - Read/Erase/Write Transfer Timeout\n"));
+ }
+
+ UINT32 Edm = MmioRead32(SDHOST_EDM);
+ DEBUG(((Hsts & SDHOST_HSTS_ERROR) ?
+ DEBUG_MMCHOST_SD_ERROR : DEBUG_MMCHOST_SD,
+ "SdHost: Diagnose EDM: 0x%8.8X\n", Edm));
+ DEBUG(((Hsts & SDHOST_HSTS_ERROR) ?
+ DEBUG_MMCHOST_SD_ERROR : DEBUG_MMCHOST_SD,
+ " - FSM: 0x%x (%a)\n", (Edm & 0xF), mFsmState[Edm & 0xF]));
+ DEBUG(((Hsts & SDHOST_HSTS_ERROR) ?
+ DEBUG_MMCHOST_SD_ERROR : DEBUG_MMCHOST_SD,
+ " - Fifo Count: %d\n", ((Edm >> 4) & 0x1F)));
+ DEBUG(((Hsts & SDHOST_HSTS_ERROR) ?
+ DEBUG_MMCHOST_SD_ERROR : DEBUG_MMCHOST_SD,
+ " - Fifo Write Threshold: %d\n",
+ ((Edm >> SDHOST_EDM_WRITE_THRESHOLD_SHIFT) &
+ SDHOST_EDM_THRESHOLD_MASK)));
+ DEBUG(((Hsts & SDHOST_HSTS_ERROR) ?
+ DEBUG_MMCHOST_SD_ERROR : DEBUG_MMCHOST_SD,
+ " - Fifo Read Threshold: %d\n",
+ ((Edm >> SDHOST_EDM_READ_THRESHOLD_SHIFT) & SDHOST_EDM_THRESHOLD_MASK)));
+#endif
+
+ SdHostDumpSdCardStatus();
+}
+
+STATIC EFI_STATUS
+SdHostSetClockFrequency(
+ IN UINTN TargetSdFreqHz
+ )
+{
+ EFI_STATUS Status;
+ UINT32 CoreClockFreqHz = 0;
+
+ // First figure out the core clock
+ Status = mFwProtocol->GetClockRate(RPI_FW_CLOCK_RATE_CORE, &CoreClockFreqHz);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ ASSERT (CoreClockFreqHz != 0);
+
+ // fSDCLK = fcore_pclk/(ClockDiv+2)
+ UINT32 ClockDiv = (CoreClockFreqHz - (2 * TargetSdFreqHz)) / TargetSdFreqHz;
+ UINT32 ActualSdFreqHz = CoreClockFreqHz / (ClockDiv + 2);
+
+ DEBUG((
+ DEBUG_MMCHOST_SD_INFO,
+ "SdHost: CoreClock=%dHz, CDIV=%d, Requested SdClock=%dHz, Actual SdClock=%dHz\n",
+ CoreClockFreqHz,
+ ClockDiv,
+ TargetSdFreqHz,
+ ActualSdFreqHz));
+
+ MmioWrite32(SDHOST_CDIV, ClockDiv);
+ // Set timeout after 1 second, i.e ActualSdFreqHz SD clock cycles
+ MmioWrite32(SDHOST_TOUT, ActualSdFreqHz);
+
+ gBS->Stall(STALL_TO_STABILIZE_US);
+
+ return Status;
+}
+
+STATIC BOOLEAN
+SdIsCardPresent(
+ IN EFI_MMC_HOST_PROTOCOL *This
+ )
+{
+ return TRUE;
+}
+
+STATIC BOOLEAN
+SdIsReadOnly(
+ IN EFI_MMC_HOST_PROTOCOL *This
+ )
+{
+ return FALSE;
+}
+
+STATIC EFI_STATUS
+SdBuildDevicePath(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
+ EFI_GUID DevicePathGuid = EFI_CALLER_ID_GUID;
+
+ DEBUG((DEBUG_MMCHOST_SD, "SdHost: SdBuildDevicePath()\n"));
+
+ NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof(VENDOR_DEVICE_PATH));
+ CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &DevicePathGuid);
+ *DevicePath = NewDevicePathNode;
+
+ return EFI_SUCCESS;
+}
+
+STATIC EFI_STATUS
+SdSendCommand(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_CMD MmcCmd,
+ IN UINT32 Argument
+ )
+{
+ UINT32 Hsts;
+
+ //
+ // Fail fast, CMD5 (CMD_IO_SEND_OP_COND)
+ // is only valid for SDIO cards and thus
+ // expected to always fail.
+ //
+ if (MmcCmd == MMC_CMD5) {
+ DEBUG((
+ DEBUG_MMCHOST_SD,
+ "SdHost: SdSendCommand(CMD%d, Argument: %08x) ignored\n",
+ MMC_GET_INDX(MmcCmd),
+ Argument));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (MmioRead32(SDHOST_CMD) & SDHOST_CMD_NEW_FLAG) {
+ DEBUG((
+ DEBUG_MMCHOST_SD_ERROR,
+ "SdHost: SdSendCommand(): Failed to execute CMD%d, a CMD is already being executed.\n",
+ MMC_GET_INDX(MmcCmd)));
+ SdHostDumpStatus();
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Write command argument
+ MmioWrite32(SDHOST_ARG, Argument);
+
+ UINT32 SdCmd = 0;
+ {
+ // Set response type
+ if (MmcCmd & MMC_CMD_WAIT_RESPONSE) {
+ if (MmcCmd & MMC_CMD_LONG_RESPONSE) {
+ SdCmd |= SDHOST_CMD_RESPONSE_CMD_LONG_RESP;
+ }
+ } else {
+ SdCmd |= SDHOST_CMD_RESPONSE_CMD_NO_RESP;
+ }
+
+ if (IsBusyCmd(MmcCmd)) {
+ SdCmd |= SDHOST_CMD_BUSY_CMD;
+ }
+
+ if (IsReadCmd(MmcCmd, Argument)) {
+ SdCmd |= SDHOST_CMD_READ_CMD;
+ }
+
+ if (IsWriteCmd(MmcCmd)) {
+ SdCmd |= SDHOST_CMD_WRITE_CMD;
+ }
+
+ SdCmd |= MMC_GET_INDX(MmcCmd);
+ }
+
+ if (IsReadCmd(MmcCmd, Argument) || IsWriteCmd(MmcCmd)) {
+ if (IsAppCmd() && MmcCmd == MMC_ACMD22) {
+ MmioWrite32(SDHOST_HBCT, 0x4);
+ } else if (IsAppCmd() && MmcCmd == MMC_ACMD51) {
+ MmioWrite32(SDHOST_HBCT, 0x8);
+ } else if (!IsAppCmd() && MmcCmd == MMC_CMD6) {
+ MmioWrite32(SDHOST_HBCT, 0x40);
+ } else {
+ MmioWrite32(SDHOST_HBCT, SDHOST_BLOCK_BYTE_LENGTH);
+ }
+ }
+
+ DEBUG((
+ DEBUG_MMCHOST_SD,
+ "SdHost: SdSendCommand(CMD%d, Argument: %08x): BUSY=%d, RESP=%d, WRITE=%d, READ=%d\n",
+ MMC_GET_INDX(MmcCmd),
+ Argument,
+ ((SdCmd & SDHOST_CMD_BUSY_CMD) ? 1 : 0),
+ ((SdCmd & (SDHOST_CMD_RESPONSE_CMD_LONG_RESP | SDHOST_CMD_RESPONSE_CMD_NO_RESP)) >> 9),
+ ((SdCmd & SDHOST_CMD_WRITE_CMD) ? 1 : 0),
+ ((SdCmd & SDHOST_CMD_READ_CMD) ? 1 : 0)));
+
+ UINT32 PollCount = 0;
+ UINT32 RetryCount = 0;
+ BOOLEAN IsCmdExecuted = FALSE;
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ // Keep retrying the command until it succeeds.
+ while ((RetryCount < CMD_MAX_RETRY_COUNT) && !IsCmdExecuted) {
+ Status = EFI_SUCCESS;
+
+ // Clear prev cmd status
+ MmioWrite32(SDHOST_HSTS, SDHOST_HSTS_CLEAR);
+
+ if (IsReadCmd(MmcCmd, Argument) || IsWriteCmd(MmcCmd)) {
+ // Flush Fifo if this cmd will start a new transfer in case
+ // there is stale bytes in the Fifo
+ MmioOr32(SDHOST_EDM, SDHOST_EDM_FIFO_CLEAR);
+ }
+
+ if (MmioRead32(SDHOST_CMD) & SDHOST_CMD_NEW_FLAG) {
+ DEBUG((
+ DEBUG_MMCHOST_SD_ERROR,
+ "%a(%u): CMD%d is still being executed after %d trial(s)\n",
+ __FUNCTION__, __LINE__, MMC_GET_INDX(MmcCmd), RetryCount));
+ }
+
+ // Write command and set it to start execution
+ MmioWrite32(SDHOST_CMD, SDHOST_CMD_NEW_FLAG | SdCmd);
+
+ // Poll for the command status until it finishes execution
+ while (PollCount < CMD_MAX_POLL_COUNT) {
+ UINT32 CmdReg = MmioRead32(SDHOST_CMD);
+
+ // Read status of command response
+ if (CmdReg & SDHOST_CMD_FAIL_FLAG) {
+ Status = EFI_DEVICE_ERROR;
+ /*
+ * Must fall-through and wait for the command completion!
+ */
+ }
+
+ // Check if command is completed.
+ if (!(CmdReg & SDHOST_CMD_NEW_FLAG)) {
+ IsCmdExecuted = TRUE;
+ break;
+ }
+
+ ++PollCount;
+ gBS->Stall(CMD_STALL_AFTER_POLL_US);
+ }
+
+ if (!IsCmdExecuted) {
+ ++RetryCount;
+ gBS->Stall(CMD_STALL_AFTER_RETRY_US);
+ }
+ }
+
+ if (RetryCount == CMD_MAX_RETRY_COUNT) {
+ Status = EFI_TIMEOUT;
+ }
+
+ Hsts = MmioRead32(SDHOST_HSTS);
+ if (EFI_ERROR(Status) ||
+ (Hsts & SDHOST_HSTS_ERROR) != 0) {
+ if (MmcCmd == MMC_CMD1 &&
+ (Hsts & SDHOST_HSTS_CRC7_ERROR) != 0) {
+ /*
+ * SdHost seems to have no way to specify
+ * R3 as a transfer type.
+ */
+ IsCmdExecuted = TRUE;
+ Status = EFI_SUCCESS;
+ MmioWrite32(SDHOST_HSTS, SDHOST_HSTS_CLEAR);
+ } else if (MmcCmd == MMC_CMD7 && Argument == 0) {
+ /*
+ * Deselecting the SDCard with CMD7 and RCA=0x0
+ * always timeout on SDHost.
+ */
+ Status = EFI_SUCCESS;
+ } else {
+ DEBUG((
+ DEBUG_MMCHOST_SD_ERROR,
+ "%a(%u): CMD%d execution failed after %d trial(s)\n",
+ __FUNCTION__, __LINE__,
+ MMC_GET_INDX(MmcCmd),
+ RetryCount));
+ SdHostDumpStatus();
+ }
+
+ MmioWrite32(SDHOST_HSTS, SDHOST_HSTS_CLEAR);
+ }
+
+ if (IsCmdExecuted && !EFI_ERROR(Status)) {
+ ASSERT(!(MmioRead32(SDHOST_HSTS) & SDHOST_HSTS_ERROR));
+ mLastGoodCmd = MmcCmd;
+ }
+
+ return Status;
+}
+
+STATIC EFI_STATUS
+SdReceiveResponse(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_RESPONSE_TYPE Type,
+ IN UINT32* Buffer
+ )
+{
+ if (Buffer == NULL) {
+ DEBUG((DEBUG_MMCHOST_SD_ERROR,
+ "SdHost: SdReceiveResponse(): Input Buffer is NULL\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Type == MMC_RESPONSE_TYPE_R1) ||
+ (Type == MMC_RESPONSE_TYPE_R1b) ||
+ (Type == MMC_RESPONSE_TYPE_R3) ||
+ (Type == MMC_RESPONSE_TYPE_R6) ||
+ (Type == MMC_RESPONSE_TYPE_R7)) {
+ Buffer[0] = MmioRead32(SDHOST_RSP0);
+ DEBUG((
+ DEBUG_MMCHOST_SD,
+ "SdHost: SdReceiveResponse(Type: %x), Buffer[0]: %08x\n",
+ Type, Buffer[0]));
+
+ } else if (Type == MMC_RESPONSE_TYPE_R2) {
+ Buffer[0] = MmioRead32(SDHOST_RSP0);
+ Buffer[1] = MmioRead32(SDHOST_RSP1);
+ Buffer[2] = MmioRead32(SDHOST_RSP2);
+ Buffer[3] = MmioRead32(SDHOST_RSP3);
+
+ DEBUG((
+ DEBUG_MMCHOST_SD,
+ "SdHost: SdReceiveResponse(Type: %x), Buffer[0-3]: %08x, %08x, %08x, %08x\n",
+ Type, Buffer[0], Buffer[1], Buffer[2], Buffer[3]));
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC EFI_STATUS
+SdReadBlockData(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Length,
+ IN UINT32* Buffer
+ )
+{
+ DEBUG((
+ DEBUG_MMCHOST_SD,
+ "SdHost: SdReadBlockData(LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n",
+ (UINT32)Lba, Length, Buffer));
+
+ ASSERT(Buffer != NULL);
+ ASSERT(Length % 4 == 0);
+
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ mFwProtocol->SetLed(TRUE);
+ {
+ UINT32 NumWords = Length / 4;
+ UINT32 WordIdx;
+
+ for (WordIdx = 0; WordIdx < NumWords; ++WordIdx) {
+ UINT32 PollCount = 0;
+ while (PollCount < FIFO_MAX_POLL_COUNT) {
+ UINT32 Hsts = MmioRead32(SDHOST_HSTS);
+ if ((Hsts & SDHOST_HSTS_DATA_FLAG) != 0) {
+ MmioWrite32(SDHOST_HSTS, SDHOST_HSTS_DATA_FLAG);
+ Buffer[WordIdx] = MmioRead32(SDHOST_DATA);
+ break;
+ }
+
+ ++PollCount;
+ gBS->Stall(CMD_STALL_AFTER_RETRY_US);
+ }
+
+ if (PollCount == FIFO_MAX_POLL_COUNT) {
+ DEBUG(
+ (DEBUG_MMCHOST_SD_ERROR,
+ "SdHost: SdReadBlockData(): Block Word%d read poll timed-out\n",
+ WordIdx));
+ SdHostDumpStatus();
+ MmioWrite32(SDHOST_HSTS, SDHOST_HSTS_CLEAR);
+ Status = EFI_TIMEOUT;
+ break;
+ }
+ }
+ }
+ mFwProtocol->SetLed(FALSE);
+
+ return Status;
+}
+
+STATIC EFI_STATUS
+SdWriteBlockData(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Length,
+ IN UINT32* Buffer
+ )
+{
+ DEBUG((
+ DEBUG_MMCHOST_SD,
+ "SdHost: SdWriteBlockData(LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n",
+ (UINT32)Lba, Length, Buffer));
+
+ ASSERT(Buffer != NULL);
+ ASSERT(Length % SDHOST_BLOCK_BYTE_LENGTH == 0);
+
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ mFwProtocol->SetLed(TRUE);
+ {
+ UINT32 NumWords = Length / 4;
+ UINT32 WordIdx;
+
+ for (WordIdx = 0; WordIdx < NumWords; ++WordIdx) {
+ UINT32 PollCount = 0;
+ while (PollCount < FIFO_MAX_POLL_COUNT) {
+ if (MmioRead32(SDHOST_HSTS) & SDHOST_HSTS_DATA_FLAG) {
+ MmioWrite32(SDHOST_HSTS, SDHOST_HSTS_DATA_FLAG);
+ MmioWrite32(SDHOST_DATA, Buffer[WordIdx]);
+ break;
+ }
+
+ ++PollCount;
+ gBS->Stall(CMD_STALL_AFTER_RETRY_US);
+ }
+
+ if (PollCount == FIFO_MAX_POLL_COUNT) {
+ DEBUG((
+ DEBUG_MMCHOST_SD_ERROR,
+ "SdHost: SdWriteBlockData(): Block Word%d write poll timed-out\n",
+ WordIdx));
+ SdHostDumpStatus();
+ MmioWrite32(SDHOST_HSTS, SDHOST_HSTS_CLEAR);
+ Status = EFI_TIMEOUT;
+ break;
+ }
+ }
+ }
+ mFwProtocol->SetLed(FALSE);
+
+ return Status;
+}
+
+STATIC EFI_STATUS
+SdSetIos (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN UINT32 BusClockFreq,
+ IN UINT32 BusWidth,
+ IN UINT32 TimingMode
+ )
+{
+ if (BusWidth != 0) {
+ UINT32 Hcfg = MmioRead32(SDHOST_HCFG);
+
+ DEBUG((DEBUG_MMCHOST_SD_INFO, "Setting BusWidth %u\n", BusWidth));
+ if (BusWidth == 4) {
+ Hcfg |= SDHOST_HCFG_WIDE_EXT_BUS;
+ } else {
+ Hcfg &= ~SDHOST_HCFG_WIDE_EXT_BUS;
+ }
+
+ Hcfg |= SDHOST_HCFG_WIDE_INT_BUS | SDHOST_HCFG_SLOW_CARD;
+ MmioWrite32(SDHOST_HCFG, Hcfg);
+ }
+
+ if (BusClockFreq != 0) {
+ DEBUG((DEBUG_MMCHOST_SD_INFO, "Setting Freq %u Hz\n", BusClockFreq));
+ SdHostSetClockFrequency(BusClockFreq);
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC EFI_STATUS
+SdNotifyState(
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_STATE State
+ )
+{
+ DEBUG((DEBUG_MMCHOST_SD, "SdHost: SdNotifyState(State: %d) ", State));
+
+ switch (State) {
+ case MmcHwInitializationState:
+ {
+ DEBUG((DEBUG_MMCHOST_SD, "MmcHwInitializationState\n", State));
+
+ // Turn-off SD Card power
+ MmioWrite32(SDHOST_VDD, 0);
+ {
+ // Reset command and arg
+ MmioWrite32(SDHOST_CMD, 0);
+ MmioWrite32(SDHOST_ARG, 0);
+ // Reset clock divider
+ MmioWrite32(SDHOST_CDIV, 0);
+ // Default timeout
+ MmioWrite32(SDHOST_TOUT, 0xffffffff);
+ // Clear status flags
+ MmioWrite32(SDHOST_HSTS, SDHOST_HSTS_CLEAR);;
+ // Reset controller configs
+ MmioWrite32(SDHOST_HCFG, 0);
+ MmioWrite32(SDHOST_HBCT, 0);
+ MmioWrite32(SDHOST_HBLC, 0);
+
+ gBS->Stall(STALL_TO_STABILIZE_US);
+ }
+ // Turn-on SD Card power
+ MmioWrite32(SDHOST_VDD, 1);
+
+ gBS->Stall(STALL_TO_STABILIZE_US);
+
+ // Write controller configs
+ UINT32 Hcfg = 0;
+ Hcfg |= SDHOST_HCFG_WIDE_INT_BUS;
+ Hcfg |= SDHOST_HCFG_SLOW_CARD; // Use all bits of CDIV in DataMode
+ MmioWrite32(SDHOST_HCFG, Hcfg);
+
+ // Set default clock frequency
+ EFI_STATUS Status = SdHostSetClockFrequency(IDENT_MODE_SD_CLOCK_FREQ_HZ);
+ if (EFI_ERROR(Status)) {
+ DEBUG((
+ DEBUG_MMCHOST_SD_ERROR,
+ "SdHost: SdNotifyState(): Fail to initialize SD clock to %dHz\n",
+ IDENT_MODE_SD_CLOCK_FREQ_HZ));
+ SdHostDumpStatus();
+ return Status;
+ }
+ }
+ break;
+ case MmcIdleState:
+ DEBUG((DEBUG_MMCHOST_SD, "MmcIdleState\n", State));
+ break;
+ case MmcReadyState:
+ DEBUG((DEBUG_MMCHOST_SD, "MmcReadyState\n", State));
+ break;
+ case MmcIdentificationState:
+ DEBUG((DEBUG_MMCHOST_SD, "MmcIdentificationState\n", State));
+ break;
+ case MmcStandByState:
+ DEBUG((DEBUG_MMCHOST_SD, "MmcStandByState\n", State));
+ break;
+ case MmcTransferState:
+ DEBUG((DEBUG_MMCHOST_SD, "MmcTransferState\n", State));
+ break;
+ break;
+ case MmcSendingDataState:
+ DEBUG((DEBUG_MMCHOST_SD, "MmcSendingDataState\n", State));
+ break;
+ case MmcReceiveDataState:
+ DEBUG((DEBUG_MMCHOST_SD, "MmcReceiveDataState\n", State));
+ break;
+ case MmcProgrammingState:
+ DEBUG((DEBUG_MMCHOST_SD, "MmcProgrammingState\n", State));
+ break;
+ case MmcDisconnectState:
+ case MmcInvalidState:
+ default:
+ DEBUG((DEBUG_MMCHOST_SD_ERROR,
+ "SdHost: SdNotifyState(): Invalid State: %d\n", State));
+ ASSERT(0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+SdIsMultiBlock (
+ IN EFI_MMC_HOST_PROTOCOL *This
+ )
+{
+ return TRUE;
+}
+
+EFI_MMC_HOST_PROTOCOL gMmcHost =
+ {
+ MMC_HOST_PROTOCOL_REVISION,
+ SdIsCardPresent,
+ SdIsReadOnly,
+ SdBuildDevicePath,
+ SdNotifyState,
+ SdSendCommand,
+ SdReceiveResponse,
+ SdReadBlockData,
+ SdWriteBlockData,
+ SdSetIos,
+ SdIsMultiBlock
+ };
+
+EFI_STATUS
+SdHostInitialize(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle = NULL;
+
+ if (PcdGet32 (PcdSdIsArasan)) {
+ DEBUG((DEBUG_INFO, "SD is not routed to SdHost\n"));
+ return EFI_REQUEST_UNLOAD_IMAGE;
+ }
+
+ Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid, NULL,
+ (VOID **)&mFwProtocol);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG((DEBUG_MMCHOST_SD, "SdHost: Initialize\n"));
+ DEBUG((DEBUG_MMCHOST_SD, "Config:\n"));
+ DEBUG((DEBUG_MMCHOST_SD, " - FIFO_MAX_POLL_COUNT=%d\n", FIFO_MAX_POLL_COUNT));
+ DEBUG((DEBUG_MMCHOST_SD, " - CMD_STALL_AFTER_POLL_US=%dus\n", CMD_STALL_AFTER_POLL_US));
+ DEBUG((DEBUG_MMCHOST_SD, " - CMD_MIN_POLL_TOTAL_TIME_US=%dms\n", CMD_MIN_POLL_TOTAL_TIME_US / 1000));
+ DEBUG((DEBUG_MMCHOST_SD, " - CMD_MAX_POLL_COUNT=%d\n", CMD_MAX_POLL_COUNT));
+ DEBUG((DEBUG_MMCHOST_SD, " - CMD_MAX_RETRY_COUNT=%d\n", CMD_MAX_RETRY_COUNT));
+ DEBUG((DEBUG_MMCHOST_SD, " - CMD_STALL_AFTER_RETRY_US=%dus\n", CMD_STALL_AFTER_RETRY_US));
+
+ Status = gBS->InstallMultipleProtocolInterfaces(
+ &Handle,
+ &gRaspberryPiMmcHostProtocolGuid, &gMmcHost,
+ NULL
+ );
+ ASSERT_EFI_ERROR(Status);
+ return Status;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/SdHostDxe/SdHostDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/SdHostDxe/SdHostDxe.inf
new file mode 100644
index 000000000000..3469b4611cc9
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/SdHostDxe/SdHostDxe.inf
@@ -0,0 +1,54 @@
+#/** @file
+#
+# Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) Microsoft Corporation. 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 = 0x00010005
+ BASE_NAME = SdHost
+ FILE_GUID = 58ABD787-F64D-4CA2-A034-B9AC2D5AD0CF
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = SdHostInitialize
+
+
+[Sources.common]
+ SdHostDxe.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ PcdLib
+ UefiLib
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ IoLib
+ DmaLib
+ CacheMaintenanceLib
+
+[Guids]
+
+[Protocols]
+ gRaspberryPiMmcHostProtocolGuid ## PRODUCES
+ gRaspberryPiFirmwareProtocolGuid ## CONSUMES
+
+[Pcd]
+ gRaspberryPiTokenSpaceGuid.PcdSdIsArasan
+
+[Depex]
+ gRaspberryPiFirmwareProtocolGuid AND gRaspberryPiConfigAppliedProtocolGuid
diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FileIo.c b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FileIo.c
new file mode 100644
index 000000000000..961de586c78b
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FileIo.c
@@ -0,0 +1,196 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2007-2009, Intel Corporation. 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 "VarBlockService.h"
+
+
+EFI_STATUS
+FileWrite (
+ IN EFI_FILE_PROTOCOL *File,
+ IN UINTN Offset,
+ IN UINTN Buffer,
+ IN UINTN Size
+ )
+{
+ EFI_STATUS Status;
+
+ Status = File->SetPosition (File, Offset);
+ ASSERT_EFI_ERROR (Status);
+ if (!EFI_ERROR (Status)) {
+ Status = File->Write (File, &Size, (VOID *) Buffer);
+ ASSERT_EFI_ERROR (Status);
+ }
+ return Status;
+}
+
+
+VOID
+FileClose (
+ IN EFI_FILE_PROTOCOL *File
+ )
+{
+ File->Flush (File);
+ File->Close (File);
+}
+
+
+EFI_STATUS
+FileOpen (
+ IN EFI_DEVICE_PATH_PROTOCOL *Device,
+ IN CHAR16 *MappedFile,
+ OUT EFI_FILE_PROTOCOL **File,
+ IN UINT64 OpenMode
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_FILE_HANDLE Root;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_STATUS Status;
+
+ *File = NULL;
+
+ Status = gBS->LocateDevicePath (
+ &gEfiSimpleFileSystemProtocolGuid,
+ &Device,
+ &Handle
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (void **) &Volume
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the root directory of the volume
+ //
+ Root = NULL;
+ Status = Volume->OpenVolume (
+ Volume,
+ &Root
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Root != NULL);
+
+ //
+ // Open file
+ //
+ Status = Root->Open (
+ Root,
+ File,
+ MappedFile,
+ OpenMode,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ *File = NULL;
+ }
+
+ //
+ // Close the Root directory
+ //
+ Root->Close (Root);
+ return Status;
+}
+
+
+EFI_STATUS
+CheckStore (
+ IN EFI_HANDLE SimpleFileSystemHandle,
+ OUT EFI_DEVICE_PATH_PROTOCOL **Device
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ EFI_FILE_PROTOCOL *File;
+
+ *Device = NULL;
+ Status = gBS->HandleProtocol (
+ SimpleFileSystemHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID*)&BlkIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrHandle;
+ }
+ if (!BlkIo->Media->MediaPresent) {
+ DEBUG ((DEBUG_ERROR, "FwhMappedFile: Media not present!\n"));
+ Status = EFI_NO_MEDIA;
+ goto ErrHandle;
+ }
+ if (BlkIo->Media->ReadOnly) {
+ DEBUG ((DEBUG_ERROR, "FwhMappedFile: Media is read-only!\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto ErrHandle;
+ }
+
+ Status = FileOpen (DevicePathFromHandle (SimpleFileSystemHandle),
+ mFvInstance->MappedFile, &File,
+ EFI_FILE_MODE_READ);
+ if (EFI_ERROR (Status)) {
+ goto ErrHandle;
+ }
+
+ /* We found it! Maybe do more checks...? */
+
+ FileClose (File);
+ *Device = DuplicateDevicePath (DevicePathFromHandle (SimpleFileSystemHandle));
+
+ ASSERT (*Device != NULL);
+
+ErrHandle:
+ return Status;
+}
+
+
+EFI_STATUS
+CheckStoreExists (
+ IN EFI_DEVICE_PATH_PROTOCOL *Device
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_STATUS Status;
+
+ Status = gBS->LocateDevicePath (
+ &gEfiSimpleFileSystemProtocolGuid,
+ &Device,
+ &Handle
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (void **) &Volume
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FvbInfo.c b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FvbInfo.c
new file mode 100644
index 000000000000..ddfd746b0eca
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FvbInfo.c
@@ -0,0 +1,118 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2006-2014, Intel Corporation. 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 <Pi/PiFirmwareVolume.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+
+typedef struct {
+ UINT64 FvLength;
+ EFI_FIRMWARE_VOLUME_HEADER FvbInfo;
+ //
+ // EFI_FV_BLOCK_MAP_ENTRY ExtraBlockMap[n];//n=0
+ //
+ EFI_FV_BLOCK_MAP_ENTRY End[1];
+} EFI_FVB_MEDIA_INFO;
+
+EFI_FVB_MEDIA_INFO mPlatformFvbMediaInfo[] = {
+ //
+ // System NvStorage FVB
+ //
+ {
+ FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) +
+ FixedPcdGet32 (PcdNvStorageEventLogSize),
+ {
+ {
+ 0,
+ }, // ZeroVector[16]
+ EFI_SYSTEM_NV_DATA_FV_GUID,
+ FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) +
+ FixedPcdGet32 (PcdNvStorageEventLogSize),
+ EFI_FVH_SIGNATURE,
+ EFI_FVB2_MEMORY_MAPPED |
+ EFI_FVB2_READ_ENABLED_CAP |
+ EFI_FVB2_READ_STATUS |
+ EFI_FVB2_WRITE_ENABLED_CAP |
+ EFI_FVB2_WRITE_STATUS |
+ EFI_FVB2_ERASE_POLARITY |
+ EFI_FVB2_ALIGNMENT_16,
+ sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY),
+ 0, // CheckSum
+ 0, // ExtHeaderOffset
+ {
+ 0,
+ }, // Reserved[1]
+ 2, // Revision
+ {
+ {
+ (FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) +
+ FixedPcdGet32 (PcdNvStorageEventLogSize)) /
+ FixedPcdGet32 (PcdFirmwareBlockSize),
+ FixedPcdGet32 (PcdFirmwareBlockSize),
+ }
+ } // BlockMap[1]
+ },
+ {
+ {
+ 0,
+ 0
+ }
+ } // End[1]
+ }
+};
+
+
+EFI_STATUS
+GetFvbInfo (
+ IN UINT64 FvLength,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo
+ )
+{
+ STATIC BOOLEAN Checksummed = FALSE;
+ UINTN Index;
+
+ if (!Checksummed) {
+ for (Index = 0;
+ Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_INFO);
+ Index += 1) {
+ UINT16 Checksum;
+ mPlatformFvbMediaInfo[Index].FvbInfo.Checksum = 0;
+ Checksum = CalculateCheckSum16 (
+ (UINT16*) &mPlatformFvbMediaInfo[Index].FvbInfo,
+ mPlatformFvbMediaInfo[Index].FvbInfo.HeaderLength
+ );
+ mPlatformFvbMediaInfo[Index].FvbInfo.Checksum = Checksum;
+ }
+ Checksummed = TRUE;
+ }
+
+ for (Index = 0;
+ Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_INFO);
+ Index += 1) {
+ if (mPlatformFvbMediaInfo[Index].FvLength == FvLength) {
+ *FvbInfo = &mPlatformFvbMediaInfo[Index].FvbInfo;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.c b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.c
new file mode 100644
index 000000000000..1cea51936ba2
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.c
@@ -0,0 +1,984 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2006 - 2014, Intel Corporation. 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 <Protocol/DevicePath.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "VarBlockService.h"
+
+#define EFI_FVB2_STATUS \
+ (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
+
+EFI_FW_VOL_INSTANCE *mFvInstance;
+
+FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_MEMMAP_DP,
+ {
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
+ }
+ },
+ EfiMemoryMappedIO,
+ (EFI_PHYSICAL_ADDRESS) 0,
+ (EFI_PHYSICAL_ADDRESS) 0,
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
+ {
+ {
+ MEDIA_DEVICE_PATH,
+ MEDIA_PIWG_FW_VOL_DP,
+ {
+ (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
+ (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
+ }
+ },
+ { 0 }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
+ NULL,
+ {
+ FvbProtocolGetAttributes,
+ FvbProtocolSetAttributes,
+ FvbProtocolGetPhysicalAddress,
+ FvbProtocolGetBlockSize,
+ FvbProtocolRead,
+ FvbProtocolWrite,
+ FvbProtocolEraseBlocks,
+ NULL
+ }
+};
+
+
+EFI_STATUS
+VarStoreWrite (
+ IN UINTN Address,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ CopyMem ((VOID *) Address, Buffer, *NumBytes);
+ mFvInstance->Dirty = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+VarStoreErase (
+ IN UINTN Address,
+ IN UINTN LbaLength
+ )
+{
+ SetMem ((VOID *)Address, LbaLength, 0xff);
+ mFvInstance->Dirty = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+FvbGetVolumeAttributes (
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ *Attributes = mFvInstance->VolumeHeader->Attributes;
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+FvbGetLbaAddress (
+ IN EFI_LBA Lba,
+ OUT UINTN *LbaAddress,
+ OUT UINTN *LbaLength,
+ OUT UINTN *NumOfBlocks
+ )
+/*++
+
+ Routine Description:
+ Retrieves the starting address of an LBA in an FV
+
+ Arguments:
+ Lba - The logical block address
+ LbaAddress - On output, contains the physical starting address
+ of the Lba
+ LbaLength - On output, contains the length of the block
+ NumOfBlocks - A pointer to a caller allocated UINTN in which the
+ number of consecutive blocks starting with Lba is
+ returned. All blocks in this range have a size of
+ BlockSize
+
+ Returns:
+ EFI_SUCCESS
+ EFI_INVALID_PARAMETER
+
+--*/
+{
+ UINT32 NumBlocks;
+ UINT32 BlockLength;
+ UINTN Offset;
+ EFI_LBA StartLba;
+ EFI_LBA NextLba;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+
+ StartLba = 0;
+ Offset = 0;
+ BlockMap = &(mFvInstance->VolumeHeader->BlockMap[0]);
+
+ //
+ // Parse the blockmap of the FV to find which map entry the Lba belongs to.
+ //
+ while (TRUE) {
+ NumBlocks = BlockMap->NumBlocks;
+ BlockLength = BlockMap->Length;
+
+ if (NumBlocks == 0 || BlockLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NextLba = StartLba + NumBlocks;
+
+ //
+ // The map entry found.
+ //
+ if (Lba >= StartLba && Lba < NextLba) {
+ Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
+ if (LbaAddress != NULL) {
+ *LbaAddress = mFvInstance->FvBase + Offset;
+ }
+
+ if (LbaLength != NULL) {
+ *LbaLength = BlockLength;
+ }
+
+ if (NumOfBlocks != NULL) {
+ *NumOfBlocks = (UINTN) (NextLba - Lba);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ StartLba = NextLba;
+ Offset = Offset + NumBlocks * BlockLength;
+ BlockMap++;
+ }
+}
+
+
+EFI_STATUS
+FvbEraseBlock (
+ IN EFI_LBA Lba
+ )
+/*++
+
+Routine Description:
+ Erases and initializes a firmware volume block
+
+Arguments:
+ Lba - The logical block index to be erased
+
+Returns:
+ EFI_SUCCESS - The erase request was successfully completed
+ EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
+ EFI_DEVICE_ERROR - The block device is not functioning correctly and
+ could not be written. Firmware device may have been
+ partially erased
+ EFI_INVALID_PARAMETER
+
+--*/
+{
+ EFI_FVB_ATTRIBUTES_2 Attributes;
+ UINTN LbaAddress;
+ UINTN LbaLength;
+ EFI_STATUS Status;
+
+ //
+ // Check if the FV is write enabled
+ //
+ FvbGetVolumeAttributes (&Attributes);
+
+ if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Get the starting address of the block for erase. For debug reasons,
+ // LbaWriteAddress may not be the same as LbaAddress.
+ //
+ Status = FvbGetLbaAddress (Lba, &LbaAddress, &LbaLength, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return VarStoreErase (
+ LbaAddress,
+ LbaLength
+ );
+}
+
+
+EFI_STATUS
+FvbSetVolumeAttributes (
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+/*++
+
+ Routine Description:
+ Modifies the current settings of the firmware volume according to the
+ input parameter, and returns the new setting of the volume
+
+ Arguments:
+ Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
+ containing the desired firmware volume settings.
+ On successful return, it contains the new setting.
+
+ Returns:
+ EFI_SUCCESS - Successfully returns
+ EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
+ EFI_INVALID_PARAMETER
+
+--*/
+{
+ EFI_FVB_ATTRIBUTES_2 OldAttributes;
+ EFI_FVB_ATTRIBUTES_2 *AttribPtr;
+ UINT32 Capabilities;
+ UINT32 OldStatus;
+ UINT32 NewStatus;
+ EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
+
+ AttribPtr =
+ (EFI_FVB_ATTRIBUTES_2 *) &(mFvInstance->VolumeHeader->Attributes);
+ OldAttributes = *AttribPtr;
+ Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
+ EFI_FVB2_READ_ENABLED_CAP | \
+ EFI_FVB2_WRITE_DISABLED_CAP | \
+ EFI_FVB2_WRITE_ENABLED_CAP | \
+ EFI_FVB2_LOCK_CAP \
+ );
+ OldStatus = OldAttributes & EFI_FVB2_STATUS;
+ NewStatus = *Attributes & EFI_FVB2_STATUS;
+
+ UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
+ EFI_FVB2_READ_ENABLED_CAP | \
+ EFI_FVB2_WRITE_DISABLED_CAP | \
+ EFI_FVB2_WRITE_ENABLED_CAP | \
+ EFI_FVB2_LOCK_CAP | \
+ EFI_FVB2_STICKY_WRITE | \
+ EFI_FVB2_MEMORY_MAPPED | \
+ EFI_FVB2_ERASE_POLARITY | \
+ EFI_FVB2_READ_LOCK_CAP | \
+ EFI_FVB2_WRITE_LOCK_CAP | \
+ EFI_FVB2_ALIGNMENT;
+
+ //
+ // Some attributes of FV is read only can *not* be set.
+ //
+ if ((OldAttributes & UnchangedAttributes) ^
+ (*Attributes & UnchangedAttributes)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If firmware volume is locked, no status bit can be updated.
+ //
+ if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
+ if (OldStatus ^ NewStatus) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+
+ //
+ // Test read disable.
+ //
+ if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Test read enable.
+ //
+ if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_READ_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Test write disable.
+ //
+ if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Test write enable.
+ //
+ if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_WRITE_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Test lock.
+ //
+ if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_LOCK_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
+ *AttribPtr = (*AttribPtr) | NewStatus;
+ *Attributes = *AttribPtr;
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+FvbProtocolGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ *Address = mFvInstance->FvBase;
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+FvbProtocolGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumOfBlocks
+ )
+/*++
+
+ Routine Description:
+ Retrieve the size of a logical block
+
+ Arguments:
+ This - Calling context
+ Lba - Indicates which block to return the size for.
+ BlockSize - A pointer to a caller allocated UINTN in which
+ the size of the block is returned
+ NumOfBlocks - a pointer to a caller allocated UINTN in which the
+ number of consecutive blocks starting with Lba is
+ returned. All blocks in this range have a size of
+ BlockSize
+
+ Returns:
+ EFI_SUCCESS - The firmware volume was read successfully and
+ contents are in Buffer
+
+--*/
+{
+ return FvbGetLbaAddress (
+ Lba,
+ NULL,
+ BlockSize,
+ NumOfBlocks
+ );
+}
+
+
+EFI_STATUS
+EFIAPI
+FvbProtocolGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+/*++
+
+ Routine Description:
+ Retrieves Volume attributes. No polarity translations are done.
+
+ Arguments:
+ This - Calling context
+ Attributes - output buffer which contains attributes
+
+ Returns:
+ EFI_SUCCESS - Successfully returns
+
+--*/
+{
+ return FvbGetVolumeAttributes (Attributes);
+}
+
+
+EFI_STATUS
+EFIAPI
+FvbProtocolSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+/*++
+
+ Routine Description:
+ Sets Volume attributes. No polarity translations are done.
+
+ Arguments:
+ This - Calling context
+ Attributes - output buffer which contains attributes
+
+ Returns:
+ EFI_SUCCESS - Successfully returns
+
+--*/
+{
+ return FvbSetVolumeAttributes (Attributes);
+}
+
+
+EFI_STATUS
+EFIAPI
+FvbProtocolEraseBlocks (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL*This,
+ ...
+ )
+/*++
+
+ Routine Description:
+
+ The EraseBlock() function erases one or more blocks as denoted by the
+ variable argument list. The entire parameter list of blocks must be
+ verified prior to erasing any blocks. If a block is requested that does
+ not exist within the associated firmware volume (it has a larger index than
+ the last block of the firmware volume), the EraseBlock() function must
+ return EFI_INVALID_PARAMETER without modifying the contents of the firmware
+ volume.
+
+ Arguments:
+ This - Calling context
+ ... - Starting LBA followed by Number of Lba to erase.
+ a -1 to terminate the list.
+
+ Returns:
+ EFI_SUCCESS - The erase request was successfully completed
+ EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
+ EFI_DEVICE_ERROR - The block device is not functioning correctly and
+ could not be written. Firmware device may have been
+ partially erased
+
+--*/
+{
+ UINTN NumOfBlocks;
+ VA_LIST args;
+ EFI_LBA StartingLba;
+ UINTN NumOfLba;
+ EFI_STATUS Status;
+
+ NumOfBlocks = mFvInstance->NumOfBlocks;
+ VA_START (args, This);
+
+ do {
+ StartingLba = VA_ARG (args, EFI_LBA);
+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+ break;
+ }
+
+ NumOfLba = VA_ARG (args, UINTN);
+
+ if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {
+ VA_END (args);
+ return EFI_INVALID_PARAMETER;
+ }
+ } while (1);
+
+ VA_END (args);
+
+ VA_START (args, This);
+ do {
+ StartingLba = VA_ARG (args, EFI_LBA);
+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+ break;
+ }
+
+ NumOfLba = VA_ARG (args, UINTN);
+
+ while (NumOfLba > 0) {
+ Status = FvbEraseBlock (StartingLba);
+ if (EFI_ERROR (Status)) {
+ VA_END (args);
+ return Status;
+ }
+
+ StartingLba++;
+ NumOfLba--;
+ }
+
+ } while (1);
+
+ VA_END (args);
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+FvbProtocolWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+/*++
+
+ Routine Description:
+
+ Writes data beginning at Lba:Offset from FV. The write terminates either
+ when *NumBytes of data have been written, or when a block boundary is
+ reached. *NumBytes is updated to reflect the actual number of bytes
+ written. The write opertion does not include erase. This routine will
+ attempt to write only the specified bytes. If the writes do not stick,
+ it will return an error.
+
+ Arguments:
+ This - Calling context
+ Lba - Block in which to begin write
+ Offset - Offset in the block at which to begin write
+ NumBytes - On input, indicates the requested write size. On
+ output, indicates the actual number of bytes
+ written
+ Buffer - Buffer containing source data for the write.
+
+ Returns:
+ EFI_SUCCESS - The firmware volume was written successfully
+ EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
+ NumBytes contains the total number of bytes
+ actually written
+ EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
+ EFI_DEVICE_ERROR - The block device is not functioning correctly and
+ could not be written
+ EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
+
+--*/
+{
+ EFI_FVB_ATTRIBUTES_2 Attributes;
+ UINTN LbaAddress;
+ UINTN LbaLength;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+
+ //
+ // Check for invalid conditions.
+ //
+ if ((NumBytes == NULL) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*NumBytes == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FvbGetLbaAddress (Lba, &LbaAddress, &LbaLength, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if the FV is write enabled.
+ //
+ FvbGetVolumeAttributes (&Attributes);
+
+ if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Perform boundary checks and adjust NumBytes.
+ //
+ if (Offset > LbaLength) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (LbaLength < (*NumBytes + Offset)) {
+ *NumBytes = (UINT32) (LbaLength - Offset);
+ Status = EFI_BAD_BUFFER_SIZE;
+ }
+
+ ReturnStatus = VarStoreWrite (
+ LbaAddress + Offset,
+ NumBytes,
+ Buffer
+ );
+ if (EFI_ERROR (ReturnStatus)) {
+ return ReturnStatus;
+ }
+
+ return Status;
+}
+
+
+EFI_STATUS
+EFIAPI
+FvbProtocolRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN CONST UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+/*++
+
+ Routine Description:
+
+ Reads data beginning at Lba:Offset from FV. The Read terminates either
+ when *NumBytes of data have been read, or when a block boundary is
+ reached. *NumBytes is updated to reflect the actual number of bytes
+ written. The write opertion does not include erase. This routine will
+ attempt to write only the specified bytes. If the writes do not stick,
+ it will return an error.
+
+ Arguments:
+ This - Calling context
+ Lba - Block in which to begin Read
+ Offset - Offset in the block at which to begin Read
+ NumBytes - On input, indicates the requested write size. On
+ output, indicates the actual number of bytes Read
+ Buffer - Buffer containing source data for the Read.
+
+ Returns:
+ EFI_SUCCESS - The firmware volume was read successfully and
+ contents are in Buffer
+ EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
+ NumBytes contains the total number of bytes
+ returned in Buffer
+ EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
+ EFI_DEVICE_ERROR - The block device is not functioning correctly and
+ could not be read
+ EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
+
+--*/
+{
+ EFI_FVB_ATTRIBUTES_2 Attributes;
+ UINTN LbaAddress;
+ UINTN LbaLength;
+ EFI_STATUS Status;
+
+ //
+ // Check for invalid conditions.
+ //
+ if ((NumBytes == NULL) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*NumBytes == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FvbGetLbaAddress (Lba, &LbaAddress, &LbaLength, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if the FV is read enabled.
+ //
+ FvbGetVolumeAttributes (&Attributes);
+
+ if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Perform boundary checks and adjust NumBytes.
+ //
+ if (Offset > LbaLength) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (LbaLength < (*NumBytes + Offset)) {
+ *NumBytes = (UINT32) (LbaLength - Offset);
+ Status = EFI_BAD_BUFFER_SIZE;
+ }
+
+ CopyMem (Buffer, (VOID *) (LbaAddress + Offset), (UINTN) *NumBytes);
+
+ return Status;
+}
+
+
+EFI_STATUS
+ValidateFvHeader (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ )
+/*++
+
+ Routine Description:
+ Check the integrity of firmware volume header
+
+ Arguments:
+ FwVolHeader - A pointer to a firmware volume header
+
+ Returns:
+ EFI_SUCCESS - The firmware volume is consistent
+ EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an
+ FV
+
+--*/
+{
+ UINT16 Checksum;
+
+ //
+ // Verify the header revision, header signature, length
+ // Length of FvBlock cannot be 2**64-1
+ // HeaderLength cannot be an odd number.
+ //
+ if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
+ (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
+ (FwVolHeader->FvLength == ((UINTN) -1)) ||
+ ((FwVolHeader->HeaderLength & 0x01) != 0)
+ ) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Verify the header checksum.
+ //
+
+ Checksum = CalculateSum16 ((UINT16 *) FwVolHeader,
+ FwVolHeader->HeaderLength);
+ if (Checksum != 0) {
+ UINT16 Expected;
+
+ Expected =
+ (UINT16) (((UINTN) FwVolHeader->Checksum + 0x10000 - Checksum) & 0xffff);
+
+ DEBUG ((DEBUG_INFO, "FV@%p Checksum is 0x%x, expected 0x%x\n",
+ FwVolHeader, FwVolHeader->Checksum, Expected));
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+FvbInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+ Routine Description:
+ This function does common initialization for FVB services
+
+ Arguments:
+
+ Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT32 BufferSize;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ UINT32 MaxLbaSize;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINTN Length;
+ UINTN NumOfBlocks;
+ RETURN_STATUS PcdStatus;
+ UINTN StartOffset;
+
+ BaseAddress = PcdGet32 (PcdNvStorageVariableBase);
+ Length = (FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) +
+ FixedPcdGet32 (PcdNvStorageEventLogSize));
+ StartOffset = BaseAddress - FixedPcdGet64 (PcdFdBaseAddress);
+
+ BufferSize = sizeof (EFI_FW_VOL_INSTANCE);
+
+ mFvInstance = AllocateRuntimeZeroPool (BufferSize);
+ if (mFvInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mFvInstance->FvBase = (UINTN) BaseAddress;
+ mFvInstance->FvLength = (UINTN) Length;
+ mFvInstance->Offset = StartOffset;
+ /*
+ * Should I parse config.txt instead and find the real name?
+ */
+ mFvInstance->MappedFile = L"RPI_EFI.FD";
+
+ Status = ValidateFvHeader (mFvInstance->VolumeHeader);
+ if (!EFI_ERROR (Status)) {
+ if (mFvInstance->VolumeHeader->FvLength != Length ||
+ mFvInstance->VolumeHeader->BlockMap[0].Length !=
+ PcdGet32 (PcdFirmwareBlockSize)) {
+ Status = EFI_VOLUME_CORRUPTED;
+ }
+ }
+ if (EFI_ERROR (Status)) {
+ EFI_FIRMWARE_VOLUME_HEADER *GoodFwVolHeader;
+ UINTN WriteLength;
+
+ DEBUG ((DEBUG_INFO,
+ "Variable FV header is not valid. It will be reinitialized.\n"));
+
+ //
+ // Get FvbInfo
+ //
+ Status = GetFvbInfo (Length, &GoodFwVolHeader);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Erase all the blocks
+ //
+ Status = VarStoreErase ((UINTN) mFvInstance->FvBase,
+ mFvInstance->FvLength);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Write good FV header
+ //
+ WriteLength = GoodFwVolHeader->HeaderLength;
+ Status = VarStoreWrite((UINTN) mFvInstance->FvBase,
+ &WriteLength,
+ (UINT8*) GoodFwVolHeader);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (WriteLength == GoodFwVolHeader->HeaderLength);
+
+ Status = ValidateFvHeader (mFvInstance->VolumeHeader);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ MaxLbaSize = 0;
+ NumOfBlocks = 0;
+ for (PtrBlockMapEntry = mFvInstance->VolumeHeader->BlockMap;
+ PtrBlockMapEntry->NumBlocks != 0;
+ PtrBlockMapEntry++) {
+ //
+ // Get the maximum size of a block.
+ //
+ if (MaxLbaSize < PtrBlockMapEntry->Length) {
+ MaxLbaSize = PtrBlockMapEntry->Length;
+ }
+
+ NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
+ }
+
+ //
+ // The total number of blocks in the FV.
+ //
+ mFvInstance->NumOfBlocks = NumOfBlocks;
+
+ //
+ // Add a FVB Protocol Instance
+ //
+ FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));
+ ASSERT (FvbDevice != NULL);
+ CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
+
+ //
+ // Set up the devicepath
+ //
+ if (mFvInstance->VolumeHeader->ExtHeaderOffset == 0) {
+ FV_MEMMAP_DEVICE_PATH *FvMemmapDevicePath;
+
+ //
+ // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
+ //
+ FvMemmapDevicePath = AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH),
+ &mFvMemmapDevicePathTemplate);
+ FvMemmapDevicePath->MemMapDevPath.StartingAddress = mFvInstance->FvBase;
+ FvMemmapDevicePath->MemMapDevPath.EndingAddress = mFvInstance->FvBase +
+ mFvInstance->FvLength - 1;
+ FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvMemmapDevicePath;
+ } else {
+ FV_PIWG_DEVICE_PATH *FvPiwgDevicePath;
+
+ FvPiwgDevicePath = AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH),
+ &mFvPIWGDevicePathTemplate);
+ CopyGuid (
+ &FvPiwgDevicePath->FvDevPath.FvName,
+ (GUID *)(UINTN)(mFvInstance->FvBase +
+ mFvInstance->VolumeHeader->ExtHeaderOffset)
+ );
+ FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvPiwgDevicePath;
+ }
+
+ //
+ // Module type specific hook.
+ //
+ InstallProtocolInterfaces (FvbDevice);
+
+ //
+ // Set several PCD values to point to flash.
+ //
+ PcdStatus = PcdSet64S (
+ PcdFlashNvStorageVariableBase64,
+ (UINTN) PcdGet32 (PcdNvStorageVariableBase)
+ );
+ ASSERT_RETURN_ERROR (PcdStatus);
+ PcdStatus = PcdSet32S (
+ PcdFlashNvStorageFtwWorkingBase,
+ PcdGet32 (PcdNvStorageFtwWorkingBase)
+ );
+ ASSERT_RETURN_ERROR (PcdStatus);
+ PcdStatus = PcdSet32S (
+ PcdFlashNvStorageFtwSpareBase,
+ PcdGet32 (PcdNvStorageFtwSpareBase)
+ );
+ ASSERT_RETURN_ERROR (PcdStatus);
+
+ InstallFSNotifyHandler ();
+ InstallDumpVarEventHandlers ();
+ InstallVirtualAddressChangeHandler ();
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.h b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.h
new file mode 100644
index 000000000000..3596c4ac55b9
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.h
@@ -0,0 +1,217 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2007-2009, Intel Corporation. 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 _FW_BLOCK_SERVICE_H
+#define _FW_BLOCK_SERVICE_H
+
+#include <Guid/EventGroup.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+
+typedef struct {
+ union {
+ UINTN FvBase;
+ EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader;
+ };
+ UINTN FvLength;
+ UINTN Offset;
+ UINTN NumOfBlocks;
+ EFI_DEVICE_PATH_PROTOCOL *Device;
+ CHAR16 *MappedFile;
+ BOOLEAN Dirty;
+} EFI_FW_VOL_INSTANCE;
+
+extern EFI_FW_VOL_INSTANCE *mFvInstance;
+
+typedef struct {
+ MEDIA_FW_VOL_DEVICE_PATH FvDevPath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;
+} FV_PIWG_DEVICE_PATH;
+
+typedef struct {
+ MEMMAP_DEVICE_PATH MemMapDevPath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;
+} FV_MEMMAP_DEVICE_PATH;
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance;
+} EFI_FW_VOL_BLOCK_DEVICE;
+
+EFI_STATUS
+GetFvbInfo (
+ IN UINT64 FvLength,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo
+ );
+
+EFI_STATUS
+FvbSetVolumeAttributes (
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+EFI_STATUS
+FvbGetVolumeAttributes (
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+EFI_STATUS
+FvbGetPhysicalAddress (
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ );
+
+EFI_STATUS
+EFIAPI
+FvbInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+
+VOID
+EFIAPI
+FvbClassAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+FvbGetLbaAddress (
+ IN EFI_LBA Lba,
+ OUT UINTN *LbaAddress,
+ OUT UINTN *LbaLength,
+ OUT UINTN *NumOfBlocks
+ );
+
+//
+// Protocol APIs
+//
+EFI_STATUS
+EFIAPI
+FvbProtocolGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+EFI_STATUS
+EFIAPI
+FvbProtocolSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+EFI_STATUS
+EFIAPI
+FvbProtocolGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ );
+
+EFI_STATUS
+EFIAPI
+FvbProtocolGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumOfBlocks
+ );
+
+EFI_STATUS
+EFIAPI
+FvbProtocolRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN CONST UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+FvbProtocolWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+FvbProtocolEraseBlocks (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ ...
+ );
+
+VOID
+InstallProtocolInterfaces (
+ IN EFI_FW_VOL_BLOCK_DEVICE *FvbDevice
+ );
+
+VOID
+InstallVirtualAddressChangeHandler (
+ VOID
+ );
+
+VOID
+InstallFSNotifyHandler (
+ VOID
+ );
+
+VOID
+InstallDumpVarEventHandlers (
+ VOID
+);
+
+EFI_STATUS
+FileWrite (
+ IN EFI_FILE_PROTOCOL *File,
+ IN UINTN Offset,
+ IN UINTN Buffer,
+ IN UINTN Size
+ );
+
+EFI_STATUS
+CheckStore (
+ IN EFI_HANDLE SimpleFileSystemHandle,
+ OUT EFI_DEVICE_PATH_PROTOCOL **Device
+ );
+
+EFI_STATUS
+CheckStoreExists (
+ IN EFI_DEVICE_PATH_PROTOCOL *Device
+ );
+
+EFI_STATUS
+FileOpen (
+ IN EFI_DEVICE_PATH_PROTOCOL *Device,
+ IN CHAR16 *MappedFile,
+ OUT EFI_FILE_PROTOCOL **File,
+ IN UINT64 OpenMode
+ );
+
+VOID
+FileClose (
+ IN EFI_FILE_PROTOCOL *File
+ );
+
+#endif
diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c
new file mode 100644
index 000000000000..8c4db3dcfd59
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c
@@ -0,0 +1,334 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (C) 2015, Red Hat, Inc.
+ * Copyright (c) 2006-2014, Intel Corporation. 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 "VarBlockService.h"
+
+VOID *mSFSRegistration;
+
+
+VOID
+InstallProtocolInterfaces (
+ IN EFI_FW_VOL_BLOCK_DEVICE *FvbDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE FwbHandle;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;
+
+ //
+ // Find a handle with a matching device path that has supports FW Block
+ // protocol.
+ //
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid,
+ &FvbDevice->DevicePath, &FwbHandle);
+ if (EFI_ERROR (Status)) {
+ //
+ // LocateDevicePath fails so install a new interface and device path.
+ //
+ FwbHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &FwbHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ &FvbDevice->FwVolBlockInstance,
+ &gEfiDevicePathProtocolGuid,
+ FvbDevice->DevicePath,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
+ //
+ // Device already exists, so reinstall the FVB protocol
+ //
+ Status = gBS->HandleProtocol (
+ FwbHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID**)&OldFwbInterface
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->ReinstallProtocolInterface (
+ FwbHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ OldFwbInterface,
+ &FvbDevice->FwVolBlockInstance
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // There was a FVB protocol on an End Device Path node
+ //
+ ASSERT (FALSE);
+ }
+}
+
+
+STATIC
+VOID
+EFIAPI
+FvbVirtualAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/*++
+
+ Routine Description:
+
+ Fixup internal data so that EFI can be called in virtual mode.
+
+ Arguments:
+
+ (Standard EFI notify event - EFI_EVENT_NOTIFY)
+
+ Returns:
+
+ None
+
+--*/
+{
+ EfiConvertPointer (0x0, (VOID **) &mFvInstance->FvBase);
+ EfiConvertPointer (0x0, (VOID **) &mFvInstance->VolumeHeader);
+ EfiConvertPointer (0x0, (VOID **) &mFvInstance);
+}
+
+
+VOID
+InstallVirtualAddressChangeHandler (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT VirtualAddressChangeEvent;
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ FvbVirtualAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &VirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+STATIC
+EFI_STATUS
+DoDump(
+ IN EFI_DEVICE_PATH_PROTOCOL *Device
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_PROTOCOL *File;
+
+ Status = FileOpen (Device,
+ mFvInstance->MappedFile,
+ &File,
+ EFI_FILE_MODE_WRITE |
+ EFI_FILE_MODE_READ);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = FileWrite (File,
+ mFvInstance->Offset,
+ mFvInstance->FvBase,
+ mFvInstance->FvLength);
+ FileClose (File);
+ return Status;
+}
+
+
+STATIC
+VOID
+EFIAPI
+DumpVars(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ if (mFvInstance->Device == NULL) {
+ DEBUG((DEBUG_INFO, "Variable store not found?\n"));
+ return;
+ }
+
+ if (!mFvInstance->Dirty) {
+ DEBUG((DEBUG_INFO, "Variables not dirty, not dumping!\n"));
+ return;
+ }
+
+ Status = DoDump (mFvInstance->Device);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "Couldn't dump '%s'\n",
+ mFvInstance->MappedFile));
+ ASSERT_EFI_ERROR(Status);
+ return;
+ }
+
+ DEBUG((DEBUG_INFO, "Variables dumped!\n"));
+ mFvInstance->Dirty = FALSE;
+}
+
+
+VOID
+ReadyToBootHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ImageInstallEvent;
+ VOID *ImageRegistration;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DumpVars,
+ NULL,
+ &ImageInstallEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->RegisterProtocolNotify (
+ &gEfiLoadedImageProtocolGuid,
+ ImageInstallEvent,
+ &ImageRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DumpVars(NULL, NULL);
+ Status = gBS->CloseEvent(Event);
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+VOID
+InstallDumpVarEventHandlers (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ResetEvent;
+ EFI_EVENT ReadyToBootEvent;
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DumpVars,
+ NULL,
+ &gRaspberryPiEventResetGuid,
+ &ResetEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ ReadyToBootHandler,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &ReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+VOID
+EFIAPI
+OnSimpleFileSystemInstall (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleSize;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *Device;
+
+ if ((mFvInstance->Device != NULL) &&
+ !EFI_ERROR (CheckStoreExists (mFvInstance->Device))
+ ) {
+ //
+ // We've already found the variable store before,
+ // and that device is not removed from the ssystem.
+ //
+ return;
+ }
+
+ while (TRUE) {
+ HandleSize = sizeof (EFI_HANDLE);
+ Status = gBS->LocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mSFSRegistration,
+ &HandleSize,
+ &Handle
+ );
+ if (Status == EFI_NOT_FOUND) {
+ break;
+ }
+
+ ASSERT_EFI_ERROR (Status);
+
+ Status = CheckStore (Handle, &Device);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = DoDump (Device);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "Couldn't update '%s'\n",
+ mFvInstance->MappedFile));
+ ASSERT_EFI_ERROR(Status);
+ continue;
+ }
+
+ if (mFvInstance->Device != NULL) {
+ gBS->FreePool (mFvInstance->Device);
+ }
+
+ DEBUG((DEBUG_INFO, "Found variable store!\n"));
+ mFvInstance->Device = Device;
+ break;
+ }
+}
+
+
+VOID
+InstallFSNotifyHandler (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ OnSimpleFileSystemInstall,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->RegisterProtocolNotify (
+ &gEfiSimpleFileSystemProtocolGuid,
+ Event,
+ &mSFSRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf
new file mode 100644
index 000000000000..95ec0f8a64e9
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf
@@ -0,0 +1,93 @@
+#/** @file
+#
+# Support for the FS-backed "flash" device.
+# The trick is to keep it inside the RPI firmware file itself...
+#
+# Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) 2006-2013, Intel Corporation. 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 = 0x00010005
+ BASE_NAME = VarBlockServiceDxe
+ FILE_GUID = 733cbac2-b23f-4b92-bc8e-fb01ce5907b7
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FvbInitialize
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = AARCH64
+#
+
+[Sources]
+ FvbInfo.c
+ VarBlockService.c
+ VarBlockServiceDxe.c
+ FileIo.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ PcdLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+ gRaspberryPiEventResetGuid
+ gEfiEventReadyToBootGuid
+
+[Protocols]
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiLoadedImageProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiFirmwareVolumeBlockProtocolGuid # PROTOCOL SOMETIMES_PRODUCED
+ gEfiDevicePathProtocolGuid # PROTOCOL SOMETIMES_PRODUCED
+
+[FixedPcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageVariableBase
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageFtwWorkingBase
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageFtwSpareBase
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageEventLogSize
+ gRaspberryPiTokenSpaceGuid.PcdFirmwareBlockSize
+ gArmTokenSpaceGuid.PcdFdBaseAddress
+ gArmTokenSpaceGuid.PcdFdSize
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageEventLogBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+
+[FeaturePcd]
+
+[Depex]
+ TRUE
diff --git a/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836.h b/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836.h
new file mode 100644
index 000000000000..bd30324ff073
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836.h
@@ -0,0 +1,70 @@
+/** @file
+ *
+ * Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2016, Linaro Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ **/
+
+/*
+ * Both "core" and SoC perpherals (1M each).
+ */
+#define BCM2836_SOC_REGISTERS 0x3f000000
+#define BCM2836_SOC_REGISTER_LENGTH 0x02000000
+
+/* Synopsis DW2/DWC USB 2.0 OTG. */
+#define BCM2836_USB_DW2_BASE_ADDRESS 0x3f980000
+
+/*
+ * Offset between the CPU's view and the VC's view of system memory.
+ */
+#define BCM2836_DMA_DEVICE_OFFSET 0xc0000000
+
+/* watchdog constants */
+#define BCM2836_WDOG_BASE_ADDRESS 0x3f100000
+#define BCM2836_WDOG_PASSWORD 0x5a000000
+#define BCM2836_WDOG_RSTC_OFFSET 0x0000001c
+#define BCM2836_WDOG_WDOG_OFFSET 0x00000024
+#define BCM2836_WDOG_RSTC_WRCFG_MASK 0x00000030
+#define BCM2836_WDOG_RSTC_WRCFG_FULL_RESET 0x00000020
+
+/* mailbox interface constants */
+#define BCM2836_MBOX_BASE_ADDRESS 0x3f00b880
+#define BCM2836_MBOX_READ_OFFSET 0x00000000
+#define BCM2836_MBOX_STATUS_OFFSET 0x00000018
+#define BCM2836_MBOX_CONFIG_OFFSET 0x0000001c
+#define BCM2836_MBOX_WRITE_OFFSET 0x00000020
+
+#define BCM2836_MBOX_STATUS_FULL 0x1f
+#define BCM2836_MBOX_STATUS_EMPTY 0x1e
+
+#define BCM2836_MBOX_NUM_CHANNELS 16
+
+/* interrupt controller constants */
+#define BCM2836_INTC_TIMER_CONTROL_OFFSET 0x00000040
+#define BCM2836_INTC_TIMER_PENDING_OFFSET 0x00000060
diff --git a/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836MmcHs.h b/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836MmcHs.h
new file mode 100644
index 000000000000..2bd1742fcdff
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836MmcHs.h
@@ -0,0 +1,199 @@
+/** @file
+ *
+ * Copyright (c) Microsoft Corporation. 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 __BCM2836SDIO_H__
+#define __BCM2836SDIO_H__
+
+//MMC/SD/SDIO1 register definitions.
+#define MMCHS1BASE 0x3F300000
+
+#define MMCHS_BLK (MMCHS1BASE + 0x4)
+#define BLEN_512BYTES (0x200UL << 0)
+
+#define MMCHS_ARG (MMCHS1BASE + 0x8)
+
+#define MMCHS_CMD (MMCHS1BASE + 0xC)
+#define BCE_ENABLE BIT1
+#define DDIR_READ BIT4
+#define DDIR_WRITE (0x0UL << 4)
+#define MSBS_SGLEBLK (0x0UL << 5)
+#define MSBS_MULTBLK BIT5
+#define RSP_TYPE_MASK (0x3UL << 16)
+#define RSP_TYPE_136BITS BIT16
+#define RSP_TYPE_48BITS (0x2UL << 16)
+#define RSP_TYPE_48BUSY (0x3UL << 16)
+#define CCCE_ENABLE BIT19
+#define CICE_ENABLE BIT20
+#define DP_ENABLE BIT21
+
+#define CMD_TYPE_NORMAL 0
+#define CMD_TYPE_ABORT 3
+#define TYPE(CMD_TYPE) (((CMD_TYPE) & 0x3) << 22)
+#define _INDX(CMD_INDX) ((CMD_INDX & 0x3F) << 24)
+#define MMC_CMD_NUM(CMD) (((CMD) >> 24) & 0x3F)
+#define INDX(CMD_INDX) (TYPE(CMD_TYPE_NORMAL) | _INDX(CMD_INDX))
+#define INDX_ABORT(CMD_INDX) (TYPE(CMD_TYPE_ABORT) | _INDX(CMD_INDX))
+
+#define MMCHS_RSP10 (MMCHS1BASE + 0x10)
+#define MMCHS_RSP32 (MMCHS1BASE + 0x14)
+#define MMCHS_RSP54 (MMCHS1BASE + 0x18)
+#define MMCHS_RSP76 (MMCHS1BASE + 0x1C)
+#define MMCHS_DATA (MMCHS1BASE + 0x20)
+
+#define MMCHS_PRES_STATE (MMCHS1BASE + 0x24)
+#define CMDI_MASK BIT0
+#define CMDI_ALLOWED (0x0UL << 0)
+#define CMDI_NOT_ALLOWED BIT0
+#define DATI_MASK BIT1
+#define DATI_ALLOWED (0x0UL << 1)
+#define DATI_NOT_ALLOWED BIT1
+#define WRITE_PROTECT_OFF BIT19
+
+#define MMCHS_HCTL (MMCHS1BASE + 0x28)
+#define DTW_1_BIT (0x0UL << 1)
+#define DTW_4_BIT BIT1
+#define SDBP_MASK BIT8
+#define SDBP_OFF (0x0UL << 8)
+#define SDBP_ON BIT8
+#define SDVS_1_8_V (0x5UL << 9)
+#define SDVS_3_0_V (0x6UL << 9)
+#define IWE BIT24
+
+#define MMCHS_SYSCTL (MMCHS1BASE + 0x2C)
+#define ICE BIT0
+#define ICS_MASK BIT1
+#define ICS BIT1
+#define CEN BIT2
+#define CLKD_MASK (0x3FFUL << 6)
+#define CLKD_80KHZ (0x258UL) //(96*1000/80)/2
+#define CLKD_400KHZ (0xF0UL)
+#define CLKD_12500KHZ (0x200UL)
+#define DTO_MASK (0xFUL << 16)
+#define DTO_VAL (0xEUL << 16)
+#define SRA BIT24
+#define SRC_MASK BIT25
+#define SRC BIT25
+#define SRD BIT26
+
+#define MMCHS_INT_STAT (MMCHS1BASE + 0x30)
+#define CC BIT0
+#define TC BIT1
+#define BWR BIT4
+#define BRR BIT5
+#define CARD_INS BIT6
+#define ERRI BIT15
+#define CTO BIT16
+#define DTO BIT20
+#define DCRC BIT21
+#define DEB BIT22
+
+#define MMCHS_IE (MMCHS1BASE + 0x34)
+#define CC_EN BIT0
+#define TC_EN BIT1
+#define BWR_EN BIT4
+#define BRR_EN BIT5
+#define CTO_EN BIT16
+#define CCRC_EN BIT17
+#define CEB_EN BIT18
+#define CIE_EN BIT19
+#define DTO_EN BIT20
+#define DCRC_EN BIT21
+#define DEB_EN BIT22
+#define CERR_EN BIT28
+#define BADA_EN BIT29
+#define ALL_EN 0xFFFFFFFF
+
+#define MMCHS_ISE (MMCHS1BASE + 0x38)
+#define CC_SIGEN BIT0
+#define TC_SIGEN BIT1
+#define BWR_SIGEN BIT4
+#define BRR_SIGEN BIT5
+#define CTO_SIGEN BIT16
+#define CCRC_SIGEN BIT17
+#define CEB_SIGEN BIT18
+#define CIE_SIGEN BIT19
+#define DTO_SIGEN BIT20
+#define DCRC_SIGEN BIT21
+#define DEB_SIGEN BIT22
+#define CERR_SIGEN BIT28
+#define BADA_SIGEN BIT29
+
+#define MMCHS_AC12 (MMCHS1BASE + 0x3C)
+
+#define MMCHS_CAPA (MMCHS1BASE + 0x40)
+#define VS30 BIT25
+#define VS18 BIT26
+
+#define MMCHS_CUR_CAPA (MMCHS1BASE + 0x48)
+#define MMCHS_REV (MMCHS1BASE + 0xFC)
+
+#define BLOCK_COUNT_SHIFT 16
+#define RCA_SHIFT 16
+
+#define CMD_R1 (RSP_TYPE_48BITS | CCCE_ENABLE | CICE_ENABLE)
+#define CMD_R1B (RSP_TYPE_48BUSY | CCCE_ENABLE | CICE_ENABLE)
+#define CMD_R2 (RSP_TYPE_136BITS | CCCE_ENABLE)
+#define CMD_R3 (RSP_TYPE_48BITS)
+#define CMD_R6 (RSP_TYPE_48BITS | CCCE_ENABLE | CICE_ENABLE)
+#define CMD_R7 (RSP_TYPE_48BITS | CCCE_ENABLE | CICE_ENABLE)
+
+#define CMD_R1_ADTC (CMD_R1 | DP_ENABLE)
+#define CMD_R1_ADTC_READ (CMD_R1_ADTC | DDIR_READ)
+#define CMD_R1_ADTC_WRITE (CMD_R1_ADTC | DDIR_WRITE)
+
+#define CMD0 (INDX(0)) // Go idle
+#define CMD1 (INDX(1) | CMD_R3) // MMC: Send Op Cond
+#define CMD2 (INDX(2) | CMD_R2) // Send CID
+#define CMD3 (INDX(3) | CMD_R6) // Set Relative Addr
+#define CMD4 (INDX(4)) // Set DSR
+#define CMD5 (INDX(5) | CMD_R1B) // SDIO: Sleep/Awake
+#define CMD6 (INDX(6) | CMD_R1_ADTC_READ) // Switch
+#define CMD7 (INDX(7) | CMD_R1B) // Select/Deselect
+#define CMD8_SD (INDX(8) | CMD_R7) // Send If Cond
+#define CMD8_SD_ARG (0x0UL << 12 | BIT8 | 0xCEUL << 0)
+#define CMD8_MMC (INDX(8) | CMD_R1_ADTC_READ) // Send Ext Csd
+#define CMD8_MMC_ARG (0)
+#define CMD9 (INDX(9) | CMD_R2) // Send CSD
+#define CMD10 (INDX(10) | CMD_R2) // Send CID
+#define CMD11 (INDX(11) | CMD_R1) // Voltage Switch
+#define CMD12 (INDX_ABORT(12) | CMD_R1B) // Stop Transmission
+#define CMD13 (INDX(13) | CMD_R1) // Send Status
+#define CMD15 (INDX(15)) // Go inactive state
+#define CMD16 (INDX(16) | CMD_R1) // Set Blocklen
+#define CMD17 (INDX(17) | CMD_R1_ADTC_READ) // Read Single Block
+#define CMD18 (INDX(18) | CMD_R1_ADTC_READ | MSBS_MULTBLK) // Read Multiple Blocks
+#define CMD19 (INDX(19) | CMD_R1_ADTC_READ) // SD: Send Tuning Block (64 bytes)
+#define CMD20 (INDX(20) | CMD_R1B) // SD: Speed Class Control
+#define CMD23 (INDX(23) | CMD_R1) // Set Block Count for CMD18 and CMD25
+#define CMD24 (INDX(24) | CMD_R1_ADTC_WRITE) // Write Block
+#define CMD25 (INDX(25) | CMD_R1_ADTC_WRITE | MSBS_MULTBLK) // Write Multiple Blocks
+#define CMD55 (INDX(55) | CMD_R1) // App Cmd
+
+#define ACMD6 (INDX(6) | CMD_R1) // Set Bus Width
+#define ACMD22 (INDX(22) | CMD_R1_ADTC_READ) // SEND_NUM_WR_BLOCKS
+#define ACMD41 (INDX(41) | CMD_R3) // Send Op Cond
+#define ACMD51 (INDX(51) | CMD_R1_ADTC_READ) // Send SCR
+
+// User-friendly command names
+#define CMD_IO_SEND_OP_COND CMD5
+#define CMD_SEND_CSD CMD9 // CSD: Card-Specific Data
+#define CMD_STOP_TRANSMISSION CMD12
+#define CMD_SEND_STATUS CMD13
+#define CMD_READ_SINGLE_BLOCK CMD17
+#define CMD_READ_MULTIPLE_BLOCK CMD18
+#define CMD_SET_BLOCK_COUNT CMD23
+#define CMD_WRITE_SINGLE_BLOCK CMD24
+#define CMD_WRITE_MULTIPLE_BLOCK CMD25
+
+#endif //__BCM2836SDIO_H__
diff --git a/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836SdHost.h b/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836SdHost.h
new file mode 100644
index 000000000000..fb3d6b5ccad3
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836SdHost.h
@@ -0,0 +1,92 @@
+/** @file
+ *
+ * Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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 __BCM2836SDHOST_H__
+#define __BCM2836SDHOST_H__
+
+#define SDHOST_BASE_ADDRESS (BCM2836_SOC_REGISTERS + 0x00202000)
+#define SDHOST_REG(X) (SDHOST_BASE_ADDRESS + (X))
+#define SDHOST_CMD SDHOST_REG(0x0)
+#define SDHOST_ARG SDHOST_REG(0x4)
+#define SDHOST_TOUT SDHOST_REG(0x8)
+#define SDHOST_CDIV SDHOST_REG(0xC)
+#define SDHOST_RSP0 SDHOST_REG(0x10) // [31:0]
+#define SDHOST_RSP1 SDHOST_REG(0x14) // [63:32]
+#define SDHOST_RSP2 SDHOST_REG(0x18) // [95:64]
+#define SDHOST_RSP3 SDHOST_REG(0x1C) // [127:96]
+#define SDHOST_HSTS SDHOST_REG(0x20)
+#define SDHOST_VDD SDHOST_REG(0x30)
+#define SDHOST_EDM SDHOST_REG(0x34)
+#define SDHOST_HCFG SDHOST_REG(0x38)
+#define SDHOST_HBCT SDHOST_REG(0x3C)
+#define SDHOST_DATA SDHOST_REG(0x40)
+#define SDHOST_HBLC SDHOST_REG(0x50)
+
+//
+// CMD
+//
+#define SDHOST_CMD_READ_CMD BIT6
+#define SDHOST_CMD_WRITE_CMD BIT7
+#define SDHOST_CMD_RESPONSE_CMD_LONG_RESP BIT9
+#define SDHOST_CMD_RESPONSE_CMD_NO_RESP BIT10
+#define SDHOST_CMD_BUSY_CMD BIT11
+#define SDHOST_CMD_FAIL_FLAG BIT14
+#define SDHOST_CMD_NEW_FLAG BIT15
+
+//
+// VDD
+//
+#define SDHOST_VDD_POWER_ON BIT0
+
+//
+// HSTS
+//
+#define SDHOST_HSTS_CLEAR 0x7F8
+#define SDHOST_HSTS_BLOCK_IRPT BIT9
+#define SDHOST_HSTS_REW_TIME_OUT BIT7
+#define SDHOST_HSTS_CMD_TIME_OUT BIT6
+#define SDHOST_HSTS_CRC16_ERROR BIT5
+#define SDHOST_HSTS_CRC7_ERROR BIT4
+#define SDHOST_HSTS_FIFO_ERROR BIT3
+#define SDHOST_HSTS_DATA_FLAG BIT0
+
+#define SDHOST_HSTS_TIMOUT_ERROR (SDHOST_HSTS_CMD_TIME_OUT | SDHOST_HSTS_REW_TIME_OUT)
+#define SDHOST_HSTS_TRANSFER_ERROR (SDHOST_HSTS_FIFO_ERROR | SDHOST_HSTS_CRC7_ERROR | SDHOST_HSTS_CRC16_ERROR)
+#define SDHOST_HSTS_ERROR (SDHOST_HSTS_TIMOUT_ERROR | SDHOST_HSTS_TRANSFER_ERROR)
+
+//
+// HCFG
+//
+#define SDHOST_HCFG_SLOW_CARD BIT3
+#define SDHOST_HCFG_WIDE_EXT_BUS BIT2
+#define SDHOST_HCFG_WIDE_INT_BUS BIT1
+#define SDHOST_HCFG_DATA_IRPT_EN BIT4
+#define SDHOST_HCFG_BLOCK_IRPT_EN BIT8
+#define SDHOST_HCFG_BUSY_IRPT_EN BIT10
+
+//
+// EDM
+//
+#define SDHOST_EDM_FIFO_CLEAR BIT21
+#define SDHOST_EDM_WRITE_THRESHOLD_SHIFT 9
+#define SDHOST_EDM_READ_THRESHOLD_SHIFT 14
+#define SDHOST_EDM_THRESHOLD_MASK 0x1F
+#define SDHOST_EDM_READ_THRESHOLD(X) ((X) << SDHOST_EDM_READ_THRESHOLD_SHIFT)
+#define SDHOST_EDM_WRITE_THRESHOLD(X) ((X) << SDHOST_EDM_WRITE_THRESHOLD_SHIFT)
+
+#define CMD8_SD_ARG (0x0UL << 12 | BIT8 | 0xCEUL << 0)
+#define CMD8_MMC_ARG (0)
+
+#endif //__BCM2836SDHOST_H__
diff --git a/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2837Gpio.h b/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2837Gpio.h
new file mode 100644
index 000000000000..27e6665f1745
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2837Gpio.h
@@ -0,0 +1,50 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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 __BCM2837GPIO_H__
+#define __BCM2837GPIO_H__
+
+#define GPIO_BASE_ADDRESS (BCM2836_SOC_REGISTERS + 0x00200000)
+
+#define GPIO_GPFSEL0 (GPIO_BASE_ADDRESS + 0x00)
+#define GPIO_GPFSEL1 (GPIO_BASE_ADDRESS + 0x04)
+#define GPIO_GPFSEL2 (GPIO_BASE_ADDRESS + 0x08)
+#define GPIO_GPFSEL3 (GPIO_BASE_ADDRESS + 0x0C)
+#define GPIO_GPFSEL4 (GPIO_BASE_ADDRESS + 0x10)
+#define GPIO_GPFSEL5 (GPIO_BASE_ADDRESS + 0x14)
+
+#define GPIO_GPCLR0 (GPIO_BASE_ADDRESS + 0x28)
+#define GPIO_GPCLR1 (GPIO_BASE_ADDRESS + 0x2C)
+
+#define GPIO_GPSET0 (GPIO_BASE_ADDRESS + 0x1C)
+#define GPIO_GPSET1 (GPIO_BASE_ADDRESS + 0x20)
+
+#define GPIO_FSEL_INPUT 0x0
+#define GPIO_FSEL_OUTPUT 0x1
+#define GPIO_FSEL_ALT0 0x4
+#define GPIO_FSEL_ALT1 0x5
+#define GPIO_FSEL_ALT2 0x6
+#define GPIO_FSEL_ALT3 0x7
+#define GPIO_FSEL_ALT4 0x3
+#define GPIO_FSEL_ALT5 0x2
+
+#define GPIO_FSEL_PINS_PER_REGISTER 10
+#define GPIO_FSEL_BITS_PER_PIN 3
+#define GPIO_FSEL_MASK ((1 << GPIO_FSEL_BITS_PER_PIN) - 1)
+
+#define GPIO_PINS 54
+
+#endif // __BCM2837GPIO_H__
+
diff --git a/Platform/Broadcom/Bcm283x/Include/IndustryStandard/RpiFirmware.h b/Platform/Broadcom/Bcm283x/Include/IndustryStandard/RpiFirmware.h
new file mode 100644
index 000000000000..83f8633c26cf
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/IndustryStandard/RpiFirmware.h
@@ -0,0 +1,93 @@
+/** @file
+ *
+ * Copyright (c) 2016, Linaro Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ **/
+
+#define RPI_FW_MBOX_CHANNEL 0x00000008
+
+#define RPI_FW_RESP_SUCCESS 0x80000000
+#define RPI_FW_RESP_FAILURE 0x80000001
+
+#define RPI_FW_VALUE_SIZE_RESPONSE_MASK BIT31
+
+#define RPI_FW_GET_REVISION 0x00000001
+#define RPI_FW_GET_BOARD_MODEL 0x00010001
+#define RPI_FW_GET_BOARD_REVISION 0x00010002
+#define RPI_FW_GET_MAC_ADDRESS 0x00010003
+#define RPI_FW_GET_BOARD_SERIAL 0x00010004
+#define RPI_FW_GET_ARM_MEMSIZE 0x00010005
+
+#define RPI_FW_SET_POWER_STATE 0x00028001
+
+#define RPI_FW_POWER_STATE_SDHCI 0x00000000
+#define RPI_FW_POWER_STATE_UART0 0x00000001
+#define RPI_FW_POWER_STATE_UART1 0x00000002
+#define RPI_FW_POWER_STATE_USB_HCD 0x00000003
+#define RPI_FW_POWER_STATE_I2C0 0x00000004
+#define RPI_FW_POWER_STATE_I2C1 0x00000005
+#define RPI_FW_POWER_STATE_I2C2 0x00000006
+#define RPI_FW_POWER_STATE_SPI 0x00000007
+#define RPI_FW_POWER_STATE_CCP2TX 0x00000008
+
+#define RPI_FW_GET_CLOCK_RATE 0x00030002
+#define RPI_FW_GET_MAX_CLOCK_RATE 0x00030004
+#define RPI_FW_GET_MIN_CLOCK_RATE 0x00030007
+
+#define RPI_FW_SET_CLOCK_RATE 0x00038002
+#define RPI_FW_SET_GPIO 0x00038041
+
+#define RPI_FW_GET_FB_GEOMETRY 0x00040003
+#define RPI_FW_GET_FB_LINELENGTH 0x00040008
+#define RPI_FW_GET_FB_COLOR_DEPTH 0x00040005
+#define RPI_FW_GET_FB_REGION 0x00040001
+
+#define RPI_FW_SET_FB_PGEOM 0x00048003
+#define RPI_FW_SET_FB_VGEOM 0x00048004
+#define RPI_FW_SET_FB_DEPTH 0x00048005
+#define RPI_FW_ALLOC_FB 0x00040001
+#define RPI_FW_FREE_FB 0x00048001
+
+#define RPI_FW_GET_COMMAND_LINE 0x00050001
+
+#define RPI_FW_POWER_STATE_ENABLE BIT0
+#define RPI_FW_POWER_STATE_WAIT BIT1
+
+#define RPI_FW_CLOCK_RATE_EMMC 0x000000001
+#define RPI_FW_CLOCK_RATE_UART 0x000000002
+#define RPI_FW_CLOCK_RATE_ARM 0x000000003
+#define RPI_FW_CLOCK_RATE_CORE 0x000000004
+#define RPI_FW_CLOCK_RATE_V3D 0x000000005
+#define RPI_FW_CLOCK_RATE_H264 0x000000006
+#define RPI_FW_CLOCK_RATE_ISP 0x000000007
+#define RPI_FW_CLOCK_RATE_SDRAM 0x000000008
+#define RPI_FW_CLOCK_RATE_PIXEL 0x000000009
+#define RPI_FW_CLOCK_RATE_PWM 0x00000000a
+
+#define RPI_FB_MBOX_CHANNEL 0x1
diff --git a/Platform/Broadcom/Bcm283x/Include/Library/GpioLib.h b/Platform/Broadcom/Bcm283x/Include/Library/GpioLib.h
new file mode 100644
index 000000000000..ca9da4b11a87
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/Library/GpioLib.h
@@ -0,0 +1,33 @@
+/** @file
+ *
+ * GPIO manipulation.
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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 __GPIO_LIB__
+#define __GPIO_LIB__
+
+#include <IndustryStandard/Bcm2837Gpio.h>
+
+VOID
+GpioPinFuncSet(
+ IN UINTN Pin,
+ IN UINTN Function
+ );
+
+UINTN
+GpioPinFuncGet(
+ IN UINTN Pin
+ );
+
+#endif /* __GPIO_LIB__ */
diff --git a/Platform/Broadcom/Bcm283x/Include/Protocol/DwUsb.h b/Platform/Broadcom/Bcm283x/Include/Protocol/DwUsb.h
new file mode 100644
index 000000000000..dfad80c719e1
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/Protocol/DwUsb.h
@@ -0,0 +1,53 @@
+/** @file
+ *
+ * Copyright (c) 2015-2016, Linaro. All rights reserved.
+ * Copyright (c) 2015-2016, Hisilicon 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 __DW_USB_H__
+#define __DW_USB_H__
+
+//
+// Protocol GUID
+//
+#define DW_USB_PROTOCOL_GUID { 0x109fa264, 0x7811, 0x4862, { 0xa9, 0x73, 0x4a, 0xb2, 0xef, 0x2e, 0xe2, 0xff }}
+
+//
+// Protocol interface structure
+//
+typedef struct _DW_USB_PROTOCOL DW_USB_PROTOCOL;
+
+#define USB_HOST_MODE 0
+#define USB_DEVICE_MODE 1
+#define USB_CABLE_NOT_ATTACHED 2
+
+typedef
+EFI_STATUS
+(EFIAPI *DW_USB_GET_SERIAL_NO) (
+ OUT CHAR16 *SerialNo,
+ OUT UINT8 *Length
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *DW_USB_PHY_INIT) (
+ IN UINT8 Mode
+ );
+
+struct _DW_USB_PROTOCOL {
+ DW_USB_GET_SERIAL_NO Get;
+ DW_USB_PHY_INIT PhyInit;
+};
+
+extern EFI_GUID gDwUsbProtocolGuid;
+
+#endif
diff --git a/Platform/Broadcom/Bcm283x/Include/Protocol/ExtendedTextOut.h b/Platform/Broadcom/Bcm283x/Include/Protocol/ExtendedTextOut.h
new file mode 100644
index 000000000000..35e82a17e922
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/Protocol/ExtendedTextOut.h
@@ -0,0 +1,36 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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 __EXTENDED_TEXT_OUT_H__
+#define __EXTENDED_TEXT_OUT_H__
+
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/GraphicsOutput.h>
+
+#define EXTENDED_TEXT_OUTPUT_PROTOCOL_GUID \
+ { \
+ 0x387477ff, 0xffc7, 0xffd2, {0x8e, 0x39, 0x0, 0xff, 0xc9, 0x69, 0x72, 0x3b } \
+ }
+
+typedef struct _EXTENDED_TEXT_OUTPUT_PROTOCOL EXTENDED_TEXT_OUTPUT_PROTOCOL;
+
+struct _EXTENDED_TEXT_OUTPUT_PROTOCOL {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ BOOLEAN AutoWrap;
+};
+
+extern EFI_GUID gExtendedTextOutputProtocolGuid;
+
+#endif /* __EXTENDED_TEXT_OUT__ */
diff --git a/Platform/Broadcom/Bcm283x/Include/Protocol/PiMmcHost.h b/Platform/Broadcom/Bcm283x/Include/Protocol/PiMmcHost.h
new file mode 100644
index 000000000000..c0e65687e8d4
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/Protocol/PiMmcHost.h
@@ -0,0 +1,187 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2011-2014, ARM 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 __PI_MMC_HOST_H__
+#define __PI_MMC_HOST_H__
+
+///
+/// Global ID for the MMC Host Protocol
+///
+#define RASPBERRY_PI_MMC_HOST_PROTOCOL_GUID \
+ { 0x3e591c00, 0x9e4a, 0x11df, {0x92, 0x44, 0x00, 0x02, 0xA5, 0xF5, 0xF5, 0x1B } }
+
+#define MMC_RESPONSE_TYPE_R1 0
+#define MMC_RESPONSE_TYPE_R1b 0
+#define MMC_RESPONSE_TYPE_R2 1
+#define MMC_RESPONSE_TYPE_R3 0
+#define MMC_RESPONSE_TYPE_R6 0
+#define MMC_RESPONSE_TYPE_R7 0
+#define MMC_RESPONSE_TYPE_OCR 0
+#define MMC_RESPONSE_TYPE_CID 1
+#define MMC_RESPONSE_TYPE_CSD 1
+#define MMC_RESPONSE_TYPE_RCA 0
+
+typedef UINT32 MMC_RESPONSE_TYPE;
+
+typedef UINT32 MMC_CMD;
+
+#define MMC_CMD_WAIT_RESPONSE (1 << 16)
+#define MMC_CMD_LONG_RESPONSE (1 << 17)
+#define MMC_CMD_NO_CRC_RESPONSE (1 << 18)
+
+#define MMC_INDX(Index) ((Index) & 0xFFFF)
+#define MMC_GET_INDX(MmcCmd) ((MmcCmd) & 0xFFFF)
+
+#define MMC_CMD0 (MMC_INDX(0) | MMC_CMD_NO_CRC_RESPONSE)
+#define MMC_CMD1 (MMC_INDX(1) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE)
+#define MMC_CMD2 (MMC_INDX(2) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_LONG_RESPONSE)
+#define MMC_CMD3 (MMC_INDX(3) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD5 (MMC_INDX(5) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE)
+#define MMC_CMD6 (MMC_INDX(6) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD7 (MMC_INDX(7) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD8 (MMC_INDX(8) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD9 (MMC_INDX(9) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_LONG_RESPONSE)
+#define MMC_CMD11 (MMC_INDX(11) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD12 (MMC_INDX(12) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD13 (MMC_INDX(13) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD16 (MMC_INDX(16) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD17 (MMC_INDX(17) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD18 (MMC_INDX(18) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD20 (MMC_INDX(20) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD23 (MMC_INDX(23) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD24 (MMC_INDX(24) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD25 (MMC_INDX(25) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_CMD55 (MMC_INDX(55) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_ACMD22 (MMC_INDX(22) | MMC_CMD_WAIT_RESPONSE)
+#define MMC_ACMD41 (MMC_INDX(41) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE)
+#define MMC_ACMD51 (MMC_INDX(51) | MMC_CMD_WAIT_RESPONSE)
+
+// Valid responses for CMD1 in eMMC
+#define EMMC_CMD1_CAPACITY_LESS_THAN_2GB 0x00FF8080 // Capacity <= 2GB, byte addressing used
+#define EMMC_CMD1_CAPACITY_GREATER_THAN_2GB 0x40FF8080 // Capacity > 2GB, 512-byte sector addressing used
+
+#define MMC_STATUS_APP_CMD (1 << 5)
+
+typedef enum _MMC_STATE {
+ MmcInvalidState = 0,
+ MmcHwInitializationState,
+ MmcIdleState,
+ MmcReadyState,
+ MmcIdentificationState,
+ MmcStandByState,
+ MmcTransferState,
+ MmcSendingDataState,
+ MmcReceiveDataState,
+ MmcProgrammingState,
+ MmcDisconnectState,
+} MMC_STATE;
+
+#define EMMCBACKWARD (0)
+#define EMMCHS26 (1 << 0) // High-Speed @26MHz at rated device voltages
+#define EMMCHS52 (1 << 1) // High-Speed @52MHz at rated device voltages
+#define EMMCHS52DDR1V8 (1 << 2) // High-Speed Dual Data Rate @52MHz 1.8V or 3V I/O
+#define EMMCHS52DDR1V2 (1 << 3) // High-Speed Dual Data Rate @52MHz 1.2V I/O
+#define EMMCHS200SDR1V8 (1 << 4) // HS200 Single Data Rate @200MHz 1.8V I/O
+#define EMMCHS200SDR1V2 (1 << 5) // HS200 Single Data Rate @200MHz 1.2V I/O
+#define EMMCHS400DDR1V8 (1 << 6) // HS400 Dual Data Rate @400MHz 1.8V I/O
+#define EMMCHS400DDR1V2 (1 << 7) // HS400 Dual Data Rate @400MHz 1.2V I/O
+
+///
+/// Forward declaration for EFI_MMC_HOST_PROTOCOL
+///
+typedef struct _EFI_MMC_HOST_PROTOCOL EFI_MMC_HOST_PROTOCOL;
+
+typedef BOOLEAN (EFIAPI *MMC_ISCARDPRESENT) (
+ IN EFI_MMC_HOST_PROTOCOL *This
+ );
+
+typedef BOOLEAN (EFIAPI *MMC_ISREADONLY) (
+ IN EFI_MMC_HOST_PROTOCOL *This
+ );
+
+typedef EFI_STATUS (EFIAPI *MMC_BUILDDEVICEPATH) (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+typedef EFI_STATUS (EFIAPI *MMC_NOTIFYSTATE) (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_STATE State
+ );
+
+typedef EFI_STATUS (EFIAPI *MMC_SENDCOMMAND) (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_CMD Cmd,
+ IN UINT32 Argument
+ );
+
+typedef EFI_STATUS (EFIAPI *MMC_RECEIVERESPONSE) (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_RESPONSE_TYPE Type,
+ IN UINT32 *Buffer
+ );
+
+typedef EFI_STATUS (EFIAPI *MMC_READBLOCKDATA) (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Length,
+ OUT UINT32 *Buffer
+ );
+
+typedef EFI_STATUS (EFIAPI *MMC_WRITEBLOCKDATA) (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Length,
+ IN UINT32 *Buffer
+ );
+
+typedef EFI_STATUS (EFIAPI *MMC_SETIOS) (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN UINT32 BusClockFreq,
+ IN UINT32 BusWidth,
+ IN UINT32 TimingMode
+ );
+
+typedef BOOLEAN (EFIAPI *MMC_ISMULTIBLOCK) (
+ IN EFI_MMC_HOST_PROTOCOL *This
+ );
+
+struct _EFI_MMC_HOST_PROTOCOL {
+ UINT32 Revision;
+ MMC_ISCARDPRESENT IsCardPresent;
+ MMC_ISREADONLY IsReadOnly;
+ MMC_BUILDDEVICEPATH BuildDevicePath;
+
+ MMC_NOTIFYSTATE NotifyState;
+
+ MMC_SENDCOMMAND SendCommand;
+ MMC_RECEIVERESPONSE ReceiveResponse;
+
+ MMC_READBLOCKDATA ReadBlockData;
+ MMC_WRITEBLOCKDATA WriteBlockData;
+
+ MMC_SETIOS SetIos;
+ MMC_ISMULTIBLOCK IsMultiBlock;
+};
+
+#define MMC_HOST_PROTOCOL_REVISION 0x00010002 // 1.2
+
+#define MMC_HOST_HAS_SETIOS(Host) (Host->Revision >= MMC_HOST_PROTOCOL_REVISION && \
+ Host->SetIos != NULL)
+#define MMC_HOST_HAS_ISMULTIBLOCK(Host) (Host->Revision >= MMC_HOST_PROTOCOL_REVISION && \
+ Host->IsMultiBlock != NULL)
+
+#endif
+
diff --git a/Platform/Broadcom/Bcm283x/Include/Protocol/RaspberryPiFirmware.h b/Platform/Broadcom/Bcm283x/Include/Protocol/RaspberryPiFirmware.h
new file mode 100644
index 000000000000..2a4247584641
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/Protocol/RaspberryPiFirmware.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
diff --git a/Platform/Broadcom/Bcm283x/Include/Utils.h b/Platform/Broadcom/Bcm283x/Include/Utils.h
new file mode 100644
index 000000000000..47713275de3f
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Include/Utils.h
@@ -0,0 +1,33 @@
+/** @file
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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 UTILS_H
+#define UTILS_H
+
+#define _IX_BITS(sm, bg) ((bg) - (sm) + 1)
+#define _IX_MASK(sm, bg) ((1ul << _IX_BITS((sm), (bg))) - 1)
+#define _X(val, sm, bg) ((val) >> (sm)) & _IX_MASK((sm), (bg))
+#define X(val, ix1, ix2) (((ix1) < (ix2)) ? _X((val), (ix1), (ix2)) : \
+ _X((val), (ix2), (ix1)))
+
+#define _I(val, sm, bg) (((val) & _IX_MASK((sm), (bg))) << (sm))
+#define I(val, ix1, ix2) (((ix1) < (ix2)) ? _I((val), (ix1), (ix2)) : \
+ _I((val), (ix2), (ix1)))
+#define _M(val, sm, bg) ((val) & (_IX_MASK((sm), (bg)) << (sm)))
+#define M(val, ix1, ix2) (((ix1) < (ix2)) ? _M((val), (ix1), (ix2)) : \
+ _M((val), (ix2), (ix1)))
+
+#define ELES(x) (sizeof((x)) / sizeof((x)[0]))
+
+#endif /* UTILS_H */
diff --git a/Platform/Broadcom/Bcm283x/Library/GpioLib/GpioLib.c b/Platform/Broadcom/Bcm283x/Library/GpioLib/GpioLib.c
new file mode 100644
index 000000000000..db38acefb7c3
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/GpioLib/GpioLib.c
@@ -0,0 +1,79 @@
+/** @file
+ *
+ * GPIO manipulation.
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ *
+ * 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 <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/GpioLib.h>
+#include <IndustryStandard/Bcm2836.h>
+#include <Utils.h>
+
+STATIC VOID
+GpioFSELModify(
+ IN UINTN RegIndex,
+ IN UINT32 ModifyMask,
+ IN UINT32 FunctionMask
+ )
+{
+ UINT32 Val;
+ EFI_PHYSICAL_ADDRESS Reg = RegIndex * sizeof(UINT32) + GPIO_GPFSEL0;
+
+ ASSERT(Reg <= GPIO_GPFSEL5);
+ ASSERT((~ModifyMask & FunctionMask) == 0);
+
+ Val = MmioRead32(Reg);
+ Val &= ~ModifyMask;
+ Val |= FunctionMask;
+ MmioWrite32(Reg, Val);
+}
+
+VOID
+GpioPinFuncSet(
+ IN UINTN Pin,
+ IN UINTN Function
+ )
+{
+ UINTN RegIndex = Pin / 10;
+ UINTN SelIndex = Pin % 10;
+ UINT32 ModifyMask;
+ UINT32 FunctionMask;
+
+ ASSERT(Pin < GPIO_PINS);
+ ASSERT(Function <= GPIO_FSEL_MASK);
+
+ ModifyMask = GPIO_FSEL_MASK << (SelIndex * GPIO_FSEL_BITS_PER_PIN);
+ FunctionMask = Function << (SelIndex * GPIO_FSEL_BITS_PER_PIN);
+ GpioFSELModify(RegIndex, ModifyMask, FunctionMask);
+}
+
+UINTN
+GpioPinFuncGet(
+ IN UINTN Pin
+ )
+{
+ UINT32 Val;
+ UINTN RegIndex = Pin / 10;
+ UINTN SelIndex = Pin % 10;
+ EFI_PHYSICAL_ADDRESS Reg = RegIndex * sizeof(UINT32) + GPIO_GPFSEL0;
+
+ ASSERT(Pin < GPIO_PINS);
+
+ Val = MmioRead32(Reg);
+ Val >>= SelIndex * GPIO_FSEL_BITS_PER_PIN;
+ Val &= GPIO_FSEL_MASK;
+ return Val;
+}
diff --git a/Platform/Broadcom/Bcm283x/Library/GpioLib/GpioLib.inf b/Platform/Broadcom/Bcm283x/Library/GpioLib/GpioLib.inf
new file mode 100644
index 000000000000..82114568b0a6
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/GpioLib/GpioLib.inf
@@ -0,0 +1,39 @@
+#/** @file
+#
+# Manipulate GPIOs.
+#
+# Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+#
+# 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 = 0x00010005
+ BASE_NAME = GpioLib
+ FILE_GUID = B9F59B6B-B105-41C7-8F5A-2C60DD7FD7AB
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = GpioLib
+
+[Sources]
+ GpioLib.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ IoLib
+
+[Guids]
diff --git a/Platform/Broadcom/Bcm283x/Library/MemoryInitPeiLib/MemoryInitPeiLib.c b/Platform/Broadcom/Bcm283x/Library/MemoryInitPeiLib/MemoryInitPeiLib.c
new file mode 100644
index 000000000000..81d810b5d428
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/MemoryInitPeiLib/MemoryInitPeiLib.c
@@ -0,0 +1,183 @@
+/** @file
+ *
+ * Copyright (c) 2017-2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2011-2015, ARM 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.
+ *
+ **/
+
+#include <PiPei.h>
+
+#include <Library/ArmMmuLib.h>
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+
+extern UINT64 mSystemMemoryEnd;
+
+VOID
+BuildMemoryTypeInformationHob (
+ VOID
+ );
+
+STATIC
+VOID
+InitMmu (
+ IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable
+ )
+{
+
+ VOID *TranslationTableBase;
+ UINTN TranslationTableSize;
+ RETURN_STATUS Status;
+
+ //Note: Because we called PeiServicesInstallPeiMemory() before to call InitMmu() the MMU Page Table resides in
+ // DRAM (even at the top of DRAM as it is the first permanent memory allocation)
+ Status = ArmConfigureMmu (MemoryTable, &TranslationTableBase, &TranslationTableSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Error: Failed to enable MMU\n"));
+ }
+}
+
+STATIC
+VOID
+AddAndRTSData(ARM_MEMORY_REGION_DESCRIPTOR *Desc)
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ Desc->PhysicalBase,
+ Desc->Length
+ );
+
+ BuildMemoryAllocationHob (
+ Desc->PhysicalBase,
+ Desc->Length,
+ EfiRuntimeServicesData
+ );
+}
+
+STATIC
+VOID
+AddAndReserved(ARM_MEMORY_REGION_DESCRIPTOR *Desc)
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ Desc->PhysicalBase,
+ Desc->Length
+ );
+
+ BuildMemoryAllocationHob (
+ Desc->PhysicalBase,
+ Desc->Length,
+ EfiReservedMemoryType
+ );
+}
+
+STATIC
+VOID
+AddAndMmio(ARM_MEMORY_REGION_DESCRIPTOR *Desc)
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ (EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED),
+ Desc->PhysicalBase,
+ Desc->Length
+ );
+
+ BuildMemoryAllocationHob (
+ Desc->PhysicalBase,
+ Desc->Length,
+ EfiMemoryMappedIO
+ );
+}
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ FileHandle - Handle of the file being invoked.
+ PeiServices - Describes the list of possible PEI Services.
+
+Returns:
+
+ Status - EFI_SUCCESS if the boot mode could be set
+
+--*/
+EFI_STATUS
+EFIAPI
+MemoryPeim (
+ IN EFI_PHYSICAL_ADDRESS UefiMemoryBase,
+ IN UINT64 UefiMemorySize
+ )
+{
+ ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable;
+
+ // Get Virtual Memory Map from the Platform Library
+ ArmPlatformGetVirtualMemoryMap (&MemoryTable);
+
+ // Ensure PcdSystemMemorySize has been set
+ ASSERT (PcdGet64 (PcdSystemMemorySize) != 0);
+
+ // FD without variable store
+ AddAndReserved(&MemoryTable[0]);
+
+ // Variable store.
+ AddAndRTSData(&MemoryTable[1]);
+
+ // Trusted Firmware region
+ AddAndReserved(&MemoryTable[2]);
+
+ // Usable memory.
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ MemoryTable[3].PhysicalBase,
+ MemoryTable[3].Length
+ );
+
+ AddAndReserved(&MemoryTable[4]);
+ AddAndMmio(&MemoryTable[5]);
+
+ // Build Memory Allocation Hob
+ InitMmu (MemoryTable);
+
+ if (FeaturePcdGet (PcdPrePiProduceMemoryTypeInformationHob)) {
+ // Optional feature that helps prevent EFI memory map fragmentation.
+ BuildMemoryTypeInformationHob ();
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Broadcom/Bcm283x/Library/MemoryInitPeiLib/MemoryInitPeiLib.inf b/Platform/Broadcom/Bcm283x/Library/MemoryInitPeiLib/MemoryInitPeiLib.inf
new file mode 100644
index 000000000000..9f5204a210de
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/MemoryInitPeiLib/MemoryInitPeiLib.inf
@@ -0,0 +1,51 @@
+#/** @file
+#
+# Copyright (c) 2016, Linaro, Ltd. All rights reserved.
+# Copyright (c) 2011-2014, ARM 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 = 0x00010005
+ BASE_NAME = MemoryInitPeiLib
+ FILE_GUID = 4bbc9c10-a100-43fb-8311-332ba497d1b4
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemoryInitPeiLib|SEC PEIM
+
+[Sources]
+ MemoryInitPeiLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ HobLib
+ ArmMmuLib
+ ArmPlatformLib
+
+[Guids]
+ gEfiMemoryTypeInformationGuid
+
+[FeaturePcd]
+ gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob
+
+[FixedPcd]
+ gArmTokenSpaceGuid.PcdSystemMemoryBase
+ gArmTokenSpaceGuid.PcdSystemMemorySize
+
+[Depex]
+ TRUE
diff --git a/Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBm.c b/Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBm.c
new file mode 100644
index 000000000000..58eeb117c769
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBm.c
@@ -0,0 +1,831 @@
+/** @file
+ *
+ * Copyright (c) 2018, Pete Batard <pete@akeo.ie>
+ * Copyright (c) 2017-2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2016, Linaro Ltd. All rights reserved.
+ * Copyright (c) 2015-2016, Red Hat, Inc.
+ * Copyright (c) 2014, ARM Ltd. All rights reserved.
+ * Copyright (c) 2004-2016, Intel Corporation. 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 <Library/BootLogoLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/EsrtManagement.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/LoadedImage.h>
+#include <Guid/EventGroup.h>
+#include <Guid/TtyTerm.h>
+#include <Protocol/BootLogo.h>
+
+#include "PlatformBm.h"
+
+#define BOOT_PROMPT L"ESC (setup), F1 (shell), ENTER (boot)"
+
+#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
+
+#pragma pack (1)
+typedef struct {
+ VENDOR_DEVICE_PATH SerialDxe;
+ UART_DEVICE_PATH Uart;
+ VENDOR_DEFINED_DEVICE_PATH TermType;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_SERIAL_CONSOLE;
+#pragma pack ()
+
+typedef struct {
+ VENDOR_DEVICE_PATH Custom;
+ USB_DEVICE_PATH Hub;
+ USB_DEVICE_PATH Dev;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} PLATFORM_USB_DEV;
+
+typedef struct {
+ VENDOR_DEVICE_PATH Custom;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} PLATFORM_SD_DEV;
+
+#define DW_USB_DXE_FILE_GUID { \
+ 0x4bf1704c, 0x03f4, 0x46d5, \
+ { 0xbc, 0xa6, 0x82, 0xfa, 0x58, 0x0b, 0xad, 0xfd } \
+ }
+
+#define ARASAN_MMC_DXE_FILE_GUID { \
+ 0x100c2cfa, 0xb586, 0x4198, \
+ { 0x9b, 0x4c, 0x16, 0x83, 0xd1, 0x95, 0xb1, 0xda } \
+ }
+
+#define SDHOST_MMC_DXE_FILE_GUID { \
+ 0x58abd787, 0xf64d, 0x4ca2, \
+ { 0xa0, 0x34, 0xb9, 0xac, 0x2d, 0x5a, 0xd0, 0xcf } \
+ }
+
+STATIC PLATFORM_SD_DEV mArasan = {
+ //
+ // VENDOR_DEVICE_PATH ArasanMMCHostDxe
+ //
+ {
+ { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
+ ARASAN_MMC_DXE_FILE_GUID
+ },
+
+ //
+ // EFI_DEVICE_PATH_PROTOCOL End
+ //
+ {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+ }
+};
+
+STATIC PLATFORM_SD_DEV mSDHost = {
+ //
+ // VENDOR_DEVICE_PATH SdHostDxe
+ //
+ {
+ { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
+ SDHOST_MMC_DXE_FILE_GUID
+ },
+
+ //
+ // EFI_DEVICE_PATH_PROTOCOL End
+ //
+ {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+ }
+};
+
+STATIC PLATFORM_USB_DEV mUsbHubPort = {
+ //
+ // VENDOR_DEVICE_PATH DwUsbHostDxe
+ //
+ {
+ { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
+ DW_USB_DXE_FILE_GUID
+ },
+
+ //
+ // USB_DEVICE_PATH Hub
+ //
+ {
+ { MESSAGING_DEVICE_PATH, MSG_USB_DP, DP_NODE_LEN (USB_DEVICE_PATH) },
+ 0, 0
+ },
+
+ //
+ // USB_DEVICE_PATH Dev
+ //
+ {
+ { MESSAGING_DEVICE_PATH, MSG_USB_DP, DP_NODE_LEN (USB_DEVICE_PATH) },
+ 1, 0
+ },
+
+ //
+ // EFI_DEVICE_PATH_PROTOCOL End
+ //
+ {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+ }
+};
+
+#define SERIAL_DXE_FILE_GUID { \
+ 0xD3987D4B, 0x971A, 0x435F, \
+ { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
+ }
+
+STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
+ //
+ // VENDOR_DEVICE_PATH SerialDxe
+ //
+ {
+ { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
+ SERIAL_DXE_FILE_GUID
+ },
+
+ //
+ // UART_DEVICE_PATH Uart
+ //
+ {
+ { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
+ 0, // Reserved
+ FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
+ FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
+ FixedPcdGet8 (PcdUartDefaultParity), // Parity
+ FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
+ },
+
+ //
+ // VENDOR_DEFINED_DEVICE_PATH TermType
+ //
+ {
+ {
+ MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
+ DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
+ }
+ //
+ // Guid to be filled in dynamically
+ //
+ },
+
+ //
+ // EFI_DEVICE_PATH_PROTOCOL End
+ //
+ {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+ }
+};
+
+
+#pragma pack (1)
+typedef struct {
+ USB_CLASS_DEVICE_PATH Keyboard;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_USB_KEYBOARD;
+#pragma pack ()
+
+STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
+ //
+ // USB_CLASS_DEVICE_PATH Keyboard
+ //
+ {
+ {
+ MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
+ DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
+ },
+ 0xFFFF, // VendorId: any
+ 0xFFFF, // ProductId: any
+ 3, // DeviceClass: HID
+ 1, // DeviceSubClass: boot
+ 1 // DeviceProtocol: keyboard
+ },
+
+ //
+ // EFI_DEVICE_PATH_PROTOCOL End
+ //
+ {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+ }
+};
+
+STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mSerialConProtocol;
+
+/**
+ Check if the handle satisfies a particular condition.
+
+ @param[in] Handle The handle to check.
+ @param[in] ReportText A caller-allocated string passed in for reporting
+ purposes. It must never be NULL.
+
+ @retval TRUE The condition is satisfied.
+ @retval FALSE Otherwise. This includes the case when the condition could not
+ be fully evaluated due to an error.
+**/
+typedef
+BOOLEAN
+(EFIAPI *FILTER_FUNCTION) (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ );
+
+
+/**
+ Process a handle.
+
+ @param[in] Handle The handle to process.
+ @param[in] ReportText A caller-allocated string passed in for reporting
+ purposes. It must never be NULL.
+**/
+typedef
+VOID
+(EFIAPI *CALLBACK_FUNCTION) (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ );
+
+/**
+ Locate all handles that carry the specified protocol, filter them with a
+ callback function, and pass each handle that passes the filter to another
+ callback.
+
+ @param[in] ProtocolGuid The protocol to look for.
+
+ @param[in] Filter The filter function to pass each handle to. If this
+ parameter is NULL, then all handles are processed.
+
+ @param[in] Process The callback function to pass each handle to that
+ clears the filter.
+**/
+STATIC
+VOID
+FilterAndProcess (
+ IN EFI_GUID *ProtocolGuid,
+ IN FILTER_FUNCTION Filter OPTIONAL,
+ IN CALLBACK_FUNCTION Process
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN NoHandles;
+ UINTN Idx;
+
+ Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,
+ NULL /* SearchKey */, &NoHandles, &Handles);
+ if (EFI_ERROR (Status)) {
+ //
+ // This is not an error, just an informative condition.
+ //
+ DEBUG ((DEBUG_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,
+ Status));
+ return;
+ }
+
+ ASSERT (NoHandles > 0);
+ for (Idx = 0; Idx < NoHandles; ++Idx) {
+ CHAR16 *DevicePathText;
+ STATIC CHAR16 Fallback[] = L"<device path unavailable>";
+
+ //
+ // The ConvertDevicePathToText() function handles NULL input transparently.
+ //
+ DevicePathText = ConvertDevicePathToText (
+ DevicePathFromHandle (Handles[Idx]),
+ FALSE, // DisplayOnly
+ FALSE // AllowShortcuts
+ );
+ if (DevicePathText == NULL) {
+ DevicePathText = Fallback;
+ }
+
+ if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {
+ Process (Handles[Idx], DevicePathText);
+ }
+
+ if (DevicePathText != Fallback) {
+ FreePool (DevicePathText);
+ }
+ }
+ gBS->FreePool (Handles);
+}
+
+/**
+ This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
+ handle, and adds it to ConOut and ErrOut.
+**/
+STATIC
+VOID
+EFIAPI
+AddOutput (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ DevicePath = DevicePathFromHandle (Handle);
+ if (DevicePath == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: %s: handle %p: device path not found\n",
+ __FUNCTION__, ReportText, Handle));
+ return;
+ }
+
+ Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,
+ ReportText, Status));
+ return;
+ }
+
+ Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,
+ ReportText, Status));
+ return;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,
+ ReportText));
+}
+
+STATIC
+INTN
+PlatformRegisterBootOption (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ CHAR16 *Description,
+ UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ INTN OptionIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &NewOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ Attributes,
+ Description,
+ DevicePath,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ BootOptions = EfiBootManagerGetLoadOptions (
+ &BootOptionCount, LoadOptionTypeBoot
+ );
+
+ OptionIndex = EfiBootManagerFindLoadOption (
+ &NewOption, BootOptions, BootOptionCount
+ );
+
+ if (OptionIndex == -1) {
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
+ ASSERT_EFI_ERROR (Status);
+ OptionIndex = BootOptionCount;
+ }
+
+ EfiBootManagerFreeLoadOption (&NewOption);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+
+ return OptionIndex;
+}
+
+STATIC
+INTN
+PlatformRegisterFvBootOption (
+ CONST EFI_GUID *FileGuid,
+ CHAR16 *Description,
+ UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ INTN OptionIndex;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
+ DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
+ ASSERT (DevicePath != NULL);
+ DevicePath = AppendDevicePathNode (
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
+ );
+ ASSERT (DevicePath != NULL);
+
+ OptionIndex = PlatformRegisterBootOption (DevicePath,
+ Description,
+ Attributes);
+ FreePool (DevicePath);
+
+ return OptionIndex;
+}
+
+
+STATIC
+VOID
+PlatformRegisterOptionsAndKeys (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Enter;
+ EFI_INPUT_KEY F1;
+ EFI_INPUT_KEY Esc;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+ INTN ShellOption;
+
+ ShellOption = PlatformRegisterFvBootOption (&gUefiShellFileGuid, L"UEFI Shell",
+ LOAD_OPTION_ACTIVE);
+ if (ShellOption != -1) {
+ //
+ // F1 boots Shell.
+ //
+ F1.ScanCode = SCAN_F1;
+ F1.UnicodeChar = CHAR_NULL;
+ Status = EfiBootManagerAddKeyOptionVariable (
+ NULL, (UINT16) ShellOption, 0, &F1, NULL);
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+ }
+
+ //
+ // Register ENTER as CONTINUE key
+ //
+ Enter.ScanCode = SCAN_NULL;
+ Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
+ Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Map ESC to Boot Manager Menu
+ //
+ Esc.ScanCode = SCAN_ESC;
+ Esc.UnicodeChar = CHAR_NULL;
+ Status = EfiBootManagerGetBootManagerMenu (&BootOption);
+ ASSERT_EFI_ERROR (Status);
+ Status = EfiBootManagerAddKeyOptionVariable (
+ NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
+ );
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+}
+
+STATIC VOID
+SerialConPrint (
+ IN CHAR16 *Text
+ )
+{
+ if (mSerialConProtocol != NULL) {
+ mSerialConProtocol->OutputString (mSerialConProtocol, Text);
+ }
+}
+
+STATIC VOID EFIAPI
+ExitBootServicesHandler (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *OsBootStr;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Green;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Yellow;
+ //
+ // Long enough to occlude the string printed
+ // in PlatformBootManagerWaitCallback.
+ //
+ STATIC CHAR16 *OsBootStrEL1 = L"Exiting UEFI and booting EL1 OS kernel!\r\n";
+ STATIC CHAR16 *OsBootStrEL2 = L"Exiting UEFI and booting EL2 OS kernel!\r\n";
+
+ if (!PcdGet32 (PcdDebugShowUEFIExit)) {
+ return;
+ }
+
+ if (PcdGet32 (PcdHypEnable)) {
+ OsBootStr = OsBootStrEL1;
+ } else {
+ OsBootStr = OsBootStrEL2;
+ }
+
+ Green.Raw = 0x00007F00;
+ Black.Raw = 0x00000000;
+ Yellow.Raw = 0x00FFFF00;
+
+ Status = BootLogoUpdateProgress (Yellow.Pixel,
+ Black.Pixel,
+ OsBootStr,
+ Green.Pixel,
+ 100, 0);
+ if (Status == EFI_SUCCESS) {
+ SerialConPrint(OsBootStr);
+ } else {
+ Print(L"\n");
+ Print(OsBootStr);
+ Print(L"\n");
+ }
+}
+
+//
+// BDS Platform Functions
+//
+/**
+ Do the platform init, can be customized by OEM/IBV
+ Possible things that can be done in PlatformBootManagerBeforeConsole:
+ > Update console variable: 1. include hot-plug devices;
+ > 2. Clear ConIn and add SOL for AMT
+ > Register new Driver#### or Boot####
+ > Register new Key####: e.g.: F12
+ > Signal ReadyToLock event
+ > Authentication action: 1. connect Auth devices;
+ > 2. Identify auto logon user.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ExitBSEvent;
+ ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ExitBootServicesHandler,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &ExitBSEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to register ExitBootServices handler\n",
+ __FUNCTION__));
+ }
+
+ if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE) {
+ DEBUG ((DEBUG_INFO, "ProcessCapsules Before EndOfDxe ......\n"));
+ Status = ProcessCapsules ();
+ DEBUG ((DEBUG_INFO, "ProcessCapsules returned %r\n", Status));
+ } else {
+ Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL,
+ (VOID **)&EsrtManagement);
+ if (!EFI_ERROR (Status)) {
+ EsrtManagement->SyncEsrtFmp ();
+ }
+ }
+
+ //
+ // Now add the device path of all handles with GOP on them to ConOut and
+ // ErrOut.
+ //
+ FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
+
+ //
+ // Add the hardcoded short-form USB keyboard device path to ConIn.
+ //
+ EfiBootManagerUpdateConsoleVariable (ConIn,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
+
+ //
+ // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
+ //
+ ASSERT (FixedPcdGet8 (PcdDefaultTerminalType) == 4);
+ CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
+
+ EfiBootManagerUpdateConsoleVariable (ConIn,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
+ EfiBootManagerUpdateConsoleVariable (ConOut,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
+ EfiBootManagerUpdateConsoleVariable (ErrOut,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
+
+ //
+ // Signal EndOfDxe PI Event
+ //
+ EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
+
+ //
+ // Dispatch deferred images after EndOfDxe event and ReadyToLock installation.
+ //
+ EfiBootManagerDispatchDeferredImages ();
+}
+
+/**
+ Do the platform specific action after the console is ready
+ Possible things that can be done in PlatformBootManagerAfterConsole:
+ > Console post action:
+ > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
+ > Signal console ready platform customized event
+ > Run diagnostics like memory testing
+ > Connect certain devices
+ > Dispatch aditional option roms
+ > Special boot: e.g.: USB boot, enter UI
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+ VOID
+ )
+{
+ UINTN Index;
+ ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
+ EFI_STATUS Status;
+ EFI_HANDLE SerialHandle;
+
+ Status = EfiBootManagerConnectDevicePath((EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, &SerialHandle);
+ if (Status == EFI_SUCCESS) {
+ gBS->HandleProtocol(SerialHandle, &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &mSerialConProtocol);
+ }
+
+ //
+ // Show the splash screen.
+ //
+ Status = BootLogoEnableLogo ();
+ if (Status == EFI_SUCCESS) {
+ SerialConPrint(BOOT_PROMPT);
+ } else {
+ Print(BOOT_PROMPT);
+ }
+
+ //
+ // Connect the rest of the devices.
+ //
+ EfiBootManagerConnectAll ();
+
+ Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL,
+ (VOID **)&EsrtManagement);
+ if (!EFI_ERROR (Status)) {
+ EsrtManagement->SyncEsrtFmp ();
+ }
+
+ if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE) {
+ DEBUG((DEBUG_INFO, "ProcessCapsules After EndOfDxe ......\n"));
+ Status = ProcessCapsules ();
+ DEBUG((DEBUG_INFO, "ProcessCapsules returned %r\n", Status));
+ }
+
+ for (Index = 1; Index < 5; Index++) {
+ UINT16 Desc[11];
+ /*
+ * Add boot options to allow booting from
+ * a mass storage device plugged into any
+ * of the RPi USB ports.
+ */
+ mUsbHubPort.Dev.ParentPortNumber = Index;
+ UnicodeSPrint(Desc, sizeof (Desc), L"USB Port %u", Index);
+ PlatformRegisterBootOption ((VOID *) &mUsbHubPort,
+ Desc, LOAD_OPTION_ACTIVE);
+ }
+
+ PlatformRegisterBootOption ((VOID *) &mSDHost,
+ L"uSD on SD Host",
+ LOAD_OPTION_ACTIVE);
+ PlatformRegisterBootOption ((VOID *) &mArasan,
+ L"uSD on Arasan MMC Host",
+ LOAD_OPTION_ACTIVE);
+
+ PlatformRegisterOptionsAndKeys ();
+}
+
+/**
+ This function is called each second during the boot manager waits the
+ timeout.
+
+ @param TimeoutRemain The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+ UINT16 TimeoutRemain
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
+ UINT16 Timeout;
+ EFI_STATUS Status;
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;
+
+ Timeout = PcdGet16 (PcdPlatformBootTimeOut);
+
+ Black.Raw = 0x00000000;
+ White.Raw = 0x00FFFFFF;
+
+ Status = BootLogoUpdateProgress (
+ White.Pixel,
+ Black.Pixel,
+ BOOT_PROMPT,
+ White.Pixel,
+ (Timeout - TimeoutRemain) * 100 / Timeout,
+ 0
+ );
+ if (Status == EFI_SUCCESS) {
+ SerialConPrint(L".");
+ } else {
+ Print(L".");
+ }
+
+ if (TimeoutRemain == 0) {
+ BootLogo = NULL;
+
+ //
+ // Clear out the boot logo so that Windows displays its own logo
+ // instead of ours.
+ //
+ Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+ if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
+ Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
+ ASSERT_EFI_ERROR (Status);
+ };
+
+ gST->ConOut->ClearScreen (gST->ConOut);
+ }
+}
+
+/**
+ The function is called when no boot option could be launched,
+ including platform recovery options and options pointing to applications
+ built into firmware volumes.
+ If this function returns, BDS attempts to enter an infinite loop.
+**/
+VOID
+EFIAPI
+PlatformBootManagerUnableToBoot(
+ VOID
+)
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
+ UINTN Index;
+
+ //
+ // BootManagerMenu doesn't contain the correct information when return status
+ // is EFI_NOT_FOUND.
+ //
+ Status = EfiBootManagerGetBootManagerMenu(&BootManagerMenu);
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+ //
+ // Normally BdsDxe does not print anything to the system console, but this is
+ // a last resort -- the end-user will likely not see any DEBUG messages
+ // logged in this situation.
+ //
+ // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
+ // here to see if it makes sense to request and wait for a keypress.
+ //
+ if (gST->ConIn != NULL) {
+ AsciiPrint(
+ "%a: No bootable option or device was found.\n"
+ "%a: Press any key to enter the Boot Manager Menu.\n",
+ gEfiCallerBaseName,
+ gEfiCallerBaseName
+ );
+ Status = gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index);
+ ASSERT_EFI_ERROR(Status);
+ ASSERT(Index == 0);
+
+ //
+ // Drain any queued keys.
+ //
+ while (!EFI_ERROR(gST->ConIn->ReadKeyStroke(gST->ConIn, &Key))) {
+ //
+ // just throw away Key
+ //
+ }
+ }
+
+ for (;;) {
+ EfiBootManagerBoot(&BootManagerMenu);
+ }
+}
diff --git a/Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBm.h b/Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBm.h
new file mode 100644
index 000000000000..3717ba6174df
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBm.h
@@ -0,0 +1,60 @@
+/** @file
+ *
+ * Copyright (c) 2017-2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2016, Linaro Ltd. All rights reserved.
+ * Copyright (c) 2015-2016, Red Hat, Inc.
+ * Copyright (c) 2014, ARM Ltd. All rights reserved.
+ * Copyright (c) 2004-2016, Intel Corporation. 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 _PLATFORM_BM_H_
+#define _PLATFORM_BM_H_
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+/**
+ Use SystemTable Conout to stop video based Simple Text Out consoles from
+ going to the video device. Put up LogoFile on every video device that is a
+ console.
+
+ @param[in] LogoFile File name of logo to display on the center of the
+ screen.
+
+ @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo
+ displayed.
+ @retval EFI_UNSUPPORTED Logo not found
+**/
+EFI_STATUS
+EnableQuietBoot (
+ IN EFI_GUID *LogoFile
+ );
+
+/**
+ Use SystemTable Conout to turn on video based Simple Text Out consoles. The
+ Simple Text Out screens will now be synced up with all non video output
+ devices
+
+ @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
+**/
+EFI_STATUS
+DisableQuietBoot (
+ VOID
+ );
+
+#endif // _PLATFORM_BM_H_
diff --git a/Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
new file mode 100644
index 000000000000..cb1d42364265
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -0,0 +1,90 @@
+#/** @file
+#
+# Copyright (c) 2017-2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) 2016, Linaro Ltd. All rights reserved.
+# Copyright (c) 2015-2016, Red Hat, Inc.
+# Copyright (c) 2014, ARM Ltd. All rights reserved.
+# Copyright (c) 2007-2014, Intel Corporation. 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 = 0x00010005
+ BASE_NAME = PlatformBootManagerLib
+ FILE_GUID = 92FD2DE3-B9CB-4B35-8141-42AD34D73C9F
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = AARCH64
+#
+
+[Sources]
+ PlatformBm.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ BootLogoLib
+ CapsuleLib
+ DebugLib
+ DevicePathLib
+ DxeServicesLib
+ HobLib
+ MemoryAllocationLib
+ PcdLib
+ PrintLib
+ UefiBootManagerLib
+ UefiBootServicesTableLib
+ UefiLib
+
+[FeaturePcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport
+
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
+ gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
+ gRaspberryPiTokenSpaceGuid.PcdHypEnable
+ gRaspberryPiTokenSpaceGuid.PcdDebugShowUEFIExit
+
+[Guids]
+ gEfiFileInfoGuid
+ gEfiFileSystemInfoGuid
+ gEfiFileSystemVolumeLabelInfoIdGuid
+ gEfiEndOfDxeEventGroupGuid
+ gEfiTtyTermGuid
+ gUefiShellFileGuid
+ gEfiEventExitBootServicesGuid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid
+ gEfiGraphicsOutputProtocolGuid
+ gEfiLoadedImageProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEsrtManagementProtocolGuid
+ gEfiUsb2HcProtocolGuid
+ gEfiBootLogoProtocolGuid
diff --git a/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/AArch64/RaspberryPiHelper.S b/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/AArch64/RaspberryPiHelper.S
new file mode 100644
index 000000000000..91567de8bb78
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/AArch64/RaspberryPiHelper.S
@@ -0,0 +1,107 @@
+/** @file
+ *
+ * Copyright (c) 2016, Linaro Limited. All rights reserved.
+ * Copyright (c) 2011-2013, ARM 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.
+ *
+ **/
+
+#include <AsmMacroIoLibV8.h>
+#include <Library/ArmLib.h>
+#include <IndustryStandard/Bcm2836.h>
+#include <IndustryStandard/RpiFirmware.h>
+
+#define MAX_TRIES 0x100000
+
+ .macro drain
+ mov x5, #MAX_TRIES
+0: ldr w6, [x4, #BCM2836_MBOX_STATUS_OFFSET]
+ tbnz w6, #BCM2836_MBOX_STATUS_EMPTY, 1f
+ dmb ld
+ ldr wzr, [x4, #BCM2836_MBOX_READ_OFFSET]
+ subs x5, x5, #1
+ b.ne 0b
+1:
+ .endm
+
+ .macro poll, status
+ mov x5, #MAX_TRIES
+0: ldr w6, [x4, #BCM2836_MBOX_STATUS_OFFSET]
+ tbz w6, #\status, 1f
+ dmb ld
+ subs x5, x5, #1
+ b.ne 0b
+1:
+ .endm
+
+ASM_FUNC(ArmPlatformPeiBootAction)
+ adr x0, .Lmeminfo_buffer
+ mov x1, #FixedPcdGet64 (PcdDmaDeviceOffset)
+ orr x0, x0, #RPI_FW_MBOX_CHANNEL
+ add x0, x0, x1
+
+ MOV32 (x4, BCM2836_MBOX_BASE_ADDRESS)
+
+ drain
+ poll BCM2836_MBOX_STATUS_FULL
+ str w0, [x4, #BCM2836_MBOX_WRITE_OFFSET]
+ dmb sy
+ poll BCM2836_MBOX_STATUS_EMPTY
+ dmb sy
+ ldr wzr, [x4, #BCM2836_MBOX_READ_OFFSET]
+ dmb ld
+
+ ldr w0, .Lmemsize
+ sub x0, x0, #1
+ adr x1, mSystemMemoryEnd
+ str x0, [x1]
+ ret
+
+ .align 4
+.Lmeminfo_buffer:
+ .long .Lbuffer_size
+ .long 0x0
+ .long RPI_FW_GET_ARM_MEMSIZE
+ .long 8 // buf size
+ .long 0 // input len
+ .long 0 // mem base
+.Lmemsize:
+ .long 0 // mem size
+ .long 0 // end tag
+ .set .Lbuffer_size, . - .Lmeminfo_buffer
+
+//UINTN
+//ArmPlatformGetPrimaryCoreMpId (
+// VOID
+// );
+ASM_FUNC(ArmPlatformGetPrimaryCoreMpId)
+ MOV32 (w0, FixedPcdGet32 (PcdArmPrimaryCore))
+ ret
+
+//UINTN
+//ArmPlatformIsPrimaryCore (
+// IN UINTN MpId
+// );
+ASM_FUNC(ArmPlatformIsPrimaryCore)
+ mov x0, #1
+ ret
+
+//UINTN
+//ArmPlatformGetCorePosition (
+// IN UINTN MpId
+// );
+// With this function: CorePos = (ClusterId * 4) + CoreId
+ASM_FUNC(ArmPlatformGetCorePosition)
+ and x1, x0, #ARM_CORE_MASK
+ and x0, x0, #ARM_CLUSTER_MASK
+ add x0, x1, x0, LSR #6
+ ret
+
+ASM_FUNCTION_REMOVE_IF_UNREFERENCED
diff --git a/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPi.c b/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPi.c
new file mode 100644
index 000000000000..ae0b7680f3c3
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPi.c
@@ -0,0 +1,99 @@
+/** @file
+ *
+ * Copyright (c) 2014-2016, Linaro Limited. All rights reserved.
+ * Copyright (c) 2014, Red Hat, Inc.
+ * Copyright (c) 2011-2013, ARM 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.
+ *
+ **/
+
+#include <Library/IoLib.h>
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <Pi/PiBootMode.h>
+
+#include <Ppi/ArmMpCoreInfo.h>
+
+/**
+ Return the current Boot Mode
+
+ This function returns the boot reason on the platform
+
+ @return Return the current Boot Mode of the platform
+
+**/
+EFI_BOOT_MODE
+ArmPlatformGetBootMode (
+ VOID
+ )
+{
+ return BOOT_WITH_FULL_CONFIGURATION;
+}
+
+/**
+ This function is called by PrePeiCore, in the SEC phase.
+**/
+RETURN_STATUS
+ArmPlatformInitialize (
+ IN UINTN MpId
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+VOID
+ArmPlatformInitializeSystemMemory (
+ VOID
+ )
+{
+}
+
+STATIC ARM_CORE_INFO mRpi3InfoTable[] = {
+ { 0x0, 0x0, }, // Cluster 0, Core 0
+ { 0x0, 0x1, }, // Cluster 0, Core 1
+ { 0x0, 0x2, }, // Cluster 0, Core 2
+ { 0x0, 0x3, }, // Cluster 0, Core 3
+};
+
+STATIC
+EFI_STATUS
+PrePeiCoreGetMpCoreInfo (
+ OUT UINTN *CoreCount,
+ OUT ARM_CORE_INFO **ArmCoreTable
+ )
+{
+ // Only support one cluster
+ *CoreCount = sizeof(mRpi3InfoTable) / sizeof(ARM_CORE_INFO);
+ *ArmCoreTable = mRpi3InfoTable;
+
+ return EFI_SUCCESS;
+}
+
+STATIC ARM_MP_CORE_INFO_PPI mMpCoreInfoPpi = {
+ PrePeiCoreGetMpCoreInfo
+};
+STATIC EFI_PEI_PPI_DESCRIPTOR mPlatformPpiTable[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gArmMpCoreInfoPpiGuid,
+ &mMpCoreInfoPpi
+ }
+};
+
+VOID
+ArmPlatformGetPlatformPpiList (
+ OUT UINTN *PpiListSize,
+ OUT EFI_PEI_PPI_DESCRIPTOR **PpiList
+ )
+{
+ *PpiListSize = sizeof(mPlatformPpiTable);
+ *PpiList = mPlatformPpiTable;
+}
diff --git a/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPiMem.c b/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPiMem.c
new file mode 100644
index 000000000000..69821e405134
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPiMem.c
@@ -0,0 +1,160 @@
+/** @file
+ *
+ * Copyright (c) 2017-2018, Andrey Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2014, 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.
+ *
+ **/
+
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Bcm2836.h>
+#include <Library/PcdLib.h>
+
+extern UINT64 mSystemMemoryEnd;
+extern UINT64 mGPUMemoryBase;
+extern UINT64 mGPUMemoryLength;
+
+#define VariablesSize (FixedPcdGet32(PcdFlashNvStorageVariableSize) + \
+ FixedPcdGet32(PcdFlashNvStorageFtwWorkingSize) + \
+ FixedPcdGet32(PcdFlashNvStorageFtwSpareSize) + \
+ FixedPcdGet32(PcdNvStorageEventLogSize))
+
+#define VariablesBase (FixedPcdGet64(PcdFdBaseAddress) + \
+ FixedPcdGet32(PcdFdSize) - \
+ VariablesSize)
+
+#define ATFBase (FixedPcdGet64(PcdFdBaseAddress) + FixedPcdGet32(PcdFdSize))
+
+STATIC ARM_MEMORY_REGION_DESCRIPTOR RaspberryPiMemoryRegionDescriptor[] = {
+ {
+ /* Firmware Volume. */
+ FixedPcdGet64(PcdFdBaseAddress), FixedPcdGet64(PcdFdBaseAddress),
+ FixedPcdGet32(PcdFdSize) - VariablesSize,
+ ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK
+ },
+ {
+ /* Variables Volume. */
+ VariablesBase, VariablesBase,
+ VariablesSize,
+ ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK
+ },
+ {
+ /* ATF reserved RAM. */
+ ATFBase, ATFBase,
+ FixedPcdGet64(PcdSystemMemoryBase) - ATFBase,
+ ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK
+ },
+ {
+ /* System RAM. */
+ FixedPcdGet64(PcdSystemMemoryBase), FixedPcdGet64(PcdSystemMemoryBase),
+ 0,
+ ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK
+ },
+ {
+ /* Reserved GPU RAM. */
+ 0,
+ 0,
+ 0,
+ ARM_MEMORY_REGION_ATTRIBUTE_DEVICE
+ },
+ {
+ /* SOC registers. */
+ BCM2836_SOC_REGISTERS,
+ BCM2836_SOC_REGISTERS,
+ BCM2836_SOC_REGISTER_LENGTH,
+ ARM_MEMORY_REGION_ATTRIBUTE_DEVICE
+ },
+ {
+ }
+};
+
+/**
+ Return the Virtual Memory Map of your platform
+
+ This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
+ on your platform.
+
+ @param[out] VirtualMemoryMap Array of ARM_MEMORY_REGION_DESCRIPTOR
+ describing a Physical-to-Virtual Memory
+ mapping. This array must be ended by a
+ zero-filled entry
+
+**/
+VOID
+ArmPlatformGetVirtualMemoryMap (
+ IN ARM_MEMORY_REGION_DESCRIPTOR** VirtualMemoryMap
+ )
+{
+ RaspberryPiMemoryRegionDescriptor[3].Length = mSystemMemoryEnd + 1 -
+ FixedPcdGet64(PcdSystemMemoryBase);
+
+ RaspberryPiMemoryRegionDescriptor[4].PhysicalBase =
+ RaspberryPiMemoryRegionDescriptor[3].PhysicalBase +
+ RaspberryPiMemoryRegionDescriptor[3].Length;
+
+ RaspberryPiMemoryRegionDescriptor[4].VirtualBase =
+ RaspberryPiMemoryRegionDescriptor[4].PhysicalBase;
+
+ RaspberryPiMemoryRegionDescriptor[4].Length =
+ RaspberryPiMemoryRegionDescriptor[5].PhysicalBase -
+ RaspberryPiMemoryRegionDescriptor[4].PhysicalBase;
+
+ DEBUG ((DEBUG_INFO, "FD:\n"
+ "\tPhysicalBase: 0x%lX\n"
+ "\tVirtualBase: 0x%lX\n"
+ "\tLength: 0x%lX\n",
+ RaspberryPiMemoryRegionDescriptor[0].PhysicalBase,
+ RaspberryPiMemoryRegionDescriptor[0].VirtualBase,
+ RaspberryPiMemoryRegionDescriptor[0].Length +
+ RaspberryPiMemoryRegionDescriptor[1].Length));
+
+ DEBUG ((DEBUG_INFO, "Variables (part of FD):\n"
+ "\tPhysicalBase: 0x%lX\n"
+ "\tVirtualBase: 0x%lX\n"
+ "\tLength: 0x%lX\n",
+ RaspberryPiMemoryRegionDescriptor[1].PhysicalBase,
+ RaspberryPiMemoryRegionDescriptor[1].VirtualBase,
+ RaspberryPiMemoryRegionDescriptor[1].Length));
+
+ DEBUG ((DEBUG_INFO, "ATF RAM:\n"
+ "\tPhysicalBase: 0x%lX\n"
+ "\tVirtualBase: 0x%lX\n"
+ "\tLength: 0x%lX\n",
+ RaspberryPiMemoryRegionDescriptor[2].PhysicalBase,
+ RaspberryPiMemoryRegionDescriptor[2].VirtualBase,
+ RaspberryPiMemoryRegionDescriptor[2].Length));
+
+ DEBUG ((DEBUG_INFO, "System RAM:\n"
+ "\tPhysicalBase: 0x%lX\n"
+ "\tVirtualBase: 0x%lX\n"
+ "\tLength: 0x%lX\n",
+ RaspberryPiMemoryRegionDescriptor[3].PhysicalBase,
+ RaspberryPiMemoryRegionDescriptor[3].VirtualBase,
+ RaspberryPiMemoryRegionDescriptor[3].Length));
+
+ DEBUG ((DEBUG_INFO, "GPU Reserved:\n"
+ "\tPhysicalBase: 0x%lX\n"
+ "\tVirtualBase: 0x%lX\n"
+ "\tLength: 0x%lX\n",
+ RaspberryPiMemoryRegionDescriptor[4].PhysicalBase,
+ RaspberryPiMemoryRegionDescriptor[4].VirtualBase,
+ RaspberryPiMemoryRegionDescriptor[4].Length));
+
+ DEBUG ((DEBUG_INFO, "SoC reserved:\n"
+ "\tPhysicalBase: 0x%lX\n"
+ "\tVirtualBase: 0x%lX\n"
+ "\tLength: 0x%lX\n",
+ RaspberryPiMemoryRegionDescriptor[5].PhysicalBase,
+ RaspberryPiMemoryRegionDescriptor[5].VirtualBase,
+ RaspberryPiMemoryRegionDescriptor[5].Length));
+
+ *VirtualMemoryMap = RaspberryPiMemoryRegionDescriptor;
+}
diff --git a/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPiPlatformLib.inf b/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPiPlatformLib.inf
new file mode 100644
index 000000000000..2ee4450d79e4
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPiPlatformLib.inf
@@ -0,0 +1,64 @@
+#/** @file
+#
+# Copyright (c) 2017-2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) 2014-2016, Linaro Limited. All rights reserved.
+# Copyright (c) 2011-2014, ARM 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.
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RaspberryPiPlatformLib
+ FILE_GUID = 050182ef-f708-4148-b4bc-256cabf74fea
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ArmPlatformLib|SEC PEIM
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ ArmLib
+ FdtLib
+ IoLib
+ MemoryAllocationLib
+ PcdLib
+ PrintLib
+
+[Sources.common]
+ RaspberryPi.c
+ RaspberryPiMem.c
+
+[Sources.AARCH64]
+ AArch64/RaspberryPiHelper.S
+
+[FixedPcd]
+ gArmTokenSpaceGuid.PcdFdBaseAddress
+ gArmTokenSpaceGuid.PcdFvBaseAddress
+ gArmPlatformTokenSpaceGuid.PcdCoreCount
+ gArmTokenSpaceGuid.PcdArmPrimaryCoreMask
+ gArmTokenSpaceGuid.PcdArmPrimaryCore
+ gArmTokenSpaceGuid.PcdFdSize
+ gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset
+ gArmTokenSpaceGuid.PcdSystemMemoryBase
+ gArmTokenSpaceGuid.PcdSystemMemorySize
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageEventLogSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+[Ppis]
+ gArmMpCoreInfoPpiGuid
diff --git a/Platform/Broadcom/Bcm283x/Library/ResetLib/ResetLib.c b/Platform/Broadcom/Bcm283x/Library/ResetLib/ResetLib.c
new file mode 100644
index 000000000000..1a3944b71d03
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/ResetLib/ResetLib.c
@@ -0,0 +1,104 @@
+/** @file
+ *
+ * Support ResetSystem Runtime call using PSCI calls.
+ * Signals the gRaspberryPiEventResetGuid event group on reset.
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) 2014, Linaro Ltd. All rights reserved.
+ * Copyright (c) 2013-2015, ARM Ltd. All rights reserved.
+ * Copyright (c) 2008-2009, Apple Inc. 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/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/EfiResetSystemLib.h>
+#include <Library/ArmSmcLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <IndustryStandard/ArmStdSmc.h>
+
+/**
+ Resets the entire platform.
+
+ @param ResetType The type of reset to perform.
+ @param ResetStatus The status code for the reset.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
+ EfiResetShutdown the data buffer starts with a Null-terminated
+ Unicode string, optionally followed by additional binary data.
+
+**/
+EFI_STATUS
+EFIAPI
+LibResetSystem (
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN CHAR16 *ResetData OPTIONAL
+ )
+{
+ ARM_SMC_ARGS ArmSmcArgs;
+
+ if (!EfiAtRuntime ()) {
+ /*
+ * Only if still in UEFI.
+ */
+ EfiEventGroupSignal(&gRaspberryPiEventResetGuid);
+ }
+
+ switch (ResetType) {
+ case EfiResetPlatformSpecific:
+ // Map the platform specific reset as reboot
+ case EfiResetWarm:
+ // Map a warm reset into a cold reset
+ case EfiResetCold:
+ // Send a PSCI 0.2 SYSTEM_RESET command
+ ArmSmcArgs.Arg0 = ARM_SMC_ID_PSCI_SYSTEM_RESET;
+ break;
+ case EfiResetShutdown:
+ // Send a PSCI 0.2 SYSTEM_OFF command
+ ArmSmcArgs.Arg0 = ARM_SMC_ID_PSCI_SYSTEM_OFF;
+ break;
+ default:
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ ArmCallSmc (&ArmSmcArgs);
+
+ // We should never be here
+ DEBUG ((DEBUG_ERROR, "%a: PSCI Reset failed\n", __FUNCTION__));
+ CpuDeadLoop ();
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Initialize any infrastructure required for LibResetSystem () to function.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+LibInitializeResetSystem (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Broadcom/Bcm283x/Library/ResetLib/ResetLib.inf b/Platform/Broadcom/Bcm283x/Library/ResetLib/ResetLib.inf
new file mode 100644
index 000000000000..1c32a4b08162
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/ResetLib/ResetLib.inf
@@ -0,0 +1,46 @@
+#/** @file
+#
+# Reset System lib using PSCI hypervisor or secure monitor calls.
+# Signals the gRaspberryPiEventResetGuid event group on reset.
+#
+# Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) 2014, Linaro Ltd. All rights reserved.
+# Copyright (c) 2014, ARM Ltd. All rights reserved.
+# Copyright (c) 2008, Apple Inc. 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 = 0x00010005
+ BASE_NAME = ResetLib
+ FILE_GUID = B9F59B69-A105-41C7-8F5A-2C60DD7FD7AB
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = EfiResetSystemLib
+
+[Sources]
+ ResetLib.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseLib
+ ArmSmcLib
+ UefiLib
+ UefiRuntimeLib
+
+[Guids]
+ gRaspberryPiEventResetGuid
diff --git a/Platform/Broadcom/Bcm283x/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c b/Platform/Broadcom/Bcm283x/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
new file mode 100644
index 000000000000..5e1dd768331a
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
@@ -0,0 +1,222 @@
+/** @file
+ *
+ * Implement dummy EFI RealTimeClock runtime services.
+ *
+ * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+ * Copyright (c) Microsoft Corporation. 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/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/RealTimeClockLib.h>
+#include <Library/TimerLib.h>
+#include <Library/TimeBaseLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/ArmGenericTimerCounterLib.h>
+
+/**
+ Returns the current time and date information, and the time-keeping capabilities
+ of the virtual RTC.
+
+ For simplicity, this LibGetTime does not report Years/Months, instead it will only report current
+ Day, Hours, Minutes and Seconds starting from the begining of CPU up-time. Otherwise, a more
+ complex logic will be required to account for leap years and days/month differences.
+
+ @param Time A pointer to storage to receive a snapshot of the current time.
+ @param Capabilities An optional pointer to a buffer to receive the real time clock
+ device's capabilities.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Time is NULL.
+ @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetTime (
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities
+ )
+{
+ UINTN DataSize;
+ UINT64 Counter;
+ EFI_STATUS Status;
+ UINTN ElapsedSeconds;
+ UINT32 Remainder;
+ UINT32 Freq = ArmGenericTimerGetTimerFreq();
+
+ if (Time == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Depend on ARM generic timer to report date/time relative to the
+ // start of CPU timer counting where date and time will always
+ // be relative to the date/time 1/1/1900 00H:00M:00S
+ //
+
+ ASSERT (Freq != 0);
+ if (Freq == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Capabilities) {
+ Capabilities->Accuracy = 0;
+ Capabilities->Resolution = Freq;
+ Capabilities->SetsToZero = FALSE;
+ }
+
+ DataSize = sizeof (UINTN);
+ ElapsedSeconds = 0;
+ Status = EfiGetVariable (L"RtcEpochSeconds",
+ &gEfiCallerIdGuid,
+ NULL,
+ &DataSize,
+ &ElapsedSeconds);
+ if (EFI_ERROR (Status)) {
+ ElapsedSeconds = PcdGet64(PcdBootEpochSeconds);
+ }
+ Counter = GetPerformanceCounter ();
+ ElapsedSeconds += DivU64x32Remainder (Counter, Freq, &Remainder);
+ EpochToEfiTime (ElapsedSeconds, Time);
+
+ //
+ // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)
+ // will not overflow 64-bit.
+ //
+ Time->Nanosecond = DivU64x32 (MultU64x64 ((UINT64) Remainder,
+ 1000000000U), Freq);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Sets the current local time and date information.
+
+ @param Time A pointer to the current time.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetTime (
+ IN EFI_TIME *Time
+ )
+{
+ UINTN Epoch;
+
+ if (!IsTimeValid(Time)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Epoch = EfiTimeToEpoch(Time);
+ return EfiSetVariable(L"RtcEpochSeconds", &gEfiCallerIdGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ sizeof (Epoch),
+ &Epoch);
+}
+
+
+/**
+ Returns the current wakeup alarm clock setting.
+
+ @param Enabled Indicates if the alarm is currently enabled or disabled.
+ @param Pending Indicates if the alarm signal is pending and requires acknowledgement.
+ @param Time The current alarm setting.
+
+ @retval EFI_SUCCESS The alarm settings were returned.
+ @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetWakeupTime (
+ OUT BOOLEAN *Enabled,
+ OUT BOOLEAN *Pending,
+ OUT EFI_TIME *Time
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Sets the system wakeup alarm clock time.
+
+ @param Enabled Enable or disable the wakeup alarm.
+ @param Time If Enable is TRUE, the time to set the wakeup alarm for.
+
+ @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If
+ Enable is FALSE, then the wakeup alarm was disabled.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetWakeupTime (
+ IN BOOLEAN Enabled,
+ OUT EFI_TIME *Time
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ This is the declaration of an EFI image entry point. This can be the entry point to an application
+ written to this specification, an EFI boot service driver, or an EFI runtime driver.
+
+ @param ImageHandle Handle that identifies the loaded image.
+ @param SystemTable System Table for this image.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+LibRtcInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fixup internal data so that EFI can be call in virtual mode.
+ Call the passed in Child Notify event and convert any pointers in
+ lib to virtual mode.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ return;
+}
diff --git a/Platform/Broadcom/Bcm283x/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf b/Platform/Broadcom/Bcm283x/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
new file mode 100644
index 000000000000..847bcfadd824
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
@@ -0,0 +1,43 @@
+#/** @file
+#
+# Implement dummy EFI RealTimeClock runtime services.
+#
+# Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) Microsoft Corporation. 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 = 0x00010005
+ BASE_NAME = VirtualRealTimeClockLib
+ FILE_GUID = 1E27D461-78F3-4F7D-B1C2-F72384F13A6E
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RealTimeClockLib
+
+[Sources.common]
+ VirtualRealTimeClockLib.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
+
+[LibraryClasses]
+ IoLib
+ DebugLib
+ TimerLib
+ TimeBaseLib
+ UefiRuntimeLib
+
+[Pcd]
+ gRaspberryPiTokenSpaceGuid.PcdBootEpochSeconds
diff --git a/Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec b/Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
new file mode 100644
index 000000000000..51f2f07aab8a
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec
@@ -0,0 +1,63 @@
+## @file
+#
+# Copyright (c) 2016, Linaro, Ltd. All rights reserved.
+# Copyright (c) 2017 - 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+#
+# 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]
+ DEC_SPECIFICATION = 0x0001001A
+ PACKAGE_NAME = RaspberryPiPkg
+ PACKAGE_GUID = DFA0CA8B-F3AC-4607-96AC-46FA04B84DCC
+ PACKAGE_VERSION = 0.1
+
+[Includes]
+ Include
+
+[Protocols]
+ gRaspberryPiFirmwareProtocolGuid = { 0x0ACA9535, 0x7AD0, 0x4286, { 0xB0, 0x2E, 0x87, 0xFA, 0x7E, 0x2A, 0x57, 0x11 } }
+ gRaspberryPiConfigAppliedProtocolGuid = { 0x0ACA4444, 0x7AD0, 0x4286, { 0xB0, 0x2E, 0x87, 0xFA, 0x7E, 0x2A, 0x57, 0x11 } }
+ gRaspberryPiMmcHostProtocolGuid = { 0x3e591c00, 0x9e4a, 0x11df, {0x92, 0x44, 0x00, 0x02, 0xA5, 0xF5, 0xF5, 0x1B } }
+ gExtendedTextOutputProtocolGuid = { 0x387477ff, 0xffc7, 0xffd2, {0x8e, 0x39, 0x0, 0xff, 0xc9, 0x69, 0x72, 0x3b } }
+
+[Guids]
+ gRaspberryPiTokenSpaceGuid = {0xCD7CC258, 0x31DB, 0x11E6, {0x9F, 0xD3, 0x63, 0xB0, 0xB8, 0xEE, 0xD6, 0xB5}}
+ gRaspberryPiFdtFileGuid = {0xDF5DA223, 0x1D27, 0x47C3, { 0x8D, 0x1B, 0x9A, 0x41, 0xB5, 0x5A, 0x18, 0xBC}}
+ gRaspberryPiEventResetGuid = {0xCD7CC258, 0x31DB, 0x11E6, {0x9F, 0xD3, 0x63, 0xB4, 0xB4, 0xE4, 0xD4, 0xB4}}
+ gConfigDxeFormSetGuid = {0xCD7CC258, 0x31DB, 0x22E6, {0x9F, 0x22, 0x63, 0xB0, 0xB8, 0xEE, 0xD6, 0xB5}}
+
+[PcdsFixedAtBuild.common]
+ gRaspberryPiTokenSpaceGuid.PcdFdtBaseAddress|0x10000|UINT32|0x00000001
+ gRaspberryPiTokenSpaceGuid.PcdFirmwareBlockSize|0x0|UINT32|0x00000002
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageEventLogBase|0x0|UINT32|0x00000003
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageEventLogSize|0x0|UINT32|0x00000004
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageVariableBase|0x0|UINT32|0x00000005
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageFtwSpareBase|0x0|UINT32|0x00000006
+ gRaspberryPiTokenSpaceGuid.PcdNvStorageFtwWorkingBase|0x0|UINT32|0x00000007
+ gRaspberryPiTokenSpaceGuid.PcdBootEpochSeconds|0x0|UINT64|0x00000008
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+ gRaspberryPiTokenSpaceGuid.PcdHypEnable|0|UINT32|0x00000009
+ gRaspberryPiTokenSpaceGuid.PcdHypLogMask|0|UINT32|0x0000000a
+ gRaspberryPiTokenSpaceGuid.PcdHypWindowsDebugHook|0|UINT32|0x0000000b
+ gRaspberryPiTokenSpaceGuid.PcdHypWin2000Mask|0|UINT32|0x0000000c
+ gRaspberryPiTokenSpaceGuid.PcdCpuClock|0|UINT32|0x0000000d
+ gRaspberryPiTokenSpaceGuid.PcdSdIsArasan|0|UINT32|0x0000000e
+ gRaspberryPiTokenSpaceGuid.PcdMmcForce1Bit|0|UINT32|0x0000000f
+ gRaspberryPiTokenSpaceGuid.PcdMmcForceDefaultSpeed|0|UINT32|0x00000010
+ gRaspberryPiTokenSpaceGuid.PcdMmcSdDefaultSpeedMHz|0|UINT32|0x00000011
+ gRaspberryPiTokenSpaceGuid.PcdMmcSdHighSpeedMHz|0|UINT32|0x00000012
+ gRaspberryPiTokenSpaceGuid.PcdMmcDisableMulti|0|UINT32|0x00000013
+ gRaspberryPiTokenSpaceGuid.PcdDebugEnableJTAG|0|UINT32|0x00000014
+ gRaspberryPiTokenSpaceGuid.PcdDebugShowUEFIExit|0|UINT32|0x00000015
+ gRaspberryPiTokenSpaceGuid.PcdDisplayEnableVModes|0|UINT32|0x00000017
+ gRaspberryPiTokenSpaceGuid.PcdDisplayEnableSShot|0|UINT32|0x00000018
diff --git a/Platform/Broadcom/Bcm283x/RaspberryPiPkg.dsc b/Platform/Broadcom/Bcm283x/RaspberryPiPkg.dsc
new file mode 100644
index 000000000000..8610fae0b92f
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/RaspberryPiPkg.dsc
@@ -0,0 +1,636 @@
+# @file
+#
+# Copyright (c) 2011-2015, ARM Limited. All rights reserved.
+# Copyright (c) 2014, Linaro Limited. All rights reserved.
+# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+# Copyright (c) 2017 - 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+#
+# 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 Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ PLATFORM_NAME = RaspberryPi
+ PLATFORM_GUID = 5d30c4fc-93cf-40c9-8486-3badc0410816
+ PLATFORM_VERSION = 0.3
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/RaspberryPiPkg
+ SUPPORTED_ARCHITECTURES = AARCH64
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+ FLASH_DEFINITION = Platform/Broadcom/Bcm283x/RaspberryPiPkg.fdf
+
+ #
+ # Defines for default states. These can be changed on the command line.
+ # -D FLAG=VALUE
+ #
+ DEFINE SECURE_BOOT_ENABLE = FALSE
+ DEFINE DEBUG_PRINT_ERROR_LEVEL = 0x8000004F
+
+!ifndef BUILD_EPOCH
+ DEFINE BUILD_EPOCH = 1546300800
+!endif
+################################################################################
+#
+# Library Class section - list of all Library Classes needed by this Platform.
+#
+################################################################################
+[LibraryClasses.common]
+!if $(TARGET) == RELEASE
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+!else
+ DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+!endif
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
+ BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
+ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
+ PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf
+ CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
+
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
+ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+ SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
+
+ UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+ OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf
+
+ #
+ # Ramdisk Requirements
+ #
+ FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
+
+ # Allow dynamic PCDs
+ #
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+
+ # use the accelerated BaseMemoryLibOptDxe by default, overrides for SEC/PEI below
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLibOptDxe/BaseMemoryLibOptDxe.inf
+
+ # Networking Requirements
+ NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf
+ DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf
+ UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf
+ IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf
+
+ #
+ # It is not possible to prevent the ARM compiler from inserting calls to intrinsic functions.
+ # This library provides the instrinsic functions such a compiler may generate calls to.
+ #
+ NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
+
+ # Add support for GCC stack protector
+ NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
+
+ # ARM Architectural Libraries
+ CacheMaintenanceLib|ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.inf
+ DefaultExceptionHandlerLib|ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf
+ CpuExceptionHandlerLib|ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.inf
+ ArmDisassemblerLib|ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf
+ DmaLib|EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf
+ TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
+ ArmPlatformStackLib|ArmPlatformPkg/Library/ArmPlatformStackLib/ArmPlatformStackLib.inf
+ ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
+ ArmHvcLib|ArmPkg/Library/ArmHvcLib/ArmHvcLib.inf
+ ArmGenericTimerCounterLib|ArmPkg/Library/ArmGenericTimerPhyCounterLib/ArmGenericTimerPhyCounterLib.inf
+
+ PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
+ PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+ PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
+ SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
+
+ #
+ # Uncomment (and comment out the next line) For RealView Debugger. The Standard IO window
+ # in the debugger will show load and unload commands for symbols. You can cut and paste this
+ # into the command window to load symbols. We should be able to use a script to do this, but
+ # the version of RVD I have does not support scripts accessing system memory.
+ #
+ #PeCoffExtraActionLib|ArmPkg/Library/RvdPeCoffExtraActionLib/RvdPeCoffExtraActionLib.inf
+ PeCoffExtraActionLib|ArmPkg/Library/DebugPeCoffExtraActionLib/DebugPeCoffExtraActionLib.inf
+ #PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
+
+ DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+ DebugAgentTimerLib|EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf
+
+ # Flattened Device Tree (FDT) access library
+ FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf
+
+ # USB Libraries
+ UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
+
+ #
+ # Secure Boot dependencies
+ #
+!if $(SECURE_BOOT_ENABLE) == TRUE
+ IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
+ OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf
+ TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf
+ AuthVariableLib|SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
+
+ # re-use the UserPhysicalPresent() dummy implementation from the ovmf tree
+ PlatformSecureLib|OvmfPkg/Library/PlatformSecureLib/PlatformSecureLib.inf
+!else
+ TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
+!endif
+ VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
+ GpioLib|Platform/Broadcom/Bcm283x/Library/GpioLib/GpioLib.inf
+
+[LibraryClasses.common.SEC]
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ MemoryInitPeiLib|Platform/Broadcom/Bcm283x/Library/MemoryInitPeiLib/MemoryInitPeiLib.inf
+ PlatformPeiLib|ArmPlatformPkg/PlatformPei/PlatformPeiLib.inf
+ ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf
+ LzmaDecompressLib|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+ PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf
+ HobLib|EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf
+ PrePiHobListPointerLib|ArmPlatformPkg/Library/PrePiHobListPointerLib/PrePiHobListPointerLib.inf
+ MemoryAllocationLib|EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf
+
+[LibraryClasses.common.DXE_CORE]
+ HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
+ MemoryAllocationLib|MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
+ DxeCoreEntryPoint|MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf
+ ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf
+ ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+ UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf
+ PerformanceLib|MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+ ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf
+ SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
+ PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+
+[LibraryClasses.common.UEFI_APPLICATION]
+ UefiDecompressLib|IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf
+ PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
+ FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+ ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+
+[LibraryClasses.common.UEFI_DRIVER]
+ ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf
+ UefiDecompressLib|IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf
+ ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+ PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+
+[LibraryClasses.common.DXE_RUNTIME_DRIVER]
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf
+ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+ EfiResetSystemLib|Platform/Broadcom/Bcm283x/Library/ResetLib/ResetLib.inf
+ ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
+
+!if $(SECURE_BOOT_ENABLE) == TRUE
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
+!endif
+
+###################################################################################################
+# BuildOptions Section - Define the module specific tool chain flags that should be used as
+# the default flags for a module. These flags are appended to any
+# standard flags that are defined by the build process.
+###################################################################################################
+
+[BuildOptions]
+ GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG -DNDEBUG
+
+[BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
+ GCC:*_*_AARCH64_DLINK_FLAGS = -z common-page-size=0x10000
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+
+[PcdsFeatureFlag.common]
+ # Use the Vector Table location in CpuDxe. We will not copy the Vector Table at PcdCpuVectorBaseAddress
+ gArmTokenSpaceGuid.PcdRelocateVectorTable|FALSE
+
+ gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|TRUE
+
+ ## If TRUE, Graphics Output Protocol will be installed on virtual handle created by ConsplitterDxe.
+ # It could be set FALSE to save size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
+
+[PcdsFixedAtBuild.common]
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|1000000
+ gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout|10000000
+ gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue|0xAF
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask|1
+ gEfiMdePkgTokenSpaceGuid.PcdPostCodePropertyMask|0
+ gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|320
+
+ # DEBUG_ASSERT_ENABLED 0x01
+ # DEBUG_PRINT_ENABLED 0x02
+ # DEBUG_CODE_ENABLED 0x04
+ # CLEAR_MEMORY_ENABLED 0x08
+ # ASSERT_BREAKPOINT_ENABLED 0x10
+ # ASSERT_DEADLOOP_ENABLED 0x20
+!if $(TARGET) == RELEASE
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x21
+!else
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2f
+!endif
+
+ # DEBUG_INIT 0x00000001 // Initialization
+ # DEBUG_WARN 0x00000002 // Warnings
+ # DEBUG_LOAD 0x00000004 // Load events
+ # DEBUG_FS 0x00000008 // EFI File system
+ # DEBUG_POOL 0x00000010 // Alloc & Free (pool)
+ # DEBUG_PAGE 0x00000020 // Alloc & Free (page)
+ # DEBUG_INFO 0x00000040 // Informational debug messages
+ # DEBUG_DISPATCH 0x00000080 // PEI/DXE/SMM Dispatchers
+ # DEBUG_VARIABLE 0x00000100 // Variable
+ # DEBUG_BM 0x00000400 // Boot Manager
+ # DEBUG_BLKIO 0x00001000 // BlkIo Driver
+ # DEBUG_NET 0x00004000 // SNP Driver
+ # DEBUG_UNDI 0x00010000 // UNDI Driver
+ # DEBUG_LOADFILE 0x00020000 // LoadFile
+ # DEBUG_EVENT 0x00080000 // Event messages
+ # DEBUG_GCD 0x00100000 // Global Coherency Database changes
+ # DEBUG_CACHE 0x00200000 // Memory range cachability changes
+ # DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may
+ # // significantly impact boot performance
+ # DEBUG_ERROR 0x80000000 // Error
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|$(DEBUG_PRINT_ERROR_LEVEL)
+
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x07
+
+ #
+ # Optional feature to help prevent EFI memory map fragments
+ # Turned on and off via: PcdPrePiProduceMemoryTypeInformationHob
+ # Values are in EFI Pages (4K). DXE Core will make sure that
+ # at least this much of each type of memory can be allocated
+ # from a single memory range. This way you only end up with
+ # maximum of two fragments for each type in the memory map
+ # (the memory used, and the free memory that was prereserved
+ # but not used).
+ #
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory|0
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS|0
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType|0
+!if $(SECURE_BOOT_ENABLE) == TRUE
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|600
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|400
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode|1500
+!else
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|300
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|150
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode|1000
+!endif
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData|12000
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode|20
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData|0
+
+ gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset|0xc0000000
+
+!if $(SECURE_BOOT_ENABLE) == TRUE
+ # override the default values from SecurityPkg to ensure images from all sources are verified in secure boot
+ gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x04
+ gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy|0x04
+ gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy|0x04
+!endif
+
+ gEmbeddedTokenSpaceGuid.PcdInterruptBaseAddress|0x40000000
+ gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum|0x0
+ gArmTokenSpaceGuid.PcdArmArchTimerIntrNum|0x1
+ gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|0x2
+ gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|0x3
+
+[LibraryClasses.common]
+ ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
+ ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
+ ArmPlatformLib|Platform/Broadcom/Bcm283x/Library/RaspberryPiPlatformLib/RaspberryPiPlatformLib.inf
+ TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
+ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+ UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
+ BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
+ PlatformBootManagerLib|Platform/Broadcom/Bcm283x/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+ CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
+ FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
+
+[LibraryClasses.common.UEFI_DRIVER]
+ UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
+
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+
+[PcdsFeatureFlag.common]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
+
+[PcdsFixedAtBuild.common]
+ gArmPlatformTokenSpaceGuid.PcdCoreCount|4
+ gArmTokenSpaceGuid.PcdVFPEnabled|1
+
+ gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize|0x4000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
+
+ # Size of the region used by UEFI in permanent memory (Reserved 64MB)
+ gArmPlatformTokenSpaceGuid.PcdSystemMemoryUefiRegionSize|0x04000000
+ #
+ # This matches PcdFvBaseAddress, since everything less is ATF, and
+ # will be reserved away.
+ #
+ gArmTokenSpaceGuid.PcdSystemMemoryBase|0x00400000
+ gArmTokenSpaceGuid.PcdSystemMemorySize|0x3FC00000
+
+ ## NS16550 compatible UART
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0x3f215040
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio|TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride|4
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|500000000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl|0x27
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialExtendedTxFifoSize|8
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200
+
+ ## Default Terminal Type
+ ## 0-PCANSI, 1-VT100, 2-VT00+, 3-UTF8, 4-TTYTERM
+ gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|4
+
+ gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 }
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdShellFile|{ 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1 }
+
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVendor|L"Raspberry Pi 3 64-bit UEFI"
+
+ #
+ # Build timestamp. This is used if RtcEpochSeconds NVRAM
+ # variable is not present.
+ #
+ gRaspberryPiTokenSpaceGuid.PcdBootEpochSeconds|$(BUILD_EPOCH)
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|TRUE
+
+[PcdsDynamicHii.common.DEFAULT]
+
+ #
+ # Clock overrides.
+ #
+
+ gRaspberryPiTokenSpaceGuid.PcdCpuClock|L"CpuClock"|gConfigDxeFormSetGuid|0x0|0
+
+ #
+ # SD-related.
+ #
+
+ gRaspberryPiTokenSpaceGuid.PcdSdIsArasan|L"SdIsArasan"|gConfigDxeFormSetGuid|0x0|0
+ gRaspberryPiTokenSpaceGuid.PcdMmcForce1Bit|L"MmcForce1Bit"|gConfigDxeFormSetGuid|0x0|0
+ gRaspberryPiTokenSpaceGuid.PcdMmcForceDefaultSpeed|L"MmcForceDefaultSpeed"|gConfigDxeFormSetGuid|0x0|0
+ gRaspberryPiTokenSpaceGuid.PcdMmcSdDefaultSpeedMHz|L"MmcSdDefaultSpeedMHz"|gConfigDxeFormSetGuid|0x0|25
+ gRaspberryPiTokenSpaceGuid.PcdMmcSdHighSpeedMHz|L"MmcSdHighSpeedMHz"|gConfigDxeFormSetGuid|0x0|50
+ gRaspberryPiTokenSpaceGuid.PcdMmcDisableMulti|L"MmcDisableMulti"|gConfigDxeFormSetGuid|0x0|0
+
+ #
+ # Debug-related.
+ #
+
+ gRaspberryPiTokenSpaceGuid.PcdDebugEnableJTAG|L"DebugEnableJTAG"|gConfigDxeFormSetGuid|0x0|0
+ gRaspberryPiTokenSpaceGuid.PcdDebugShowUEFIExit|L"DebugShowUEFIExit"|gConfigDxeFormSetGuid|0x0|0
+
+ #
+ # Display-related.
+ #
+ gRaspberryPiTokenSpaceGuid.PcdDisplayEnableVModes|L"DisplayEnableVModes"|gConfigDxeFormSetGuid|0x0|0
+ gRaspberryPiTokenSpaceGuid.PcdDisplayEnableSShot|L"DisplayEnableSShot"|gConfigDxeFormSetGuid|0x0|1
+
+ #
+ # Common UEFI ones.
+ #
+
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEfiGlobalVariableGuid|0x0|5
+ #
+ # This is silly, but by pointing SetupConXXX and ConXXX PCDs to
+ # the same variables, I can use the graphical configuration to
+ # change the mode used by ConSplitter.
+ #
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn|L"Columns"|gRaspberryPiTokenSpaceGuid|0x0|80
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn|L"Columns"|gRaspberryPiTokenSpaceGuid|0x0|80
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow|L"Rows"|gRaspberryPiTokenSpaceGuid|0x0|25
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow|L"Rows"|gRaspberryPiTokenSpaceGuid|0x0|25
+
+[PcdsDynamicDefault.common]
+ #
+ # Set video resolution for boot options and for text setup.
+ #
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution|0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution|0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution|640
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution|480
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0
+
+################################################################################
+#
+# Components Section - list of all EDK II Modules needed by this Platform
+#
+################################################################################
+[Components.common]
+ #
+ # PEI Phase modules
+ #
+ ArmPlatformPkg/PrePi/PeiUniCore.inf
+
+ #
+ # DXE
+ #
+ MdeModulePkg/Core/Dxe/DxeMain.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
+ }
+ MdeModulePkg/Universal/PCD/Dxe/Pcd.inf {
+ <LibraryClasses>
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ }
+
+ #
+ # Architectural Protocols
+ #
+ ArmPkg/Drivers/CpuDxe/CpuDxe.inf
+ MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+ Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+ }
+!if $(SECURE_BOOT_ENABLE) == TRUE
+ MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf {
+ <LibraryClasses>
+ NULL|SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
+ }
+ SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
+!else
+ MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+!endif
+ MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+ MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
+ EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf
+ EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf {
+ <LibraryClasses>
+ RealTimeClockLib|Platform/Broadcom/Bcm283x/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
+ }
+ EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf
+
+ MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+ MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+ Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
+ MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+ MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+ Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.inf
+
+ MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+
+ UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
+ Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.inf
+ Platform/Broadcom/Bcm283x/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.inf
+ Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.inf
+ Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxe.inf
+ ArmPkg/Drivers/TimerDxe/TimerDxe.inf
+ MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
+ MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
+
+ #
+ # FAT filesystem + GPT/MBR partitioning
+ #
+ MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
+ MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+ MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+ FatPkg/EnhancedFatDxe/Fat.inf
+
+ #
+ # ACPI Support
+ #
+ MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
+ MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf
+ MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
+ Platform/Broadcom/Bcm283x/AcpiTables/AcpiTables.inf
+
+ #
+ # SMBIOS Support
+ #
+ Platform/Broadcom/Bcm283x/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf
+ MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
+
+ #
+ # Bds
+ #
+ MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
+ MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
+ MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+ MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
+ MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
+ Platform/Broadcom/Bcm283x/Drivers/Logo/LogoDxe.inf
+ MdeModulePkg/Application/UiApp/UiApp.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
+ NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
+ NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
+ }
+
+ #
+ # SCSI Bus and Disk Driver
+ #
+ MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+ MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+ #
+ # USB Support
+ #
+ Platform/Broadcom/Bcm283x/Drivers/DwUsbHostDxe/DwUsbHostDxe.inf
+ MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
+ MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
+ MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
+ OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf
+
+ #
+ # SD/MMC support
+ #
+ Platform/Broadcom/Bcm283x/Drivers/SdHostDxe/SdHostDxe.inf
+ Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.inf
+ Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcDxe.inf
+
+ #
+ # Networking stack
+ #
+ MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
+ MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf
+
+ #
+ # UEFI application (Shell Embedded Boot Loader)
+ #
+ ShellPkg/Application/Shell/Shell.inf {
+ <LibraryClasses>
+ ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf
+ HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
+
+ <PcdsFixedAtBuild>
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
+ gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
+ gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
+ gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize|0x200000
+ }
diff --git a/Platform/Broadcom/Bcm283x/RaspberryPiPkg.fdf b/Platform/Broadcom/Bcm283x/RaspberryPiPkg.fdf
new file mode 100644
index 000000000000..4da8849b3646
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/RaspberryPiPkg.fdf
@@ -0,0 +1,450 @@
+## @file
+#
+# Copyright (c) 2011-2015, ARM Limited. All rights reserved.
+# Copyright (c) 2014, Linaro Limited. All rights reserved.
+# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+# Copyright (c) 2017 - 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
+#
+# 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.
+#
+##
+
+################################################################################
+#
+# FD Section
+# The [FD] Section is made up of the definition statements and a
+# description of what goes into the Flash Device Image. Each FD section
+# defines one flash "device" image. A flash device image may be one of
+# the following: Removable media bootable image (like a boot floppy
+# image,) an Option ROM image (that would be "flashed" into an add-in
+# card,) a System "Flash" image (that would be burned into a system's
+# flash) or an Update ("Capsule") image that will be used to update and
+# existing system flash.
+#
+################################################################################
+
+[FD.RPI_EFI]
+BaseAddress = 0x00000000|gArmTokenSpaceGuid.PcdFdBaseAddress
+Size = 0x00200000|gArmTokenSpaceGuid.PcdFdSize
+ErasePolarity = 1
+
+BlockSize = 0x00001000|gRaspberryPiTokenSpaceGuid.PcdFirmwareBlockSize
+NumBlocks = 0x200
+
+################################################################################
+#
+# Following are lists of FD Region layout which correspond to the locations of different
+# images within the flash device.
+#
+# Regions must be defined in ascending order and may not overlap.
+#
+# A Layout Region start with a eight digit hex offset (leading "0x" required) followed by
+# the pipe "|" character, followed by the size of the region, also in hex with the leading
+# "0x" characters. Like:
+# Offset|Size
+# PcdOffsetCName|PcdSizeCName
+# RegionType <FV, DATA, or FILE>
+#
+################################################################################
+
+#
+# ATF primary boot image
+#
+0x00000000|0x00010000
+FILE = Platform/Broadcom/Bcm283x/Binary/bl1.bin
+
+#
+# DTB.
+#
+0x00010000|0x00010000
+DATA = { 0x00 }
+
+#
+# ATF secondary boot image in FIP format (BL2 + BL31)
+#
+0x00020000|0x00010000
+FILE = Platform/Broadcom/Bcm283x/Binary/fip.bin
+
+#
+# UEFI image
+#
+0x00030000|0x001b0000
+gArmTokenSpaceGuid.PcdFvBaseAddress|gArmTokenSpaceGuid.PcdFvSize
+FV = FVMAIN_COMPACT
+
+#
+# Variables (0x20000 overall).
+#
+# 0x001e0000 - 0x001edfff EFI_FIRMWARE_VOLUME_HEADER
+# 0x001ee000 - 0x001eefff Event log
+# 0x001ef000 - 0x001effff EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER-
+# 0x001f0000 - 0x001fffff Data
+#
+
+# NV_VARIABLE_STORE
+0x001e0000|0x0000e000
+gRaspberryPiTokenSpaceGuid.PcdNvStorageVariableBase|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+
+DATA = {
+ ## This is the EFI_FIRMWARE_VOLUME_HEADER
+ # ZeroVector []
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ # FileSystemGuid: gEfiSystemNvDataFvGuid =
+ # { 0xFFF12B8D, 0x7696, 0x4C8B,
+ # { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
+ 0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C,
+ 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
+ # FvLength: 0x20000
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ # Signature "_FVH" # Attributes
+ 0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00,
+ # HeaderLength
+ 0x48, 0x00,
+ # CheckSum
+ 0x19, 0xF9,
+ # ExtHeaderOffset #Reserved #Revision
+ 0x00, 0x00, 0x00, 0x02,
+ # Blockmap[0]: 0x20 Blocks * 0x1000 Bytes / Block
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ # Blockmap[1]: End
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ## This is the VARIABLE_STORE_HEADER
+ # It is compatible with SECURE_BOOT_ENABLE == FALSE as well.
+ # Signature: gEfiAuthenticatedVariableGuid =
+ # { 0xaaf32c78, 0x947b, 0x439a,
+ # { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }}
+ 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43,
+ 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,
+ # Size: 0xe000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) -
+ # 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0xdfb8
+ # This can speed up the Variable Dispatch a bit.
+ 0xB8, 0xDF, 0x00, 0x00,
+ # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
+ 0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}
+
+# NV_EVENT_LOG
+0x001ee000|0x00001000
+gRaspberryPiTokenSpaceGuid.PcdNvStorageEventLogBase|gRaspberryPiTokenSpaceGuid.PcdNvStorageEventLogSize
+
+# NV_FTW_WORKING header
+0x001ef000|0x00001000
+gRaspberryPiTokenSpaceGuid.PcdNvStorageFtwWorkingBase|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+
+DATA = {
+ # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid =
+ # { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
+ 0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,
+ 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95,
+ # Crc:UINT32 #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved
+ 0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF,
+ # WriteQueueSize: UINT64
+ 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}
+
+# NV_FTW_WORKING data
+0x001f0000|0x00010000
+gRaspberryPiTokenSpaceGuid.PcdNvStorageFtwSpareBase|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+################################################################################
+#
+# FV Section
+#
+# [FV] section is used to define what components or modules are placed within a flash
+# device file. This section also defines order the components and modules are positioned
+# within the image. The [FV] section consists of define statements, set statements and
+# module statements.
+#
+################################################################################
+
+[FV.FvMain]
+FvNameGuid = 9a15aa37-d555-4a4e-b541-86391ff68164
+BlockSize = 0x40
+NumBlocks = 0 # This FV gets compressed so make it just big enough
+FvAlignment = 16 # FV alignment and FV attributes setting.
+ERASE_POLARITY = 1
+MEMORY_MAPPED = TRUE
+STICKY_WRITE = TRUE
+LOCK_CAP = TRUE
+LOCK_STATUS = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP = TRUE
+WRITE_STATUS = TRUE
+WRITE_LOCK_CAP = TRUE
+WRITE_LOCK_STATUS = TRUE
+READ_DISABLED_CAP = TRUE
+READ_ENABLED_CAP = TRUE
+READ_STATUS = TRUE
+READ_LOCK_CAP = TRUE
+READ_LOCK_STATUS = TRUE
+
+ INF MdeModulePkg/Core/Dxe/DxeMain.inf
+ INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
+
+ #
+ # PI DXE Drivers producing Architectural Protocols (EFI Services)
+ #
+ INF ArmPkg/Drivers/CpuDxe/CpuDxe.inf
+ INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+ INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+ INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+ INF Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf
+ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+ INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+!if $(SECURE_BOOT_ENABLE) == TRUE
+ INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
+!endif
+ INF MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
+ INF EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf
+ INF EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf
+ INF EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf
+ INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+
+ #
+ # Multiple Console IO support
+ #
+ INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+ INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+ INF Platform/Broadcom/Bcm283x/Drivers/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
+ INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+ INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+ INF Platform/Broadcom/Bcm283x/Drivers/DisplayDxe/DisplayDxe.inf
+
+ INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
+ INF Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.inf
+ INF Platform/Broadcom/Bcm283x/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.inf
+ INF Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.inf
+ INF Platform/Broadcom/Bcm283x/Drivers/ConfigDxe/ConfigDxe.inf
+ INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf
+ INF MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
+ INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
+
+ #
+ # FAT filesystem + GPT/MBR partitioning
+ #
+ INF MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
+ INF MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+ INF FatPkg/EnhancedFatDxe/Fat.inf
+ INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+
+ #
+ # UEFI application (Shell Embedded Boot Loader)
+ #
+ INF ShellPkg/Application/Shell/Shell.inf
+
+ #
+ # ACPI Support
+ #
+ INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
+ INF MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf
+ INF MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
+ INF RuleOverride = ACPITABLE Platform/Broadcom/Bcm283x/AcpiTables/AcpiTables.inf
+
+ #
+ # SMBIOS Support
+ #
+ INF Platform/Broadcom/Bcm283x/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf
+ INF MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
+
+ #
+ # Bds
+ #
+ INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
+ INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
+ INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+ INF MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
+ INF MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
+ INF MdeModulePkg/Application/UiApp/UiApp.inf
+
+ #
+ # Networking stack
+ #
+ INF MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ INF MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ INF MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ INF MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ INF MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
+ INF MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf
+
+ #
+ # SCSI Bus and Disk Driver
+ #
+ INF MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+ INF MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+ #
+ # USB Support
+ #
+ INF Platform/Broadcom/Bcm283x/Drivers/DwUsbHostDxe/DwUsbHostDxe.inf
+ INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
+ INF MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
+ INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
+ INF OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf
+
+ #
+ # SD/MMC support
+ #
+ INF Platform/Broadcom/Bcm283x/Drivers/SdHostDxe/SdHostDxe.inf
+ INF Platform/Broadcom/Bcm283x/Drivers/ArasanMmcHostDxe/ArasanMmcHostDxe.inf
+ INF Platform/Broadcom/Bcm283x/Drivers/PiMmcDxe/MmcDxe.inf
+
+ #
+ # Pi logo (splash screen)
+ #
+ INF Platform/Broadcom/Bcm283x/Drivers/Logo/LogoDxe.inf
+
+ #
+ # FDT (GUID matches mRaspberryPiFfsFileGuid in RaspberryPiPlatformDxe)
+ #
+ FILE FREEFORM = DF5DA223-1D27-47C3-8D1B-9A41B55A18BC {
+ SECTION RAW = Platform/Broadcom/Bcm283x/DeviceTree/bcm2710-rpi-3-b.dtb
+ }
+
+[FV.FVMAIN_COMPACT]
+FvAlignment = 16
+ERASE_POLARITY = 1
+MEMORY_MAPPED = TRUE
+STICKY_WRITE = TRUE
+LOCK_CAP = TRUE
+LOCK_STATUS = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP = TRUE
+WRITE_STATUS = TRUE
+WRITE_LOCK_CAP = TRUE
+WRITE_LOCK_STATUS = TRUE
+READ_DISABLED_CAP = TRUE
+READ_ENABLED_CAP = TRUE
+READ_STATUS = TRUE
+READ_LOCK_CAP = TRUE
+READ_LOCK_STATUS = TRUE
+
+ INF ArmPlatformPkg/PrePi/PeiUniCore.inf
+ FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 {
+ SECTION GUIDED EE4E5898-3914-4259-9D6E-DC7BD79403CF PROCESSING_REQUIRED = TRUE {
+ SECTION FV_IMAGE = FVMAIN
+ }
+ }
+
+################################################################################
+#
+# Rules are use with the [FV] section's module INF type to define
+# how an FFS file is created for a given INF file. The following Rule are the default
+# rules for the different module type. User can add the customized rules to define the
+# content of the FFS file.
+#
+################################################################################
+
+
+############################################################################
+# Example of a DXE_DRIVER FFS file with a Checksum encapsulation section #
+############################################################################
+#
+#[Rule.Common.DXE_DRIVER]
+# FILE DRIVER = $(NAMED_GUID) {
+# DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+# COMPRESS PI_STD {
+# GUIDED {
+# PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+# UI STRING="$(MODULE_NAME)" Optional
+# VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+# }
+# }
+# }
+#
+############################################################################
+
+[Rule.Common.SEC]
+ FILE SEC = $(NAMED_GUID) RELOCS_STRIPPED FIXED {
+ TE TE Align = Auto $(INF_OUTPUT)/$(MODULE_NAME).efi
+ }
+
+[Rule.Common.PEI_CORE]
+ FILE PEI_CORE = $(NAMED_GUID) FIXED {
+ TE TE Align = Auto $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING ="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.PEIM]
+ FILE PEIM = $(NAMED_GUID) FIXED {
+ PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ TE TE Align = Auto $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.PEIM.TIANOCOMPRESSED]
+ FILE PEIM = $(NAMED_GUID) DEBUG_MYTOOLS_IA32 {
+ PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ GUIDED A31280AD-481E-41B6-95E8-127F4C984779 PROCESSING_REQUIRED = TRUE {
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+ }
+
+[Rule.Common.DXE_CORE]
+ FILE DXE_CORE = $(NAMED_GUID) {
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.UEFI_DRIVER]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.DXE_DRIVER]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ RAW ACPI Optional |.acpi
+ RAW ASL Optional |.aml
+ }
+
+[Rule.Common.DXE_RUNTIME_DRIVER]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.UEFI_APPLICATION]
+ FILE APPLICATION = $(NAMED_GUID) {
+ UI STRING ="$(MODULE_NAME)" Optional
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ }
+
+[Rule.Common.UEFI_DRIVER.BINARY]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional |.depex
+ PE32 PE32 |.efi
+ UI STRING="$(MODULE_NAME)" Optional
+ VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+ }
+
+[Rule.Common.UEFI_APPLICATION.BINARY]
+ FILE APPLICATION = $(NAMED_GUID) {
+ PE32 PE32 |.efi
+ UI STRING="$(MODULE_NAME)" Optional
+ VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+ }
+
+[Rule.Common.USER_DEFINED.ACPITABLE]
+ FILE FREEFORM = $(NAMED_GUID) {
+ RAW ACPI |.acpi
+ RAW ASL |.aml
+ }
diff --git a/Platform/Broadcom/Bcm283x/Readme.md b/Platform/Broadcom/Bcm283x/Readme.md
new file mode 100644
index 000000000000..a2633434c7bf
--- /dev/null
+++ b/Platform/Broadcom/Bcm283x/Readme.md
@@ -0,0 +1,263 @@
+Raspberry Pi (Broadcom BCM283x) EDK2 Platform Support
+=====================================================
+
+# Summary
+
+This is a port of 64-bit Tiano Core UEFI firmware for the Raspberry Pi 3/3B+ platforms,
+based on [Ard Bisheuvel's 64-bit](http://www.workofard.com/2017/02/uefi-on-the-pi/)
+and [Microsoft's 32-bit](https://github.com/ms-iot/RPi-UEFI/tree/ms-iot/Pi3BoardPkg)
+implementations, as maintained by [Andrei Warkentin](https://github.com/andreiw/RaspberryPiPkg).
+
+This is meant as a generally useful 64-bit ATF + UEFI implementation for the Raspberry
+Pi 3/3B+ which should be good enough for most kind of UEFI development, as well as for
+running consummer Operating Systems in such as Linux or Windows.
+
+Raspberry Pi is a trademark of the [Raspberry Pi Foundation](http://www.raspberrypi.org).
+
+# Status
+
+This firmware, that has been validated to compile against the current
+[edk2](https://github.com/tianocore/edk2)/[edk2-platforms](https://github.com/tianocore/edk2-platforms),
+should be able to boot Linux (SUSE, Ubuntu), NetBSD, FreeBSD as well as Windows 10 ARM64
+(full GUI version).
+
+It also provides support for ATF ([Arm Trusted Platform](https://github.com/ARM-software/arm-trusted-firmware)).
+
+HDMI and the mini-UART serial port can be used for output devices, with mirrored output.
+USB keyboards and the mini-UART serial port can be used as input.
+
+The boot order is currently hardcoded, first to the USB ports and then to the uSD card.
+If there no bootable media media is found, the UEFI Shell is launched.
+<kbd>Esc</kbd> enters platform setup. <kbd>F1</kbd> boots the UEFI Shell.
+
+# Building
+
+(These instructions were validated against the latest edk2 / edk2-platforms /
+edk2-non-osi as of 2018.12.06, on a Debian 9.6 x64 system).
+
+You may need to install the relevant compilation tools. Especially you should have the
+ACPI Source Language (ASL) compiler, `nasm` as well as a native compiler installed.
+On a Debian system, you can get these prerequisites installed with:
+```
+sudo apt-get install build-essential acpica-tools nasm uuid-dev
+```
+
+**IMPORTANT:** Do not be tempted to install Debian's ARM64 GCC cross compiler package,
+as this currently results in GCC 6.x being installed, which is known to create issues.
+Instead, you should stick with GCC 5.5, such as the one provided by Linaro, as per the
+instructions below.
+
+You can then build the firmware as follows:
+
+```
+mkdir ~/workspace
+cd ~/workspace
+git clone https://github.com/tianocore/edk2.git
+# The following is only needed once, after you cloned edk2
+make -C edk2/BaseTools
+# You may also have to issue git submodule init/update in edk2 if you want to enable Secure Boot
+git clone https://github.com/tianocore/edk2-platforms.git
+git clone https://github.com/tianocore/edk2-non-osi.git
+# You *MUST* use a GCC5 toolchain (*NOT* GCC6 or later), such as the one from
+# https://releases.linaro.org/components/toolchain/binaries/5.5-2017.10/aarch64-linux-gnu/
+# GCC6 and later toolchains may result in Synchronous Exceptions. You have been warned!
+wget https://releases.linaro.org/components/toolchain/binaries/5.5-2017.10/aarch64-linux-gnu/gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu.tar.xz
+tar -xJvf gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu.tar.xz
+# If you have multiple AARCH64 toolchains, make sure the GCC5 one comes first in your path
+export PATH=$PWD/gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu/bin:$PATH
+export GCC5_AARCH64_PREFIX=aarch64-linux-gnu-
+export WORKSPACE=$PWD
+export PACKAGES_PATH=$WORKSPACE/edk2:$WORKSPACE/edk2-platforms:$WORKSPACE/edk2-non-osi
+. edk2/edksetup.sh
+build -a AARCH64 -t GCC5 -p edk2-platforms/Platform/Broadcom/Bcm283x/RaspberryPiPkg.dsc -b RELEASE -DBUILD_EPOCH=`date +%s`
+```
+
+# Booting the firmware
+
+1. Format a uSD card as FAT32
+2. Copy the generated `RPI_EFI.fd` firmware onto the partition
+3. Download and copy the following files from https://github.com/raspberrypi/firmware/tree/master/boot
+ - `bootcode.bin`
+ - `fixup.dat`
+ - `start.elf`
+4. Create a `config.txt` with the following content:
+ ```
+ arm_control=0x200
+ enable_uart=1
+ armstub=RPI_EFI.fd
+ disable_commandline_tags=1
+ ```
+5. Insert the uSD card and power up the Pi.
+
+Note that if you have a model 3+ or a model 3 where you enabled USB boot through OTP
+(see [here](https://www.raspberrypi.org/documentation/hardware/raspberrypi/bootmodes/msd.md))
+you may also be able to boot from a FAT32 USB driver rather than uSD.
+
+# Notes
+
+## ARM Trusted Firmware (ATF)
+
+The ATF binaries being used were compiled from the latest ATF source.
+
+For more details on the ATF compilation, see the [README](./Binary/README.md) in the `Binary/` directory.
+
+## Custom Device Tree
+
+The default Device Tree included in the firmware is the one for a Raspberry Pi 3 Model B (not B+).
+If you want to use a different Device Tree, to boot a Pi 3 Model B+ for instance (for which a
+DTB is also provided under `DeviceTree/`), you should copy the relevant `.dtb` into the root of
+the SD or USB, and then edit your `config.txt` so that it looks like:
+
+```
+(...)
+disable_commandline_tags=2
+device_tree_address=0x10000
+device_tree_end=0x20000
+device_tree=bcm2710-rpi-3-b-plus.dtb
+```
+
+Note: the address range **must** be `[0x10000:0x20000]`.
+`dtoverlay` and `dtparam` parameters are also supported **when** providing a Device Tree`.
+
+## Custom `bootargs`
+
+This firmware will honor the command line passed by the GPU via `cmdline.txt`.
+
+Note, that the ultimate contents of `/chosen/bootargs` are a combination of several pieces:
+- Original `/chosen/bootargs` if using the internal DTB. Seems to be completely discarded by GPU when booting with a custom device tree.
+- GPU-passed hardware configuration. This one is always present.
+- Additional boot options passed via `cmdline.txt`.
+
+# Tested Platforms
+
+## Ubuntu
+
+[Ubuntu 18.04 LTS](http://releases.ubuntu.com/18.04/) has been tested and confirmed to work,
+on a Raspberry 3 Model B, including the installation process. Note however that network
+installation and networking may not work on the Model B+, due to the `lan78xx` Linux driver
+still requiring some support.
+
+Below are the steps you can follow to install Ubuntu LTS onto SD/USB:
+* Download the latest Ubuntu LTS ARM64 [`mini.iso`](http://ports.ubuntu.com/ubuntu-ports/dists/bionic/main/installer-arm64/current/images/netboot/mini.iso).
+* Partition the media as MBR and create a ~200 MB FAT32 partition on it with MBR type `0x0c`.
+ Note: Do not be tempted to use GPT partition scheme or `0xef` (EFI System Partition) for the
+ type, as none of these are supported by the Raspberry Pi's internal boot rom.
+* Extract the full content of the ISO onto the partition you created.
+* Also extract the GRUB EFI bootloader `bootaa64.efi` from `/boot/grub/efi.img` to `/boot/grub/`.
+ Note: Do not be tempted to copy this file to another directory (such as `/efi/boot/`) as GRUB looks for its
+ modules and configuration data in the same directory as the EFI loader and also, the installation
+ process will create a `bootaa64.efi` into `/efi/boot/`.
+* If needed, copy the UEFI firmware files (`RPI_EFI.fd`, `bootcode.bin`, `fixup.dat` and `start.elf`)
+ onto the FAT partition.
+* Boot the pi and let it go into the UEFI shell.
+* Navigate to `fs0:` then `/boot/grub/` and launch the GRUB efi loader.
+* Follow the Ubuntu installation process.
+
+Note: Because Ubuntu operates in quiet mode by default (no boot messages), you may think the system is frozen
+on first reboot after installation. However, if you wait long enough you **will** get to a login prompt.
+
+Once Linux is running, if desired, you can disable quiet boot, as well as force the display
+of the GRUB selector, by editing `/etc/default/grub` and changing:
+* `GRUB_TIMEOUT_STYLE=hidden` → `GRUB_TIMEOUT_STYLE=menu`
+* `GRUB_CMDLINE_LINUX_DEFAULT="splash quiet"` → `GRUB_CMDLINE_LINUX_DEFAULT=""`
+
+Then, to have your changes applied run `update-grub` and reboot.
+
+## Other Linux distributions
+
+* Debian ARM64 does not currently work, most likely due to missing required module support
+ in its kernel. However its installation process works, so it may be possible to get it
+ running with a custom kernel.
+
+* OpenSUSE Leap 42.3 has been reported to work on Raspberry 3 Model B.
+
+* Other ARM64 Linux releases, that support UEFI boot and have the required hardware support
+ for Pi hardware are expected to run, though their installation process might require some
+ cajoling.
+
+## Windows
+
+Windows 10 1809 for ARM64 (build 17763) has been tested and confirmed to work (after replacing
+`C:\Windows\System32\Drivers\WppRecorder.sys` with an older version, since the one from 1809
+appears to be buggy across all archs, and results in a similar BSOD when trying to run Windows
+To Go on x64 with native drivers for instance).
+
+Windows 10 1803 for ARM64 and earlier do not work due to the presence of a hardware ASSERT check
+in the Windows kernel, that was removed in later versions.
+
+You probably want to look at https://www.worproject.ml/ as well as the
+[Windows thread in the original RaspberryPiPkg](https://github.com/andreiw/RaspberryPiPkg/issues/12)
+for installation details.
+
+## Other platforms
+
+Details you may need to run other platforms, including FreeBSD, is provided in the
+[Readme from the original RaspberryPiPkg](https://github.com/andreiw/RaspberryPiPkg).
+
+# Limitations
+
+## HDMI
+
+The UEFI HDMI video support relies on the VC (that's the GPU)
+firmware to correctly detect and configure the attached screen.
+Some screens are slow, and this detection may not occur fast
+enough. Finally, you may wish to be able to boot your Pi
+headless, yet be able to attach a display to it later for
+debugging.
+
+To accommodate these issues, the following extra lines
+are recommended for your `config.txt`:
+- `hdmi_force_hotplug=1` to allow plugging in video after system is booted.
+- `hdmi_group=1` and `hdmi_mode=4` to force a specific mode, both to accommodate
+ late-plugged screens or buggy/slow screens. See [official documentation](https://www.raspberrypi.org/documentation/configuration/config-txt/video.md)
+ to make sense of these parameters (example above sets up 720p 60Hz).
+
+## NVRAM
+
+The Raspberry Pi has no NVRAM.
+
+NVRAM is emulated, with the non-volatile store backed by the UEFI image itself. This means
+that any changes made in UEFI proper will be persisted, but changes made in HLOS will not.
+It would be nice to implement ATF-assisted warm reboot, to allow persisting HLOS
+NVRAM changes.
+
+## RTC
+
+The Rasberry Pi has no RTC.
+
+`RtcEpochSeconds` NVRAM variable is used to store the boot time
+This should allow you to set whatever date/time you
+want using the Shell date and time commands. While in UEFI
+or HLOS, the time will tick forward. `RtcEpochSeconds`
+is not updated on reboots.
+
+## uSD
+
+UEFI supports both the Arasan SDHCI and the Broadcom SDHost controllers to access the uSD slot.
+You can use either. The other controller gets routed to the SDIO card. The choice made will
+impact ACPI OSes booted (e.g. Windows 10). Arasan, being an SDIO controller, is usually used
+with the WiFi adapter where available. SDHost cannot be used with SDIO. In UEFI setup screen:
+- go to `Device Manager`
+- go to `Raspberry Pi Configuration`
+- go to `Chipset`
+- configure `Boot uSD Routing`
+
+Known issues:
+- Arasan HS/4bit support is missing.
+- No 8 bit mode support for (e)MMC (irrelevant for the Pi 3).
+- Hacky (e)MMC support (no HS).
+- No card removal/replacement detection, tons of timeouts and slow down during boot without an uSD card present.
+
+## USB
+
+- USB1 BBB mass storage devices untested (USB2 and USB3 devices are fine).
+- USB1 CBI mass storage devices don't work (e.g. HP FD-05PUB floppy).
+
+## ACPI
+
+ACPI should match the MS-IoT one. Both Arasan and SDHost SD controllers are exposed.
+
+## Missing Functionality
+
+- Network booting via onboard NIC.
+- Ability to switch UART use to PL011.
--
2.17.0.windows.1
next prev parent reply other threads:[~2018-12-07 12:06 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-12-07 12:05 [PATCH v1 edk2-platfoms 0/2] Platform/Broadcom: Add Raspberry Pi 3 support Pete Batard
2018-12-07 12:05 ` Pete Batard [this message]
2018-12-07 12:05 ` [PATCH v1 edk2-platfoms 2/2] Platform/Broadcom: Add Raspberry Pi 3 support (non OSI) Pete Batard
2018-12-07 14:08 ` [PATCH v1 edk2-platfoms 0/2] Platform/Broadcom: Add Raspberry Pi 3 support Ard Biesheuvel
2018-12-07 14:33 ` Pete Batard
2018-12-07 14:39 ` Ard Biesheuvel
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=20181207120511.8724-2-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