[edk2-devel] [PATCH v1 0/1] Added GOP driver for DisplayLink-based Universal USB Docks to edk2-platforms

Andy Hayes posted 1 patch 4 years, 7 months ago
Only 0 patches received!
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc                    |   61 ++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf  |   63 ++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h                 |  129 +++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h       |  109 ++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h       |  284 +++++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c |  137 +++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c        |  235 +++++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c                 |  598 +++++++++++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c                  |  587 +++++++++++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c       |  144 +++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c       | 1109 ++++++++++++++++++++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c          |  180 ++++
Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c           |  254 +++++
Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md                             |   77 ++
Maintainers.txt                                                          |    5 +
15 files changed, 3972 insertions(+)
[edk2-devel] [PATCH v1 0/1] Added GOP driver for DisplayLink-based Universal USB Docks to edk2-platforms
Posted by Andy Hayes 4 years, 7 months ago
From 4a42eb997aeb3699217b40bf3bc47dec56458847 Mon Sep 17 00:00:00 2001
From: "Andy Hayes" < andy.hayes@displaylink.com >
Date: Wed, 14 Aug 2019 15:30:20 +0100
Subject: [PATCH v1 0/1] Added GOP graphics driver for DisplayLink-based Universal USB Docks to edk2-platforms

andy.hayes@displaylink.com (1):
  Added GOP driver for USB Docks which use DisplayLink chips.

.../DisplayLinkPkg/DisplayLinkPkg.dsc         |   61 +
.../DisplayLinkGop/DisplayLinkGopDxe.inf      |   63 +
.../DisplayLinkPkg/DisplayLinkGop/Edid.h      |  129 ++
.../DisplayLinkGop/UsbDescriptors.h           |  109 ++
.../DisplayLinkGop/UsbDisplayLink.h           |  284 +++++
.../DisplayLinkGop/CapabilityDescriptor.c     |  137 ++
.../DisplayLinkGop/ComponentName.c            |  235 ++++
.../DisplayLinkPkg/DisplayLinkGop/Edid.c      |  598 +++++++++
.../DisplayLinkPkg/DisplayLinkGop/Gop.c       |  587 +++++++++
.../DisplayLinkGop/UsbDescriptors.c           |  144 +++
.../DisplayLinkGop/UsbDisplayLink.c           | 1109 +++++++++++++++++
.../DisplayLinkGop/UsbTransfer.c              |  180 +++
.../DisplayLinkGop/VideoModes.c               |  254 ++++
Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md  |   77 ++
Maintainers.txt                               |    5 +
15 files changed, 3972 insertions(+)
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md

--
2.17.1

-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#45609): https://edk2.groups.io/g/devel/message/45609
Mute This Topic: https://groups.io/mt/32864415/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

From 4a42eb997aeb3699217b40bf3bc47dec56458847 Mon Sep 17 00:00:00 2001
From: "andy.hayes@displaylink.com" <ahayes@UKCAML3148.NewnhamResearch.local>
Date: Wed, 14 Aug 2019 15:28:51 +0100
Subject: [PATCH v1 1/1] Added GOP driver for USB Docks using DisplayLink
 chips.

---
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc                    |   61 ++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf  |   63 ++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h                 |  129 +++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h       |  109 ++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h       |  284 +++++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c |  137 +++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c        |  235 +++++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c                 |  598 +++++++++++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c                  |  587 +++++++++++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c       |  144 +++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c       | 1109 ++++++++++++++++++++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c          |  180 ++++
 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c           |  254 +++++
 Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md                             |   77 ++
 Maintainers.txt                                                          |    5 +
 15 files changed, 3972 insertions(+)

diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
new file mode 100644
index 000000000000..955331ba6076
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
@@ -0,0 +1,61 @@
+#/** @file
+#
+#  Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+  PLATFORM_NAME                  = DisplayLinkPkg
+  PLATFORM_GUID                  = ad3b37b0-f798-4f97-9b3f-0c6f43d7c993
+  PLATFORM_VERSION               = 0.1
+  DSC_SPECIFICATION              = 0x0001001C
+  OUTPUT_DIRECTORY               = Build/DisplayLink
+  SUPPORTED_ARCHITECTURES        = X64|IA32|AARCH64|ARM
+  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
+  SKUID_IDENTIFIER               = DEFAULT
+
+[LibraryClasses]
+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+  DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
+  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+  UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
+
+[LibraryClasses.common.UEFI_DRIVER]
+  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+
+[LibraryClasses.AARCH64]
+  NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
+  NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
+
+[LibraryClasses.ARM]
+  NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
+  NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
+
+[PcdsFixedAtBuild]
+!ifdef $(DEBUG_ENABLE_OUTPUT)
+  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x3f
+  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80080043  # Flags to control amount of debug output - see https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Debugging
+  gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x07
+!endif
+
+[Components]
+  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
+
+[BuildOptions]
+  *_*_*_CC_FLAGS               = -D DISABLE_NEW_DEPRECATED_INTERFACES -D INF_DRIVER_VERSION=$(INF_DRIVER_VERSION)
+  GCC:RELEASE_*_*_CC_FLAGS     = -DMDEPKG_NDEBUG
+  MSFT:RELEASE_*_*_CC_FLAGS    = /D MDEPKG_NDEBUG
+!ifdef $(COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE)
+  *_*_*_CC_FLAGS = -D COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
+!endif
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
new file mode 100644
index 000000000000..9f1e1cd7f3b3
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
@@ -0,0 +1,63 @@
+#/** @file
+# USB DisplayLink driver that implements blt and EDID commands
+#
+# USB DisplayLink driver consumes I/O Protocol and Device Path Protocol, and produces
+# Graphics Output Protocol on DisplayLink devices.
+# 1. DisplayLink reference
+# 2. UEFI Specification, v2.1
+#
+#  Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = DisplayLinkGop
+  FILE_GUID                      = 2D2E62AA-9ECF-43b7-8219-94E7FC713DFF
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = UsbDisplayLinkDriverBindingEntryPoint
+  UNLOAD_IMAGE                   = UsbDisplayLinkDriverCombinedGopUnload
+  INF_DRIVER_VERSION             = 0x00000001
+
+[Sources]
+  CapabilityDescriptor.c
+  ComponentName.c
+  Edid.c
+  Gop.c
+  UsbDescriptors.c
+  UsbDisplayLink.c
+  UsbDisplayLink.h
+  UsbTransfer.c
+  VideoModes.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  ReportStatusCodeLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  UefiUsbLib
+
+[Protocols]
+  gEfiUsbIoProtocolGuid                         ## TO_START
+  gEfiEdidActiveProtocolGuid                    # PROTOCOL BY_START
+  gEfiEdidDiscoveredProtocolGuid                # PROTOCOL BY_START
+  gEfiEdidOverrideProtocolGuid                  # PROTOCOL TO_START
+  gEfiHiiDatabaseProtocolGuid
+  gEfiHiiFontProtocolGuid
+
+[Guids]
+  gEfiEventExitBootServicesGuid
+  gEfiGlobalVariableGuid
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize     ## CONSUMES
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
new file mode 100644
index 000000000000..80e443ced4a8
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
@@ -0,0 +1,129 @@
+/** @file Edid.h
+ * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
+ * Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#ifndef EDID_H
+#define EDID_H
+
+#include "UsbDisplayLink.h"
+
+#define EDID_HEADER_SIZE                          ((size_t)8)
+#define EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES  ((UINTN)3)
+#define EDID_NUMBER_OF_STANDARD_TIMINGS           ((UINTN)8)
+#define EDID_NUMBER_OF_DETAILED_TIMINGS           ((UINTN)4)
+
+
+typedef struct {
+  UINT16  HRes;
+  UINT16  VRes;
+  UINT16  Refresh;
+} EDID_TIMING;
+
+
+EFI_STATUS
+DlEdidGetSupportedVideoMode (
+    UINT32 ModeNumber,
+    CONST VOID *EDID,
+    UINT32 EdidSize,
+    CONST struct VideoMode **VideoMode
+    );
+
+EFI_STATUS
+DlEdidGetSupportedVideoModeWithFallback (
+    UINT32 ModeNumber,
+    CONST VOID *EDID,
+    UINT32 EdidSize,
+    CONST struct VideoMode **VideoMode
+    );
+
+UINT32
+DlEdidGetNumSupportedModesInEdid (
+    CONST VOID *EDID,
+    UINT32 EdidSize
+    );
+
+EFI_STATUS
+DlReadEdid (
+  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
+);
+
+// EDID Detailed timings section - Features
+enum EdidDetailedTimingsFeatures {
+  EdidDetailedTimingsFeaturesInterlaced              = 0x80,
+  EdidDetailedTimingsFeaturesStereoModeMask          = 0x60,
+  EdidDetailedTimingsFeaturesSyncSchemeMask          = 0x18,
+  EdidDetailedTimingsFeaturesHorizontalSyncPositive  = 0x02,
+  EdidDetailedTimingsFeaturesVerticalSyncPositive    = 0x04,
+};
+
+// NR-110497-TC-7ZM Section 4.3.3 0x22 Set Video Mode - Flags
+enum VideoModeFlags {
+  VideoModeFlagsInterlaced             = 0x0001,
+  VideoModeFlagsHorizontalSyncInverted = 0x0100,
+  VideoModeFlagsVerticalSyncInverted   = 0x0200,
+};
+
+struct StandardTimingIdentification {
+  UINT8 HorizontalActivePixels;           // X resolution, from 256->2288 in increments of 8 pixels
+  UINT8 ImageAspectRatioAndrefresh;   // Bits 7,6 Aspect ratio - 0=16:10 1=4:3 2=5:4 3=16:9
+                                          // Bits 5,0 Refresh rate Range 60->1213Hz
+};
+
+struct DetailedTimingIdentification {
+  UINT16 PixelClock;                  // wPixelClock in VideoMode struct
+  UINT8  HActiveLo;                   // wHActive
+  UINT8  HBlankingLo;                 // wHBlanking
+  UINT8  HActiveHiBlankingHi;
+  UINT8  VActiveLo;                   // wVActive
+  UINT8  VBlankingLo;                 // wVBlanking
+  UINT8  VActiveHiBlankingHi;
+  UINT8  HSyncOffsetLo;               // wHSyncOffset, front porch
+  UINT8  HSyncWidthLo;                // wHSyncWidth
+  UINT8  VSyncOffsetLoSyncWidthLo;
+  UINT8  HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi;
+  UINT8  HImageSizeHi;
+  UINT8  VImageSizeHi;
+  UINT8  HImageSizeLoVImageSizeLo;
+  UINT8  HBorder;
+  UINT8  VBorder;
+  UINT8  Features;
+};
+
+struct Edid {
+  UINT8  Header[EDID_HEADER_SIZE];           //EDID header "00 FF FF FF FF FF FF 00"
+  UINT16 ManufactureName;                  //EISA 3-character ID
+  UINT16 ProductCode;                      //Vendor assigned code
+  UINT32 SerialNumber;                     //32-bit serial number
+  UINT8  WeekOfManufacture;                //Week number
+  UINT8  YearOfManufacture;                //Year
+  UINT8  EdidVersion;                      //EDID Structure Version
+  UINT8  EdidRevision;                     //EDID Structure Revision
+  UINT8  VideoInputDefinition;
+  UINT8  MaxHorizontalImageSize;           //cm
+  UINT8  MaxVerticalImageSize;             //cm
+  UINT8  DisplayTransferCharacteristic;
+  UINT8  FeatureSupport;
+  UINT8  RedGreenLowBits;                  //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
+  UINT8  BlueWhiteLowBits;                 //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
+  UINT8  RedX;                             //Red-x Bits 9 - 2
+  UINT8  RedY;                             //Red-y Bits 9 - 2
+  UINT8  GreenX;                           //Green-x Bits 9 - 2
+  UINT8  GreenY;                           //Green-y Bits 9 - 2
+  UINT8  BlueX;                            //Blue-x Bits 9 - 2
+  UINT8  BlueY;                            //Blue-y Bits 9 - 2
+  UINT8  WhiteX;                           //White-x Bits 9 - 2
+  UINT8  WhiteY;                           //White-x Bits 9 - 2
+  UINT8  EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES];
+  struct StandardTimingIdentification  standardTimingIdentifications[EDID_NUMBER_OF_STANDARD_TIMINGS];
+  struct DetailedTimingIdentification  detailedTimingDescriptions[EDID_NUMBER_OF_DETAILED_TIMINGS];
+  UINT8  ExtensionFlag;                    //Number of (optional) 128-byte EDID extension blocks to follow
+  UINT8  Checksum;
+};
+
+#endif // EDID_H
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
new file mode 100644
index 000000000000..cdc01aad193a
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
@@ -0,0 +1,109 @@
+/**
+ * @file UsbDescriptors.h
+ * @brief Functions to read USB Interface and Capabilities descriptors
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#ifndef USB_DESCRIPTORS_H_
+#define USB_DESCRIPTORS_H_
+
+  /**
+  Type of the Direct Framebuffer capability descriptor.
+  This is a vendor specific USB descriptor for DisplayLink.
+  @see NR-140082 Section 3.5
+  **/
+#define DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY 0x5e
+
+  /**
+  Identifiers for capabllity keys
+  @see NR-140082 Section 3.2
+  **/
+
+  /**
+  Key for Capabilities 1 - See section 3.2.1
+  **/
+#define CAPABILITIES1_KEY 0x0
+
+  /**
+  Lengths for capabllity fields
+  **/
+#define CAPABILITIES1_LENGTH 0x4
+
+  /**
+  Bits for the capability bitmask Capabilities1
+  **/
+
+  /**
+  This is the first capability defined for the protocol.
+  It represents the mode of operation as of initial release.
+  If a device ever breaks compatibility with this initial release,
+  it will cease
+  to support CapabilityBaseProtocol.
+  **/
+#define CAPABILITIES1_BASE_PROTOCOL (1 << 0)
+
+  /**
+  Idealised VendorDescriptor which is the result
+  of parsing vendor descriptor from device.
+  **/
+  typedef struct {
+    UINT32 Capabilities1;
+  } VendorDescriptor;
+
+#pragma pack(push, 1)
+  typedef struct {
+    UINT16 Key; /** Really of type enum DescrptorKeys */
+    UINT8 Length;
+    UINT8 Value[];
+  } DescriptorKLV;
+
+  typedef struct {
+    UINT8 Length;
+    UINT8 Type;
+    UINT16 CapabilityVersion;
+    UINT8 CapabilityLength;
+    UINT8 Klv[];
+  } VendorDescriptorGeneric;
+#pragma pack(pop)
+
+
+EFI_STATUS UsbDisplayLinkGetInterfaceDescriptor (
+    IN EFI_USB_IO_PROTOCOL *UsbIo,
+    EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
+    UINT8 index
+    );
+
+EFI_STATUS ReadCapabilitiesDescriptor (IN EFI_USB_IO_PROTOCOL *UsbIo, VOID* Buffer, UINT16 Length);
+
+/**
+Parse data in buffer to a VendorDescriptor, if possible.
+
+@param Data      Buffer
+@param Length    Length of buffer
+
+@retval EFI_SUCCESS      The descriptor was parsed successfully
+@retval EFI_UNSUPPORTED  Simple Pointer Protocol is not installed on Controller.
+**/
+EFI_STATUS
+UsbDisplayLinkParseCapabilitiesDescriptor (
+  CONST IN VOID* Data,
+  IN UINTN Length,
+  OUT VendorDescriptor* Descriptor
+);
+
+/**
+Decide if binding may proceed, given capabilities
+
+@retval TRUE   Binding may proceed
+@retval FALSE  Binding is not possible
+**/
+BOOLEAN
+UsbDisplayLinkCapabilitiesSufficientToBind (
+  CONST IN VendorDescriptor* Descriptor
+);
+
+#endif // USB_DESCRIPTORS_H_
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
new file mode 100644
index 000000000000..7c2722c9870a
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
@@ -0,0 +1,284 @@
+/**
+ * @file UsbDisplayLink.h
+ * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#ifndef _EFI_USB_DISPLAYLINK_H_
+#define _EFI_USB_DISPLAYLINK_H_
+
+#undef _DEBUG
+
+#undef NULL
+#undef _ASSERT
+
+#include <wchar.h>
+
+#include <Uefi/UefiBaseType.h>
+#include <Uefi/UefiSpec.h>
+
+#include <Protocol/EdidActive.h>
+#include <Protocol/EdidDiscovered.h>
+#include <Protocol/EdidOverride.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/UsbIo.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#define VENDOR_DISPLAYLINK      0x17e9
+#define CLASS_VENDOR            0xFF
+
+#define DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO ((UINTN)0)
+
+#define INTERFACE_PROTOCOL_DIRECT_FB    4
+
+#define USB_DISPLAYLINK_DEV_SIGNATURE SIGNATURE_32 ('d', 'l', 'i', 'n')
+
+#define USB_TRANSFER_LENGTH           (64 * 1024)
+#define DISPLAYLINK_MODE_DATA_LENGTH  (146)
+#define DISPLAYLINK_USB_CTRL_TIMEOUT  (1000)
+#define DISPLAYLINK_USB_BULK_TIMEOUT  (1)
+
+#define DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD  ((UINTN)1000000) // 0.1s in us
+#define DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD   ((UINTN)30000) // 3s in ticks
+
+#define DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE ((UINT16)60)
+
+// Requests to read values from the firmware
+#define EDID_BLOCK_SIZE 128
+#define EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK ((UINT16)(0x64))
+
+/** Structures ported from firmware - protocol.h */
+enum ID {
+  // VideoCommands
+  GET_OUTPUT_EDID = 0,
+  SET_VIDEO_MODE = 1
+};
+
+typedef struct {
+  UINT32                     HorizontalResolution;
+  UINT32                     VerticalResolution;
+  UINT32                     ColorDepth;
+  UINT32                     RefreshRate;
+  UINT8                      Commands[DISPLAYLINK_MODE_DATA_LENGTH];
+} DISPLAYLINK_MODE_DATA;
+
+#define GRAPHICS_OUTPUT_INVALID_MODE_NUMBER 0xffff
+
+/**
+ *  Device instance of USB display.
+ */
+typedef struct {
+  UINT64                        Signature;
+  EFI_HANDLE                    Handle;
+  EFI_USB_IO_PROTOCOL           *UsbIo;
+  EFI_USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
+  EFI_USB_ENDPOINT_DESCRIPTOR   BulkOutEndpointDescriptor;
+  EFI_USB_ENDPOINT_DESCRIPTOR   BulkInEndpointDescriptor;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL  GraphicsOutputProtocol;
+  EFI_EDID_DISCOVERED_PROTOCOL  EdidDiscovered;
+  EFI_EDID_ACTIVE_PROTOCOL      EdidActive;
+  EFI_UNICODE_STRING_TABLE      *ControllerNameTable;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Screen;
+  UINTN                         DataSent;                       /** Debug - used to track the bandwidth */
+  EFI_EVENT                     TimerEvent;
+  EFI_EVENT                     DriverExitBootServicesEvent;
+  BOOLEAN                       ShowBandwidth;                 /** Debugging - show the bandwidth on the screen */
+  BOOLEAN                       ShowTestPattern;               /** Show a colourbar pattern instead of the BLTd contents of the framebuffer */
+  UINTN                         LastY1;                        /** Used to track if we can do a partial screen update */
+  UINTN                         LastY2;
+  UINTN                         LastWidth;
+  UINTN                         TimeSinceLastScreenUpdate;     /** Do a full screen update every (x) seconds */
+} USB_DISPLAYLINK_DEV;
+
+struct VideoMode {
+  UINT8  Reserved1;          /* Reserved - must be 0. */
+  UINT8  Reserved2;          /* Reserved - must be 2. */
+
+  // Values matching the EDID Detailed Timing Descriptor spec
+  UINT16 PixelClock;
+  UINT16 HActive;
+  UINT16 HBlanking;
+  UINT16 HSyncOffset;  // Horizontal Front Porch
+  UINT16 HSyncWidth;
+  UINT16 VActive;
+  UINT16 VBlanking;
+  UINT16 VSyncOffset;  // Vertical Front Porch
+  UINT16 VSyncWidth;
+  // End of Edid Detailed Timing Descriptor
+
+  UINT16 Flags               /*ModeFlags*/;
+  UINT16 Accumulate;
+  UINT16 Reserved3;         /* Reserved - must be 0. */
+  UINT16 Reserved4;         /* Reserved - must be 0. */
+  UINT16 InsetLeft;
+  UINT16 InsetTop;
+  UINT16 InsetRight;
+  UINT16 InsetBottom;
+  UINT32 FillValue;
+  UINT32 Reserved5;        /* Reserved - must be 0. */
+  UINT8  Vic;
+  UINT8  ActiveFormat;
+  UINT16 Reserved6;
+};
+
+#define USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(a) \
+  CR(a, USB_DISPLAYLINK_DEV, GraphicsOutputProtocol, USB_DISPLAYLINK_DEV_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL   gUsbDisplayLinkDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   mUsbDisplayLinkComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  mUsbDisplayLinkComponentName2;
+
+
+/* ******************************************* */
+/* ********  GOP interface functions  ******** */
+/* ******************************************* */
+
+/**
+ * Implementation of the GOP protocol QueryMode API function
+ * @param This         Instance of the GOP protocol
+ * @param ModeNumber
+ * @param SizeOfInfo
+ * @param Info
+ * @return
+ */
+EFI_STATUS
+  EFIAPI
+  DisplayLinkQueryMode (
+    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
+    IN  UINT32                                ModeNumber,
+    OUT UINTN                                 *SizeOfInfo,
+    OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
+  );
+
+
+/**
+ * Implementation of the GOP protocol SetMode API function
+ * @param This
+ * @param ModeNumber
+ * @return
+ */
+EFI_STATUS
+  EFIAPI
+  DisplayLinkSetMode (
+    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *This,
+    IN  UINT32                        ModeNumber
+  );
+
+/**
+ * Implementation of the GOP protocol Blt API function
+ * @param This
+ * @param BltBuffer
+ * @param BltOperation
+ * @param SourceX
+ * @param SourceY
+ * @param DestinationX
+ * @param DestinationY
+ * @param Width
+ * @param Height
+ * @param Delta
+ * @return
+ */
+EFI_STATUS
+  EFIAPI
+  DisplayLinkBlt (
+    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
+  );
+
+/* *************************** */
+/* **  GOP helper functions ** */
+/* *************************** */
+
+VOID
+DlGopPrintTextToScreen (
+  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+  UINTN X,
+  UINTN Y,
+  IN CONST CHAR16 *Format,
+  ...
+);
+
+EFI_STATUS
+DlGopSendTestPattern (
+  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
+  UINTN PatternNumber
+);
+
+EFI_STATUS
+DlGopSendScreenUpdate (
+  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
+);
+
+
+/* ******************************************* */
+/* ********  USB interface functions  ******** */
+/* ******************************************* */
+
+EFI_STATUS
+DlUsbSendControlWriteMessage (
+  IN USB_DISPLAYLINK_DEV *Device,
+  IN UINT8 Request,
+  IN UINT16 Value,
+  IN CONST VOID *ControlMsg,
+  IN UINT16 ControlMsgLen
+);
+
+EFI_STATUS
+DlUsbSendControlReadMessage (
+  IN USB_DISPLAYLINK_DEV *Device,
+  IN UINT8 Request,
+  IN UINT16 Value,
+  OUT VOID *ControlMsg,
+  IN UINT16 ControlMsgLen
+);
+
+EFI_STATUS
+DlUsbBulkWrite (
+  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
+  CONST UINT8* Buffer,
+  UINTN DataLen,
+  UINT32 *USBStatus
+);
+
+UINTN
+DlUsbBulkRead (
+  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
+  UINT8* Buffer,
+  UINTN BufferLen
+);
+
+/* ******************************************* */
+/* ********   Video Mode functions    ******** */
+/* ******************************************* */
+
+// Pre-calculated video modes
+UINT32
+DlVideoModeGetNumSupportedVideoModes ();
+
+CONST struct VideoMode *
+DlVideoModeGetSupportedVideoMode (
+  UINT32 index
+);
+
+#endif
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
new file mode 100644
index 000000000000..4bfadd770b81
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
@@ -0,0 +1,137 @@
+/** @file CapabilityDescriptor.c
+ * @brief Definitions for reading USB capability descriptor DisplayLink dock
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#include "UsbDisplayLink.h"
+#include "UsbDescriptors.h"
+
+/**
+ * Check that the Capability Descriptor is valid and hasn't been tampered with.
+ * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
+ * @param Length
+ * @param out
+ * @return
+ */
+STATIC EFI_STATUS
+ValidateHeader (
+    CONST IN VOID* Data,
+    IN UINTN Length,
+    OUT CONST VendorDescriptorGeneric** Out
+    )
+{
+  if (Length < sizeof (VendorDescriptorGeneric)) {
+    DEBUG ((DEBUG_ERROR, "Data too short (%d bytes) for capability descriptor header section\n", Length));
+    return EFI_INVALID_PARAMETER;
+  }
+  CONST VendorDescriptorGeneric* Desc = (VendorDescriptorGeneric*)Data;
+  if (Desc->Length > Length) {
+    DEBUG ((DEBUG_ERROR, "Capability descriptor: Descriptor (%d bytes) exceeds buffer (%d bytes)\n",
+          Length, Desc->Length));
+    return EFI_BUFFER_TOO_SMALL;
+  }
+  if (Desc->Type != DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY) {
+    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid type (0x%08x)\n", Desc->Type));
+    return EFI_UNSUPPORTED;
+  }
+  if (Desc->CapabilityVersion != 1) {
+    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid version (%d)\n", Desc->CapabilityVersion));
+    return EFI_INCOMPATIBLE_VERSION;
+  }
+  // Capability length must fit within remaining space
+  if (Desc->CapabilityLength > (Desc->Length - (sizeof (Desc->Length) + sizeof (Desc->Type)))) {
+    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid CapabilityLength (%d)\n", Desc->CapabilityLength));
+    return EFI_INVALID_PARAMETER;
+  }
+  *Out = Desc;
+  return EFI_SUCCESS;
+}
+
+
+/**
+ * Check that the connected DisplayLink device supports the functionality that this driver requires, e.g. video formats
+ * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
+ * @param Length
+ * @param Output
+ * @return
+ */
+EFI_STATUS
+UsbDisplayLinkParseCapabilitiesDescriptor (
+    CONST IN VOID* Data,
+    IN UINTN Length,
+    OUT VendorDescriptor* Output
+    )
+{
+  CONST VendorDescriptorGeneric* Desc;
+  EFI_STATUS Status;
+
+  Desc = NULL;
+  Status = ValidateHeader (Data, Length, &Desc);
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  // Default capabilities
+  Output->Capabilities1 = 0;
+
+  CONST UINTN CapsHeaderLength = sizeof (Desc->CapabilityVersion) + sizeof (Desc->CapabilityLength);
+  ASSERT (CapsHeaderLength < MAX_UINT8);
+
+  UINTN DataRemaining;
+  UINTN Offset;
+
+  DataRemaining = Desc->CapabilityLength - CapsHeaderLength;
+  Offset = 0;
+
+  while (DataRemaining >= sizeof (DescriptorKLV)) {
+    CONST DescriptorKLV* KeyHeader = (CONST DescriptorKLV*)(Desc->Klv + Offset);
+    CONST UINTN KeyValueSize = sizeof (DescriptorKLV) + KeyHeader->Length;
+    if (KeyValueSize > DataRemaining) {
+      DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid value Length (%d)\n", Desc->CapabilityLength));
+      return EFI_INVALID_PARAMETER;
+    }
+
+    switch (KeyHeader->Key) {
+      case CAPABILITIES1_KEY: {
+        if (KeyHeader->Length != CAPABILITIES1_LENGTH) {
+          DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid length (%d) for Capabilities 1\n", KeyHeader->Length));
+          return EFI_INVALID_PARAMETER;
+        }
+        Output->Capabilities1 = *(UINT32*)KeyHeader->Value;
+        break;
+      default:
+        // Ignore unknown types
+        break;
+      }
+    }
+    DataRemaining -= KeyValueSize;
+    Offset += KeyValueSize;
+  }
+  return EFI_SUCCESS;
+}
+
+
+/**
+ * Check that the DisplayLink device supports the basic level of functionality to display GOP pixels.
+ * @param Descriptor The USB descriptor received from the DisplayLink device
+ * @return True we can bind, False we can't
+ */
+BOOLEAN
+UsbDisplayLinkCapabilitiesSufficientToBind (
+    CONST IN VendorDescriptor* Descriptor
+    )
+{
+  BOOLEAN Sufficient;
+  Sufficient = (BOOLEAN)(Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL);
+
+  if (Sufficient == FALSE) {
+    DEBUG ((DEBUG_ERROR, "DisplayLink device does not report support for base capabilites - reports x%x, required x%x\n", Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL));
+  }
+  return Sufficient;
+}
+
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
new file mode 100644
index 000000000000..74498f339eb7
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
@@ -0,0 +1,235 @@
+/**
+ * @file ComponentName.c
+ * @brief UEFI Component Name protocol implementation for USB DisplayLink driver.
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#include "UsbDisplayLink.h"
+
+
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+);
+
+
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+);
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  mUsbDisplayLinkComponentName = {
+  UsbDisplayLinkComponentNameGetDriverName,
+  UsbDisplayLinkComponentNameGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mUsbDisplayLinkComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbDisplayLinkComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbDisplayLinkComponentNameGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbDisplayLinkDriverNameTable[] = {
+  { (CHAR8*)"eng;en", (CHAR16*)L"DisplayLink USB GOP Driver" },
+  { (CHAR8*)NULL , (CHAR16*)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
+UsbDisplayLinkComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mUsbDisplayLinkDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
+}
+
+/**
+  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
+UsbDisplayLinkComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS                   Status;
+  USB_DISPLAYLINK_DEV          *UsbDisplayLinkDev;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
+  EFI_USB_IO_PROTOCOL          *UsbIoProtocol;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check Controller's handle
+  //
+  Status = gBS->OpenProtocol  (
+                  ControllerHandle,
+                  &gEfiUsbIoProtocolGuid,
+                  (VOID **) &UsbIoProtocol,
+                  gUsbDisplayLinkDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER);
+
+  if (!EFI_ERROR (Status)) {
+    gBS->CloseProtocol  (
+           ControllerHandle,
+           &gEfiUsbIoProtocolGuid,
+           gUsbDisplayLinkDriverBinding.DriverBindingHandle,
+           ControllerHandle);
+
+    return EFI_UNSUPPORTED;
+  }
+
+  if (Status != EFI_ALREADY_STARTED) {
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiGraphicsOutputProtocolGuid,
+                  (VOID**)&GraphicsOutputProtocol,
+                  gUsbDisplayLinkDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           UsbDisplayLinkDev->ControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
+}
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
new file mode 100644
index 000000000000..21f4b7d9c736
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
@@ -0,0 +1,598 @@
+/** @file Edid.c
+ * @brief Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#include "UsbDisplayLink.h"
+#include "Edid.h"
+
+CONST UINT8 ExpectedEdidHeader[EDID_HEADER_SIZE] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
+
+//
+// Standard timing defined by VESA EDID
+//
+CONST EDID_TIMING EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES][8] = {
+  //
+  // Established Timing I
+  //
+  {
+    { 800, 600, 60 },
+    { 800, 600, 56 },
+    { 640, 480, 75 },
+    { 640, 480, 72 },
+    { 640, 480, 67 },
+    { 640, 480, 60 },
+    { 720, 400, 88 },
+    { 720, 400, 70 },
+  },
+  {
+    //
+    // Established Timing II
+    //
+    { 1280, 1024, 75 },
+    { 1024,  768, 75 },
+    { 1024,  768, 70 },
+    { 1024,  768, 60 },
+    { 1024,  768, 87 },
+    { 832,   624, 75 },
+    { 800,   600, 75 },
+    { 800,   600, 72 },
+  },
+  //
+  // Established Timing III
+  //
+  {
+    { 1152, 870, 75 },
+    { 0, 0, 0 },
+    { 0, 0, 0 },
+    { 0, 0, 0 },
+    { 0, 0, 0 },
+    { 0, 0, 0 },
+    { 0, 0, 0 },
+    { 0, 0, 0 },
+  }
+};
+
+/**
+ * Requests the monitor EDID data from the connected DisplayLink device
+ * @param UsbDisplayLinkDev
+ * @param EdidDataBlock
+ * @param EdidSize
+ * @retval EFI_DEVICE_ERROR - No EDID received, or EDID is corrupted
+ * @retval EFI_OUT_OF_RESOURCES - Cannot allocate memory
+ * @retval EFI_SUCCESS
+ *
+ */
+STATIC EFI_STATUS
+ReadEdidData (
+  IN USB_DISPLAYLINK_DEV      *UsbDisplayLinkDev,
+  OUT UINT8                    **EdidDataBlock,
+  OUT UINTN                    *EdidSize
+)
+{
+  EFI_STATUS Status;
+
+  UINT8 EdidDataRead[EDID_BLOCK_SIZE];
+  UINT8 *EdidData = EdidDataRead;
+  UINT8* ValidEdid;
+
+  Status = DlUsbSendControlReadMessage (UsbDisplayLinkDev, GET_OUTPUT_EDID, 0, EdidDataRead, sizeof (EdidDataRead));
+
+  if (EFI_ERROR (Status) || (EdidData[0] != 0)) {
+    DEBUG ((DEBUG_ERROR, "No monitor EDID received from DisplayLink device - System error %r, EDID error %d. Monitor connected correctly?\n", Status, EdidData[0]));
+    return EFI_DEVICE_ERROR;
+  } else {
+    //
+    // Search for the EDID signature
+    //
+    ValidEdid = &EdidData[0];
+    CONST UINT64 Signature = 0x00ffffffffffff00ull;
+    if (CompareMem (ValidEdid, &Signature, 8) != 0) {
+      //
+      // No EDID signature found
+      //
+      DEBUG ((DEBUG_ERROR, "Monitor EDID received from DisplayLink device did not have a valid signature - corrupted?\n"));
+      Status = EFI_DEVICE_ERROR;
+      return Status;
+    }
+  }
+
+  *EdidDataBlock = (UINT8*)AllocateCopyPool (
+    EDID_BLOCK_SIZE,
+    ValidEdid);
+
+  if (*EdidDataBlock == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Currently only support EDID 1.x
+  //
+  *EdidSize = EDID_BLOCK_SIZE;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+Calculates the mod256 checksum of the EDID and compares it with the one supplied at the end of the EDID
+@param  EDID        Pointer to the 128-byte EDID
+@retval TRUE        The EDID checksum is correct
+**/
+BOOLEAN
+IsEdidChecksumCorrect (
+    CONST VOID *EDID
+    )
+{
+  CONST UINT8 EdidChecksum = ((UINT8 *)EDID)[EDID_BLOCK_SIZE - 1];
+  UINT8 CalculatedChecksum;
+
+  CalculatedChecksum = 0;
+
+  UINTN i;
+  for (i = 0; i < EDID_BLOCK_SIZE - 1; i++) {
+    CalculatedChecksum += ((UINT8 *)EDID)[i];
+  }
+  CalculatedChecksum = 0 - CalculatedChecksum;
+
+  return (CalculatedChecksum == EdidChecksum);
+}
+
+/**
+Check if a particular video mode is in the Established Timings section of the EDID.
+
+@param  EDID        Pointer to the 128-byte EDID
+@param  hRes        Horizontal resolution
+@param  vRes        Vertical resolution
+@param  refresh     Refresh rate
+@retval TRUE        The requested mode is present in the Established Timings section
+
+**/
+STATIC BOOLEAN
+IsModeInEstablishedTimings (
+    IN CONST VOID *EDID,
+    IN UINT16 HRes,
+    IN UINT16 VRes,
+    IN UINT16 Refresh
+    )
+{
+  CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
+  BOOLEAN ModeSupported;
+
+  ModeSupported = FALSE;
+
+  int EstByteNum;
+  int BitNum;
+  for (EstByteNum = 0; EstByteNum < EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES; EstByteNum++) {
+    for (BitNum = 0; BitNum < 8; BitNum++) {
+      if (pEDID->EstablishedTimings[EstByteNum] & (1 << BitNum)) { // The bit is set in the established timings of the EDID
+
+        if ((EstablishedTimings[EstByteNum][BitNum].HRes == HRes) && // The passed-in resolution matches the resolution represented by the set bit
+          (EstablishedTimings[EstByteNum][BitNum].VRes == VRes) &&
+          (EstablishedTimings[EstByteNum][BitNum].Refresh == Refresh)) {
+
+          ModeSupported = TRUE;
+          break;
+        }
+      }
+    }
+    if (ModeSupported == TRUE) {
+      break;
+    }
+  }
+  return ModeSupported;
+}
+
+/**
+Extract the resolutions and refresh rate from one of the entries in the Standard Timings section of the EDID.
+
+@param  EDID          Pointer to the 128-byte EDID
+@param  timingNumber  The entry that we want to extract
+@param  hRes          Output - Horizontal resolution
+@param  vRes          Output - Vertical resolution
+@param  refresh       Output - Refresh rate
+@retval TRUE          The requested Standard Timings entry contains valid data
+
+**/
+STATIC BOOLEAN ReadStandardTiming (
+  CONST VOID *EDID,
+  IN UINT8 TimingNumber,
+  OUT UINT16 *HRes,
+  OUT UINT16 *VRes,
+  OUT UINT8 *Refresh)
+{
+  CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
+
+  // See section 3.9.1 of the VESA EDID spec
+
+  if (((pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels) == 0x01) &&
+    (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh) == 0x01) {
+    *HRes = 0;
+    *VRes = 0;
+    *Refresh = 0;
+    return FALSE;
+  }
+  *HRes = (pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels + 31) * 8;
+
+  UINT8 AspectRatio;
+  AspectRatio = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh >> 6) & 0x3;
+
+  switch (AspectRatio) {
+  case 0: *VRes = (*HRes * 10) / 16;
+    break;
+  case 1: *VRes = (*HRes * 3) / 4;
+    break;
+  case 2: *VRes = (*HRes * 4) / 5;
+    break;
+  case 3: *VRes = (*HRes * 9) / 16;
+    break;
+  default: break;
+  }
+
+  // WORKAROUND - 1360x768 is not a perfect aspect ratio
+  if ((*HRes == 1360) && (*VRes == 765)) {
+    *VRes = 768;
+  }
+
+  *Refresh = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh & 0x1F) + 60;
+
+  return TRUE;
+}
+
+/**
+Extract the resolutions and refresh rate from one of the entries in the Detailed Timings section of the EDID.
+
+@param  EDID          Pointer to the 128-byte EDID
+@param  timingNumber  The entry that we want to extract
+@param  videoMode     Output - Filled in with details from the detailed timing
+@retval TRUE          The requested Detailed Timings entry contains valid data
+
+**/
+STATIC BOOLEAN
+ReadDetailedTiming (
+  IN CONST VOID *EDID,
+  IN UINT8 TimingNumber,
+  OUT struct VideoMode *VideoMode
+  )
+{
+  if (TimingNumber >= EDID_NUMBER_OF_DETAILED_TIMINGS) {
+    return FALSE;
+  }
+
+  UINT16 NumValidDetailedTimingsFound;
+  NumValidDetailedTimingsFound = 0;
+
+  // Spin through the detailed timings until we find a valid one - then check if this has the index that we want
+  int BlockNumber;
+  for (BlockNumber = 0; BlockNumber < EDID_NUMBER_OF_DETAILED_TIMINGS; BlockNumber++) {
+    CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
+    CONST struct DetailedTimingIdentification *pTiming = &pEDID->detailedTimingDescriptions[BlockNumber];
+
+    if (((BlockNumber == 0) && (pTiming->PixelClock == EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK)) ||
+      (pTiming->PixelClock == 0)) {
+      // This is not a valid detailed timing descriptor
+      continue;
+    }
+
+    if ((pTiming->Features & EdidDetailedTimingsFeaturesSyncSchemeMask) != EdidDetailedTimingsFeaturesSyncSchemeMask) {
+      DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported sync scheme found - not processing.\n"));
+      continue;
+    }
+
+    if ((pTiming->Features & EdidDetailedTimingsFeaturesStereoModeMask) != 0) {
+      DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported stereo mode found - not processing.\n"));
+      continue;
+    }
+
+    // We've found a supported detailed timing - now see if this is the requested one
+    if (TimingNumber != NumValidDetailedTimingsFound) {
+      NumValidDetailedTimingsFound++;
+      continue;
+    }
+
+    ZeroMem ((VOID *)VideoMode, sizeof (struct VideoMode));
+
+    // Bit manipulations copied from host software class EDIDTimingDescriptor
+
+    VideoMode->PixelClock = (UINT16)pTiming->PixelClock;
+    VideoMode->HActive = pTiming->HActiveLo + ((pTiming->HActiveHiBlankingHi & 0xF0) << 4);
+    VideoMode->VActive = pTiming->VActiveLo + ((pTiming->VActiveHiBlankingHi & 0xF0) << 4);
+
+    VideoMode->HBlanking = pTiming->HBlankingLo + ((pTiming->HActiveHiBlankingHi & 0x0F) << 8);
+    VideoMode->VBlanking = pTiming->VBlankingLo + ((pTiming->VActiveHiBlankingHi & 0x0F) << 8);
+
+    VideoMode->HSyncOffset = pTiming->HSyncOffsetLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0xC0) << 2);  // Horizontal Front Porch
+    VideoMode->HSyncWidth = pTiming->HSyncWidthLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x30) << 4);
+
+    VideoMode->VSyncOffset = ((pTiming->VSyncOffsetLoSyncWidthLo & 0xF0) >> 4) + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x0C) << 2); // Vertical Front Porch
+    VideoMode->VSyncWidth = (pTiming->VSyncOffsetLoSyncWidthLo & 0x0F) + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x03) << 4);
+
+    VideoMode->Reserved2 = 2;
+    VideoMode->Accumulate = 1;
+
+    // Horizontal and vertical sync inversions - positive if bit set in descriptor (EDID spec)
+    // In the VideoMode, they are negative if the bit is set (NR-110497-TC 4.3.3 0x22 Set Video Mode)
+
+    // Horizontal sync
+    if ((pTiming->Features & EdidDetailedTimingsFeaturesHorizontalSyncPositive) == 0) {
+      VideoMode->Flags |= VideoModeFlagsHorizontalSyncInverted;
+    }
+    // Vertical sync
+    if ((pTiming->Features & EdidDetailedTimingsFeaturesVerticalSyncPositive) == 0) {
+      VideoMode->Flags |= VideoModeFlagsVerticalSyncInverted;
+    }
+    // Interlace
+    if ((pTiming->Features & EdidDetailedTimingsFeaturesInterlaced) == EdidDetailedTimingsFeaturesInterlaced) {
+      VideoMode->Flags |= VideoModeFlagsInterlaced;
+    }
+
+    DEBUG ((DEBUG_INFO, "Read mode %dx%d from detailed timings\n", VideoMode->HActive, VideoMode->VActive));
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+Check if a particular video mode is in either the Established or Standard Timings section of the EDID.
+
+@param  EDID        Pointer to the 128-byte EDID
+@param  hRes        Horizontal resolution
+@param  vRes        Vertical resolution
+@param  refresh     Refresh rate
+@retval TRUE        The requested mode is present in the EDID
+
+**/
+STATIC BOOLEAN
+IsModeInEdid (
+    IN CONST VOID *EDID,
+    IN UINT16 HRes,
+    IN UINT16 VRes,
+    IN UINT16 Refresh
+    )
+{
+  UINT16 EdidHRes;
+  UINT16 EdidVRes;
+  UINT8 EdidRefresh;
+  BOOLEAN ModeSupported;
+
+  ModeSupported = IsModeInEstablishedTimings (EDID, HRes, VRes, Refresh);
+
+  if (ModeSupported == FALSE) {
+    // Check if the mode is in the Standard Timings section of the EDID
+    UINT8 i;
+    for (i = 0; i < EDID_NUMBER_OF_STANDARD_TIMINGS; i++) {
+      if (TRUE == ReadStandardTiming (EDID, i, &EdidHRes, &EdidVRes, &EdidRefresh)) {
+        if ((HRes == EdidHRes) && (VRes == EdidVRes) && (Refresh == EdidRefresh)) {
+          ModeSupported = TRUE;
+          break;
+        }
+      }
+    }
+  }
+  return ModeSupported;
+}
+
+/**
+Returns the (index)'th entry from the list of pre-calculated video timings that is also present in the EDID,
+or, video mode data corresponding to any detailed timings present in the EDID.
+
+Like QueryVideoMode, finds the number (and contents) of video modes available by repeatedly calling this function
+with an increasing index value, until it returns FALSE
+@param  index       The caller wants the _index_'th video mode
+@param  EDID        Pointer to the 128-byte EDID
+@param  edidSize    Size in bytes of the EDID
+@param  videoMode   Video timings extracted from the modeData structure
+@retval EFI_SUCCESS The requested mode is present in the EDID
+@retval EFI_INVALID_PARAMETER The requested mode is not present in the EDID
+**/
+EFI_STATUS
+DlEdidGetSupportedVideoMode (
+    IN UINT32 Index,
+    IN CONST VOID *EDID,
+    IN UINT32 EdidSize,
+    OUT CONST struct VideoMode **VideoMode
+    )
+{
+  UINTN SupportedVideoModesFoundInEdid;
+  EFI_STATUS Status;
+
+  SupportedVideoModesFoundInEdid = 0;
+  Status = EFI_INVALID_PARAMETER;
+
+  // If we didn't manage to find an EDID earlier, just use one of the hard-coded video modes
+  if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
+    if (Index >= DlVideoModeGetNumSupportedVideoModes ()) {
+      return EFI_INVALID_PARAMETER;
+    }
+    else {
+      *VideoMode = DlVideoModeGetSupportedVideoMode (Index);
+      DEBUG ((DEBUG_WARN, "No monitor EDID loaded - returning mode from default list (%dx%d)\n", (*VideoMode)->HActive, (*VideoMode)->VActive));
+      return EFI_SUCCESS;
+    }
+  }
+
+  UINT16 ModeNumber;
+  for (ModeNumber = 0; ModeNumber < DlVideoModeGetNumSupportedVideoModes (); ModeNumber++) {
+
+    CONST struct VideoMode *SupportedVideoMode = DlVideoModeGetSupportedVideoMode (ModeNumber);
+    ASSERT (SupportedVideoMode);
+
+    if (IsModeInEdid (EDID, SupportedVideoMode->HActive, SupportedVideoMode->VActive, DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE)) {
+      if (Index == SupportedVideoModesFoundInEdid) {
+        *VideoMode = SupportedVideoMode;
+        Status = EFI_SUCCESS;
+        break;
+      }
+      SupportedVideoModesFoundInEdid++;
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    // Have a look in the detailed timings
+    UINTN DetailedTimingNumber;
+    STATIC struct VideoMode TmpVideoMode;
+    DetailedTimingNumber = Index - SupportedVideoModesFoundInEdid;
+
+    if (DetailedTimingNumber < EDID_NUMBER_OF_DETAILED_TIMINGS) {
+      if (ReadDetailedTiming (EDID, (UINT8)DetailedTimingNumber, &TmpVideoMode)) {
+        *VideoMode = &TmpVideoMode;
+        Status = EFI_SUCCESS;
+      }
+    }
+  }
+
+  return Status;
+}
+
+/**
+ * Like GetSupportedEdidVideoMode, but will return a fallback fixed mode of 640x480@60Hz
+ * for index 0 if no suitable modes found in EDID.
+ * @param index
+ * @param EDID
+ * @param edidSize
+ * @param videoMode
+ * @return EFI_SUCCESS
+ */
+EFI_STATUS
+DlEdidGetSupportedVideoModeWithFallback (
+    IN UINT32 Index,
+    IN CONST VOID *EDID,
+    IN UINT32 EdidSize,
+    OUT CONST struct VideoMode **VideoMode
+    )
+{
+  EFI_STATUS Status;
+  Status = DlEdidGetSupportedVideoMode (Index, EDID, EdidSize, VideoMode);
+
+  if (EFI_ERROR (Status)) {
+    // Special case - if we didn't find any matching video modes in the EDID, fall back to 640x480@60Hz
+    if (Index == 0) {
+      *VideoMode = DlVideoModeGetSupportedVideoMode (0);
+      DEBUG ((DEBUG_WARN, "No video modes supported by driver found in monitor EDID received from DL device - falling back to %dx%d\n", (*VideoMode)->HActive, (*VideoMode)->VActive));
+      Status = EFI_SUCCESS;
+    }
+  }
+
+  return Status;
+}
+
+/**
+Count the number of video modes that we have timing information for that are present in the EDID
+@param  EDID        Pointer to the 128-byte EDID
+@param  edidSize
+@retval             The number of modes in the EDID
+
+**/
+UINT32
+DlEdidGetNumSupportedModesInEdid (
+    IN CONST VOID *EDID,
+    IN UINT32 EdidSize
+    )
+{
+  UINT32 MaxMode;
+
+  if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
+    return DlVideoModeGetNumSupportedVideoModes ();
+  }
+
+  for (MaxMode = 0; ; MaxMode++) {
+    CONST struct VideoMode *videoMode;
+    if (EFI_ERROR (DlEdidGetSupportedVideoMode (MaxMode, EDID, EdidSize, &videoMode))) {
+      break;
+    }
+  }
+  DEBUG ((DEBUG_INFO, "Found %d video modes supported by driver in monitor EDID.\n", MaxMode));
+  return MaxMode;
+}
+
+
+
+/**
+ * Read the EDID from the connected monitor, store it in the local data structure
+ * @param UsbDisplayLinkDev
+ * @retval EFI_OUT_OF_RESOURCES - Could not allocate memory
+ * @retval EFI_SUCCESS
+ */
+EFI_STATUS
+DlReadEdid (
+    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
+    )
+{
+  EFI_STATUS Status;
+  BOOLEAN EdidFound;
+  EFI_EDID_OVERRIDE_PROTOCOL* EdidOverride;
+
+  //
+  // setup EDID information
+  //
+  UsbDisplayLinkDev->EdidDiscovered.Edid = (UINT8 *)NULL;
+  UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = 0;
+
+  EdidFound = FALSE;
+
+  //
+  // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
+  //
+  Status = gBS->LocateProtocol (&gEfiEdidOverrideProtocolGuid, NULL, (VOID**)&EdidOverride);
+
+  if (!EFI_ERROR (Status)) {
+    UINT32 EdidAttributes = 0xff;
+    UINTN EdidDataSize = 0;
+    UINT8* EdidDataBlock = (UINT8*)NULL;
+
+    // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
+    EdidDataBlock = (UINT8*)AllocatePool (EDID_BLOCK_SIZE * 2);
+
+    if (NULL == EdidDataBlock) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    Status = EdidOverride->GetEdid (
+      EdidOverride,
+      &UsbDisplayLinkDev->Handle,
+      &EdidAttributes,
+      &EdidDataSize,
+      &EdidDataBlock);
+
+    if (!EFI_ERROR (Status) && EdidAttributes == 0 && EdidDataSize != 0) {
+      UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
+      UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
+      EdidFound = TRUE;
+    }
+    else {
+      FreePool (EdidDataBlock);
+      EdidDataBlock = NULL;
+    }
+  }
+
+  if (EdidFound != TRUE) {
+    UINTN EdidDataSize = 0;
+    UINT8* EdidDataBlock = (UINT8*)NULL;
+
+    if (ReadEdidData (UsbDisplayLinkDev, &EdidDataBlock, &EdidDataSize) == EFI_SUCCESS) {
+
+      if (IsEdidChecksumCorrect (EdidDataBlock)) {
+        UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
+        UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
+        EdidFound = TRUE;
+      } else {
+        DEBUG ((DEBUG_WARN, "Monitor EDID received from DisplayLink device had an invalid checksum. Corrupted?\n"));
+      }
+    }
+  }
+
+  if (EdidFound == FALSE) {
+    DEBUG ((DEBUG_WARN, "No valid monitor EDID received from DisplayLink device. Cannot detect resolutions supported by monitor.\n"));
+  }
+
+  // Set the EDID active.
+  // In an error case this will be set 0/NULL, which flags to the parsing code that there is no EDID.
+  UsbDisplayLinkDev->EdidActive.SizeOfEdid = UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid;
+  UsbDisplayLinkDev->EdidActive.Edid = UsbDisplayLinkDev->EdidDiscovered.Edid;
+
+  return EFI_SUCCESS;
+}
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
new file mode 100644
index 000000000000..db1b8952a470
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
@@ -0,0 +1,587 @@
+/**
+ * @file Gop.c
+ * @brief UEFI GOP protocol API implementation for USB DisplayLink driver.
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#include "UsbDisplayLink.h"
+#include "Edid.h"
+
+
+/**
+ *
+ * @param This            Pointer to the instance of the GOP protocol
+ * @param BltOperation
+ * @param SourceX
+ * @param SourceY
+ * @param Width
+ * @param Height
+ * @param DestinationX
+ * @param DestinationY
+ * @return
+ */
+STATIC EFI_STATUS
+CheckBounds (
+    IN EFI_GRAPHICS_OUTPUT_PROTOCOL* This,
+    IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+    IN UINTN SourceX,
+    IN UINTN SourceY,
+    IN UINTN Width,
+    IN UINTN Height,
+    IN UINTN DestinationX,
+    IN UINTN DestinationY
+    )
+{
+  USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
+
+  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
+  Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
+
+  CONST EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* ScreenMode = Gop->Mode->Info;
+
+  if (BltOperation == EfiBltVideoToBltBuffer || BltOperation == EfiBltVideoToVideo) {
+    if (SourceY + Height > ScreenMode->VerticalResolution) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if (SourceX + Width > ScreenMode->HorizontalResolution) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  if (BltOperation == EfiBltBufferToVideo
+    || BltOperation == EfiBltVideoToVideo
+    || BltOperation == EfiBltVideoFill) {
+    if (DestinationY + Height > ScreenMode->VerticalResolution) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if (DestinationX + Width > ScreenMode->HorizontalResolution) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+#if 0
+  // Check if the buffer areas overlap when copying to and from the same buffer
+  if (BltOperation == EfiBltVideoToVideo) {
+    if ((SourceX < DestinationX + Width) &&
+      (SourceX + Width > DestinationX) &&
+      (SourceY < DestinationY + Height) &&
+      (SourceY + Height > DestinationY)) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+#endif
+  return EFI_SUCCESS;
+}
+
+/**
+ * Update the local copy of the Frame Buffer. This local copy is periodically transmitted to the
+ * DisplayLink device (via DlGopSendScreenUpdate)
+ * @param UsbDisplayLinkDev
+ * @param BltBuffer
+ * @param BltOperation
+ * @param SourceX
+ * @param SourceY
+ * @param DestinationX
+ * @param DestinationY
+ * @param Width
+ * @param Height
+ * @param BltBufferStride
+ * @param PixelsPerScanLine
+ */
+STATIC VOID
+BuildBackBuffer (
+  IN  USB_DISPLAYLINK_DEV                     *UsbDisplayLinkDev,
+  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                                   BltBufferStride,
+  IN  UINTN                                   PixelsPerScanLine
+)
+{
+  UINTN H;
+  UINTN W;
+  switch (BltOperation) {
+  case EfiBltVideoToBltBuffer:
+  {
+    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
+    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
+    Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)((UINT8 *)BltBuffer + (DestinationY * BltBufferStride) + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+    SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
+
+    for (H = 0; H < Height; H++) {
+      for (W = 0; W < Width; W++) {
+        Blt[W] = *SrcB++;
+      }
+      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
+      SrcB += PixelsPerScanLine - Width;
+    }
+  }
+  break;
+
+  case EfiBltBufferToVideo:
+  {
+    // Update the store of the area of the screen that is "dirty" - that we need to send in the next screen update.
+    if (DestinationY < UsbDisplayLinkDev->LastY1) {
+      UsbDisplayLinkDev->LastY1 = DestinationY;
+    }
+    if ((DestinationY + Height) > UsbDisplayLinkDev->LastY2) {
+      UsbDisplayLinkDev->LastY2 = DestinationY + Height;
+    }
+
+    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
+    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
+    Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)(((UINT8 *)BltBuffer) + (SourceY * BltBufferStride) + SourceX * sizeof *Blt);
+    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
+
+    for (H = 0; H < Height; H++) {
+      for (W = 0; W < Width; W++) {
+        *DstB++ = Blt[W];
+      }
+      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
+      DstB += PixelsPerScanLine - Width;
+    }
+  }
+  break;
+
+  case EfiBltVideoToVideo:
+  {
+    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
+    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
+    SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
+    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
+
+    for (H = 0; H < Height; H++) {
+      for (W = 0; W < Width; W++) {
+        *DstB++ = *SrcB++;
+      }
+      SrcB += PixelsPerScanLine - Width;
+      DstB += PixelsPerScanLine - Width;
+    }
+  }
+  break;
+
+  case EfiBltVideoFill:
+  {
+    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
+    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
+    for (H = 0; H < Height; H++) {
+      for (W = 0; W < Width; W++) {
+        *DstB++ = *BltBuffer;
+      }
+      DstB += PixelsPerScanLine - Width;
+    }
+  }
+  break;
+  default: break;
+  }
+}
+
+/**
+ * Display a colour bar pattern on the DisplayLink device.
+ * @param UsbDisplayLinkDev
+ * @param PatternNumber
+ * @return
+ */
+EFI_STATUS
+DlGopSendTestPattern (
+    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
+    IN UINTN PatternNumber)
+{
+  EFI_STATUS Status;
+  UINTN DataLen;
+  UINT8 *DstBuf;
+  UINT32 USBStatus;
+
+  Status = EFI_SUCCESS;
+  DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per pixel
+  DstBuf = AllocateZeroPool (DataLen);
+
+  if (DstBuf == NULL) {
+    DEBUG ((DEBUG_ERROR, "SendTestPattern Failed to allocate memory\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //DEBUG ((DEBUG_ERROR, "Called DlGopSendTestPattern %d\n", PatternNumber));
+
+  CONST UINT8 RedPixel[3] = { 0xFF, 0x00, 0x00 };
+  CONST UINT8 GreenPixel[3] = { 0x00, 0xFF, 0x00 };
+  CONST UINT8 BluePixel[3] = { 0x00, 0x00, 0xFF };
+  CONST UINT8 YellowPixel[3] = { 0xFF, 0xFF, 0x00 };
+  CONST UINT8 MagentaPixel[3] = { 0xFF, 0x00, 0xFF };
+  CONST UINT8 CyanPixel[3] = { 0x00, 0xFF, 0xFF };
+
+  UINTN Row;
+  UINTN Column;
+  for (Row = 0; Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution; Row++) {
+    for (Column = 0; Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution; Column++) {
+
+      if (0 == PatternNumber) {
+        if (Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution / 3) {
+          CopyMem (&DstBuf[Column * 3], RedPixel, sizeof (RedPixel));
+        }
+        else if (Row < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution * 2) / 3)
+        {
+          CopyMem (&DstBuf[Column * 3], GreenPixel, sizeof (GreenPixel));
+        }
+        else {
+          CopyMem (&DstBuf[Column * 3], BluePixel, sizeof (BluePixel));
+        }
+      }
+      else {
+        if (Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution / 3) {
+          CopyMem (&DstBuf[Column * 3], YellowPixel, sizeof (RedPixel));
+        }
+        else if (Column < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 2) / 3)
+        {
+          CopyMem (&DstBuf[Column * 3], MagentaPixel, sizeof (GreenPixel));
+        }
+        else {
+          CopyMem (&DstBuf[Column * 3], CyanPixel, sizeof (BluePixel));
+        }
+      }
+    }
+    DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, DataLen, &USBStatus);
+  }
+  // Payload with length of 1 to terminate the frame
+  DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, 1, &USBStatus);
+  FreePool (DstBuf);
+
+  return Status;
+}
+
+
+/**
+ * Transfer the latest copy of the Blt buffer over USB to the DisplayLink device
+ * @param UsbDisplayLinkDev
+ * @return
+ */
+EFI_STATUS
+DlGopSendScreenUpdate (
+    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
+    )
+{
+  EFI_STATUS Status;
+  UINT32 USBStatus;
+  Status = EFI_SUCCESS;
+
+  // If it has been a while since we sent an update, send a full screen.
+  // This allows us to update a hot-plugged monitor quickly.
+  if (UsbDisplayLinkDev->TimeSinceLastScreenUpdate > DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD) {
+    UsbDisplayLinkDev->LastY1 = 0;
+    UsbDisplayLinkDev->LastY2 = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution - 1;
+  }
+
+  // If there has been no BLT since the last update/poll, drop out quietly.
+  if (UsbDisplayLinkDev->LastY2 < UsbDisplayLinkDev->LastY1) {
+    UsbDisplayLinkDev->TimeSinceLastScreenUpdate += (DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 1000);  // Convert us to ms
+    return EFI_SUCCESS;
+  }
+
+  UsbDisplayLinkDev->TimeSinceLastScreenUpdate = 0;
+
+  EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+  UINTN DataLen;
+  UINTN Width;
+  UINTN Height;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcPtr;
+  UINT8* DstPtr;
+  UINT8 DstBuffer[1920 * 3]; // TODO - Get rid of the magic numbers
+                             // ALSO TODO - Use a buffer allocated at runtime to store the line, stored in the USB_DISPLAYLINK_DEV structure.
+  UINTN H;
+
+  DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per pixel - TODO - Get rid of the magic number
+  Width = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution;
+  Height = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution;
+  SrcPtr = UsbDisplayLinkDev->Screen;
+  DstPtr = DstBuffer;
+
+  for (H = 0; H < Height; H++) {
+    DstPtr = DstBuffer;
+
+    UINTN W;
+    for (W = 0; W < Width; W++) {
+      // Need to swap round the RGB values
+      DstPtr[0] = ((UINT8 *)SrcPtr)[2];
+      DstPtr[1] = ((UINT8 *)SrcPtr)[1];
+      DstPtr[2] = ((UINT8 *)SrcPtr)[0];
+      SrcPtr++;
+      DstPtr += 3;
+    }
+
+    Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, DataLen, &USBStatus);
+
+    // USBStatus values defined in usbio.h, e.g. EFI_USB_ERR_TIMEOUT 0x40
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB status x%x\n", H, DataLen, Status, USBStatus));
+      break;
+    }
+    // Need an extra DlUsbBulkWrite if the data length is divisible by USB MaxPacketSize. This spare data will just get written into the (invisible) stride area.
+    // Note that the API doesn't let us do a bulk write of 0.
+    if ((DataLen & (UsbDisplayLinkDev->BulkOutEndpointDescriptor.MaxPacketSize - 1)) == 0) {
+      Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 2, &USBStatus);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB status x%x\n", H, DataLen, Status, USBStatus));
+        break;
+      }
+    }
+  }
+
+  if (!EFI_ERROR (Status)) {
+    // If we've successfully transmitted the frame, reset the values that store which area of the screen has been BLTted to.
+    // If we haven't succeeded, this will mean we'll try to resend it after the next poll period.
+    UsbDisplayLinkDev->LastY2 = 0;
+    UsbDisplayLinkDev->LastY1 = (UINTN)-1;
+  }
+
+  // Payload with length of 1 to terminate the frame
+  // We need to do this even if we had an error, to indicate to the DL device that it should now expect a new frame.
+  DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 1, &USBStatus);
+
+  gBS->RestoreTPL (OriginalTPL);
+
+  return Status;
+}
+
+/**
+ * Calculate the video refresh rate from the video timing parameters (pixel clock etc)
+ * @param videoMode
+ * @return
+ */
+STATIC inline UINT16
+CalculateRefreshRate (
+    IN CONST struct VideoMode *VideoMode)
+{
+  UINT16 RefreshRate;
+  UINT16 Rmod;
+  UINT16 Rate10Hz;
+
+  RefreshRate = (VideoMode->PixelClock * 10000) / ((VideoMode->HActive + VideoMode->HBlanking) * (VideoMode->VActive + VideoMode->VBlanking));
+  Rmod = RefreshRate % 10;
+  Rate10Hz = RefreshRate - Rmod;
+
+  if (Rmod >= 5) {
+    Rate10Hz += 10;
+  }
+  return Rate10Hz;
+}
+
+/* ***************************************************************************************************** */
+/* ***************************************************************************************************** */
+/* ******************        START OF FUNCTIONS WHICH IMPLEMENT GOP INTERFACE         ****************** */
+/* ***************************************************************************************************** */
+/* ***************************************************************************************************** */
+
+
+/**
+ *
+ * @param Gop          Pointer to the instance of the GOP protocol
+ * @param ModeNumber
+ * @param SizeOfInfo
+ * @param Info
+ * @return
+ */
+EFI_STATUS
+EFIAPI
+DisplayLinkQueryMode (
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *Gop,
+  IN  UINT32                                ModeNumber,
+  OUT UINTN                                 *SizeOfInfo,
+  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
+)
+{
+  USB_DISPLAYLINK_DEV *Dev;
+  CONST struct VideoMode *VideoMode;
+  EFI_STATUS Status;
+
+  Dev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
+  Status = EFI_INVALID_PARAMETER;
+
+  if ((SizeOfInfo == NULL) || (Info == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Get a video mode from the EDID
+  Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, Dev->EdidActive.Edid, Dev->EdidActive.SizeOfEdid, &VideoMode);
+
+  if (!EFI_ERROR (Status)) {
+
+    *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+    if (*Info == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    DEBUG ((DEBUG_INFO, "BIOS querying mode number %d - returning %dx%d @ %dHz\n", ModeNumber, VideoMode->HActive, VideoMode->VActive, CalculateRefreshRate (VideoMode)));
+
+    *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+
+    (*Info)->Version = 0;
+    (*Info)->HorizontalResolution = VideoMode->HActive;
+    (*Info)->VerticalResolution = VideoMode->VActive;
+    (*Info)->PixelFormat = PixelBltOnly;
+    (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution;
+    (*Info)->PixelInformation.RedMask = 0;
+    (*Info)->PixelInformation.GreenMask = 0;
+    (*Info)->PixelInformation.BlueMask = 0;
+    (*Info)->PixelInformation.ReservedMask = 0;
+  }
+  return Status;
+}
+
+/**
+ *
+ * @param Gop         Pointer to the instance of the GOP protocol
+ * @param ModeNumber
+ * @return
+ */
+EFI_STATUS
+EFIAPI
+DisplayLinkSetMode (
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *Gop,
+  IN  UINT32                        ModeNumber
+)
+{
+  USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
+  EFI_STATUS Status;
+  CONST struct VideoMode *VideoMode;
+
+  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
+
+  // Prevent the DisplayLinkPeriodicTimer from interrupting us (bug 28877).
+  // When the driver is manually loaded, the TPL is TPL_NOTIFY (16) which prevents the interrupt from the timer.
+  // When the GOP driver is sideloaded, the TPL of this call is TPL_APPLICATION (4) and the timer can interrupt us.
+  Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
+
+  // Get a video mode from the EDID
+  Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, UsbDisplayLinkDev->EdidActive.Edid, UsbDisplayLinkDev->EdidActive.SizeOfEdid, &VideoMode);
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Gop->Mode->Info->Version = 0;
+  Gop->Mode->Info->HorizontalResolution = VideoMode->HActive;
+  Gop->Mode->Info->VerticalResolution = VideoMode->VActive;
+  Gop->Mode->Info->PixelFormat = PixelBltOnly;
+  Gop->Mode->Info->PixelsPerScanLine = Gop->Mode->Info->HorizontalResolution;
+  Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+  Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
+  Gop->Mode->FrameBufferSize = 0;
+
+  //
+  // Allocate the back buffer
+  //
+  if (UsbDisplayLinkDev->Screen != NULL) {
+    FreePool (UsbDisplayLinkDev->Screen);
+  }
+
+  UsbDisplayLinkDev->Screen = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)AllocateZeroPool (
+    Gop->Mode->Info->HorizontalResolution *
+    Gop->Mode->Info->VerticalResolution *
+    sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+
+  if (UsbDisplayLinkDev->Screen == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  DEBUG ((DEBUG_INFO, "Video mode %d selected by BIOS - %d x %d.\n", ModeNumber, VideoMode->HActive, VideoMode->VActive));
+  // Wait until we are sure that we can set the video mode before we tell the firmware
+  Status = DlUsbSendControlWriteMessage (UsbDisplayLinkDev, SET_VIDEO_MODE, 0, VideoMode, sizeof (struct VideoMode));
+
+  if (Status != EFI_SUCCESS) {
+    // Flag up that we haven't set the video mode correctly yet.
+    DEBUG ((DEBUG_ERROR, "Failed to send USB message to DisplayLink device to set monitor video mode. Monitor connected correctly?\n"));
+    Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
+    FreePool (UsbDisplayLinkDev->Screen);
+    UsbDisplayLinkDev->Screen = NULL;
+  } else {
+    BuildBackBuffer (
+      UsbDisplayLinkDev,
+      UsbDisplayLinkDev->Screen,
+      EfiBltBufferToVideo,
+      0, 0,
+      0, 0,
+      Gop->Mode->Info->HorizontalResolution,
+      Gop->Mode->Info->VerticalResolution,
+      Gop->Mode->Info->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
+      Gop->Mode->Info->HorizontalResolution);
+    // unlock the DisplayLinkPeriodicTimer
+    Gop->Mode->Mode = ModeNumber;
+  }
+
+  return Status;
+}
+
+/**
+ * Implementation of the GOP protocol Blt API function
+ * @param This            Pointer to the instance of the GOP protocol
+ * @param BltBuffer
+ * @param BltOperation
+ * @param SourceX
+ * @param SourceY
+ * @param DestinationX
+ * @param DestinationY
+ * @param Width
+ * @param Height
+ * @param Delta
+ * @return
+ */
+EFI_STATUS
+EFIAPI
+DisplayLinkBlt (
+  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
+)
+{
+  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
+  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
+
+  // Drop out if we haven't set the video mode up yet
+  if (This->Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
+    return EFI_SUCCESS;
+  }
+
+  if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Width == 0 || Height == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Lock so we make an atomic write the frame buffer.
+  // We would not want a timer based event (Cursor, ...) to come in while we are doing this operation.
+  EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+  CONST UINTN BltBufferStride = (Delta == 0) ? Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) : Delta;
+  CONST EFI_STATUS boundsCheckStatus = CheckBounds (This, BltOperation, SourceX, SourceY, Width, Height, DestinationX, DestinationY);
+  if (EFI_ERROR (boundsCheckStatus)) {
+    gBS->RestoreTPL (OriginalTPL);
+    return boundsCheckStatus;
+  }
+
+  BuildBackBuffer (UsbDisplayLinkDev, BltBuffer, BltOperation, SourceX, SourceY, DestinationX, DestinationY, Width, Height, BltBufferStride, This->Mode->Info->PixelsPerScanLine);
+
+  gBS->RestoreTPL (OriginalTPL);
+  return EFI_SUCCESS;
+}
+
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
new file mode 100644
index 000000000000..2a7886ed6523
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
@@ -0,0 +1,144 @@
+/**
+ * @file UsbDescriptors.c
+ * @brief Functions to read USB Interface and Capabilities descriptors
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#include "UsbDisplayLink.h"
+#include "UsbDescriptors.h"
+
+/**
+ *
+ * @param UsbIo
+ * @param descriptorType
+ * @param index
+ * @param Buffer
+ * @param Length
+ * @param UsbStatus
+ * @return
+ */
+STATIC EFI_STATUS
+ReadDescriptor (
+    IN EFI_USB_IO_PROTOCOL *UsbIo,
+    UINT8 DescriptorType,
+    UINT8 Index,
+    VOID* Buffer,
+    UINT16 Length,
+    UINT32* UsbStatus)
+{
+  EFI_STATUS Status;
+
+  UINT8 Header[2] = {0, 0};
+
+  EFI_USB_DEVICE_REQUEST Request;
+  ZeroMem (&Request, sizeof (Request));
+  Request.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_STANDARD | USB_TARGET_DEVICE;
+  Request.Request = USB_REQ_GET_DESCRIPTOR;
+  Request.Index = 0;
+  Request.Value = DescriptorType << 8 | Index;
+  Request.Length = sizeof (Header);
+
+  // Read the descriptor header to see how many bytes it contains
+  Status = UsbIo->UsbControlTransfer (
+      UsbIo,
+      &Request,
+      EfiUsbDataIn,
+      DISPLAYLINK_USB_CTRL_TIMEOUT,
+      Header,
+      sizeof (Header),
+      UsbStatus);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to read length of descriptor type x%x, index %u (code %r, USB status x%x)\n",
+          DescriptorType, Index, Status, *UsbStatus));
+    return Status;
+  }
+  CONST UINT16 TotalLength = Header[0];
+
+  // Now we know the size of it, we can read the entire descriptor
+  Request.Length = TotalLength;
+
+  Status = UsbIo->UsbControlTransfer (
+      UsbIo,
+      &Request,
+      EfiUsbDataIn,
+      DISPLAYLINK_USB_CTRL_TIMEOUT,
+      Buffer,
+      TotalLength,
+      UsbStatus);
+
+  return Status;
+}
+
+/**
+  Perform a USB control transfer to read the DisplayLink vendor descriptor.
+
+  @param UsbIo   Pointer to the instance of the USBIO protocol
+  @param Buffer  Pointer to the buffer where descriptor should be written
+  @param Length  Length of buffer (and the maximum amount of descriptor data that shall be read)
+
+  @retval EFI_SUCCESS  The descriptor has been copied into Buffer
+  @retval Other        The descriptor could not be read
+**/
+EFI_STATUS
+ReadCapabilitiesDescriptor (
+    IN EFI_USB_IO_PROTOCOL *UsbIo,
+    OUT VOID* Buffer,
+    IN UINT16 Length)
+{
+  UINT32 UsbStatus;
+  EFI_STATUS Status;
+
+  Status = ReadDescriptor (
+      UsbIo,
+      DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY,
+      0,
+      Buffer,
+      Length,
+      &UsbStatus);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Could not read capabilities descriptor from DL device (code %r, USB status x%x). Unrecognised firmware version?\n", Status, UsbStatus));
+  }
+
+  return Status;
+}
+
+
+/**
+ An alternative to the UBSIO protocol function EFI_USB_IO_GET_INTERFACE_DESCRIPTOR.
+ This version allows you to specify an index.
+ * @param UsbIo                 Pointer to the instance of the USBIO protocol
+ * @param interfaceDescriptor   Where the descriptor should be written
+ * @param index                 The index of the descriptor required (the standard USBIO function doesn't let you do this)
+ * @return
+ */
+EFI_STATUS
+UsbDisplayLinkGetInterfaceDescriptor (
+    IN EFI_USB_IO_PROTOCOL *UsbIo,
+    OUT EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
+    UINT8 Index
+    )
+{
+  UINT32 UsbStatus;
+  EFI_STATUS Status;
+
+  Status = ReadDescriptor (
+      UsbIo,
+      USB_DESC_TYPE_INTERFACE,
+      Index,
+      InterfaceDescriptor,
+      sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
+      &UsbStatus);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "USB control transfer failed while reading interface descriptor (code %r, USB status x%x)\n", Status, UsbStatus));
+  }
+
+  return Status;
+}
+
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
new file mode 100644
index 000000000000..99be66a9bd2d
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
@@ -0,0 +1,1109 @@
+/**
+ * @file UsbDisplayLink.c
+ * @brief USB DisplayLink Driver that manages USB DisplayLink device and produces Graphics Output Protocol
+ * This file implements the functions of the Driver Binding / Start / Stop / Unload interface
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#include "UsbDisplayLink.h"
+
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PrintLib.h>
+#include <Protocol/HiiFont.h>
+
+#include "Edid.h"
+#include "UsbDescriptors.h"
+
+//
+// Functions of Driver Binding Protocol
+//
+
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
+  IN EFI_HANDLE                     Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
+);
+
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
+  IN EFI_HANDLE                     Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
+);
+
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
+  IN  EFI_HANDLE                    Controller,
+  IN  UINTN                         NumberOfChildren,
+  IN  EFI_HANDLE                    *ChildHandleBuffer
+);
+
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverBindingEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+);
+
+
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable,
+  IN EFI_HANDLE           DriverBindingHandle
+);
+
+
+// Generated with https://www.guidgen.com/ - "B70E5A79-C6D6-4267-B02E-9108C989E287"
+EFI_GUID gEfiDlGopVariableGuid = { 0xB70E5A79, 0xC6D6, 0x4267,{ 0xB0, 0x2E, 0x91, 0x08, 0xC9, 0x89, 0xE2, 0x87 } };
+
+
+EFI_DRIVER_BINDING_PROTOCOL gUsbDisplayLinkDriverBinding = {
+  UsbDisplayLinkDriverBindingSupported,
+  UsbDisplayLinkDriverBindingStart,
+  UsbDisplayLinkDriverBindingStop,
+  INF_DRIVER_VERSION,
+  NULL,
+  NULL
+};
+
+
+/**
+ * Reads integer environment variable with default fallback.
+ * @param variableName   variable name to read
+ * @param defaultValue   default value to return if requested not found
+ */
+STATIC UINT32
+ReadEnvironmentInt (
+    CONST wchar_t* VariableName,
+    UINT32 DefaultValue
+    )
+{
+  UINT32 Result;
+  UINTN DataSize;
+  DataSize = sizeof (Result);
+  CONST EFI_STATUS Status = gRT->GetVariable ((CHAR16*)VariableName, &gEfiDlGopVariableGuid, (UINT32*)NULL, &DataSize, &Result);
+  if (!EFI_ERROR (Status) && (sizeof (Result) == DataSize)) {
+    return Result;
+  }
+  return DefaultValue;
+}
+
+/**
+* Reads boolean environment variable with default fallback.
+* @param variableName   variable name to read
+* @param defaultValue   default value to return if requested not found
+*/
+STATIC BOOLEAN
+ReadEnvironmentBool (
+    CONST wchar_t* VariableName,
+    BOOLEAN DefaultValue
+    )
+{
+  return ReadEnvironmentInt (VariableName, DefaultValue ? 1 : 0) == 1;
+}
+
+
+/**
+*
+* @param UsbDisplayLinkDev
+* @return
+*/
+STATIC EFI_STATUS
+InitializeUsbDisplayLinkDevice (
+  IN OUT USB_DISPLAYLINK_DEV *UsbDisplayLinkDev
+)
+{
+  EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
+  Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
+  Gop->QueryMode = DisplayLinkQueryMode;
+  Gop->SetMode = DisplayLinkSetMode;
+  Gop->Blt = DisplayLinkBlt;
+
+  //
+  // Allocate buffer for Graphics Output Protocol mode information
+  //
+  Gop->Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
+  if (Gop->Mode == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  Gop->Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+  if (Gop->Mode->Info == NULL) {
+    FreePool (Gop->Mode);
+    Gop->Mode = NULL;
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Gop->Mode->MaxMode = MAX(1, DlEdidGetNumSupportedModesInEdid (UsbDisplayLinkDev->EdidActive.Edid, UsbDisplayLinkDev->EdidActive.SizeOfEdid));
+
+  Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
+  Gop->Mode->Info->Version = 0;
+  // TODO - Initialising the horizontal resolution prevents certain BIOSs from hanging on boot, but
+  // it is not yet clear why. See bug 28194.
+  Gop->Mode->Info->HorizontalResolution = DlVideoModeGetSupportedVideoMode (0)->HActive;
+  Gop->Mode->Info->VerticalResolution = 0;
+  Gop->Mode->Info->PixelFormat = PixelBltOnly;
+  Gop->Mode->Info->PixelsPerScanLine = 0;
+  Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+  Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
+  Gop->Mode->FrameBufferSize = 0;
+
+  // Prevent DlGopSendScreenUpdate from running until we are sure that the video mode is set
+  UsbDisplayLinkDev->LastY2 = 0;
+  UsbDisplayLinkDev->LastY1 = (UINTN)-1;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Look for alternate settings for the UsbIo handle's interface
+  which offer protocol DL_PROTOCOL_DIRECT_FB.
+
+  @retval -1                     Not found
+  @retval Other                  The alternate setting
+**/
+STATIC INTN
+GetDirectFbAltSetting (
+    IN EFI_USB_IO_PROTOCOL *UsbIo,
+    IN UINT8 ParentInterfaceNumber
+    )
+{
+  EFI_STATUS Status;
+  INTN AltSettingIndex;
+  UINT16 InterfaceIndex;
+
+  AltSettingIndex = -1;
+
+  for (InterfaceIndex = 0; InterfaceIndex <= 0xFF; InterfaceIndex++) {
+    EFI_USB_INTERFACE_DESCRIPTOR interfaceDescriptor;
+    Status = UsbDisplayLinkGetInterfaceDescriptor (UsbIo, &interfaceDescriptor, (UINT8)InterfaceIndex);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    if (interfaceDescriptor.InterfaceNumber == ParentInterfaceNumber &&
+       (interfaceDescriptor.InterfaceClass == CLASS_VENDOR) &&
+        interfaceDescriptor.InterfaceProtocol == INTERFACE_PROTOCOL_DIRECT_FB) {
+      AltSettingIndex = interfaceDescriptor.AlternateSetting;
+      break;
+    }
+  }
+  return AltSettingIndex;
+}
+
+/**
+ *
+ * @param UsbIo
+ * @param altSettingIndex
+ * @return
+ */
+STATIC EFI_STATUS
+SelectAltSetting (
+    IN EFI_USB_IO_PROTOCOL *UsbIo,
+    IN UINTN AltSettingIndex)
+{
+  // Set alternate setting 1 on the interface
+  EFI_STATUS Status;
+  UINT32 UsbStatus;
+  EFI_USB_DEVICE_REQUEST Request;
+  ZeroMem (&Request, sizeof (Request));
+  Request.RequestType = USB_REQ_TYPE_STANDARD | USB_TARGET_INTERFACE;
+  Request.Request = USB_REQ_SET_INTERFACE;
+  Request.Index = DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO;
+  Request.Value = (UINT16)AltSettingIndex;
+
+  Status = UsbIo->UsbControlTransfer (
+    UsbIo,
+    &Request,
+    EfiUsbNoData,
+    DISPLAYLINK_USB_CTRL_TIMEOUT,
+    NULL,
+    0,
+    &UsbStatus);
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    DEBUG ((DEBUG_ERROR, "USB control transfer failed while attempting to select alt setting %d on interface (code %r, USB status x%x). DisplayLink device has unsupported firmware version?\n", AltSettingIndex, Status, UsbStatus));
+  }
+  return Status;
+}
+
+
+/**
+  Report whether the driver can support the device attached via UsbIo
+  by seeing what if any capabilities it reports.
+
+  @retval TRUE     Device has sufficient capabilities for this driver.
+  @retval FALSE    Device lacks sufficient capabilities.
+**/
+STATIC BOOLEAN
+CapabilitiesSupported (
+    IN EFI_USB_IO_PROTOCOL *UsbIo
+    )
+{
+  UINT8 Buffer[256];
+  EFI_STATUS Status;
+
+  Status = ReadCapabilitiesDescriptor (UsbIo, Buffer, sizeof (Buffer));
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  VendorDescriptor descriptor;
+  Status = UsbDisplayLinkParseCapabilitiesDescriptor (Buffer, sizeof (Buffer), &descriptor);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to parse capabilities descriptor (code %r)\n", Status));
+    return FALSE;
+  }
+
+  return UsbDisplayLinkCapabilitiesSufficientToBind (&descriptor);
+}
+
+
+/**
+ *
+ * @param UsbIo
+ * @param InterfaceDescriptor
+ * @param altSettingIndex
+ * @return
+ */
+STATIC BOOLEAN
+IsDLDirectFbCapableInterface (
+    IN EFI_USB_IO_PROTOCOL *UsbIo,
+    IN EFI_USB_INTERFACE_DESCRIPTOR  *InterfaceDescriptor,
+    IN INTN *AltSettingIndex)
+{
+  EFI_STATUS Status;
+  EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+
+  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DeviceDescriptor);
+
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  if (DeviceDescriptor.IdVendor != VENDOR_DISPLAYLINK) {
+    return FALSE;
+  }
+
+  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, InterfaceDescriptor);
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  // We can assume that the interface that we want to talk to - the NIVO interface - is number 0
+  if (InterfaceDescriptor->InterfaceNumber != DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO) {
+    return FALSE;
+  }
+
+  // Check if we have an interface (alt setting) descriptor with the correct interface protocol
+  *AltSettingIndex = GetDirectFbAltSetting (UsbIo, InterfaceDescriptor->InterfaceNumber);
+
+  if (*AltSettingIndex == -1) {
+    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to find setting on device which supports GOP functionality. Check firmware / device version?\n"));
+    return FALSE;
+  }
+
+  // Now check that the capabilities that we need are properly supported
+  if (CapabilitiesSupported (UsbIo) == FALSE) {
+    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: DL device detected, but it doesn't support the required GOP features. Check firmware / device version?\n"));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/**
+ * Prints a block of text in the framebuffer (helper function).
+ * @param X   x coordinate
+ * @param Y   y coordinate
+ */
+STATIC VOID
+DisplayLinkPrintTextToScreenInternal (
+  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+  UINTN X,
+  UINTN Y,
+  IN CHAR16 *Buffer
+  )
+{
+  EFI_STATUS Status;
+  EFI_HII_FONT_PROTOCOL *HiiFont;
+  EFI_IMAGE_OUTPUT *Blt;
+  EFI_FONT_DISPLAY_INFO FontInfo;
+  EFI_HII_OUT_FLAGS Flags;
+
+  Blt = (EFI_IMAGE_OUTPUT*)NULL;
+
+  Status = gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **)&HiiFont);
+  if (!EFI_ERROR (Status)) {
+    Blt = (EFI_IMAGE_OUTPUT*)AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+    Blt->Width = (UINT16)GraphicsOutput->Mode->Info->HorizontalResolution;
+    Blt->Height = (UINT16)GraphicsOutput->Mode->Info->VerticalResolution;
+    Blt->Image.Screen = GraphicsOutput;
+
+    ZeroMem (&FontInfo, sizeof (EFI_FONT_DISPLAY_INFO));
+    FontInfo.ForegroundColor.Red = 0;
+    FontInfo.ForegroundColor.Green = 0;
+    FontInfo.ForegroundColor.Blue = 0;
+    FontInfo.BackgroundColor.Red = 0xff;
+    FontInfo.BackgroundColor.Green = 0xff;
+    FontInfo.BackgroundColor.Blue = 0xff;
+
+    Flags = EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_OUT_FLAG_CLIP |
+            EFI_HII_OUT_FLAG_CLIP_CLEAN_X | EFI_HII_OUT_FLAG_CLIP_CLEAN_Y |
+            EFI_HII_IGNORE_LINE_BREAK | EFI_HII_DIRECT_TO_SCREEN;
+
+    Status = HiiFont->StringToImage (
+                           HiiFont,
+                           Flags,
+                           Buffer,
+                           &FontInfo,
+                           &Blt,
+                           X,
+                           Y,
+                           (EFI_HII_ROW_INFO**)NULL,
+                           (UINTN*)NULL,
+                           (UINTN*)NULL);
+  }
+
+  if (Blt != NULL) {
+    FreePool (Blt);
+  }
+}
+
+
+/**
+* Prints a block of text in the framebuffer.
+* @param X       x coordinate
+* @param Y       y coordinate
+* @param Format  string format similar to stdlib's vsnprintf
+* @param ...     arguments
+*/
+VOID
+DlGopPrintTextToScreen (
+  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+  UINTN X,
+  UINTN Y,
+  IN CONST CHAR16 *Format,
+  ...
+  )
+{
+  VA_LIST Marker;
+  CHAR16 *Buffer;
+  UINTN BufferSize;
+
+  ASSERT (Format != NULL);
+  ASSERT (((UINTN) Format & BIT0) == 0);
+
+  VA_START(Marker, Format);
+
+  BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);
+
+  Buffer = (CHAR16*)AllocatePool (BufferSize);
+  ASSERT (Buffer != NULL);
+
+  UnicodeVSPrint (Buffer, BufferSize, Format, Marker);
+
+  VA_END(Marker);
+
+  DisplayLinkPrintTextToScreenInternal (GraphicsOutput, X, Y, Buffer);
+
+  FreePool (Buffer);
+}
+
+
+/**
+ * Sometimes platforms only write to the first GOP device that they find. Enabling this function allows us to copy the pixels from this device.
+ * @param UsbDisplayLinkDev
+ */
+#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
+STATIC VOID
+DisplayLinkCopyFromPrimaryGopDevice (
+  IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
+  )
+{
+  UINTN HandleCount;
+  EFI_HANDLE *HandleBuffer;
+  UINTN HandleIndex;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
+
+  gBS->LocateHandleBuffer (
+    ByProtocol,
+    &gEfiGraphicsOutputProtocolGuid,
+    NULL,
+    &HandleCount,
+    &HandleBuffer);
+
+  for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+    gBS->HandleProtocol (HandleBuffer[HandleIndex], &gEfiGraphicsOutputProtocolGuid, (VOID**)&Gop);
+    if (Gop != &UsbDisplayLinkDev->GraphicsOutputProtocol && Gop->Mode->FrameBufferBase != (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
+
+#if 0
+      if (UsbDisplayLinkDev->UseFixedMode) {
+      if ((Gop->Mode->Info->HorizontalResolution != UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution)
+       || (Gop->Mode->Info->VerticalResolution != UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution))
+      {
+        DisplayLinkSetMode (&UsbDisplayLinkDev->GraphicsOutputProtocol, GetNearestMode (Gop->Mode->Info->HorizontalResolution, Gop->Mode->Info->VerticalResolution));
+      }
+    }
+
+    // Check to see if we should skip this copy because there is corruption on the screen
+    if (Gop->Mode->Info->HorizontalResolution == 1024 && Gop->Mode->Info->VerticalResolution == 768) {
+      CONST UINT32 corruptionCrc = 0x6BB19C15;
+      UINT32 lineCrc = corruptionCrc;
+      UINTN line;
+      for (line = 15; line < 25 && lineCrc == corruptionCrc; line++) {
+        lineCrc = 0;
+        gBS->CalculateCrc32 ((char*)Gop->Mode->FrameBufferBase + (line * 4 * 1024), 1024, &lineCrc);
+      }
+      if (lineCrc == corruptionCrc) {
+        if (UsbDisplayLinkDev->ShowDebug) {
+          DlGopPrintTextToScreen (&UsbDisplayLinkDev->GraphicsOutputProtocol, 32, 196, (CONST CHAR16*)L"Skipping Copy");
+        }
+        break;
+      }
+    }
+#endif
+
+    // See if we need to do a screen update - calculate a really noddy hash to see if any screen updates have happened.
+    STATIC UINT32 prevframeBufferHash = 0; // 4 bytes per pixel
+    UINT32 currFrameBufferHash = 0;
+    UINTN i;
+    for (i = 0; i < (Gop->Mode->Info->HorizontalResolution * Gop->Mode->Info->VerticalResolution); i++) {
+      currFrameBufferHash += ((UINT32*)(UINTN)Gop->Mode->FrameBufferBase)[i];
+    }
+
+    if (currFrameBufferHash != prevframeBufferHash) {
+      prevframeBufferHash = currFrameBufferHash;
+
+      DisplayLinkBlt (
+        &UsbDisplayLinkDev->GraphicsOutputProtocol,
+        (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(UINTN)Gop->Mode->FrameBufferBase,
+        EfiBltBufferToVideo,
+        0,
+        0,
+        0,
+        0,
+        Gop->Mode->Info->HorizontalResolution,
+        Gop->Mode->Info->VerticalResolution,
+        0);
+      }
+      break;
+    }
+  }
+
+  FreePool (HandleBuffer);
+}
+#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
+
+
+/**
+ * TODO: Verify if it's true!
+ * Exit from boot services: signal handler.
+ */
+STATIC VOID
+EFIAPI
+DisplayLinkDriverExitBootServices (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
+  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
+
+  gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
+}
+
+/**
+ * Periodic screen update: timer callback.
+ */
+VOID
+EFIAPI
+DisplayLinkPeriodicTimer (
+    IN EFI_EVENT Event,
+    IN VOID* Context
+    )
+{
+  EFI_STATUS Status;
+  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
+
+  Status = EFI_SUCCESS;
+  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
+
+  // Drop out if we haven't set the video mode up yet
+  if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
+    // Restart the one-shot timer to poll the status again.
+    Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
+    }
+    return;
+  }
+
+#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
+  DisplayLinkCopyFromPrimaryGopDevice (UsbDisplayLinkDev);
+#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
+
+  if (UsbDisplayLinkDev->ShowBandwidth) {
+    STATIC UINTN Count = 0;
+
+    if (Count++ % 50 == 0) {
+      DlGopPrintTextToScreen (&UsbDisplayLinkDev->GraphicsOutputProtocol, 32, 48, (CONST CHAR16*)L"  Bandwidth: %d MB/s    ", UsbDisplayLinkDev->DataSent * 10000000 / DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 50 / 1024 / 1024);
+      UsbDisplayLinkDev->DataSent = 0;
+    }
+  }
+
+  if (UsbDisplayLinkDev->ShowTestPattern)
+  {
+    if (UsbDisplayLinkDev->ShowTestPattern == 5) {
+      DlGopSendTestPattern (UsbDisplayLinkDev, 0);
+    } else if (UsbDisplayLinkDev->ShowTestPattern >= 10) {
+      DlGopSendTestPattern (UsbDisplayLinkDev, 1);
+      UsbDisplayLinkDev->ShowTestPattern = 0;
+    }
+    UsbDisplayLinkDev->ShowTestPattern++;
+
+  }
+
+  // Send the latest version of the frame buffer to the DL device over USB
+  DlGopSendScreenUpdate (UsbDisplayLinkDev);
+
+  // Restart the timer now we've finished
+  Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
+  }
+}
+
+/* ****************************************************************************************************** */
+/* ****************************************************************************************************** */
+/* ******************   START OF FUNCTIONS WHICH IMPLEMENT DRIVER BINDING INTERFACE    ****************** */
+/* ****************************************************************************************************** */
+/* ****************************************************************************************************** */
+
+/**
+  Check whether USB DisplayLink driver supports this device.
+
+  @param  This                   The USB DisplayLink driver binding protocol.
+  @param  Controller             The controller handle to check.
+  @param  RemainingDevicePath    The remaining device path.
+
+  @retval EFI_SUCCESS            The driver supports this controller.
+  @retval other                  This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
+  IN EFI_HANDLE                     Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
+  )
+{
+  EFI_STATUS          Status;
+  EFI_USB_IO_PROTOCOL *UsbIo;
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiUsbIoProtocolGuid,
+                  (VOID **) &UsbIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER);
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Use the USB I/O Protocol interface to check whether Controller is
+  // a DisplayLink device that can be managed by this driver.
+  //
+  Status = EFI_UNSUPPORTED;
+  EFI_USB_INTERFACE_DESCRIPTOR DummyInterfaceDescriptor;
+  INTN DummyAltSettingIndex;
+
+  if (IsDLDirectFbCapableInterface (UsbIo, &DummyInterfaceDescriptor, &DummyAltSettingIndex)){
+    Status = EFI_SUCCESS;
+  }
+
+  gBS->CloseProtocol (
+        Controller,
+        &gEfiUsbIoProtocolGuid,
+        This->DriverBindingHandle,
+        Controller);
+
+  return Status;
+}
+
+
+/**
+  Starts the DisplayLink device with this driver.
+
+  This function consumes USB I/O Protocol, intializes USB DisplayLink device,
+  installs Graphics Output Protocol
+  Transfer to manage the USB DisplayLink device.
+
+  @param  This                  The USB DisplayLink driver binding instance.
+  @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 supports this device.
+  @retval EFI_UNSUPPORTED       This driver does not support this device.
+  @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
+  @retval EFI_OUT_OF_RESOURCES  Can't allocate memory resources.
+  @retval EFI_ALREADY_STARTED   This driver has been started.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS                      Status;
+  USB_DISPLAYLINK_DEV             *UsbDisplayLinkDev;
+  UINT8                           EndpointNumber;
+  EFI_USB_ENDPOINT_DESCRIPTOR     EndpointDescriptor;
+  UINT8                           Index;
+  BOOLEAN                         FoundOut;
+  BOOLEAN                         FoundIn;
+  EFI_TPL                         OriginalTPL;
+  INTN                            altSettingIndex;
+
+  OriginalTPL = gBS->RaiseTPL (TPL_CALLBACK);
+
+  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)AllocateZeroPool (sizeof (USB_DISPLAYLINK_DEV));
+  if (UsbDisplayLinkDev == NULL) {
+    DEBUG ((DEBUG_ERROR, "Device initialialisation - Failed to allocate memory for device.\n"));
+    gBS->RestoreTPL (OriginalTPL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  UsbDisplayLinkDev->Signature = USB_DISPLAYLINK_DEV_SIGNATURE;
+
+  UsbDisplayLinkDev->ShowBandwidth = ReadEnvironmentBool (L"DisplayLinkShowBandwidth", FALSE);
+  UsbDisplayLinkDev->ShowTestPattern = ReadEnvironmentBool (L"DisplayLinkShowTestPatterns", FALSE);
+
+  //
+  // Open USB I/O Protocol
+  //
+  Status = gBS->OpenProtocol (
+      Controller,
+      &gEfiUsbIoProtocolGuid,
+      (VOID **) &UsbDisplayLinkDev->UsbIo,
+      This->DriverBindingHandle,
+      Controller,
+      EFI_OPEN_PROTOCOL_BY_DRIVER);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to open usbio protocol. Is USB correctly supported on this platform?.\n"));
+    Status = EFI_UNSUPPORTED;
+    goto ErrorExit2;
+  }
+
+  if (!IsDLDirectFbCapableInterface (UsbDisplayLinkDev->UsbIo, &UsbDisplayLinkDev->InterfaceDescriptor, &altSettingIndex)) {
+    Status = EFI_UNSUPPORTED;
+    goto ErrorExit4;
+  }
+
+  Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, altSettingIndex);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to select alternate setting.\n"));
+    Status = EFI_UNSUPPORTED;
+    goto ErrorExit4;
+  }
+
+  //
+  // Parse endpoint descriptor
+  //
+  EndpointNumber = UsbDisplayLinkDev->InterfaceDescriptor.NumEndpoints;
+
+  //
+  // Traverse endpoints to find bulk endpoint
+  //
+  FoundOut = FALSE;
+  FoundIn = FALSE;
+  for (Index = 0; Index < EndpointNumber; Index++) {
+    UsbDisplayLinkDev->UsbIo->UsbGetEndpointDescriptor (
+             UsbDisplayLinkDev->UsbIo,
+             Index,
+             &EndpointDescriptor);
+
+    if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_BULK) {
+      if (!FoundOut && (EndpointDescriptor.EndpointAddress & BIT7) == 0) {
+        CopyMem (&UsbDisplayLinkDev->BulkOutEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
+        FoundOut = TRUE;
+      } else if (!FoundIn && (EndpointDescriptor.EndpointAddress & BIT7) == BIT7) {
+        CopyMem (&UsbDisplayLinkDev->BulkInEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
+        FoundIn = TRUE;
+      }
+    }
+  }
+
+  if (FoundOut == FALSE) {
+    Status = EFI_UNSUPPORTED;
+    DEBUG ((DEBUG_ERROR, "No endpoints found.  Num endpoints searched = %d.\n", EndpointNumber));
+    goto ErrorExit4;
+  }
+
+  Status = DlReadEdid (UsbDisplayLinkDev);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to read monitor EDID from DisplayLink device (code %r)\n", Status));
+    goto ErrorExit7;
+  }
+
+  Status = InitializeUsbDisplayLinkDevice (UsbDisplayLinkDev);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to initialise DisplayLink device (code %r)\n", Status));
+    goto ErrorExit7;
+  }
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+      &Controller,
+      &gEfiGraphicsOutputProtocolGuid,
+      &UsbDisplayLinkDev->GraphicsOutputProtocol,
+      &gEfiEdidDiscoveredProtocolGuid,
+      &UsbDisplayLinkDev->EdidDiscovered,
+      &gEfiEdidActiveProtocolGuid,
+      &UsbDisplayLinkDev->EdidActive,
+      NULL);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to install Graphics Output and EDID protocol interfaces - driver not installed correctly - %r\n", Status));
+    goto ErrorExit8;
+  }
+
+  UsbDisplayLinkDev->ControllerNameTable = (EFI_UNICODE_STRING_TABLE*)NULL;
+
+  AddUnicodeString2 (
+    "eng",
+    mUsbDisplayLinkComponentName.SupportedLanguages,
+    &UsbDisplayLinkDev->ControllerNameTable,
+    (CONST CHAR16*)L"Generic Usb DisplayLink",
+    TRUE);
+
+  AddUnicodeString2 (
+    "en",
+    mUsbDisplayLinkComponentName2.SupportedLanguages,
+    &UsbDisplayLinkDev->ControllerNameTable,
+    (CONST CHAR16*)L"Generic Usb DisplayLink",
+    FALSE);
+
+  //
+  // Setup a periodic timer
+  //
+  Status = gBS->CreateEvent (
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  DisplayLinkPeriodicTimer,
+                  UsbDisplayLinkDev,
+                  &UsbDisplayLinkDev->TimerEvent);
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((DEBUG_ERROR, "Failed to create screeen update polling event.\n"));
+    goto ErrorExit8;
+  }
+
+  // Start one-shot timer. The rendering operations can take quite a long time, so we
+  // don't want another timer event to happen until we have finished; so we'll restart
+  // the timer from DisplayLinkPeriodicTimer, the event handler function.
+  Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((DEBUG_ERROR, "Failed to create screen update polling timer.\n"));
+    goto ErrorExit8;
+  }
+
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  DisplayLinkDriverExitBootServices,
+                  UsbDisplayLinkDev,
+                  &gEfiEventExitBootServicesGuid,
+                  &UsbDisplayLinkDev->DriverExitBootServicesEvent);
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((DEBUG_ERROR, "Failed to create event for bootexit.\n"));
+    goto ErrorExit8;
+  }
+
+  gBS->RestoreTPL (OriginalTPL);
+
+  DEBUG ((DEBUG_INFO, "DisplayLink GOP driver successfully bound to device.\n"));
+
+  return EFI_SUCCESS;
+
+  //
+  // Error handler
+  //
+ ErrorExit8:
+ ErrorExit7:
+ ErrorExit4:
+  gBS->CloseProtocol (
+   Controller,
+   &gEfiUsbIoProtocolGuid,
+   This->DriverBindingHandle,
+   Controller);
+
+ ErrorExit2:
+  if (UsbDisplayLinkDev != NULL) {
+    FreePool (UsbDisplayLinkDev);
+    UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)NULL;
+  }
+
+  DEBUG ((DEBUG_ERROR, "Exiting - Failed to initialise driver.\n"));
+
+  gBS->RestoreTPL (OriginalTPL);
+  return Status;
+}
+
+/**
+Entrypoint of USB DisplayLink Driver.
+
+This function is the entrypoint of a combined USB DisplayLink GOP Driver. It installs Driver Binding
+Protocols together with Component Name Protocols.
+
+@param  ImageHandle       The firmware allocated handle for the EFI image.
+@param  SystemTable       A pointer to the EFI System Table.
+@param  DriverBindingHandle  The Driver binding handle
+
+@retval EFI_SUCCESS       The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable,
+  IN EFI_HANDLE           DriverBindingHandle
+)
+{
+  EFI_STATUS Status;
+
+  Status = EfiLibInstallDriverBindingComponentName2 (
+    ImageHandle,
+    SystemTable,
+    &gUsbDisplayLinkDriverBinding,
+    DriverBindingHandle,
+    &mUsbDisplayLinkComponentName,
+    &mUsbDisplayLinkComponentName2);
+
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+Entrypoint of USB DisplayLink Driver.
+
+This function is the entrypoint of USB DisplayLink Driver. It installs Driver Binding
+Protocols together with Component Name Protocols.
+
+@param  ImageHandle       The firmware allocated handle for the EFI image.
+@param  SystemTable       A pointer to the EFI System Table.
+
+@retval EFI_SUCCESS       The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverBindingEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+)
+{
+  return UsbDisplayLinkDriverCombinedGopBindingEntryPoint (ImageHandle, SystemTable, ImageHandle);
+}
+
+
+/**
+Unloads an image.
+@param  ImageHandle           Handle that identifies the image to be unloaded.
+@retval EFI_SUCCESS           The image has been unloaded.
+@retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
+**/
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverCombinedGopUnload (
+  IN EFI_HANDLE  ImageHandle
+)
+{
+  EFI_STATUS  Status = EFI_SUCCESS;
+  EFI_STATUS  handleDisconnectStatus;
+  EFI_HANDLE  *HandleBuffer;
+  UINTN       HandleCount;
+  UINTN       Index;
+
+  //
+  // Retrieve array of all handles in the handle database
+  //
+  handleDisconnectStatus = gBS->LocateHandleBuffer (
+    AllHandles,
+    NULL,
+    NULL,
+    &HandleCount,
+    &HandleBuffer
+  );
+  if (! EFI_ERROR (handleDisconnectStatus)) {
+    //
+    // Disconnect the current driver from handles in the handle database
+    //
+    for (Index = 0; Index < HandleCount; Index++) {
+      Status = gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
+    }
+    //
+    // Free the array of handles
+    //
+    if (HandleBuffer != NULL)
+    {
+      FreePool (HandleBuffer);
+    }
+  }
+
+  // Even if we didn't manage to disconnect the handles, try to uninstall the protocols
+  //
+  // Uninstall protocols installed in the driver entry point
+  //
+  Status = gBS->UninstallMultipleProtocolInterfaces (
+    ImageHandle,
+    &gEfiDriverBindingProtocolGuid,
+    &gUsbDisplayLinkDriverBinding,
+    &gEfiComponentNameProtocolGuid,
+    &mUsbDisplayLinkComponentName,
+    &gEfiComponentName2ProtocolGuid,
+    &mUsbDisplayLinkComponentName2,
+    NULL
+  );
+
+  if (EFI_ERROR (handleDisconnectStatus))
+  {
+    return handleDisconnectStatus;
+  }
+  return Status;
+}
+
+
+/**
+  Stop the USB DisplayLink device handled by this driver.
+
+  @param  This                   The USB DisplayLink driver binding protocol.
+  @param  Controller             The controller to release.
+  @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
+  @param  ChildHandleBuffer      The array of child handle.
+
+  @retval EFI_SUCCESS            The device was stopped.
+  @retval EFI_UNSUPPORTED        Simple Pointer Protocol is not installed on Controller.
+  @retval Others                 Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDisplayLinkDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
+  IN  EFI_HANDLE                    Controller,
+  IN  UINTN                         NumberOfChildren,
+  IN  EFI_HANDLE                    *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                        Status;
+  USB_DISPLAYLINK_DEV               *UsbDisplayLinkDev;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL      *GraphicsOutputProtocol;
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiGraphicsOutputProtocolGuid,
+                  (VOID **) &GraphicsOutputProtocol,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
+
+  // Reset the video mode to clear the display. Don't drop out if there is a problem, just press on.
+  // Note that this will also clear the frame buffer, as the screen buffer will be re-allocated with AllocateZeroPool.
+  if ((GraphicsOutputProtocol->Mode != NULL) &&
+      (GraphicsOutputProtocol->Mode->Mode != GRAPHICS_OUTPUT_INVALID_MODE_NUMBER)) {
+    Status = DisplayLinkSetMode (GraphicsOutputProtocol, GraphicsOutputProtocol->Mode->Mode);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "Driver stop - Problem resetting video mode - %r.\n", Status));
+    }
+  }
+
+  // Reset the alt setting on the interface (to the DL3 alt setting)
+  Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, 0);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_WARN, "Error resetting USB interface alternate setting - %r.\n", Status));
+  }
+
+  Status = gBS->UninstallMultipleProtocolInterfaces (
+                  Controller,
+                  &gEfiGraphicsOutputProtocolGuid,
+                  &UsbDisplayLinkDev->GraphicsOutputProtocol,
+                  &gEfiEdidDiscoveredProtocolGuid,
+                  &UsbDisplayLinkDev->EdidDiscovered,
+                  &gEfiEdidActiveProtocolGuid,
+                  &UsbDisplayLinkDev->EdidActive,
+                  NULL);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_WARN, "Error uninstalling Graphics Output and EDID protocol interfaces - %r.\n", Status));
+    return Status;
+  }
+
+  gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiUsbIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller);
+
+  //
+  // Free all resources.
+  //
+  if (UsbDisplayLinkDev->ControllerNameTable != NULL) {
+    FreeUnicodeStringTable (UsbDisplayLinkDev->ControllerNameTable);
+  }
+
+  if (UsbDisplayLinkDev->Screen != NULL) {
+    FreePool (UsbDisplayLinkDev->Screen);
+    UsbDisplayLinkDev->Screen = NULL;
+  }
+
+  if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode) {
+    if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info) {
+      FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info);
+      UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info = NULL;
+    }
+    FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode);
+    UsbDisplayLinkDev->GraphicsOutputProtocol.Mode = NULL;
+  }
+
+  FreePool (UsbDisplayLinkDev);
+
+  return EFI_SUCCESS;
+
+}
+
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
new file mode 100644
index 000000000000..252293da39d4
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
@@ -0,0 +1,180 @@
+/**
+ * @file UsbTransfer.c
+ * @brief Wrapper of UEFI USB bulk and control transfer interface for USB DisplayLink driver.
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#include "UsbDisplayLink.h"
+
+/**
+ * Write the data to the DisplayLink device using the USBIO protocol.
+ * @param UsbDisplayLinkDev
+ * @param Buffer
+ * @param DataLen
+ * @param USBStatus
+ * @return
+  * EFI_SUCCESS   The bulk transfer has been successfully executed.
+  * EFI_INVALID_PARAMETER   If DeviceEndpoint is not valid.
+  * EFI_INVALID_PARAMETER   Data is NULL.
+  * EFI_INVALID_PARAMETER   DataLength is NULL.
+  * EFI_INVALID_PARAMETER   Status is NULL.
+  * EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  * EFI_TIMEOUT   The bulk transfer cannot be completed within Timeout timeframe.
+  * EFI_DEVICE_ERROR  The transfer failed other than timeout, and the transfer status is returned in Status.
+ */
+EFI_STATUS
+DlUsbBulkWrite (
+    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
+    IN CONST UINT8* Buffer,
+    IN UINTN DataLen,
+    OUT UINT32 *USBStatus
+    )
+{
+  EFI_STATUS Status;
+  Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
+    UsbDisplayLinkDev->UsbIo,
+    UsbDisplayLinkDev->BulkOutEndpointDescriptor.EndpointAddress,
+    (VOID*)Buffer,
+    &DataLen,
+    DISPLAYLINK_USB_BULK_TIMEOUT,
+    USBStatus);
+
+  return Status;
+}
+
+/**
+* Read data from the DisplayLink device using the USBIO protocol.
+* @param UsbDisplayLinkDev
+* @param Buffer
+* @param BufferLen
+* @return 0 if an error occurred or 0 bytes were read, otherwise the number of bytes read
+ */
+UINTN
+DlUsbBulkRead (
+    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
+    IN UINT8* Buffer,
+    IN UINTN BufferLen
+    )
+{
+  UINT32 Result;
+  UINTN ReadLen;
+  EFI_STATUS Status;
+
+  ReadLen = BufferLen;
+
+  Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
+    UsbDisplayLinkDev->UsbIo,
+    UsbDisplayLinkDev->BulkInEndpointDescriptor.EndpointAddress,
+    Buffer,
+    &ReadLen,
+    DISPLAYLINK_USB_BULK_TIMEOUT,
+    &Result);
+
+  if (EFI_ERROR (Status)) {
+    return 0;
+  }
+
+  return ReadLen;
+}
+
+
+/**
+Send a control message (e.g set video mode) message to the DisplayLink device.
+
+@param  Device                   USB device handle.
+@param  request                  Request type, e.g. SET_VIDEO_MODE
+@param  value
+@param  controlMsg               Pointer to the message to send.
+@param  controlMsgLen            Length of the message.
+
+@retval EFI_SUCCESS            Successfully sent message.
+
+**/
+EFI_STATUS
+DlUsbSendControlWriteMessage (
+  IN USB_DISPLAYLINK_DEV *Device,
+  IN UINT8 Request,
+  IN UINT16 Value,
+  IN CONST VOID *ControlMsg,
+  IN UINT16 ControlMsgLen
+  )
+{
+  EFI_STATUS             Status;
+  UINT32                 UsbStatus;
+  EFI_USB_DEVICE_REQUEST UsbRequest;
+
+  ZeroMem (&Request, sizeof (Request));
+  UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE;
+  UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
+  UsbRequest.Request = Request;
+  UsbRequest.Value = Value;
+  UsbRequest.Length = ControlMsgLen;
+
+  Status = Device->UsbIo->UsbControlTransfer (
+    Device->UsbIo,
+    &UsbRequest,
+    EfiUsbDataOut,
+    DISPLAYLINK_USB_CTRL_TIMEOUT,
+    (VOID *)ControlMsg,
+    ControlMsgLen,
+    &UsbStatus);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "USB write control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
+    Status = EFI_DEVICE_ERROR;
+  }
+  return Status;
+}
+
+
+/**
+Request data from the DisplayLink device (e.g. the monitor EDID)
+
+@param  Device                   USB device handle.
+@param  request                  Request type, e.g. GET_OUTPUT_EDID
+@param  value
+@param  controlMsg               Pointer to the message to send.
+@param  controlMsgLen            Length of the message.
+
+@retval EFI_SUCCESS            Successfully sent message.
+
+**/
+EFI_STATUS
+DlUsbSendControlReadMessage (
+  IN USB_DISPLAYLINK_DEV *Device,
+  IN UINT8 Request,
+  IN UINT16 Value,
+  OUT VOID *ControlMsg,
+  IN UINT16 ControlMsgLen
+  )
+{
+  EFI_STATUS             Status;
+  UINT32                 UsbStatus;
+  EFI_USB_DEVICE_REQUEST UsbRequest;
+
+  ZeroMem (&UsbRequest, sizeof (UsbRequest));
+  UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE | USB_ENDPOINT_DIR_IN;
+  UsbRequest.Request = Request;
+  UsbRequest.Value = Value;
+  UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
+  UsbRequest.Length = ControlMsgLen;
+
+  Status = Device->UsbIo->UsbControlTransfer (
+    Device->UsbIo,
+    &UsbRequest,
+    EfiUsbDataIn,
+    DISPLAYLINK_USB_CTRL_TIMEOUT,
+    (VOID *)ControlMsg,
+    ControlMsgLen,
+    &UsbStatus);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "USB read control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
+    Status = EFI_DEVICE_ERROR;
+  }
+  return Status;
+}
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
new file mode 100644
index 000000000000..6218c093147c
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
@@ -0,0 +1,254 @@
+/**
+ * @file VideoModes.c
+ * @brief Pre-calculated video timings sent to the DisplayLink device when a video mode is selected
+ *
+ * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+**/
+
+#include "UsbDisplayLink.h"
+
+
+// Supported video modes - must be in order of pixel count (i.e. hres x vres)
+
+STATIC CONST struct VideoMode ModeData[] = {
+  {
+     // 640 x 480 @ 60Hz
+    .Reserved2 = 2,
+    .PixelClock = 2517,
+    .HActive = 640,
+    .HBlanking = 160,
+    .HSyncOffset = 16,
+    .HSyncWidth = 96,
+    .VActive = 480,
+    .VBlanking = 45,
+    .VSyncOffset = 10,
+    .VSyncWidth = 2,
+    .Flags = 0x00000300,
+    .Accumulate = 1,
+    .Reserved3 = 0,
+    .Reserved4 = 0,
+    .Reserved5 = 0x00000000,
+    .Vic = 0,
+    .ActiveFormat = 0,
+  },
+  {
+    // 800 x 600 @ 60Hz
+    .Reserved2 = 2,
+    .PixelClock = 4000,
+    .HActive = 800,
+    .HBlanking = 256,
+    .HSyncOffset = 40,
+    .HSyncWidth = 128,
+    .VActive = 600,
+    .VBlanking = 28,
+    .VSyncOffset = 1,
+    .VSyncWidth = 3,
+    .Flags = 0x00000000,
+    .Accumulate = 1,
+    .Reserved3 = 0,
+    .Reserved4 = 0,
+    .Reserved5 = 0x00000000,
+    .Vic = 0,
+    .ActiveFormat = 0,
+  },
+  {
+    // 1024x768 @ 60Hz
+    .Reserved1 = 0,
+    .Reserved2 = 2,
+    .PixelClock = 6500,
+    .HActive = 1024,
+    .HBlanking = 320,
+    .HSyncOffset = 24,
+    .HSyncWidth = 136,
+    .VActive = 768,
+    .VBlanking = 38,
+    .VSyncOffset = 3,
+    .VSyncWidth = 6,
+    .Flags = 0x00000300,
+    .Accumulate = 1,
+    .Reserved3 = 0,
+    .Reserved4 = 0,
+    .Reserved5 = 0x00000000,
+    .Vic = 0,
+    .ActiveFormat = 0,
+  },
+  {
+    // 1360x768 @ 60Hz
+    .Reserved1 = 0,
+    .Reserved2 = 2,
+    .PixelClock = 8550,
+    .HActive = 1360,
+    .HBlanking = 432,
+    .HSyncOffset = 64,
+    .HSyncWidth = 112,
+    .VActive = 768,
+    .VBlanking = 27,
+    .VSyncOffset = 3,
+    .VSyncWidth = 6,
+    .Flags = 0x00000000,
+    .Accumulate = 1,
+    .Reserved3 = 0,
+    .Reserved4 = 0,
+    .Reserved5 = 0x00000000,
+    .Vic = 0,
+    .ActiveFormat = 0,
+  },
+  {
+    // 1280x960 @ 60Hz
+    .Reserved1 = 0,
+    .Reserved2 = 2,
+    .PixelClock = 10800,
+    .HActive = 1280,
+    .HBlanking = 520,
+    .HSyncOffset = 96,
+    .HSyncWidth = 112,
+    .VActive = 960,
+    .VBlanking = 40,
+    .VSyncOffset = 1,
+    .VSyncWidth = 3,
+    .Flags = 0x00000000,
+    .Accumulate = 1,
+    .Reserved3 = 0,
+    .Reserved4 = 0,
+    .Reserved5 = 0x00000000,
+    .Vic = 0,
+    .ActiveFormat = 0,
+  },
+  {
+    // 1280x1024 @ 60Hz
+    .Reserved1 = 0,
+    .Reserved2 = 2,
+    .PixelClock = 10800,
+    .HActive = 1280,
+    .HBlanking = 408,
+    .HSyncOffset = 48,
+    .HSyncWidth = 112,
+    .VActive = 1024,
+    .VBlanking = 42,
+    .VSyncOffset = 1,
+    .VSyncWidth = 3,
+    .Flags = 0x00000000,
+    .Accumulate = 1,
+    .Reserved3 = 0,
+    .Reserved4 = 0,
+    .Reserved5 = 0x00000000,
+    .Vic = 0,
+    .ActiveFormat = 0,
+  },
+  {
+    // 1600x900 @ 60Hz
+    .Reserved2 = 2,
+    .PixelClock = 11825,
+    .HActive = 1600,
+    .HBlanking = 512,
+    .HSyncOffset = 88,
+    .HSyncWidth = 168,
+    .VActive = 900,
+    .VBlanking = 34,
+    .VSyncOffset = 3,
+    .VSyncWidth = 5,
+    .Flags = 0x00000500,
+    .Accumulate = 1,
+    .Reserved3 = 0,
+    .Reserved4 = 0,
+    .Reserved5 = 0x00000000,
+    .Vic = 0,
+    .ActiveFormat = 0,
+  },
+  {
+    // 1400x1050 @ 60Hz
+    .Reserved1 = 0,
+    .Reserved2 = 2,
+    .PixelClock = 12175,
+    .HActive = 1400,
+    .HBlanking = 464,
+    .HSyncOffset = 88,
+    .HSyncWidth = 144,
+    .VActive = 1050,
+    .VBlanking = 39,
+    .VSyncOffset = 3,
+    .VSyncWidth = 4,
+    .Flags = 0x00000100,
+    .Accumulate = 1,
+    .Reserved3 = 0,
+    .Reserved4 = 0,
+    .Reserved5 = 0x00000000,
+    .Vic = 0,
+    .ActiveFormat = 0,
+  },
+  {
+    // 1600x1200 @ 60Hz
+    .Reserved1 = 0,
+    .Reserved2 = 2,
+    .PixelClock = 16200,
+    .HActive = 1600,
+    .HBlanking = 560,
+    .HSyncOffset = 64,
+    .HSyncWidth = 192,
+    .VActive = 1200,
+    .VBlanking = 50,
+    .VSyncOffset = 1,
+    .VSyncWidth = 3,
+    .Flags = 0x00000000,
+    .Accumulate = 1,
+    .Reserved3 = 0,
+    .Reserved4 = 0,
+    .Reserved5 = 0x00000000,
+    .Vic = 0,
+    .ActiveFormat = 0,
+  },
+  {
+    // 1920 x 1080
+    .Reserved2 = 2,
+    .PixelClock = 14850,
+    .HActive = 1920,
+    .HBlanking = 280,
+    .HSyncOffset = 88,
+    .HSyncWidth = 44,
+    .VActive = 1080,
+    .VBlanking = 45,
+    .VSyncOffset = 4,
+    .VSyncWidth = 5,
+    .Flags = 0x00000000,
+    .Accumulate = 1,
+    .Reserved3 = 0,
+    .Reserved4 = 0,
+    .Reserved5 = 0x00000000,
+    .Vic = 0,
+    .ActiveFormat = 0,
+  }
+};
+
+STATIC CONST UINT32 NumSupportedVideoModes = (sizeof (ModeData) / sizeof (struct VideoMode));
+
+/**
+Find the number of pre-calculated video modes that we support.
+
+@retval Number of modes.
+
+**/
+UINT32 DlVideoModeGetNumSupportedVideoModes ()
+{
+  return NumSupportedVideoModes;
+}
+
+/**
+Get one of the pre-calculated video modes
+
+@param  index      The video mode that we want.
+
+@retval NULL       The index was out of range.
+
+**/
+CONST struct VideoMode *DlVideoModeGetSupportedVideoMode (
+    UINT32 Index
+    )
+{
+  if (Index >= NumSupportedVideoModes) {
+    return NULL;
+  }
+  return &ModeData[Index];
+}
diff --git a/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
new file mode 100644
index 000000000000..40061f1eb46d
--- /dev/null
+++ b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
@@ -0,0 +1,77 @@
+# DISPLAYLINK DRIVERS
+This package contains a GOP driver for Universal USB-connected docks containing the
+DisplayLink DL-6xxx chip or newer.
+
+[DisplayLink Website](http://www.displaylink.com)
+
+[Products](https://www.displaylink.com/products/universal-docking-stations)
+
+# INDEX
+
+* [Resolutions Supported](#resolutions-supported)
+* [Frame rates](#frame-rates)
+* [Multiple monitor outputs](#multiple-monitor-outputs)
+* [Multiple DisplayLink devices](#multiple-displaylink-devices)
+* [Behaviour with no monitor connected](#behaviour-with-no-monitor-connected)
+
+# Resolutions supported
+
+The driver supports the following resolutions:
+
+640 x 480 @ 60Hz
+
+800 x 600 @ 60Hz
+
+1024x768 @ 60Hz
+
+1360x768 @ 60Hz
+
+1280x960 @ 60Hz
+
+1280x1024 @ 60Hz
+
+1600x900 @ 60Hz
+
+1400x1050 @ 60Hz
+
+1600x1200 @ 60Hz
+
+1920x1080 @ 60Hz
+
+
+Note that the list of resolutions advertised by the driver may be smaller than
+this if a connected monitor does not support a particular resolution. The driver
+interrogates connected monitors to see which modes can be supported.It is the
+responsibility of the BIOS to select the video mode from this list which most
+closely matches its requirements. In some cases this may lead to the BIOS
+scaling its display.
+
+# Frame rates
+
+The driver is limited to a maximum of ten frames per second. Some slower systems
+at higher screen resolutions may perform at a lower rate than this.
+
+# Multiple monitor outputs
+
+If multiple monitors are connected to the DisplayLinkdevice, the display will be
+duplicated (cloned) across all outputs at the same resolution. The resolution
+used will be limited by the capability of the monitor with the
+lowest specification.
+
+# Multiple DisplayLink devices
+
+The driver will support the connection of multiple DisplayLink devices. The
+exact behaviourof the system with multiple devices connected is defined by the
+rest of the BIOS; usually, the BIOS causes the displays to be duplicated
+(cloned) across all devices. Note that the system performance and frame rate
+will be affected by the number of DisplayLink devices connected.
+
+# Behaviour with no monitor connected
+
+The driver uses the EDID (Extended Display Identification Data) protocol to
+detect the list of resolutions that a monitor will support.In some monitors this
+may take some time, and occasionally no EDID information will be returned at
+all. In this case the driver will not be able to detect that there is a monitor
+connected. To improve the user experience in these cases, the driver will behave
+as if there is a monitor connected, and will fall back to presenting the full
+range of supported resolutions to the BIOS.
diff --git a/Maintainers.txt b/Maintainers.txt
index 876ae5612ad8..4093375acffe 100644
--- a/Maintainers.txt
+++ b/Maintainers.txt
@@ -47,6 +47,11 @@ Drivers/OptionRomPkg
 W: https://github.com/tianocore/tianocore.github.io/wiki/OptionRomPkg
 M: Ray Ni <ray.ni@intel.com>
 
+Drivers/DisplayLink
+M: Leif Lindholm <leif.lindholm@linaro.org>
+M: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+R: Andy Hayes <andy.hayes@displaylink.com>
+
 Platform
 M: Ard Biesheuvel <ard.biesheuvel@linaro.org>
 M: Leif Lindholm <leif.lindholm@linaro.org>
-- 
2.17.1

Re: [edk2-devel] [PATCH v1 0/1] Added GOP driver for DisplayLink-based Universal USB Docks to edk2-platforms
Posted by Michael D Kinney 4 years, 7 months ago
Hi Andy,

Thanks for the contribution.  Is this patch for the edk2-platform repo?  The email subject can help clarify the intended repo.

Also, we prefer the patches to be provided inline instead of an attachment.  You can use the
'git send-email' feature to do this.  Here are a couple links to useful wikis.

https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Development-Process
https://github.com/tianocore/tianocore.github.io/wiki/Laszlo's-unkempt-git-guide-for-edk2-contributors-and-maintainers

I also noticed looking at the patch file that there are some inconsistencies with the
EDK II C Coding Standards.  Most are around function headers and indents.  Here is a link
to the latest version:

https://www.gitbook.com/download/pdf/book/edk2-docs/edk-ii-c-coding-standards-specification

I see a few #if 0 and commented out lines of code and TODO comments.  Can you please clean these up
and if needed add Tianocore Bugzillas for future enhancements/work items for this driver.

https://bugzilla.tianocore.org/

I also noticed that you are using named fields to initialize C structures:

STATIC CONST struct VideoMode ModeData[] = {
+  {
+     // 640 x 480 @ 60Hz
+    .Reserved2 = 2,
+    .PixelClock = 2517,
+    .HActive = 640,
+    .HBlanking = 160,
+    .HSyncOffset = 16,
+    .HSyncWidth = 96,

I do like this style because it has better self documentation of the field being
initialized to a value.  However, I do not see this style in the rest of the EDK II
sources, so I am concerned that we may have required compilers for the EDK II
that may not support this syntax.

If we find all the supported compilers do support this syntax, this would be
a great addition to the EDK II C Coding Standards.

I am curious how this driver interacts with the ConSplitter when displays
are hot added and hot removed.  I see a reference to a feature that appears
to sync the GOP content between frame buffers when a display is hot added.
I would be better if the common code in the ConSplitter handled these types
of operations instead of putting that code in individual GOP drivers. I have
added Ray to this thread who may have ideas on how to handle these hot
add events.

Thanks,

Mike

From: Andy Hayes [mailto:andy.hayes@displaylink.com]
Sent: Wednesday, August 14, 2019 7:44 AM
To: devel@edk2.groups.io
Cc: Leif Lindholm <leif.lindholm@linaro.org>; Kinney, Michael D <michael.d.kinney@intel.com>
Subject: [PATCH v1 0/1] Added GOP driver for DisplayLink-based Universal USB Docks to edk2-platforms

From 4a42eb997aeb3699217b40bf3bc47dec56458847 Mon Sep 17 00:00:00 2001
From: "Andy Hayes" < andy.hayes@displaylink.com<mailto:andy.hayes@displaylink.com> >
Date: Wed, 14 Aug 2019 15:30:20 +0100
Subject: [PATCH v1 0/1] Added GOP graphics driver for DisplayLink-based Universal USB Docks to edk2-platforms

andy.hayes@displaylink.com<mailto:andy.hayes@displaylink.com> (1):
  Added GOP driver for USB Docks which use DisplayLink chips.

.../DisplayLinkPkg/DisplayLinkPkg.dsc         |   61 +
.../DisplayLinkGop/DisplayLinkGopDxe.inf      |   63 +
.../DisplayLinkPkg/DisplayLinkGop/Edid.h      |  129 ++
.../DisplayLinkGop/UsbDescriptors.h           |  109 ++
.../DisplayLinkGop/UsbDisplayLink.h           |  284 +++++
.../DisplayLinkGop/CapabilityDescriptor.c     |  137 ++
.../DisplayLinkGop/ComponentName.c            |  235 ++++
.../DisplayLinkPkg/DisplayLinkGop/Edid.c      |  598 +++++++++
.../DisplayLinkPkg/DisplayLinkGop/Gop.c       |  587 +++++++++
.../DisplayLinkGop/UsbDescriptors.c           |  144 +++
.../DisplayLinkGop/UsbDisplayLink.c           | 1109 +++++++++++++++++
.../DisplayLinkGop/UsbTransfer.c              |  180 +++
.../DisplayLinkGop/VideoModes.c               |  254 ++++
Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md  |   77 ++
Maintainers.txt                               |    5 +
15 files changed, 3972 insertions(+)
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md

--
2.17.1

-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#45616): https://edk2.groups.io/g/devel/message/45616
Mute This Topic: https://groups.io/mt/32864415/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

Re: [edk2-devel] [PATCH v1 0/1] Added GOP driver for DisplayLink-based Universal USB Docks to edk2-platforms
Posted by Leif Lindholm 4 years, 7 months ago
Hi Andy,

Many thanks for this submission.

I am finding a few issues when building with gcc/clang (I expect you
use Visual Studio).

The RELEASE target barfs with
.../edk2-platforms/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c:363:1:
error: unused function 'CalculateRefreshRate'
since the function is only called from a DEBUG statement.
Could be resolved by putting the function inside #ifndef MDEPKG_NDEBUG

Clang triggers an error on the
USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL macro which seems to
go away if the USB_DISPLAYLINK_DEV_SIGNATURE macro is moved below the
USB_DISPLAYLINK_DEV definition. (I haven't bothered to figure out why
this helps.)

The NOOPT build fails for IA32/X64 on clang with
.../edk2-platforms/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c:35:
undefined reference to `memset'
You could get rid of this by doing the assignment separate from the
definition. (Indeed, I believe this is one of the reasons for the
rule.)

On X64/clang, the build fails with
.../edk2-platforms/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c:410:3:
error: '__builtin_ms_va_start' used in System V ABI function
Adding EFIAPI to the definition/declaration of DlGopPrintTextToScreen
makes this one go away.

Best Regards,

Leif

On Wed, Aug 14, 2019 at 02:43:43PM +0000, Andy Hayes wrote:
> From 4a42eb997aeb3699217b40bf3bc47dec56458847 Mon Sep 17 00:00:00 2001
> From: "Andy Hayes" < andy.hayes@displaylink.com >
> Date: Wed, 14 Aug 2019 15:30:20 +0100
> Subject: [PATCH v1 0/1] Added GOP graphics driver for DisplayLink-based Universal USB Docks to edk2-platforms
> 
> andy.hayes@displaylink.com (1):
>   Added GOP driver for USB Docks which use DisplayLink chips.
> 
> .../DisplayLinkPkg/DisplayLinkPkg.dsc         |   61 +
> .../DisplayLinkGop/DisplayLinkGopDxe.inf      |   63 +
> .../DisplayLinkPkg/DisplayLinkGop/Edid.h      |  129 ++
> .../DisplayLinkGop/UsbDescriptors.h           |  109 ++
> .../DisplayLinkGop/UsbDisplayLink.h           |  284 +++++
> .../DisplayLinkGop/CapabilityDescriptor.c     |  137 ++
> .../DisplayLinkGop/ComponentName.c            |  235 ++++
> .../DisplayLinkPkg/DisplayLinkGop/Edid.c      |  598 +++++++++
> .../DisplayLinkPkg/DisplayLinkGop/Gop.c       |  587 +++++++++
> .../DisplayLinkGop/UsbDescriptors.c           |  144 +++
> .../DisplayLinkGop/UsbDisplayLink.c           | 1109 +++++++++++++++++
> .../DisplayLinkGop/UsbTransfer.c              |  180 +++
> .../DisplayLinkGop/VideoModes.c               |  254 ++++
> Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md  |   77 ++
> Maintainers.txt                               |    5 +
> 15 files changed, 3972 insertions(+)
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> 
> --
> 2.17.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#45624): https://edk2.groups.io/g/devel/message/45624
Mute This Topic: https://groups.io/mt/32864415/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

Re: [edk2-devel] [PATCH v1 0/1] Added GOP driver for DisplayLink-based Universal USB Docks to edk2-platforms
Posted by Leif Lindholm 4 years, 7 months ago
Hi Andy,

A follow-up - a few more things need changing:

UsbDisplayLink.h (well, any .h file) should only contain the headers
it itself requires.
Moreover, the inclusion of wchar.h must disappear completely.
Instead, use CHAR16 * in the two locations in UsbDisplayLink.c.

Removing wchar.h will then trip you up in Edid.h, at
#define EDID_HEADER_SIZE                          ((size_t)8)
Please change the size_t to UINTN.

Finally, you need to (and now can after the above changes) get rid of
#undef _DEBUG

#undef NULL
#undef _ASSERT
in UsbDisplayLink.h.

With these additional changes, the driver builds successfully across
GCC 8.3 and CLANG 7.0 for AARCH64/ARM/IA32/X64.

Best Regards,

Leif

On Wed, Aug 14, 2019 at 06:03:51PM +0100, Leif Lindholm wrote:
> Hi Andy,
> 
> Many thanks for this submission.
> 
> I am finding a few issues when building with gcc/clang (I expect you
> use Visual Studio).
> 
> The RELEASE target barfs with
> .../edk2-platforms/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c:363:1:
> error: unused function 'CalculateRefreshRate'
> since the function is only called from a DEBUG statement.
> Could be resolved by putting the function inside #ifndef MDEPKG_NDEBUG
> 
> Clang triggers an error on the
> USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL macro which seems to
> go away if the USB_DISPLAYLINK_DEV_SIGNATURE macro is moved below the
> USB_DISPLAYLINK_DEV definition. (I haven't bothered to figure out why
> this helps.)
> 
> The NOOPT build fails for IA32/X64 on clang with
> .../edk2-platforms/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c:35:
> undefined reference to `memset'
> You could get rid of this by doing the assignment separate from the
> definition. (Indeed, I believe this is one of the reasons for the
> rule.)
> 
> On X64/clang, the build fails with
> .../edk2-platforms/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c:410:3:
> error: '__builtin_ms_va_start' used in System V ABI function
> Adding EFIAPI to the definition/declaration of DlGopPrintTextToScreen
> makes this one go away.
> 
> Best Regards,
> 
> Leif
> 
> On Wed, Aug 14, 2019 at 02:43:43PM +0000, Andy Hayes wrote:
> > From 4a42eb997aeb3699217b40bf3bc47dec56458847 Mon Sep 17 00:00:00 2001
> > From: "Andy Hayes" < andy.hayes@displaylink.com >
> > Date: Wed, 14 Aug 2019 15:30:20 +0100
> > Subject: [PATCH v1 0/1] Added GOP graphics driver for DisplayLink-based Universal USB Docks to edk2-platforms
> > 
> > andy.hayes@displaylink.com (1):
> >   Added GOP driver for USB Docks which use DisplayLink chips.
> > 
> > .../DisplayLinkPkg/DisplayLinkPkg.dsc         |   61 +
> > .../DisplayLinkGop/DisplayLinkGopDxe.inf      |   63 +
> > .../DisplayLinkPkg/DisplayLinkGop/Edid.h      |  129 ++
> > .../DisplayLinkGop/UsbDescriptors.h           |  109 ++
> > .../DisplayLinkGop/UsbDisplayLink.h           |  284 +++++
> > .../DisplayLinkGop/CapabilityDescriptor.c     |  137 ++
> > .../DisplayLinkGop/ComponentName.c            |  235 ++++
> > .../DisplayLinkPkg/DisplayLinkGop/Edid.c      |  598 +++++++++
> > .../DisplayLinkPkg/DisplayLinkGop/Gop.c       |  587 +++++++++
> > .../DisplayLinkGop/UsbDescriptors.c           |  144 +++
> > .../DisplayLinkGop/UsbDisplayLink.c           | 1109 +++++++++++++++++
> > .../DisplayLinkGop/UsbTransfer.c              |  180 +++
> > .../DisplayLinkGop/VideoModes.c               |  254 ++++
> > Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md  |   77 ++
> > Maintainers.txt                               |    5 +
> > 15 files changed, 3972 insertions(+)
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> > create mode 100644 Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> > 
> > --
> > 2.17.1
> 
> 

-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#45626): https://edk2.groups.io/g/devel/message/45626
Mute This Topic: https://groups.io/mt/32864415/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

Re: [edk2-devel] [PATCH v1 0/1] Added GOP driver for DisplayLink-based Universal USB Docks to edk2-platforms
Posted by sebastian.olney@synaptics.com 3 years, 2 months ago
Reviewed-by: Seb Olney <sebastian.olney@synaptics.com>


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#70160): https://edk2.groups.io/g/devel/message/70160
Mute This Topic: https://groups.io/mt/32864415/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-