diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c
new file mode 100644
index 000000000000..cabe4f652cf5
--- /dev/null
+++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c
@@ -0,0 +1,284 @@
+/** @file
+*
+*  Copyright (c) 2017, 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 <IndustryStandard/Acpi.h>
+#include <libfdt.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+
+#include "ConsolePrefDxe.h"
+
+#define SPCR_SIG    EFI_ACPI_2_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE
+
+extern  UINT8                     ConsolePrefHiiBin[];
+extern  UINT8                     ConsolePrefDxeStrings[];
+
+typedef struct {
+  VENDOR_DEVICE_PATH              VendorDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL        End;
+} HII_VENDOR_DEVICE_PATH;
+
+STATIC HII_VENDOR_DEVICE_PATH     mConsolePrefDxeVendorDevicePath = {
+  {
+    {
+      HARDWARE_DEVICE_PATH,
+      HW_VENDOR_DP,
+      {
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+      }
+    },
+    CONSOLE_PREF_FORMSET_GUID
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      (UINT8) (END_DEVICE_PATH_LENGTH),
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+    }
+  }
+};
+
+STATIC EFI_EVENT                  mReadyToBootEvent;
+STATIC UINTN                      mSpcrTableKey;
+
+STATIC
+EFI_STATUS
+InstallHiiPages (
+  VOID
+  )
+{
+  EFI_STATUS                      Status;
+  EFI_HII_HANDLE                  HiiHandle;
+  EFI_HANDLE                      DriverHandle;
+
+  DriverHandle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  &mConsolePrefDxeVendorDevicePath,
+                  NULL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  HiiHandle = HiiAddPackages (&gConsolePrefFormSetGuid,
+                              DriverHandle,
+                              ConsolePrefDxeStrings,
+                              ConsolePrefHiiBin,
+                              NULL);
+
+  if (HiiHandle == NULL) {
+    gBS->UninstallMultipleProtocolInterfaces (DriverHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  &mConsolePrefDxeVendorDevicePath,
+                  NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+  return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+RemoveDtStdoutPath (
+  VOID
+)
+{
+  VOID        *Dtb;
+  INT32       Node;
+  INT32       Error;
+  EFI_STATUS  Status;
+
+  Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &Dtb);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "%a: could not retrieve DT blob - %r\n", __FUNCTION__,
+      Status));
+  }
+
+  Node = fdt_path_offset (Dtb, "/chosen");
+  if (Node < 0) {
+    return;
+  }
+
+  Error = fdt_delprop (Dtb, Node, "stdout-path");
+  if (Error) {
+    DEBUG ((DEBUG_INFO, "%a: Failed to delete 'stdout-path' property: %a\n",
+      __FUNCTION__, fdt_strerror (Error)));
+  }
+}
+
+STATIC
+VOID
+OnReadyToBoot (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  CONSOLE_PREF_VARSTORE_DATA      ConsolePref;
+  UINTN                           BufferSize;
+  EFI_STATUS                      Status;
+  VOID                            *Gop;
+  EFI_ACPI_TABLE_PROTOCOL         *AcpiTable;
+
+  BufferSize = sizeof (ConsolePref);
+  Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,
+                  &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: variable '%s' could not be read - bailing!\n", __FUNCTION__,
+      CONSOLE_PREF_VARIABLE_NAME));
+    return;
+  }
+
+  if (ConsolePref.Console == CONSOLE_PREF_SERIAL) {
+    DEBUG ((DEBUG_INFO,
+      "%a: serial console preferred - doing nothing\n", __FUNCTION__));
+    return;
+  }
+
+  //
+  // Check if any GOP instances exist: if so, disable stdout-path and SPCR
+  //
+  Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, &Gop);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO,
+      "%a: no GOP instances found - doing nothing (%r)\n", __FUNCTION__,
+      Status));
+    return;
+  }
+
+  RemoveDtStdoutPath ();
+
+  if (mSpcrTableKey != 0) {
+    Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL,
+                    (VOID **)&AcpiTable);
+    ASSERT_EFI_ERROR (Status);
+
+    Status = AcpiTable->UninstallAcpiTable (AcpiTable, mSpcrTableKey);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "%a: failed to uninstall SPCR table - %r\n",
+        __FUNCTION__, Status));
+    }
+  }
+}
+
+STATIC
+EFI_STATUS
+OnInstallAcpiTable (
+  IN EFI_ACPI_SDT_HEADER    *Table,
+  IN EFI_ACPI_TABLE_VERSION Version,
+  IN UINTN                  TableKey
+  )
+{
+  if (Table->Signature == SPCR_SIG) {
+    mSpcrTableKey = TableKey;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  The entry point for ConsolePrefDxe driver.
+
+  @param[in] ImageHandle     The image handle of the driver.
+  @param[in] SystemTable     The system table.
+
+  @retval EFI_ALREADY_STARTED     The driver already exists in system.
+  @retval EFI_OUT_OF_RESOURCES    Fail to execute entry point due to lack of
+                                  resources.
+  @retval EFI_SUCCES              All the related protocols are installed on
+                                  the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+ConsolePrefDxeEntryPoint (
+  IN EFI_HANDLE                   ImageHandle,
+  IN EFI_SYSTEM_TABLE             *SystemTable
+  )
+{
+  EFI_STATUS                      Status;
+  CONSOLE_PREF_VARSTORE_DATA      ConsolePref;
+  UINTN                           BufferSize;
+  EFI_ACPI_SDT_PROTOCOL           *Sdt;
+
+  //
+  // Get the current console preference from the ConsolePref variable.
+  //
+  BufferSize = sizeof (ConsolePref);
+  Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,
+                  &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO,
+      "%a: no console preference found, defaulting to graphical\n",
+      __FUNCTION__));
+    ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;
+  }
+
+  if (!EFI_ERROR (Status) &&
+      ConsolePref.Console != CONSOLE_PREF_GRAPHICAL &&
+      ConsolePref.Console != CONSOLE_PREF_SERIAL) {
+    DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to graphical\n",
+      __FUNCTION__, CONSOLE_PREF_VARIABLE_NAME));
+    ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;
+    Status = EFI_INVALID_PARAMETER; // trigger setvar below
+  }
+
+  //
+  // Write the newly selected default value back to the variable store.
+  //
+  if (EFI_ERROR (Status)) {
+    ZeroMem (&ConsolePref.Reserved, sizeof (ConsolePref.Reserved));
+    Status = gRT->SetVariable (CONSOLE_PREF_VARIABLE_NAME,
+                    &gConsolePrefFormSetGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                    sizeof (ConsolePref), &ConsolePref);
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: gRT->SetVariable () failed - %r\n",
+        __FUNCTION__, Status));
+      return Status;
+    }
+  }
+
+  Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&Sdt);
+  if (!EFI_ERROR (Status)) {
+    //
+    // If we have the SDT protocol, use it to register a ACPI table
+    // installation notification callback so we can record the table
+    // key of the SPCR table.
+    //
+    Status = Sdt->RegisterNotify (TRUE, OnInstallAcpiTable);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "%a: Sdt->RegisterNotify () failed - %r\n",
+        __FUNCTION__, Status));
+    }
+  }
+
+  Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+                  OnReadyToBoot, NULL, &gEfiEventReadyToBootGuid,
+                  &mReadyToBootEvent);
+  ASSERT_EFI_ERROR (Status);
+
+  return InstallHiiPages ();
+}
diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h
new file mode 100644
index 000000000000..7ec420f89013
--- /dev/null
+++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h
@@ -0,0 +1,31 @@
+/** @file
+*
+*  Copyright (c) 2017, 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 __CONSOLE_PREF_DXE_H__
+#define __CONSOLE_PREF_DXE_H__
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/ConsolePrefFormSet.h>
+
+#define CONSOLE_PREF_GRAPHICAL      0x0
+#define CONSOLE_PREF_SERIAL         0x1
+
+#define CONSOLE_PREF_VARIABLE_NAME  L"ConsolePref"
+
+typedef struct {
+  UINT8         Console;
+  UINT8         Reserved[3];
+} CONSOLE_PREF_VARSTORE_DATA;
+
+#endif
diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf
new file mode 100644
index 000000000000..d8b412b9200a
--- /dev/null
+++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf
@@ -0,0 +1,62 @@
+## @file
+#
+#  Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
+#
+#  This program and the accompanying materials are licensed and made
+#  available under the terms and conditions of the BSD License which
+#  accompanies this distribution.  The full text of the license may be
+#  found at 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                 = ConsolePrefDxe
+  FILE_GUID                 = bbe2668c-0efc-46fb-9137-4f2da8f419f3
+  MODULE_TYPE               = DXE_DRIVER
+  VERSION_STRING            = 1.0
+  ENTRY_POINT               = ConsolePrefDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES      = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+  ConsolePrefDxe.c
+  ConsolePrefHii.vfr
+  ConsolePrefHii.uni
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  FdtLib
+  HiiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  UefiRuntimeServicesTableLib
+
+[Guids]
+  gConsolePrefFormSetGuid
+  gFdtTableGuid
+  gEfiEventReadyToBootGuid
+
+[Protocols]
+  gEfiAcpiTableProtocolGuid
+  gEfiAcpiSdtProtocolGuid
+  gEfiGraphicsOutputProtocolGuid
+
+[Depex]
+  gEfiVariableArchProtocolGuid        AND
+  gEfiVariableWriteArchProtocolGuid
diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni
new file mode 100644
index 000000000000..0442adf77163
--- /dev/null
+++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni
@@ -0,0 +1,27 @@
+/** @file
+*
+*  Copyright (c) 2017, 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.
+*
+**/
+
+#langdef en-US  "English"
+
+#string STR_FORM_SET_TITLE             #language en-US "Console Preference Selection"
+#string STR_FORM_SET_TITLE_HELP        #language en-US "Press <Enter> to choose between graphical and serial console."
+
+#string STR_MAIN_FORM_TITLE            #language en-US "Console Preference Selection"
+#string STR_NULL_STRING                #language en-US ""
+
+#string STR_CONSOLE_PREF_SELECT_PROMPT #language en-US "Preferred console"
+#string STR_CONSOLE_PREF_SELECT_HELP   #language en-US "Select the preferred console if both graphical and serial are available."
+
+#string STR_CONSOLE_PREF_GRAPHICAL     #language en-US "Graphical"
+#string STR_CONSOLE_PREF_SERIAL        #language en-US "Serial"
diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr
new file mode 100644
index 000000000000..fdfba5cf4cb3
--- /dev/null
+++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr
@@ -0,0 +1,51 @@
+/** @file
+*
+*  Copyright (c) 2017, 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 "ConsolePrefDxe.h"
+
+//
+// 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      = CONSOLE_PREF_FORMSET_GUID,
+  title     = STRING_TOKEN(STR_FORM_SET_TITLE),
+  help      = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+  efivarstore CONSOLE_PREF_VARSTORE_DATA,
+    attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,  // EFI variable attributes
+    name  = ConsolePref,
+    guid  = CONSOLE_PREF_FORMSET_GUID;
+
+  form formid = 0x1000,
+    title  = STRING_TOKEN(STR_MAIN_FORM_TITLE);
+
+    oneof varid = ConsolePref.Console,
+        prompt      = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_PROMPT),
+        help        = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_HELP),
+        flags       = NUMERIC_SIZE_1 | INTERACTIVE,
+        option text = STRING_TOKEN(STR_CONSOLE_PREF_GRAPHICAL), value = CONSOLE_PREF_GRAPHICAL, flags = DEFAULT;
+        option text = STRING_TOKEN(STR_CONSOLE_PREF_SERIAL), value = CONSOLE_PREF_SERIAL, flags = 0;
+    endoneof;
+
+    subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+  endform;
+
+endformset;
