public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Chris Co <Christopher.Co@microsoft.com>
To: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>,
	Leif Lindholm <leif.lindholm@linaro.org>,
	Michael D Kinney <michael.d.kinney@intel.com>
Subject: [PATCH edk2-platforms 12/13] Silicon/NXP: Add i.MX6 GOP driver
Date: Fri, 20 Jul 2018 06:34:02 +0000	[thread overview]
Message-ID: <20180720063328.26856-13-christopher.co@microsoft.com> (raw)
In-Reply-To: <20180720063328.26856-1-christopher.co@microsoft.com>

This adds GOP display support for NXP i.MX6 SoCs.  It has support for
HDMI, LVDS, IPU, and parses EDID using I2C.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
---
 Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.c             | 327 +++++++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.h             | 276 +++++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.c               |  58 ++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.h               |  27 +
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.c           | 442 ++++++++++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.h           | 171 ++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.c | 388 +++++++++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.h | 312 ++++++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.c  | 444 ++++++++++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.h  | 182 ++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.c              |  82 +++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.h              |  31 +
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.c              | 608 ++++++++++++++++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.h              | 537 +++++++++++++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.c             |  83 +++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.h             |  31 +
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Ipu.h               | 236 ++++++++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.c              |  81 +++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.h              |  72 +++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.c              |  38 ++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.h              |  74 +++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/iMX6GOP.inf         |  71 +++
 Silicon/NXP/iMX6Pkg/Drivers/GOP/iMXVideoDxe.c       | 488 ++++++++++++++++
 23 files changed, 5059 insertions(+)

diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.c
new file mode 100644
index 000000000000..cf05a13d95e5
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.c
@@ -0,0 +1,327 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "Osal.h"
+
+#include "Display.h"
+#include "CPMem.h"
+#include "Ipu.h"
+
+CPMEM_PARAM* CpMemParamBasePtr = (CPMEM_PARAM*)(IPU1_BASE + CSP_IPUV3_CPMEM_REGS_OFFSET);
+
+VOID DumpCPMEMParamPack (CPMEM_PARAM* ParamPtr)
+{
+    OS_INFO("--WORD0--\n");
+    OS_INFO("XVVirtualCoordinate 0x%08x\n", ParamPtr->Word0Pack.XVVirtualCoordinate);
+    OS_INFO("YVVirtualCoordinate 0x%08x\n", ParamPtr->Word0Pack.YVVirtualCoordinate);
+    OS_INFO("XBinnerBlockCoordinate 0x%08x\n", ParamPtr->Word0Pack.XBinnerBlockCoordinate);
+    OS_INFO("YBinnerBlockCoordinate 0x%08x\n", ParamPtr->Word0Pack.YBinnerBlockCoordinate);
+    OS_INFO("NewSubBlock 0x%08x\n", ParamPtr->Word0Pack.NewSubBlock);
+    OS_INFO("CurrentField 0x%08x\n", ParamPtr->Word0Pack.CurrentField);
+    OS_INFO("ScrollXCounter 0x%08x\n", ParamPtr->Word0Pack.ScrollXCounter);
+    OS_INFO("ScrollYCounter 0x%08x\n", ParamPtr->Word0Pack.ScrollYCounter);
+    OS_INFO("NumberOfScroll 0x%08x\n", ParamPtr->Word0Pack.NumberOfScroll);
+    OS_INFO("ScrollDeltaX 0x%08x\n", ParamPtr->Word0Pack.ScrollDeltaX);
+    OS_INFO("ScrollMax 0x%08x\n", ParamPtr->Word0Pack.ScrollMax);
+    OS_INFO("ScrollingConfiguration 0x%08x\n", ParamPtr->Word0Pack.ScrollingConfiguration);
+    OS_INFO("ScrollingEnable 0x%08x\n", ParamPtr->Word0Pack.ScrollingEnable);
+    OS_INFO("ScrollDeltaY 0x%08x\n", ParamPtr->Word0Pack.ScrollDeltaY);
+    OS_INFO("ScrollHorizontalDirection 0x%08x\n", ParamPtr->Word0Pack.ScrollHorizontalDirection);
+    OS_INFO("ScrollVerticalDirection 0x%08x\n", ParamPtr->Word0Pack.ScrollVerticalDirection);
+    OS_INFO("BitsPerPixel 0x%08x\n", ParamPtr->Word0Pack.BitsPerPixel);
+    OS_INFO("DecodeAddressSelect 0x%08x\n", ParamPtr->Word0Pack.DecodeAddressSelect);
+    OS_INFO("AccessDimension 0x%08x\n", ParamPtr->Word0Pack.AccessDimension);
+    OS_INFO("ScanOrder 0x%08x\n", ParamPtr->Word0Pack.ScanOrder);
+    OS_INFO("BandMode 0x%08x\n", ParamPtr->Word0Pack.BandMode);
+    OS_INFO("BlockMode 0x%08x\n", ParamPtr->Word0Pack.BlockMode);
+    OS_INFO("Rotation 0x%08x\n", ParamPtr->Word0Pack.Rotation);
+    OS_INFO("HorizontalFlip 0x%08x\n", ParamPtr->Word0Pack.HorizontalFlip);
+    OS_INFO("VerticalFlip 0x%08x\n", ParamPtr->Word0Pack.VerticalFlip);
+    OS_INFO("ThresholdEnable 0x%08x\n", ParamPtr->Word0Pack.ThresholdEnable);
+    OS_INFO("ConditionalAccessPolarity 0x%08x\n", ParamPtr->Word0Pack.ConditionalAccessPolarity);
+    OS_INFO("ConditionalAccessEnable 0x%08x\n", ParamPtr->Word0Pack.ConditionalAccessEnable);
+    OS_INFO("FrameWidth 0x%08x\n", ParamPtr->Word0Pack.FrameWidth);
+    OS_INFO("FrameHeight 0x%08x\n", ParamPtr->Word0Pack.FrameHeight);
+    OS_INFO("EndOfLineInterrupt 0x%08x\n", ParamPtr->Word0Pack.EndOfLineInterrupt);
+
+    OS_INFO("--WORD1--\n");
+    OS_INFO("ExtMemBuffer0Address 0x%08x\n", ParamPtr->Word1Pack.ExtMemBuffer0Address);
+    OS_INFO("ExtMemBuffer1Address 0x%08x\n", ParamPtr->Word1Pack.ExtMemBuffer1Address);
+    OS_INFO("InterlaceOffset 0x%08x\n", ParamPtr->Word1Pack.InterlaceOffset);
+    OS_INFO("NumberOfPixelsInWholeBurstAccess 0x%08x\n", ParamPtr->Word1Pack.NumberOfPixelsInWholeBurstAccess);
+    OS_INFO("PixelFormatSelect 0x%08x\n", ParamPtr->Word1Pack.PixelFormatSelect);
+    OS_INFO("AlphaUsed 0x%08x\n", ParamPtr->Word1Pack.AlphaUsed);
+    OS_INFO("AlphaChannelMapping 0x%08x\n", ParamPtr->Word1Pack.AlphaChannelMapping);
+    OS_INFO("AxiId 0x%08x\n", ParamPtr->Word1Pack.AxiId);
+    OS_INFO("Threshold 0x%08x\n", ParamPtr->Word1Pack.Threshold);
+    OS_INFO("StrideLine 0x%08x\n", ParamPtr->Word1Pack.StrideLine);
+    OS_INFO("Width0 0x%08x\n", ParamPtr->Word1Pack.Width0);
+    OS_INFO("Width1 0x%08x\n", ParamPtr->Word1Pack.Width1);
+    OS_INFO("Width2 0x%08x\n", ParamPtr->Word1Pack.Width2);
+    OS_INFO("Width3 0x%08x\n", ParamPtr->Word1Pack.Width3);
+    OS_INFO("Offset0 0x%08x\n", ParamPtr->Word1Pack.Offset0);
+    OS_INFO("Offset1 0x%08x\n", ParamPtr->Word1Pack.Offset1);
+    OS_INFO("Offset2 0x%08x\n", ParamPtr->Word1Pack.Offset2);
+    OS_INFO("Offset3 0x%08x\n", ParamPtr->Word1Pack.Offset3);
+    OS_INFO("SelectSXSYSet 0x%08x\n", ParamPtr->Word1Pack.SelectSXSYSet);
+    OS_INFO("ConditionalReadEnable 0x%08x\n", ParamPtr->Word1Pack.ConditionalReadEnable);
+}
+
+VOID DumpBasicCPMEMReg (
+    CPMEM_PARAM* CpmemChannel)
+{
+    OS_INFO("---------- CPMEM Register Dump ----------\n");
+    OS_INFO("CPMEM\n");
+    OS_INFO("IDMAC_CHANNEL_DP_PRIMARY_FLOW_MAIN_PLANE\n");
+    DumpCPMEMParamPack(CpmemChannel);
+    OS_INFO("------------------------------------\n");
+}
+
+//
+// Enable IDMAC lock setting, which optimises memory accesses and reduces
+// power consumption
+//
+VOID SetIdmacLockEn(
+    DISPLAY_INTERFACE_CONTEXT* DIContextPtr,
+    UINT32 Channel,
+    UINT32 Setting
+    )
+{
+    static const UINT8 channelMap[] = {
+        5, 0,
+        11, 2,
+        12, 4,
+        14, 6,
+        15, 8,
+        20, 10,
+        21, 12,
+        22, 14,
+        23, 16,
+        27, 18,
+        28, 20,
+        45, 0,
+        46, 2,
+        47, 4,
+        48, 6,
+        49, 8,
+        50, 10,
+    };
+
+    UINTN lockReg;
+    UINT32 value;
+    int shift = -1;
+    int i;
+
+    for (i = 0; i < (sizeof(channelMap) / sizeof(channelMap[0])); i += 2) {
+        if (channelMap[i] == Channel) {
+            shift = channelMap[i + 1];
+            break;
+        }
+    }
+
+    if (shift == -1) {
+        OS_WARNING("Channel %d does not have lock bits", Channel);
+        return;
+    }
+
+    if (Channel < 29) {
+        lockReg = (UINTN)DIContextPtr->IpuMmioBasePtr + IPU_IDMAC_LOCK_EN_1;
+    } else {
+        lockReg = (UINTN)DIContextPtr->IpuMmioBasePtr + IPU_IDMAC_LOCK_EN_2;
+    }
+
+    value = OS_READ32(lockReg);
+    value &= ~(0x3 << shift);
+    value |= (Setting & 0x3) << shift;
+    OS_WRITE32(lockReg, value);
+}
+
+OS_STATUS ConfigureCPMEMFrameBuffer (
+    DISPLAY_INTERFACE_CONTEXT* DIContextPtr,
+    UINT32 Channel,
+    SURFACE_INFO* FrameBufferPtr)
+{
+    OS_STATUS status;
+    CPMEM_WORD0_PACKED_REG cpmemWord0PackedReg;
+    CPMEM_WORD1_PACKED_REG cpmemWord1PackedReg;
+    CPMEM_DEC_SEL decodeAddressSelect = CPMEM_DEC_SEL_0_15; // Only applicable for 4 bpp
+    UINT32 pixelBurst = 1;
+    CPMEM_PFS_PACKED pixelFormatSelector;
+    UINT32 width0, width1, width2, width3;
+    UINT32 offset0, offset1, offset2, offset3;
+    UINT32 bytesPerPixel;
+    CPMEM_PARAM* cpmemChannel = DIContextPtr->CpMemParamBasePtr;
+
+    OS_ZERO_MEM(&cpmemWord0PackedReg, sizeof(cpmemWord0PackedReg));
+    OS_ZERO_MEM(&cpmemWord1PackedReg, sizeof(cpmemWord1PackedReg));
+
+    switch (FrameBufferPtr->PixelFormat)
+    {
+    case PIXEL_FORMAT_BGRA32:
+        pixelBurst = 15; // 16 Pixel. Valid range is 1 - 64 pixel
+        pixelFormatSelector = CPMEM_PFS_RGB;
+        offset0 = 8;
+        offset1 = 16;
+        offset2 = 24;
+        offset3 = 0;
+        bytesPerPixel = 4;
+        break;
+    default:
+        ASSERT(FALSE);
+        status = OS_STATUS_UNSUPPORTED;
+        goto Exit;
+    }
+
+    switch (FrameBufferPtr->Bpp)
+    {
+    case 8:
+        width0 = width1 = width2 = width3 = 0;
+        break;
+    case 32:
+        if (pixelFormatSelector == CPMEM_PFS_RGB) {
+            width0 = width1 = width2 = width3 = 7;
+        } else {
+            width0 = width1 = width2 = width3 = 0;
+        }
+        break;
+    default:
+        ASSERT(FALSE);
+        status = OS_STATUS_UNSUPPORTED;
+        goto Exit;
+    }
+
+    // Setting up CPMEM word 0
+    cpmemWord0PackedReg.XVVirtualCoordinate = 0;
+    cpmemWord0PackedReg.YVVirtualCoordinate = 0;
+
+    // Subblock is unused although expect to have some value after write
+    cpmemWord0PackedReg.XBinnerBlockCoordinate = 0;
+    cpmemWord0PackedReg.YBinnerBlockCoordinate = 0;
+    cpmemWord0PackedReg.NewSubBlock = 0;
+
+    // Verify "current field" definition
+    cpmemWord0PackedReg.CurrentField = 0;
+
+    // Disable scrolling
+    cpmemWord0PackedReg.ScrollXCounter= 0;
+    cpmemWord0PackedReg.ScrollYCounter = 0;
+    cpmemWord0PackedReg.NumberOfScroll = 0;
+    cpmemWord0PackedReg.ScrollDeltaX = 0;
+    cpmemWord0PackedReg.ScrollMax = 0;
+    cpmemWord0PackedReg.ScrollingConfiguration = 0;
+    cpmemWord0PackedReg.ScrollingEnable = 0;
+    cpmemWord0PackedReg.ScrollDeltaY = 0;
+    cpmemWord0PackedReg.ScrollHorizontalDirection = 0;
+    cpmemWord0PackedReg.ScrollVerticalDirection = 0;
+
+    // Bits per pixel
+    cpmemWord0PackedReg.BitsPerPixel = FrameBufferPtr->Bpp;
+
+    // Decode Address Select
+    cpmemWord0PackedReg.DecodeAddressSelect = decodeAddressSelect;
+
+    // Scan order is progressive no support for interlace mode
+    cpmemWord0PackedReg.ScanOrder = CPMEM_SO_PROGRESSIVE;
+
+    // Band mode is sub frame double buffering
+    cpmemWord0PackedReg.BandMode = CPMEM_BNDM_DISABLE;
+
+    // Block mode used for post filtering and rotation
+    cpmemWord0PackedReg.BlockMode = CPMEM_BM_DISABLE;
+
+    // No support for rotation and flipping for now
+    cpmemWord0PackedReg.Rotation = CPMEM_ROT_NO_ROTATION;
+    cpmemWord0PackedReg.HorizontalFlip = CPMEM_HF_NO_HFLIP;
+    cpmemWord0PackedReg.VerticalFlip = CPMEM_HF_NO_VFLIP;
+    cpmemWord0PackedReg.ThresholdEnable = CPMEM_THE_DISABLE;
+
+    // Disable conditional access
+    cpmemWord0PackedReg.ConditionalAccessEnable = CPMEM_CAP_SKIP_LOW;
+    cpmemWord0PackedReg.ConditionalAccessPolarity = CPMEM_CAE_DISABLE;
+
+    // Frame width and height, minus one as 0 == 1 pixel
+    cpmemWord0PackedReg.FrameWidth = FrameBufferPtr->Width - 1;
+    cpmemWord0PackedReg.FrameHeight = FrameBufferPtr->Height - 1;
+
+    // No interrupt required at the end of line
+    cpmemWord0PackedReg.EndOfLineInterrupt = CPMEM_EOLI_DISABLE;
+
+    // Setting up CPMEM word 1
+    // Buffer 0, use the [31:3] bit address
+    cpmemWord1PackedReg.ExtMemBuffer0Address = FrameBufferPtr->PhyAddr >> 3;
+
+    // Buffer 1, use the same buffer for now
+    cpmemWord1PackedReg.ExtMemBuffer1Address = FrameBufferPtr->PhyAddr >> 3;
+
+    // Currently do not support interlace mode
+    cpmemWord1PackedReg.InterlaceOffset = 0;
+
+    // Pixel format and burst
+    cpmemWord1PackedReg.NumberOfPixelsInWholeBurstAccess = pixelBurst;
+    cpmemWord1PackedReg.PixelFormatSelect = pixelFormatSelector;
+
+    // Alpha config
+    cpmemWord1PackedReg.AlphaUsed = CPMEM_ALU_SAME_BUFFER;
+
+    // AXI ID 0 should be okay, we don't have anything else contending for it
+    cpmemWord1PackedReg.AxiId = CPMEM_ID_ID_0;
+
+    cpmemWord1PackedReg.Threshold = CPMEM_THE_DISABLE;
+
+    // Stride, width and offset
+    cpmemWord1PackedReg.StrideLine =
+        (FrameBufferPtr->Pitch * bytesPerPixel) - 1;
+    cpmemWord1PackedReg.Width0 = width0;
+    cpmemWord1PackedReg.Width1 = width1;
+    cpmemWord1PackedReg.Width2 = width2;
+    cpmemWord1PackedReg.Width3 = width3;
+    cpmemWord1PackedReg.Offset0 = offset0;
+    cpmemWord1PackedReg.Offset1 = offset1;
+    cpmemWord1PackedReg.Offset2 = offset2;
+    cpmemWord1PackedReg.Offset3 = offset3;
+
+    // SX SY is ignored since scrolling is disabled
+    cpmemWord1PackedReg.SelectSXSYSet = 0;
+
+    // Conditional read is always enabled so fully transperant pixel are
+    // not read.
+    cpmemWord1PackedReg.ConditionalReadEnable = CPMEM_CRE_ENABLE;
+
+    // Finallu write into cpmem IDMAC channel
+    cpmemChannel = (cpmemChannel + Channel);
+
+    OS_MEM_COPY(
+        &cpmemChannel->Word0Pack,
+        &cpmemWord0PackedReg,
+        sizeof(cpmemChannel->Word0Pack));
+
+    OS_MEM_COPY(
+        &cpmemChannel->Word1Pack,
+        &cpmemWord1PackedReg,
+        sizeof(cpmemChannel->Word1Pack));
+
+    // IDMAC will generate 8 AXI bursts upon assertion of the DMA request
+    // This significantly reduces memory activity and power consumption
+    SetIdmacLockEn(DIContextPtr, Channel, 0x3);
+
+    // Register dump, commented out by default
+#ifdef REGISTER_DUMP
+    DumpBasicCPMEMReg(cpmemChannel);
+#endif
+
+    status = OS_STATUS_SUCCESS;
+
+Exit:
+    return status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.h
new file mode 100644
index 000000000000..27bf75decbb2
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.h
@@ -0,0 +1,276 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _CPMEM_H_
+#define _CPMEM_H_
+
+// IDMAC channel definition
+#define IDMAC_CHANNEL_CSI_0                                 0
+#define IDMAC_CHANNEL_CSI_1                                 1
+#define IDMAC_CHANNEL_CSI_2                                 2
+#define IDMAC_CHANNEL_CSI_3                                 3
+#define IDMAC_CHANNEL_VDIC_VF1_VF2                          5
+#define IDMAC_CHANNEL_VDIC_PREVIOUS_FIELD                   8
+#define IDMAC_CHANNEL_VDIC_CURRENT_FIELD                    9
+#define IDMAC_CHANNEL_VDIC_NEXT_FIELD                       10
+#define IDMAC_CHANNEL_IC_VIDEO_POST_PROCESSSING             11
+#define IDMAC_CHANNEL_IC_VIDEO_PRP_TASK                     12
+
+#define IDMAC_CHANNEL_DP_PRIMARY_FLOW_MAIN_PLANE            23
+
+typedef enum {
+    CPMEM_SO_PROGRESSIVE,
+    CPMEM_SO_INTERLACE,
+} CPMEM_SO;
+
+typedef enum {
+    CPMEM_BNDM_DISABLE,
+    CPMEM_BNDM_BAND_HEIGHT_4,
+    CPMEM_BNDM_BAND_HEIGHT_8,
+    CPMEM_BNDM_BAND_HEIGHT_16,
+    CPMEM_BNDM_BAND_HEIGHT_32,
+    CPMEM_BNDM_BAND_HEIGHT_64,
+    CPMEM_BNDM_BAND_HEIGHT_128,
+    CPMEM_BNDM_BAND_HEIGHT_256,
+} CPMEM_BNDM;
+
+typedef enum {
+    CPMEM_BM_DISABLE,
+    CPMEM_BM_BW_BH_8,
+    CPMEM_BM_BW_BH_16,
+    CPMEM_BM_UNUSED,
+} CPMEM_BM;
+
+typedef enum {
+    CPMEM_ROT_NO_ROTATION,
+    CPMEM_ROT_90_ROTATION,
+} CPMEM_ROT;
+
+typedef enum {
+    CPMEM_HF_NO_HFLIP,
+    CPMEM_HF_HFLIP_ENABLE,
+} CPMEM_HF;
+
+typedef enum {
+    CPMEM_HF_NO_VFLIP,
+    CPMEM_HF_VFLIP_ENABLE,
+} CPMEM_VF;
+
+typedef enum {
+    CPMEM_THE_DISABLE,
+    CPMEM_THE_ENABLE,
+} CPMEM_THE;
+
+typedef enum {
+    CPMEM_CAP_SKIP_LOW,
+    CPMEM_CAP_SKIP_HIGH,
+} CPMEM_CAP;
+
+typedef enum {
+    CPMEM_CAE_DISABLE,
+    CPMEM_CAE_ENABLE,
+} CPMEM_CAE;
+
+typedef enum {
+    CPMEM_EOLI_DISABLE,
+    CPMEM_EOLI_ENABLE,
+} CPMEM_EOLI;
+
+typedef enum {
+    CPMEM_PFS_NON_INT_444,
+    CPMEM_PFS_NON_INT_422,
+    CPMEM_PFS_NON_INT_420,
+    CPMEM_PFS_PAR_INT_422,
+    CPMEM_PFS_PAR_INT_420,
+} CPMEM_PFS_PLANAR;
+
+typedef enum {
+    CPMEM_DEC_SEL_0_15,
+    CPMEM_DEC_SEL_64_79,
+    CPMEM_DEC_SEL_128_143,
+    CPMEM_DEC_SEL_192_207,
+} CPMEM_DEC_SEL;
+
+typedef enum {
+    CPMEM_PFS_CODE = 5,
+    CPMEM_PFS_GENERIC_DATA,
+    CPMEM_PFS_RGB,
+    CPMEM_PFS_INT_422_Y1U1Y2V1,
+    CPMEM_PFS_INT_422_Y2U1Y1V1,
+    CPMEM_PFS_INT_422_U1Y1V1Y2,
+    CPMEM_PFS_INT_422_U1Y2V1Y1,
+} CPMEM_PFS_PACKED;
+
+typedef enum {
+    CPMEM_ALU_SAME_BUFFER,
+    CPMEM_ALU_SEPERATE_BUFFER,
+} CPMEM_ALU;
+
+typedef enum {
+    CPMEM_ID_ID_0,
+    CPMEM_ID_ID_1,
+    CPMEM_ID_ID_2,
+    CPMEM_ID_ID_3,
+} CPMEM_ID;
+
+typedef enum {
+    CPMEM_CRE_DISABLE,
+    CPMEM_CRE_ENABLE,
+} CPMEM_CRE;
+
+#pragma pack(push, 1)
+
+// CPMEM_WORD0_PLANAR - Non interlaved
+typedef union {
+    struct {
+        UINT32 XVVirtualCoordinate : 10;
+        UINT32 YVVirtualCoordinate : 9;
+        UINT32 XBinnerBlockCoordinate : 13;
+        UINT32 YBinnerBlockCoordinate : 12;
+        UINT32 NewSubBlock : 1;
+        UINT32 CurrentField : 1;
+        UINT32 MemUBufferOffset : 22;
+        UINT32 MemVBufferOffset : 22;
+        UINT32 InitialOffsetX : 4;
+        UINT32 ReduceDoubleReadOrWrites : 1;
+        UINT32 Reserved1 : 18;
+        UINT32 ScanOrder : 1;
+        UINT32 BandMode : 3;
+        UINT32 BlockMode : 2;
+        UINT32 Rotation : 1;
+        UINT32 HorizontalFlip : 1;
+        UINT32 VerticalFlip : 1;
+        UINT32 ThresholdEnable : 1;
+        UINT32 ConditionalAccessPolarity : 1;
+        UINT32 ConditionalAccessEnable : 1;
+        UINT32 FrameWidth : 13; // Max 8192 Pixel
+        UINT32 FrameHeight : 12; // Max 4096 Pixel
+        UINT32 EndOfLineInterrupt : 1;
+        UINT32 Reserved2 : 9;
+    };
+    UINT32 Word0[5];
+} CPMEM_WORD0_PLANAR_REG;
+
+// CPMEM_WORD1_PLANAR - Non interleaved
+typedef union {
+    struct {
+        UINT32 ExtMemBuffer0Address : 29;
+        UINT32 ExtMemBuffer1Address : 29;
+        UINT32 InterlaceOffset : 20;
+        UINT32 NumberOfPixelsInWholeBurstAccess : 7;
+        UINT32 PixelFormatSelect : 4;
+        UINT32 AlphaUsed : 1;
+        UINT32 AlphaChannelMapping : 3;
+        UINT32 AxiId : 2;
+        UINT32 Threshold : 7;
+        UINT32 StrideLine : 14;
+        UINT32 Reserved1 : 9;
+        UINT32 Width3 : 3;
+        UINT32 StrideLineUV : 14;
+        UINT32 Reserved2 : 7;
+        UINT32 ConditionalReadEnable : 1;
+        UINT32 Reserved3 : 10;
+    };
+    UINT32 Word1[5];
+} CPMEM_WORD1_PLANAR_REG;
+
+// CPMEM_WORD0_PACKED - Interlaved
+typedef union {
+    struct {
+        UINT32 XVVirtualCoordinate : 10;
+        UINT32 YVVirtualCoordinate : 9;
+        UINT32 XBinnerBlockCoordinate : 13;
+        UINT32 YBinnerBlockCoordinate : 12;
+        UINT32 NewSubBlock : 1;
+        UINT32 CurrentField : 1;
+        UINT32 ScrollXCounter : 12;
+        UINT32 ScrollYCounter : 11;
+        UINT32 NumberOfScroll : 10;
+        UINT32 ScrollDeltaX : 7;
+        UINT32 ScrollMax : 10;
+        UINT32 ScrollingConfiguration : 1;
+        UINT32 ScrollingEnable : 1;
+        UINT32 ScrollDeltaY : 7;
+        UINT32 ScrollHorizontalDirection : 1;
+        UINT32 ScrollVerticalDirection : 1;
+        UINT32 BitsPerPixel : 3;
+        UINT32 DecodeAddressSelect : 2;
+        UINT32 AccessDimension : 1;
+        UINT32 ScanOrder : 1;
+        UINT32 BandMode : 3;
+        UINT32 BlockMode : 2;
+        UINT32 Rotation : 1;
+        UINT32 HorizontalFlip : 1;
+        UINT32 VerticalFlip : 1;
+        UINT32 ThresholdEnable : 1;
+        UINT32 ConditionalAccessPolarity : 1;
+        UINT32 ConditionalAccessEnable : 1;
+        UINT32 FrameWidth : 13; // Max 8192 Pixel
+        UINT32 FrameHeight : 12; // Max 4096 Pixel
+        UINT32 EndOfLineInterrupt : 1;
+        UINT32 Reserved2 : 9;
+    };
+    UINT32 Word0[5];
+} CPMEM_WORD0_PACKED_REG;
+
+// CPMEM_WORD1_PACKED - Non interleaved
+typedef union {
+    struct {
+        UINT32 ExtMemBuffer0Address : 29;
+        UINT32 ExtMemBuffer1Address : 29;
+        UINT32 InterlaceOffset : 20;
+        UINT32 NumberOfPixelsInWholeBurstAccess : 7;
+        UINT32 PixelFormatSelect : 4;
+        UINT32 AlphaUsed : 1;
+        UINT32 AlphaChannelMapping : 3;
+        UINT32 AxiId : 2;
+        UINT32 Threshold : 7;
+        UINT32 StrideLine : 14;
+        UINT32 Width0 : 3;
+        UINT32 Width1 : 3;
+        UINT32 Width2 : 3;
+        UINT32 Width3 : 3;
+        UINT32 Offset0 : 5;
+        UINT32 Offset1 : 5;
+        UINT32 Offset2 : 5;
+        UINT32 Offset3 : 5;
+        UINT32 SelectSXSYSet : 1;
+        UINT32 ConditionalReadEnable : 1;
+        UINT32 Reserved1 : 10;
+    };
+    UINT32 Word1[5];
+} CPMEM_WORD1_PACKED_REG;
+
+typedef struct _CPMEM_PARAM {
+    union {
+        CPMEM_WORD0_PLANAR_REG Word0Planar;
+        CPMEM_WORD0_PACKED_REG Word0Pack;
+    };
+    UINT32 Reserved1[3];
+    union {
+        CPMEM_WORD1_PLANAR_REG Word1Planar;
+        CPMEM_WORD1_PACKED_REG Word1Pack;
+    };
+    UINT32 Reserved2[3];
+}CPMEM_PARAM, *PCPMEM_PARAM;
+
+#pragma pack(pop)
+
+OS_STATUS ConfigureCPMEMFrameBuffer (
+    DISPLAY_INTERFACE_CONTEXT* DIContextPtr,
+    UINT32 Channel,
+    SURFACE_INFO* FrameBufferPtr
+    );
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.c
new file mode 100644
index 000000000000..fc128760df32
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.c
@@ -0,0 +1,58 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright 2018 NXP
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "osal.h"
+
+#include "Display.h"
+#include "Edid.h"
+#include "Ddc.h"
+#include "Hdmi.h"
+#include "Lvds.h"
+
+OS_STATUS IMX6DDCRead (
+    DISPLAY_CONTEXT* DisplayContextPtr,
+    DISPLAY_INTERFACE DisplayInterface,
+    UINT8 SlaveAddress,
+    UINT8 RegisterAddress,
+    UINT32 ReadSize,
+    UINT8* DataReadPtr)
+{
+    OS_STATUS status;
+
+    switch (DisplayInterface)
+    {
+    case HDMI_DISPLAY:
+        status = HDMIDDCRead(
+            &DisplayContextPtr->DIContext[HDMI_DISPLAY],
+            SlaveAddress,
+            RegisterAddress,
+            ReadSize,
+            HDMI_DDC_STANDARD_MODE,
+            DataReadPtr);
+        if (status != OS_STATUS_SUCCESS) {
+            OS_ERROR("HDMIDDCRead failed\n");
+        }
+        break;
+    case MIPI_DISPLAY:
+    case LVDS0_DISPLAY:
+    case LVDS1_DISPLAY:
+    default:
+        status = OS_STATUS_UNSUPPORTED;
+        break;
+    }
+
+    return status;
+}
+
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.h
new file mode 100644
index 000000000000..169af54aa6b4
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.h
@@ -0,0 +1,27 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _DDC_H_
+#define _DDC_H_
+
+OS_STATUS IMX6DDCRead (
+    DISPLAY_CONTEXT* DisplayContextPtr,
+    DISPLAY_INTERFACE DisplayInterface,
+    UINT8 SlaveAddress,
+    UINT8 RegisterAddress,
+    UINT32 ReadSize,
+    UINT8* DataReadPtr
+    );
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.c
new file mode 100644
index 000000000000..801b3cf4edd4
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.c
@@ -0,0 +1,442 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright 2018 NXP
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "Osal.h"
+
+// Display muxing register
+#include "iMX6.h"
+
+#include "Display.h"
+#include "Edid.h"
+#include "Hdmi.h"
+#include "Lvds.h"
+#include "DisplayInterface.h"
+#include "DisplayController.h"
+#include "CPMem.h"
+#include "Ipu.h"
+#include "IoMux.h"
+
+DISPLAY_TIMING DefaultTiming =
+{
+    65000000,   // PixelClock
+    1024,       // HActive
+    320,        // HBlank
+    768,        // VActive
+    38,         // VBlank
+    136,        // HSync
+    6,          // VSync
+    24,         // HSyncOffset;
+    3,          // VSyncOffset;
+    1024,       // HImageSize
+    768,        // VImageSize
+    0,          // HBorder
+    0,          // VBorder
+    0,          // EdidFlags
+    0,          // Flags
+    1,          // PixelRepetition
+    32,          // Bpp
+    PIXEL_FORMAT_BGRA32,       // PixelFormat
+};
+
+DISPLAY_TIMING Hannstar_XGA =
+{
+    65000000,   // PixelClock
+    1024,       // HActive
+    320,        // HBlank
+    768,        // VActive
+    38,         // VBlank
+    60,         // HSync
+    10,         // VSync
+    24,         // HSyncOffset;
+    3,          // VSyncOffset;
+    1024,       // HImageSize
+    768,        // VImageSize
+    0,          // HBorder
+    0,          // VBorder
+    0,          // EdidFlags
+    0,          // Flags
+    1,          // PixelRepetition
+    32,         // Bpp
+    PIXEL_FORMAT_BGRA32,       // PixelFormat
+};
+
+OS_STATUS GetPreferedTiming (
+    UINT8* EdidDataPtr,
+    UINT32 EdidDataSize,
+    DISPLAY_TIMING* PreferredTimingPtr
+    )
+{
+    OS_STATUS status;
+
+    if (FeaturePcdGet(PcdLvdsEnable)) {
+        *PreferredTimingPtr = Hannstar_XGA;
+        status = OS_STATUS_SUCCESS;
+    } else {
+        status = GetEDIDPreferedTiming(
+            EdidDataPtr,
+            EdidDataSize,
+            PreferredTimingPtr);
+        if (status != OS_STATUS_SUCCESS) {
+            // If EDID is unavailable use the default timing
+            status = OS_STATUS_SUCCESS;
+            *PreferredTimingPtr = DefaultTiming;
+            OS_WARNING("EDID data not available, falling back to default timing\n");
+        }
+    }
+
+    // Only support 8 bit per pixel and no pixel pixel repetition for now
+    PreferredTimingPtr->PixelRepetition = 1;
+    PreferredTimingPtr->PixelFormat = PIXEL_FORMAT_BGRA32;
+    PreferredTimingPtr->Bpp = 32;
+
+#ifdef DEBUG
+    PrintDisplayTiming(
+        "Preferred Timing",
+        PreferredTimingPtr);
+#endif
+    OS_WARNING("--GetPreferedTiming()\r\n");
+    return status;
+}
+
+OS_STATUS InitDisplay (
+    DISPLAY_CONTEXT** DisplayConfigPPtr
+    )
+{
+    OS_STATUS status;
+    DISPLAY_INTERFACE displayCounter;
+    DISPLAY_CONTEXT* tempDisplayContext;
+
+    status = OS_ALLOC_CONTIGUOUS_MEMORY(
+        sizeof(*tempDisplayContext),
+        &tempDisplayContext);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_ERROR("Fail to allocate display context\n");
+        goto Exit;
+    }
+
+    OS_ZERO_MEM(tempDisplayContext, sizeof(*tempDisplayContext));
+
+    tempDisplayContext->IoMuxMmioBasePtr =
+        (VOID*)OS_MMIO_MAP(IOMUXC_GPR_BASE_ADDRESS);
+    if (tempDisplayContext->IoMuxMmioBasePtr == NULL) {
+        OS_ERROR("Fail to map IO Mux register");
+        goto Exit;
+    }
+
+    tempDisplayContext->IpuMmioBasePtr[IPU1] =
+        (VOID*)OS_MMIO_MAP(IPU1_BASE);
+    if (tempDisplayContext->IoMuxMmioBasePtr == NULL) {
+        OS_ERROR("Fail to map IPU1 IO Mux register");
+        goto Exit;
+    }
+#if !defined(CPU_IMX6SDL)
+    tempDisplayContext->IpuMmioBasePtr[IPU2] =
+        (VOID*)OS_MMIO_MAP(IPU2_BASE);
+    if (tempDisplayContext->IoMuxMmioBasePtr == NULL) {
+        OS_ERROR("Fail to map IPU2 IO Mux register");
+        goto Exit;
+    }
+#endif
+    for (displayCounter = HDMI_DISPLAY;
+         displayCounter < MAX_DISPLAY;
+         ++displayCounter) {
+        tempDisplayContext->DIContext[displayCounter].displayInterface =
+            displayCounter;
+    }
+
+    if (FeaturePcdGet(PcdLvdsEnable)) {
+        status = InitLVDS(tempDisplayContext);
+        if (status != OS_STATUS_SUCCESS) {
+            OS_ERROR("Fail to intialize LVDS\n");
+            goto Exit;
+        }
+    } else {
+        status = InitHDMI(tempDisplayContext);
+        if (status != OS_STATUS_SUCCESS) {
+            OS_ERROR("Fail to intialize HDMI\n");
+            goto Exit;
+        }
+    }
+
+    *DisplayConfigPPtr = tempDisplayContext;
+
+Exit:
+    return status;
+}
+
+
+OS_STATUS DeInitDisplay (
+    DISPLAY_CONTEXT* DisplayContextPtr
+    )
+{
+
+    return OS_STATUS_SUCCESS;
+}
+
+OS_STATUS ValidateDisplayConfig (
+    DISPLAY_CONTEXT* DisplayContextPtr,
+    DISPLAY_MODE DisplayMode,
+    DISPLAY_INTERFACE* DIOrder
+    )
+{
+    OS_STATUS status;
+    DISPLAY_INTERFACE DisplayDevice;
+
+    if (FeaturePcdGet(PcdLvdsEnable)) {
+        DisplayDevice = LVDS0_DISPLAY;
+    } else {
+        DisplayDevice = HDMI_DISPLAY;
+    }
+
+    // Currently only support single display mode on HDMI/LVDS
+    if (DisplayMode != SINGLE_MODE && DIOrder[0] != DisplayDevice) {
+        status = OS_STATUS_UNSUPPORTED;
+        goto Exit;
+    }
+
+    // Currently going to a very simplistic approach of enabling HDMI/LVDS single
+    // display on HDMI/LVDS port. This configuration is applied regardless if
+    // there is a monitor connected. No hot plug, monitor detection support.
+
+    status = OS_STATUS_SUCCESS;
+
+Exit:
+    return status;
+}
+
+OS_STATUS SetDisplayConfig (
+    DISPLAY_CONTEXT* DisplayContextPtr,
+    DISPLAY_MODE DisplayMode,
+    DISPLAY_INTERFACE* DIOrder
+    )
+{
+    OS_STATUS status;
+    IPU_INDEX iPUIndex;
+    DI_INDEX diIndex;
+    UINT32 displayModeIndex;
+    UINT32 diOffset[DI_TOTAL] =
+        { IPU_DI0_GENERAL_OFFSET, IPU_DI1_GENERAL_OFFSET };
+
+    status = ValidateDisplayConfig(
+        DisplayContextPtr,
+        DisplayMode,
+        DIOrder);
+    if (status != OS_STATUS_SUCCESS) {
+        DisplayContextPtr->DisplayConfig.DisplayMode = UNKNOWN_MODE;
+        OS_ZERO_MEM(
+            DisplayContextPtr->DisplayConfig.DIOrder,
+            sizeof(DisplayContextPtr->DisplayConfig.DIOrder));
+        OS_ERROR("Unsupported display configuration\n");
+        status = OS_STATUS_UNSUPPORTED;
+        goto Exit;
+    }
+
+    DisplayContextPtr->DisplayConfig.DisplayMode = DisplayMode;
+
+    OS_ZERO_MEM(
+        DisplayContextPtr->DisplayConfig.DIOrder,
+        sizeof(DisplayContextPtr->DisplayConfig.DIOrder));
+
+    // Assigning display interface in order. Require mode information on IPU
+    // and DI valid combination
+    for (iPUIndex = IPU1, displayModeIndex = 0;
+         iPUIndex < IPU_TOTAL && displayModeIndex < (UINT32)DisplayMode;
+        ++iPUIndex) {
+        for (diIndex = DI0;
+            diIndex < DI_TOTAL && displayModeIndex < (UINT32)DisplayMode;
+            ++diIndex) {
+            DisplayContextPtr->DisplayConfig.DIOrder[diIndex] =
+                DIOrder[diIndex];
+            DISPLAY_INTERFACE_CONTEXT* diContextPtr =
+                &DisplayContextPtr->DIContext[DIOrder[diIndex]];
+            diContextPtr->IpuMmioBasePtr =
+                DisplayContextPtr->IpuMmioBasePtr[iPUIndex];
+            diContextPtr->IpuDiRegsPtr =
+                (IPU_DIx_REGS*)(((UINTN)DisplayContextPtr->IpuMmioBasePtr[iPUIndex]) +
+                    diOffset[diIndex]);
+            diContextPtr->CpMemParamBasePtr = (VOID *)
+                (((UINTN)diContextPtr->IpuMmioBasePtr) + CSP_IPUV3_CPMEM_REGS_OFFSET);
+            ++displayModeIndex;
+        }
+    }
+
+    status = OS_STATUS_SUCCESS;
+
+Exit:
+    return status;
+}
+
+OS_STATUS ApplyDisplayConfig (
+    DISPLAY_CONTEXT* DisplayContextPtr,
+    DISPLAY_MODE DisplayMode,
+    DISPLAY_INTERFACE* DIOrder
+    )
+{
+    DISPLAY_CONFIG* displayConfigPtr = &DisplayContextPtr->DisplayConfig;
+    UINT32 displayModeIndex;
+    OS_STATUS status;
+
+    status = SetDisplayConfig(
+        DisplayContextPtr,
+        DisplayMode,
+        DIOrder);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_ERROR("Fail to set display configuration %d\n", DisplayMode);
+        status = OS_STATUS_UNSUPPORTED;
+        goto Exit;
+    }
+
+    // Setup muxing first before configuring DI and DC
+    status = SetupDisplayMux(
+        DisplayContextPtr);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_ERROR("SetDisplayMux failed \n");
+        goto Exit;
+    }
+
+    for (displayModeIndex = 0;
+         displayModeIndex < (UINT32)displayConfigPtr->DisplayMode;
+         ++displayModeIndex) {
+        UINT32 currentDI = displayConfigPtr->DIOrder[displayModeIndex];
+        DISPLAY_INTERFACE_CONTEXT* displayInterfaceContextPtr =
+            &DisplayContextPtr->DIContext[currentDI];
+        DISPLAY_TIMING* currentDisplayTimingPtr =
+            &displayConfigPtr->DisplayTiming[displayModeIndex];
+
+        status = ConfigureDCChannel(
+            displayInterfaceContextPtr,
+            currentDI,
+            displayModeIndex,
+            currentDisplayTimingPtr);
+        if (status != OS_STATUS_SUCCESS) {
+            OS_ERROR(
+                "ConfigureDCChannel fail display %d index %d\n",
+                currentDI,
+                displayModeIndex);
+            goto Exit;
+        }
+
+        status = ConfigureDI(
+            displayInterfaceContextPtr,
+            displayModeIndex,
+            currentDisplayTimingPtr);
+        if (status != OS_STATUS_SUCCESS) {
+            OS_ERROR("Fail to configure DI\n");
+            goto Exit;
+        }
+
+        switch (currentDI)
+        {
+            case HDMI_DISPLAY:
+                status = SetHDMIDisplay(
+                    displayInterfaceContextPtr,
+                    currentDisplayTimingPtr);
+                if (status != OS_STATUS_SUCCESS) {
+                    OS_ERROR("Fail to set HDMI timing\n");
+                    goto Exit;
+                }
+                break;
+            case LVDS0_DISPLAY:
+            case LVDS1_DISPLAY:
+                break;
+            default:
+                status = OS_STATUS_UNSUPPORTED;
+                goto Exit;
+        }
+
+        status = ConfigureFrameBuffer(
+            displayInterfaceContextPtr,
+            &displayConfigPtr->DisplaySurface[displayModeIndex]);
+        if (status != OS_STATUS_SUCCESS) {
+            OS_ERROR("Fail to configure frame buffer (%d)\n", displayModeIndex);
+            goto Exit;
+        }
+    }
+
+Exit:
+    return status;
+}
+
+OS_STATUS AllocateFrameBuffer (
+    SURFACE_INFO* SurfaceInfoPtr
+    )
+{
+    OS_STATUS status;
+    OS_INFO("++AllocateFrameBuffer()\r\n");
+    if((SurfaceInfoPtr->Width == 0) ||
+            (SurfaceInfoPtr->Height == 0)) {
+        status = OS_STATUS_INVALID_PARAM;
+        goto Exit;
+    }
+
+    OS_INFO("AllocateFrameBuffer() Frame Buffer AddrP=%Xh\r\n",FixedPcdGet32(PcdFrameBufferBase));
+    OS_INFO("AllocateFrameBuffer() Frame Buffer Size=%Xh\r\n",FixedPcdGet32(PcdFrameBufferSize));
+    SurfaceInfoPtr->VirtAddrPtr = (VOID*)(UINTN)FixedPcdGet32(PcdFrameBufferBase);
+
+    SurfaceInfoPtr->PhyAddr =
+        (UINT32)OS_VIRT_TO_PHY_ADDR(SurfaceInfoPtr->VirtAddrPtr);
+    SurfaceInfoPtr->Pitch = SurfaceInfoPtr->Width;
+
+    OS_INFO(
+        "Allocate FB PhyAddr %x VirtAddr %x\n",
+        SurfaceInfoPtr->PhyAddr,
+        SurfaceInfoPtr->VirtAddrPtr);
+
+    status = OS_STATUS_SUCCESS;
+
+Exit:
+    OS_INFO("--AllocateFrameBuffer()=%Xh\r\n",status);
+    return status;
+}
+
+OS_STATUS ConfigureFrameBuffer (
+    DISPLAY_INTERFACE_CONTEXT* DIContextPtr,
+    SURFACE_INFO* FrameBufferPtr
+    )
+{
+    OS_STATUS status;
+
+    // Only support single display for now
+    status = ConfigureCPMEMFrameBuffer(
+        DIContextPtr,
+        IDMAC_CHANNEL_DP_PRIMARY_FLOW_MAIN_PLANE,
+        FrameBufferPtr);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_ERROR("Fail to configure CPMEM\n");
+        goto Exit;
+    }
+
+Exit:
+    return status;
+}
+
+UINT32 GetColorDepth (
+    PIXEL_FORMAT PixelFormat
+    )
+{
+    UINT32 bitDepth;
+
+    switch(PixelFormat)
+    {
+        case PIXEL_FORMAT_ARGB32:
+        case PIXEL_FORMAT_BGRA32:
+            bitDepth = 8;
+            break;
+        default:
+            bitDepth = 0;
+    }
+
+    return bitDepth;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.h
new file mode 100644
index 000000000000..4a348bffed3a
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.h
@@ -0,0 +1,171 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright 2018 NXP
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _DISPLAY_H_
+#define _DISPLAY_H_
+
+typedef enum {
+   UNKNOWN_MODE,
+   SINGLE_MODE,
+   DUAL_MODE,
+} DISPLAY_MODE;
+
+typedef enum {
+    IPU1,
+#if !defined(CPU_IMX6SDL)
+    IPU2,
+#endif
+    IPU_TOTAL,
+} IPU_INDEX;
+
+typedef enum {
+    DI0,
+    DI1,
+    DI_TOTAL,
+} DI_INDEX;
+
+typedef enum {
+    HDMI_DISPLAY,
+    MIPI_DISPLAY,
+    LVDS0_DISPLAY,
+    LVDS1_DISPLAY,
+    MAX_DISPLAY, // Only 4 display supported by IPU
+    NO_DISPLAY = MAX_DISPLAY,
+} DISPLAY_INTERFACE;
+
+typedef struct _SURFACE_INFO {
+    UINT32 PhyAddr;
+    UINT32* VirtAddrPtr;
+    UINT32 Width;
+    UINT32 Height;
+    UINT32 Pitch;
+    UINT32 Bpp;
+    PIXEL_FORMAT PixelFormat;
+}SURFACE_INFO, *PSURFACE_INFO;
+
+typedef struct _IPU_DIx_REGS {
+    UINT32 DIxGENERAL;
+    UINT32 DIxBS_CLKGEN0;
+    UINT32 DIxBS_CLKGEN1;
+    UINT32 DIxSW_GEN0_1;
+    UINT32 DIxSW_GEN0_2;
+    UINT32 DIxSW_GEN0_3;
+    UINT32 DIxSW_GEN0_4;
+    UINT32 DIxSW_GEN0_5;
+    UINT32 DIxSW_GEN0_6;
+    UINT32 DIxSW_GEN0_7;
+    UINT32 DIxSW_GEN0_8;
+    UINT32 DIxSW_GEN0_9;
+    UINT32 DIxSW_GEN1_1;
+    UINT32 DIxSW_GEN1_2;
+    UINT32 DIxSW_GEN1_3;
+    UINT32 DIxSW_GEN1_4;
+    UINT32 DIxSW_GEN1_5;
+    UINT32 DIxSW_GEN1_6;
+    UINT32 DIxSW_GEN1_7;
+    UINT32 DIxSW_GEN1_8;
+    UINT32 DIxSW_GEN1_9;
+    UINT32 DIxSYNC_AS_GEN;
+    UINT32 DIxDW_GEN[12];
+    UINT32 DIxDW_SET0[12];
+    UINT32 DIxDW_SET1[12];
+    UINT32 DIxDW_SET2[12];
+    UINT32 DIxDW_SET3[12];
+    UINT32 DIxSTP_REP[4];
+    UINT32 DIxSTP_REP_9;
+    UINT32 DIxSER_CONF;
+    UINT32 DIxSSC;
+    UINT32 DIxPOL;
+    UINT32 DIxAW0;
+    UINT32 DIxAW1;
+    UINT32 DIxSCR_CONF;
+    UINT32 DIxSTAT;
+} IPU_DIx_REGS, *PIPU_DIx_REGS;
+
+typedef struct _DISPLAY_INTERFACE_CONTEXT {
+    DISPLAY_INTERFACE displayInterface;
+
+    VOID* MmioBasePtr;
+    VOID* IpuMmioBasePtr;
+    VOID* CpMemParamBasePtr;
+    IPU_DIx_REGS* IpuDiRegsPtr;
+    UINT32 EdidDataSize;
+    UINT8 EdidData[256];
+    DISPLAY_TIMING PreferedTiming;
+}DISPLAY_INTERFACE_CONTEXT, *PDISPLAY_INTERFACE_CONTEXT;
+
+typedef struct _DISPLAY_CONFIG {
+    DISPLAY_MODE DisplayMode;
+    DISPLAY_INTERFACE DIOrder[MAX_DISPLAY];
+    SURFACE_INFO DisplaySurface[MAX_DISPLAY];
+    DISPLAY_TIMING DisplayTiming[MAX_DISPLAY];
+    UINT32 OsHandle[MAX_DISPLAY];
+}DISPLAY_CONFIG, *PDISPLAY_CONFIG;
+
+typedef struct _DISPLAY_CONTEXT {
+    DISPLAY_CONFIG DisplayConfig;
+    VOID* IoMuxMmioBasePtr;
+    VOID* IpuMmioBasePtr[IPU_TOTAL];
+    DISPLAY_INTERFACE_CONTEXT DIContext[MAX_DISPLAY];
+}DISPLAY_CONTEXT, *PDISPLAY_CONTEXT;
+
+extern DISPLAY_TIMING DefaultTiming;
+
+OS_STATUS GetPreferedTiming (
+    UINT8* EdidDataPtr,
+    UINT32 EdidDataSize,
+    DISPLAY_TIMING* PreferedTimingPtr
+    );
+
+OS_STATUS InitDisplay (
+    DISPLAY_CONTEXT** DisplayConfigPPtr
+    );
+
+OS_STATUS DeInitDisplay (
+    DISPLAY_CONTEXT* DisplayContextPtr
+    );
+
+OS_STATUS ValidateDisplayConfig (
+    DISPLAY_CONTEXT* DisplayContextPtr,
+    DISPLAY_MODE DisplayMode,
+    DISPLAY_INTERFACE* DIOrder
+    );
+
+OS_STATUS SetDisplayConfig (
+    DISPLAY_CONTEXT* DisplayContextPtr,
+    DISPLAY_MODE DisplayMode,
+    DISPLAY_INTERFACE* DIOrder
+    );
+
+OS_STATUS ApplyDisplayConfig (
+    DISPLAY_CONTEXT* DisplayContextPtr,
+    DISPLAY_MODE DisplayMode,
+    DISPLAY_INTERFACE* DIOrder
+    );
+
+OS_STATUS AllocateFrameBuffer (
+    SURFACE_INFO* SurfaceInfoPtr
+    );
+
+OS_STATUS ConfigureFrameBuffer (
+    DISPLAY_INTERFACE_CONTEXT* DIContextPtr,
+    SURFACE_INFO* FrameBufferPtr
+    );
+
+UINT32 GetColorDepth (
+    PIXEL_FORMAT PixelFormat
+    );
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.c
new file mode 100644
index 000000000000..58830e98bd2b
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.c
@@ -0,0 +1,388 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright 2018 NXP
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "osal.h"
+
+#include "Ipu.h"
+#include "Display.h"
+#include "DisplayController.h"
+#include "DisplayInterface.h"
+
+VOID DumpBasicDCReg(
+    VOID* IpuMmioBasePtr)
+{
+    UINT32 regVal;
+    UINT32 counter, index;
+
+    OS_INFO("---------- DC Register Dump ----------\n");
+    OS_INFO("## Configuration\n\n");
+    regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OFFSET);
+    OS_INFO("IPU_DC_WR_CH_CONF_5_OFFSET %x\n", regVal);
+    regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_WR_CH_CONF_1_OFFSET);
+    OS_INFO("IPU_DC_WR_CH_CONF_1_OFFSET %x\n", regVal);
+    regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_DISP_CONF1_0_OFFSET);
+    OS_INFO("IPU_DC_DISP_CONF1_0_OFFSET %x\n", regVal);
+    regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_DISP_CONF1_1_OFFSET);
+    OS_INFO("IPU_DC_DISP_CONF1_1_OFFSET %x\n", regVal);
+    regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_DISP_CONF1_2_OFFSET);
+    OS_INFO("IPU_DC_DISP_CONF1_2_OFFSET %x\n", regVal);
+    regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_DISP_CONF1_3_OFFSET);
+    OS_INFO("IPU_DC_DISP_CONF1_3_OFFSET %x\n", regVal);
+    regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_DISP_CONF2_0_OFFSET);
+    OS_INFO("IPU_DC_DISP_CONF2_0_OFFSET %x\n", regVal);
+    regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_GEN_OFFSET);
+    OS_INFO("IPU_DC_GEN_OFFSET %x\n", regVal);
+    OS_INFO("## Bus MAPPING\n\n");
+    {
+        for (counter = 0, index = 0; index < 26; counter += 4, ++index) {
+            regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_MAP_CONF_0_OFFSET + counter);
+            OS_INFO("IPU_DC_MAP_CONF_%d %x\n", index, regVal);
+        }
+    }
+
+    OS_INFO("## Channel MicroCode setup\n\n");
+    {
+        // Only print out channel 5 as we only support single mode for now
+        regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_RL0_CH_5_OFFSET);
+        OS_INFO("IPU_DC_RL0_CH_5_OFFSET %x\n", regVal);
+        regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_RL1_CH_5_OFFSET);
+        OS_INFO("IPU_DC_RL1_CH_5_OFFSET %x\n", regVal);
+        regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_RL2_CH_5_OFFSET);
+        OS_INFO("IPU_DC_RL2_CH_5_OFFSET %x\n", regVal);
+        regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_RL3_CH_5_OFFSET);
+        OS_INFO("IPU_DC_RL3_CH_5_OFFSET %x\n", regVal);
+        regVal = IpuRead32(IpuMmioBasePtr, IPU_DC_RL4_CH_5_OFFSET);
+        OS_INFO("IPU_DC_RL4_CH_5_OFFSET %x\n", regVal);
+    }
+
+    OS_INFO("## MicroCode\n\n");
+    {
+        // There are 256 template, only print out the first 10
+        for (counter = 0, index = 0; index < 10; counter += 8, ++index) {
+            OS_INFO("(%d)", index);
+            regVal = IpuRead32(
+                IpuMmioBasePtr,
+                IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + counter);
+            OS_INFO("- %8x", regVal);
+            regVal = IpuRead32(
+                IpuMmioBasePtr,
+                IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + counter + 4);
+            OS_INFO(" %8x -\n", regVal);
+        }
+    }
+    OS_INFO("------------------------------------\n\n");
+}
+
+#pragma pack(push, 1)
+typedef union {
+    struct {
+        UINT32 SYNC : 4;
+        UINT32 GLUELOGIC : 7;
+        UINT32 WAVEFORM : 4;
+        UINT32 MAPPING : 5;
+        UINT32 DATA : 16;
+        UINT32 OPCODE : 5;
+        UINT32 STOP : 1;
+        UINT32 Unused : 22;
+    };
+    struct     {
+        UINT32 LowWord;
+        UINT32 HighWord;
+    };
+} DC_WROD_COMMAND_TEMPLATE;
+#pragma pack(pop)
+
+OS_STATUS WriteWRODCommand (
+    VOID* IpuMmioBasePtr,
+    UINT32 MicroCodeAddr,
+    UINT32 Data,
+    UINT32 Mapping,
+    UINT32 WaveForm,
+    UINT32 GlueLogic,
+    UINT32 Sync)
+{
+    DC_WROD_COMMAND_TEMPLATE wrodCommand;
+    UINT32 microCodeAddrOffset =
+        IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + (MicroCodeAddr * 8);
+
+    OS_ZERO_MEM((void*)&wrodCommand, sizeof(wrodCommand));
+    wrodCommand.STOP = 1;
+    wrodCommand.OPCODE = 0x18;
+    wrodCommand.DATA = Data;
+    wrodCommand.MAPPING = Mapping;
+    wrodCommand.WAVEFORM = WaveForm + 1;
+    wrodCommand.GLUELOGIC = GlueLogic;
+    wrodCommand.SYNC = Sync;
+
+    IpuWrite32(IpuMmioBasePtr, microCodeAddrOffset, wrodCommand.LowWord);
+    IpuWrite32(IpuMmioBasePtr, microCodeAddrOffset + 4, wrodCommand.HighWord);
+
+    return OS_STATUS_SUCCESS;
+}
+
+OS_STATUS SetDCChannelState (
+    VOID* IpuMmioBasePtr,
+    PROG_CHAN_TYP ChannelType
+    )
+{
+    IPU_DC_WR_CH_CONF_5_REG wrChConfigReg;
+
+    wrChConfigReg.Reg = IpuRead32(IpuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OFFSET);
+
+    wrChConfigReg.PROG_CHAN_TYP = ChannelType;
+
+    IpuWrite32(IpuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OFFSET, wrChConfigReg.Reg);
+
+    return OS_STATUS_SUCCESS;
+}
+
+OS_STATUS ConfigureDCChannel (
+    DISPLAY_INTERFACE_CONTEXT* DIContextPtr,
+    DISPLAY_INTERFACE DisplayInterface,
+    UINT32 DisplayIndex,
+    DISPLAY_TIMING* DisplayTimingPtr)
+{
+    OS_STATUS status;
+    IPU_DC_WR_CH_CONF_5_REG wrChConfigReg;
+    VOID* ipuMmioBasePtr = DIContextPtr->IpuMmioBasePtr;
+
+    OS_ZERO_MEM((void*)&wrChConfigReg, sizeof(wrChConfigReg));
+    wrChConfigReg.PROG_START_TIME = 0;
+    wrChConfigReg.FILED_MODE = 0;
+    wrChConfigReg.CHAN_MASK_DEFAULT = 0; // only used highest priority
+    wrChConfigReg.PROG_CHAN_TYP = 0; // Begin as disable
+    wrChConfigReg.PROG_DISP_ID = DisplayInterface;
+    wrChConfigReg.PROG_DI_ID = DisplayIndex % 2;
+    wrChConfigReg.W_SIZE = 0x02; // 24 Bits
+    wrChConfigReg.Reserved1 = 0;
+    wrChConfigReg.Reserved2 = 0;
+
+    // Channel 5 is used main primary flow
+    IpuWrite32(ipuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OFFSET, wrChConfigReg.Reg);
+    // Start address of memory always 0
+    IpuWrite32(ipuMmioBasePtr, IPU_DC_WR_CH_ADDR_5_OFFSET, 0);
+
+    OS_ZERO_MEM((void*)&wrChConfigReg, sizeof(wrChConfigReg));
+    wrChConfigReg.FILED_MODE = 0;
+    wrChConfigReg.CHAN_MASK_DEFAULT = 0; // only used highest priority
+    wrChConfigReg.PROG_CHAN_TYP = 4; // Enable
+    wrChConfigReg.PROG_DISP_ID = DisplayInterface;
+    wrChConfigReg.PROG_DI_ID = DisplayIndex % 2;
+    wrChConfigReg.W_SIZE = 0x02; // 1 Bits
+    wrChConfigReg.Reserved1 = 0;
+    wrChConfigReg.Reserved2 = 0;
+
+    // Channel 1 is used as sync/async flow
+    IpuWrite32(ipuMmioBasePtr, IPU_DC_WR_CH_CONF_1_OFFSET, wrChConfigReg.Reg);
+    IpuWrite32(ipuMmioBasePtr, IPU_DC_WR_CH_ADDR_1_OFFSET, 0);
+
+    {
+        IPUx_DC_DISP_CONF1_REG dispConf1Reg;
+
+        dispConf1Reg.DISP_TYP = 0x02; // What is byte_enabled
+        dispConf1Reg.ADDR_INCREMENT = 0; // Increase by 1 byte
+        dispConf1Reg.ADDR_BE_L_INC = 0;
+        dispConf1Reg.MCU_ACC_LB_MASK_3 = 0;
+        dispConf1Reg.DISP_RD_VALUE_PTR = 0;
+        IpuWrite32(ipuMmioBasePtr, IPU_DC_DISP_CONF1_0_OFFSET, dispConf1Reg.Reg);
+
+        // set stride
+        IpuWrite32(ipuMmioBasePtr, IPU_DC_DISP_CONF2_0_OFFSET, DisplayTimingPtr->VActive);
+    }
+
+    // Setup general register
+    {
+        IPUx_IPU_DC_GEN_REG dcGenReg;
+
+        dcGenReg.Sync_1_6 = 2; // Sync flow
+        dcGenReg.MASK_EN = 0; // Disable masking
+        dcGenReg.MASK4CHAN_5 = 0; // Ignore as mask is disabled
+        dcGenReg.SYNC_PRIORITY_5 = 1; // Higher sync priority for channel 5 which is the main channel
+        dcGenReg.SYNC_PRIORITY_1 = 0; // Lower sync priority
+        dcGenReg.DC_CH5_TYPE = 0; // Normal mode, sync flow throuh channel 5
+        dcGenReg.DC_BK_EN = 0; // No cursor support
+        dcGenReg.DC_BKDIV = 0; // No cursor support
+
+        IpuWrite32(ipuMmioBasePtr, IPU_DC_GEN_OFFSET, dcGenReg.Reg);
+    }
+
+    // Do not use any user event
+    IpuWrite32(ipuMmioBasePtr, IPU_DC_UGDE0_0_OFFSET, 0);
+    IpuWrite32(ipuMmioBasePtr, IPU_DC_UGDE1_0_OFFSET, 0);
+    IpuWrite32(ipuMmioBasePtr, IPU_DC_UGDE2_0_OFFSET, 0);
+    IpuWrite32(ipuMmioBasePtr, IPU_DC_UGDE3_0_OFFSET, 0);
+
+    {
+        IPUx_DC_MAP_CONF_MAP_REG dcMapConf0Reg;
+        DC_MAP_CONF_OFFSET_MASK_REG dcConfOffsetMaskReg;
+        UINT32 mask0, mask1, mask2;
+        UINT32 offset0, offset1, offset2;
+
+        dcMapConf0Reg.MAPPING_PNTR_BYTE0_X = 0;
+        dcMapConf0Reg.MAPPING_PNTR_BYTE1_X = 1;
+        dcMapConf0Reg.MAPPING_PNTR_BYTE2_X = 2;
+        dcMapConf0Reg.MAPPING_PNTR_BYTE0_Y = 3; // Unused
+        dcMapConf0Reg.MAPPING_PNTR_BYTE1_Y = 4; // Unused
+        dcMapConf0Reg.MAPPING_PNTR_BYTE2_Y = 5; // Unused
+
+        IpuWrite32(ipuMmioBasePtr, IPU_DC_MAP_CONF_0_OFFSET, dcMapConf0Reg.Reg);
+
+        switch (DisplayInterface)
+        {
+            // PixelFormat RGB24
+            case HDMI_DISPLAY:
+                mask0 = mask1 = mask2 = 0xFF;
+                offset0 = 7;
+                offset1 = 15;
+                offset2 = 23;
+                break;
+            // PixelFormat RGB666
+            case LVDS0_DISPLAY:
+            case LVDS1_DISPLAY:
+                mask0 = mask1 = mask2 = 0xFC;
+                offset0 = 5;
+                offset1 = 11;
+                offset2 = 17;
+                break;
+            default:
+                ASSERT(FALSE);
+                status = OS_STATUS_UNSUPPORTED;
+                goto Exit;
+        }
+
+        dcConfOffsetMaskReg.MD_MASK_X = mask0;
+        dcConfOffsetMaskReg.MD_OFFSET_X = offset0; // Blue
+        dcConfOffsetMaskReg.MD_MASK_Y = mask1;
+        dcConfOffsetMaskReg.MD_OFFSET_Y = offset1; // Green
+
+        IpuWrite32(ipuMmioBasePtr, IPU_DC_MAP_CONF_15_OFFSET, dcConfOffsetMaskReg.Reg);
+
+        dcConfOffsetMaskReg.MD_MASK_X = mask2;
+        dcConfOffsetMaskReg.MD_OFFSET_X = offset2; // Red
+        dcConfOffsetMaskReg.MD_MASK_Y = 0x00;
+        dcConfOffsetMaskReg.MD_OFFSET_Y = 0; // Unused
+
+        IpuWrite32(ipuMmioBasePtr, IPU_DC_MAP_CONF_16_OFFSET, dcConfOffsetMaskReg.Reg);
+    }
+
+    // Setup microcode
+    {
+        IPU_DC_RL0_CH_5_REG dcRl0Ch5Reg;
+        IPU_DC_RL2_CH_5_REG dcRl2Ch5Reg;
+        IPU_DC_RL4_CH_5_REG dcRl4Ch5Reg;
+
+        // New line event point to the first microcode (0)
+        OS_ZERO_MEM((void*)&dcRl0Ch5Reg, sizeof(dcRl0Ch5Reg));
+        dcRl0Ch5Reg.COD_NL_START_CHAN_5 = 0;
+        dcRl0Ch5Reg.COD_NL_PRIORITY_CHAN_5 = 3;
+        IpuWrite32(ipuMmioBasePtr, IPU_DC_RL0_CH_5_OFFSET, dcRl0Ch5Reg.Reg);
+
+        // End of line event point to the second microcode (1)
+        OS_ZERO_MEM((void*)&dcRl2Ch5Reg, sizeof(dcRl2Ch5Reg));
+        dcRl2Ch5Reg.COD_EOL_START_CHAN_5 = 1;
+        dcRl2Ch5Reg.COD_EOL_PRIORITY_CHAN_5 = 2;
+        IpuWrite32(ipuMmioBasePtr, IPU_DC_RL2_CH_5_OFFSET, dcRl2Ch5Reg.Reg);
+
+        // New data event point to the first microcode (2)
+        OS_ZERO_MEM((void*)&dcRl4Ch5Reg, sizeof(dcRl4Ch5Reg));
+        dcRl4Ch5Reg.COD_NEW_DATA_START_CHAN_5 = 2;
+        dcRl4Ch5Reg.COD_NEW_DATA_PRIORITY_CHAN_5 = 1;
+        IpuWrite32(ipuMmioBasePtr, IPU_DC_RL4_CH_5_OFFSET, dcRl4Ch5Reg.Reg);
+
+        // MicroCodeAddr
+        // - 0 set for new line event
+        // Data
+        // - Unsused
+        // Map to mapping parameter 0
+        // - In order to point to MAPPING_PNTR_BYTE2_0, MAPPING_PNTR_BYTE1_0,
+        //   MAPPING_PNTR_BYTE0_0 the user should write 1 to the MAPPING field
+        // WaveForm
+        // - Points to DI0_DW_GEN_0 or DI1_DW_GEN_0 (Define which waveform
+        //   register is used, default to first IPUx_DI0_DW_SET0_1)
+        // GlueLogic
+        // - Once the signal is asserted then it remains asserted (high or low
+        //   according to the polarity)
+        // Sync
+        // - Sync with counter 5
+        WriteWRODCommand(
+            ipuMmioBasePtr,
+            0,
+            0,
+            1,
+            DW_GEN_0,
+            8,
+            DI_COUNTER_5_ACTIVE_CLOCK);
+
+        // MicroCodeAddr
+        // - 1 set for end of line event
+        // Data
+        // - Unsused
+        // Map to mapping parameter 0
+        // - In order to point to MAPPING_PNTR_BYTE2_0, MAPPING_PNTR_BYTE1_0,
+        //   MAPPING_PNTR_BYTE0_0 the user should write 1 to the MAPPING field
+        // WaveForm
+        // - Points to DI0_DW_GEN_0 or DI1_DW_GEN_0 (Define which waveform
+        //   register is used, default to first IPUx_DI0_DW_SET0_1)
+        // GlueLogic
+        // - Once the signal is negated then it remains negated (high or low
+        //   according to the polarity)
+        // Sync
+        // - Sync with counter 5
+        WriteWRODCommand(
+            ipuMmioBasePtr,
+            1,
+            0,
+            1,
+            DW_GEN_0,
+            4,
+            DI_COUNTER_5_ACTIVE_CLOCK);
+
+        // MicroCodeAddr
+        // - 2 set for new data event
+        // Data
+        // - Unsused
+        // Map to mapping parameter 0
+        // - In order to point to MAPPING_PNTR_BYTE2_0, MAPPING_PNTR_BYTE1_0,
+        //   MAPPING_PNTR_BYTE0_0 the user should write 1 to the MAPPING field
+        // WaveForm
+        // - Points to DI0_DW_GEN_0 or DI1_DW_GEN_0 (Define which waveform
+        //   register is used, default to first IPUx_DI0_DW_SET0_1)
+        // GlueLogic
+        // - CS mode No impact on the waveform
+        // Sync
+        // - Sync with channel 5
+        WriteWRODCommand(
+            ipuMmioBasePtr,
+            2,
+            0,
+            1,
+            DW_GEN_0,
+            8,
+            DI_COUNTER_5_ACTIVE_CLOCK);
+    }
+
+    // Turn on channel without anti tearing
+    SetDCChannelState(DIContextPtr->IpuMmioBasePtr, PROG_CHAN_TYP_NORMAL);
+
+    // Register dump, commented out by default
+#ifdef REGISTER_DUMP
+    DumpBasicDCReg(ipuMmioBasePtr);
+#endif
+
+    status = OS_STATUS_SUCCESS;
+
+Exit:
+    return status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.h
new file mode 100644
index 000000000000..085632117367
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.h
@@ -0,0 +1,312 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _DC_H_
+#define _DC_H_
+
+#define IPU_DC_OFFSET 0x00058000
+
+// DC Registers
+#define IPU_DC_READ_CH_CONF_OFFSET              IPU_DC_OFFSET + 0x0000
+#define IPU_DC_READ_CH_ADDR_OFFSET              IPU_DC_OFFSET + 0x0004
+#define IPU_DC_RL0_CH_0_OFFSET                  IPU_DC_OFFSET + 0x0008
+#define IPU_DC_RL1_CH_0_OFFSET                  IPU_DC_OFFSET + 0x000C
+#define IPU_DC_RL2_CH_0_OFFSET                  IPU_DC_OFFSET + 0x0010
+#define IPU_DC_RL3_CH_0_OFFSET                  IPU_DC_OFFSET + 0x0014
+#define IPU_DC_RL4_CH_0_OFFSET                  IPU_DC_OFFSET + 0x0018
+#define IPU_DC_WR_CH_CONF_1_OFFSET              IPU_DC_OFFSET + 0x001C
+#define IPU_DC_WR_CH_ADDR_1_OFFSET              IPU_DC_OFFSET + 0x0020
+#define IPU_DC_RL0_CH_1_OFFSET                  IPU_DC_OFFSET + 0x0024
+#define IPU_DC_RL1_CH_1_OFFSET                  IPU_DC_OFFSET + 0x0028
+#define IPU_DC_RL2_CH_1_OFFSET                  IPU_DC_OFFSET + 0x002C
+#define IPU_DC_RL3_CH_1_OFFSET                  IPU_DC_OFFSET + 0x0030
+#define IPU_DC_RL4_CH_1_OFFSET                  IPU_DC_OFFSET + 0x0034
+#define IPU_DC_WR_CH_CONF_2_OFFSET              IPU_DC_OFFSET + 0x0038
+#define IPU_DC_WR_CH_ADDR_2_OFFSET              IPU_DC_OFFSET + 0x003C
+#define IPU_DC_RL0_CH_2_OFFSET                  IPU_DC_OFFSET + 0x0040
+#define IPU_DC_RL1_CH_2_OFFSET                  IPU_DC_OFFSET + 0x0044
+#define IPU_DC_RL2_CH_2_OFFSET                  IPU_DC_OFFSET + 0x0048
+#define IPU_DC_RL3_CH_2_OFFSET                  IPU_DC_OFFSET + 0x004C
+#define IPU_DC_RL4_CH_2_OFFSET                  IPU_DC_OFFSET + 0x0050
+#define IPU_DC_CMD_CH_CONF_3_OFFSET             IPU_DC_OFFSET + 0x0054
+#define IPU_DC_CMD_CH_CONF_4_OFFSET             IPU_DC_OFFSET + 0x0058
+#define IPU_DC_WR_CH_CONF_5_OFFSET              IPU_DC_OFFSET + 0x005C
+#define IPU_DC_WR_CH_ADDR_5_OFFSET              IPU_DC_OFFSET + 0x0060
+#define IPU_DC_RL0_CH_5_OFFSET                  IPU_DC_OFFSET + 0x0064
+#define IPU_DC_RL1_CH_5_OFFSET                  IPU_DC_OFFSET + 0x0068
+#define IPU_DC_RL2_CH_5_OFFSET                  IPU_DC_OFFSET + 0x006C
+#define IPU_DC_RL3_CH_5_OFFSET                  IPU_DC_OFFSET + 0x0070
+#define IPU_DC_RL4_CH_5_OFFSET                  IPU_DC_OFFSET + 0x0074
+#define IPU_DC_WR_CH_CONF_6_OFFSET              IPU_DC_OFFSET + 0x0078
+#define IPU_DC_WR_CH_ADDR_6_OFFSET              IPU_DC_OFFSET + 0x007C
+#define IPU_DC_RL0_CH_6_OFFSET                  IPU_DC_OFFSET + 0x0080
+#define IPU_DC_RL1_CH_6_OFFSET                  IPU_DC_OFFSET + 0x0084
+#define IPU_DC_RL2_CH_6_OFFSET                  IPU_DC_OFFSET + 0x0088
+#define IPU_DC_RL3_CH_6_OFFSET                  IPU_DC_OFFSET + 0x008C
+#define IPU_DC_RL4_CH_6_OFFSET                  IPU_DC_OFFSET + 0x0090
+#define IPU_DC_WR_CH_CONF1_8_OFFSET             IPU_DC_OFFSET + 0x0094
+#define IPU_DC_WR_CH_CONF2_8_OFFSET             IPU_DC_OFFSET + 0x0098
+#define IPU_DC_RL1_CH_8_OFFSET                  IPU_DC_OFFSET + 0x009C
+#define IPU_DC_RL2_CH_8_OFFSET                  IPU_DC_OFFSET + 0x00A0
+#define IPU_DC_RL3_CH_8_OFFSET                  IPU_DC_OFFSET + 0x00A4
+#define IPU_DC_RL4_CH_8_OFFSET                  IPU_DC_OFFSET + 0x00A8
+#define IPU_DC_RL5_CH_8_OFFSET                  IPU_DC_OFFSET + 0x00AC
+#define IPU_DC_RL6_CH_8_OFFSET                  IPU_DC_OFFSET + 0x00B0
+#define IPU_DC_WR_CH_CONF1_9_OFFSET             IPU_DC_OFFSET + 0x00B4
+#define IPU_DC_WR_CH_CONF2_9_OFFSET             IPU_DC_OFFSET + 0x00B8
+#define IPU_DC_RL1_CH_9_OFFSET                  IPU_DC_OFFSET + 0x00BC
+#define IPU_DC_RL2_CH_9_OFFSET                  IPU_DC_OFFSET + 0x00C0
+#define IPU_DC_RL3_CH_9_OFFSET                  IPU_DC_OFFSET + 0x00C4
+#define IPU_DC_RL4_CH_9_OFFSET                  IPU_DC_OFFSET + 0x00C8
+#define IPU_DC_RL5_CH_9_OFFSET                  IPU_DC_OFFSET + 0x00CC
+#define IPU_DC_RL6_CH_9_OFFSET                  IPU_DC_OFFSET + 0x00D0
+#define IPU_DC_GEN_OFFSET                       IPU_DC_OFFSET + 0x00D4
+#define IPU_DC_DISP_CONF1_0_OFFSET              IPU_DC_OFFSET + 0x00D8
+#define IPU_DC_DISP_CONF1_1_OFFSET              IPU_DC_OFFSET + 0x00DC
+#define IPU_DC_DISP_CONF1_2_OFFSET              IPU_DC_OFFSET + 0x00E0
+#define IPU_DC_DISP_CONF1_3_OFFSET              IPU_DC_OFFSET + 0x00E4
+#define IPU_DC_DISP_CONF2_0_OFFSET              IPU_DC_OFFSET + 0x00E8
+#define IPU_DC_DISP_CONF2_1_OFFSET              IPU_DC_OFFSET + 0x00EC
+#define IPU_DC_DISP_CONF2_2_OFFSET              IPU_DC_OFFSET + 0x00F0
+#define IPU_DC_DISP_CONF2_3_OFFSET              IPU_DC_OFFSET + 0x00F4
+#define IPU_DC_DI0_CONF1_OFFSET                 IPU_DC_OFFSET + 0x00F8
+#define IPU_DC_DI0_CONF2_OFFSET                 IPU_DC_OFFSET + 0x00FC
+#define IPU_DC_DI1_CONF1_OFFSET                 IPU_DC_OFFSET + 0x0100
+#define IPU_DC_DI1_CONF2_OFFSET                 IPU_DC_OFFSET + 0x0104
+#define IPU_DC_MAP_CONF_0_OFFSET                IPU_DC_OFFSET + 0x0108
+#define IPU_DC_MAP_CONF_1_OFFSET                IPU_DC_OFFSET + 0x010C
+#define IPU_DC_MAP_CONF_2_OFFSET                IPU_DC_OFFSET + 0x0110
+#define IPU_DC_MAP_CONF_3_OFFSET                IPU_DC_OFFSET + 0x0114
+#define IPU_DC_MAP_CONF_4_OFFSET                IPU_DC_OFFSET + 0x0118
+#define IPU_DC_MAP_CONF_5_OFFSET                IPU_DC_OFFSET + 0x011C
+#define IPU_DC_MAP_CONF_6_OFFSET                IPU_DC_OFFSET + 0x0120
+#define IPU_DC_MAP_CONF_7_OFFSET                IPU_DC_OFFSET + 0x0124
+#define IPU_DC_MAP_CONF_8_OFFSET                IPU_DC_OFFSET + 0x0128
+#define IPU_DC_MAP_CONF_9_OFFSET                IPU_DC_OFFSET + 0x012C
+#define IPU_DC_MAP_CONF_10_OFFSET               IPU_DC_OFFSET + 0x0130
+#define IPU_DC_MAP_CONF_11_OFFSET               IPU_DC_OFFSET + 0x0134
+#define IPU_DC_MAP_CONF_12_OFFSET               IPU_DC_OFFSET + 0x0138
+#define IPU_DC_MAP_CONF_13_OFFSET               IPU_DC_OFFSET + 0x013C
+#define IPU_DC_MAP_CONF_14_OFFSET               IPU_DC_OFFSET + 0x0140
+#define IPU_DC_MAP_CONF_15_OFFSET               IPU_DC_OFFSET + 0x0144
+#define IPU_DC_MAP_CONF_16_OFFSET               IPU_DC_OFFSET + 0x0148
+#define IPU_DC_MAP_CONF_17_OFFSET               IPU_DC_OFFSET + 0x014C
+#define IPU_DC_MAP_CONF_18_OFFSET               IPU_DC_OFFSET + 0x0150
+#define IPU_DC_MAP_CONF_19_OFFSET               IPU_DC_OFFSET + 0x0154
+#define IPU_DC_MAP_CONF_20_OFFSET               IPU_DC_OFFSET + 0x0158
+#define IPU_DC_MAP_CONF_21_OFFSET               IPU_DC_OFFSET + 0x015C
+#define IPU_DC_MAP_CONF_22_OFFSET               IPU_DC_OFFSET + 0x0160
+#define IPU_DC_MAP_CONF_23_OFFSET               IPU_DC_OFFSET + 0x0164
+#define IPU_DC_MAP_CONF_24_OFFSET               IPU_DC_OFFSET + 0x0168
+#define IPU_DC_MAP_CONF_25_OFFSET               IPU_DC_OFFSET + 0x016C
+#define IPU_DC_MAP_CONF_26_OFFSET               IPU_DC_OFFSET + 0x0170
+#define IPU_DC_UGDE0_0_OFFSET                   IPU_DC_OFFSET + 0x0174
+#define IPU_DC_UGDE0_1_OFFSET                   IPU_DC_OFFSET + 0x0178
+#define IPU_DC_UGDE0_2_OFFSET                   IPU_DC_OFFSET + 0x017C
+#define IPU_DC_UGDE0_3_OFFSET                   IPU_DC_OFFSET + 0x0180
+#define IPU_DC_UGDE1_0_OFFSET                   IPU_DC_OFFSET + 0x0184
+#define IPU_DC_UGDE1_1_OFFSET                   IPU_DC_OFFSET + 0x0188
+#define IPU_DC_UGDE1_2_OFFSET                   IPU_DC_OFFSET + 0x018C
+#define IPU_DC_UGDE1_3_OFFSET                   IPU_DC_OFFSET + 0x0190
+#define IPU_DC_UGDE2_0_OFFSET                   IPU_DC_OFFSET + 0x0194
+#define IPU_DC_UGDE2_1_OFFSET                   IPU_DC_OFFSET + 0x0198
+#define IPU_DC_UGDE2_2_OFFSET                   IPU_DC_OFFSET + 0x019C
+#define IPU_DC_UGDE2_3_OFFSET                   IPU_DC_OFFSET + 0x01A0
+#define IPU_DC_UGDE3_0_OFFSET                   IPU_DC_OFFSET + 0x01A4
+#define IPU_DC_UGDE3_1_OFFSET                   IPU_DC_OFFSET + 0x01A8
+#define IPU_DC_UGDE3_2_OFFSET                   IPU_DC_OFFSET + 0x01AC
+#define IPU_DC_UGDE3_3_OFFSET                   IPU_DC_OFFSET + 0x01B0
+#define IPU_DC_LLA0_OFFSET                      IPU_DC_OFFSET + 0x01B4
+#define IPU_DC_LLA1_OFFSET                      IPU_DC_OFFSET + 0x01B8
+#define IPU_DC_R_LLA0_OFFSET                    IPU_DC_OFFSET + 0x01BC
+#define IPU_DC_R_LLA1_OFFSET                    IPU_DC_OFFSET + 0x01C0
+#define IPU_DC_WR_CH_ADDR_5_ALT_OFFSET          IPU_DC_OFFSET + 0x01C4
+#define IPU_DC_STAT_OFFSET                      IPU_DC_OFFSET + 0x01C8
+
+// Microcode template
+#define IPU_DC_TEMPLATE_REGS_ADDR_OFFSET        0x00180000
+
+typedef enum {
+    DC_CHANNEL_READ = 0,
+    DC_CHANNEL_DC_SYNC_ASYNC = 1,
+    DC_CHANNEL_DC_ASYNC = 2,
+    DC_CHANNEL_DP_MAIN = 5,
+    DC_CHANNEL_DP_SECONDARY = 6,
+} DC_CHANNEL;
+
+#pragma pack(push, 1)
+
+// IPU_DC_WR_CH_CONF_1 0x1C
+// IPU_DC_WR_CH_CONF_5 0x5C
+typedef union {
+    struct {
+        UINT32 W_SIZE : 2;
+        UINT32 PROG_DI_ID : 1;
+        UINT32 PROG_DISP_ID : 2;
+        UINT32 PROG_CHAN_TYP : 3;
+        UINT32 CHAN_MASK_DEFAULT : 1;
+        UINT32 FILED_MODE : 1;
+        UINT32 Reserved1 : 6;
+        UINT32 PROG_START_TIME : 11;
+        UINT32 Reserved2 : 5;
+    };
+    UINT32 Reg;
+} IPU_DC_WR_CH_CONF_1_REG, IPU_DC_WR_CH_CONF_5_REG;
+
+typedef enum {
+    PROG_CHAN_TYP_DISABLED,
+    PROG_CHAN_TYP_RESERVED1,
+    PROG_CHAN_TYP_NORMAL = 4,
+    PROG_CHAN_TYP_NORMAL_ANTI_TEARING,
+    PROG_CHAN_TYP_RESERVED2,
+} PROG_CHAN_TYP;
+
+// IPU_DC_GEN 0xD4
+typedef union {
+    struct {
+        UINT32 Reserved1 : 1;
+        UINT32 Sync_1_6 : 2;
+        UINT32 Reserved2 : 1;
+        UINT32 MASK_EN : 1;
+        UINT32 MASK4CHAN_5 : 1;
+        UINT32 SYNC_PRIORITY_5 : 1;
+        UINT32 SYNC_PRIORITY_1 : 1;
+        UINT32 DC_CH5_TYPE : 1;
+        UINT32 Reserved3 : 7;
+        UINT32 DC_BKDIV : 8;
+        UINT32 DC_BK_EN : 1;
+        UINT32 Reserved4 : 7;
+    };
+    UINT32 Reg;
+} IPUx_IPU_DC_GEN_REG;
+
+// IPU_DC_RL0_CH_5 0x0064
+typedef union {
+    struct {
+        UINT32 COD_NF_PRIORITY_CHAN_5 : 4;
+        UINT32 Reserved1 : 4;
+        UINT32 COD_NF_START_CHAN_5 : 8;
+        UINT32 COD_NL_PRIORITY_CHAN_5 : 4;
+        UINT32 Reserved2 : 4;
+        UINT32 COD_NL_START_CHAN_5 : 24;
+    };
+    UINT32 Reg;
+} IPU_DC_RL0_CH_5_REG;
+
+// IPU_DC_RL1_CH_5 0x006C
+typedef union {
+    struct {
+        UINT32 COD_EOF_PRIORITY_CHAN_5 : 4;
+        UINT32 Reserved1 : 4;
+        UINT32 COD_EOF_START_CHAN_5 : 8;
+        UINT32 COD_NFIELD_PRIORITY_CHAN_5 : 4;
+        UINT32 Reserved2 : 4;
+        UINT32 COD_NFIELD_START_CHAN_5 : 24;
+    };
+    UINT32 Reg;
+} IPU_DC_RL1_CH_5_REG;
+
+// IPU_DC_RL2_CH_5 0x0068
+typedef union {
+    struct {
+        UINT32 COD_EOL_PRIORITY_CHAN_5 : 4;
+        UINT32 Reserved1 : 4;
+        UINT32 COD_EOL_START_CHAN_5 : 8;
+        UINT32 COD_EOFIELD_PRIORITY_CHAN_5 : 4;
+        UINT32 Reserved2 : 4;
+        UINT32 COD_EOFIELD_START_CHAN_5 : 24;
+    };
+    UINT32 Reg;
+} IPU_DC_RL2_CH_5_REG;
+
+// IPU_DC_RL3_CH_5 0x0070
+typedef union {
+    struct {
+        UINT32 COD_NEW_ADDR_PRIORITY_CHAN_5 : 4;
+        UINT32 Reserved1 : 4;
+        UINT32 COD_NEW_ADDR_START_CHAN_5 : 8;
+        UINT32 COD_NEW_CHAN_PRIORITY_CHAN_5 : 4;
+        UINT32 Reserved2 : 4;
+        UINT32 COD_NEW_CHAN_START_CHAN_5 : 24;
+    };
+    UINT32 Reg;
+} IPU_DC_RL3_CH_5_REG;
+
+// IPU_DC_RL4_CH_5 0x0074
+typedef union {
+    struct {
+        UINT32 COD_NEW_DATA_PRIORITY_CHAN_5 : 4;
+        UINT32 Reserved1 : 4;
+        UINT32 COD_NEW_DATA_START_CHAN_5 : 8;
+        UINT32 Reserved2 : 16;
+    };
+    UINT32 Reg;
+} IPU_DC_RL4_CH_5_REG;
+
+// DC_DISP_CONF1 0xD8 - 0xE4
+typedef union {
+    struct {
+        UINT32 DISP_TYP : 2;
+        UINT32 ADDR_INCREMENT : 2;
+        UINT32 ADDR_BE_L_INC : 2;
+        UINT32 MCU_ACC_LB_MASK_3 : 1;
+        UINT32 DISP_RD_VALUE_PTR : 1;
+        UINT32 Reserved : 24;
+    };
+    UINT32 Reg;
+} IPUx_DC_DISP_CONF1_REG;
+
+// DC_MAP_CONF_MAP_OFFSET 0x0108 - 0x0140
+typedef union {
+    struct {
+        UINT32 MAPPING_PNTR_BYTE0_X : 5;
+        UINT32 MAPPING_PNTR_BYTE1_X : 5;
+        UINT32 MAPPING_PNTR_BYTE2_X : 5;
+        UINT32 Reserved1 : 1;
+        UINT32 MAPPING_PNTR_BYTE0_Y : 5;
+        UINT32 MAPPING_PNTR_BYTE1_Y : 5;
+        UINT32 MAPPING_PNTR_BYTE2_Y : 5;
+        UINT32 Reserved2 : 1;
+    };
+    UINT32 Reg;
+} IPUx_DC_MAP_CONF_MAP_REG;
+
+// DC_MAP_CONF_OFFSET_MASK_OFFSET 0x0144 - 0x0170
+typedef union {
+    struct {
+        UINT32 MD_MASK_X : 8;
+        UINT32 MD_OFFSET_X : 5;
+        UINT32 Reserved1 : 3;
+        UINT32 MD_MASK_Y : 8;
+        UINT32 MD_OFFSET_Y : 5;
+        UINT32 Reserved2 : 3;
+    };
+    UINT32 Reg;
+} DC_MAP_CONF_OFFSET_MASK_REG;
+
+#pragma pack(pop)
+
+OS_STATUS SetDCChannelState (
+    VOID* IpuMmioBasePtr,
+    PROG_CHAN_TYP State
+    );
+
+OS_STATUS ConfigureDCChannel (
+    DISPLAY_INTERFACE_CONTEXT* DIContextPtr,
+    DISPLAY_INTERFACE DisplayInterface,
+    UINT32 DisplayIndex,
+    DISPLAY_TIMING* DisplayTimingPtr
+    );
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.c
new file mode 100644
index 000000000000..468cb4c90609
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.c
@@ -0,0 +1,444 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "Osal.h"
+
+#include "Ipu.h"
+#include "Display.h"
+#include "DisplayInterface.h"
+
+#define READ_WAVE_GEN(IPU_BASE, GEN_INDEX) \
+    DiRead32(IPU_BASE, IPU_DIx_DW_GEN_OFFSET + (GEN_INDEX * 0x4))
+
+#define WRITE_WAVE_GEN(IPU_BASE, GEN_INDEX, VALUE) \
+    DiWrite32(IPU_BASE, IPU_DIx_DW_GEN_OFFSET + (GEN_INDEX * 0x4), VALUE)
+
+#define READ_WAVE_SET(IPU_BASE, GEN_INDEX, SET_NUMBER) \
+    DiRead32(IPU_BASE, IPU_DIx_DW_SET0_OFFSET + (SET_NUMBER * 0x30) + (GEN_INDEX * 0x4))
+
+#define WRITE_WAVE_SET(IPU_BASE, GEN_INDEX, SET_NUMBER, VALUE) \
+    DiWrite32(IPU_BASE, IPU_DIx_DW_SET0_OFFSET + (SET_NUMBER * 0x30) + (GEN_INDEX * 0x4), VALUE)
+
+VOID DumpBasicDIReg (
+    VOID* IpuMmioBasePtr,
+    IPU_DIx_REGS* IpuDiRegsPtr
+    )
+{
+    UINT32 index, setNumber, regVal;
+    UINT32 printTotalGen = 8; // Limit printing (max 12)
+
+    OS_INFO("---------- DI Register Dump ----------\n");
+    // Print out generator value for D0
+    OS_INFO("## Wave Gen\n");
+    for (index = 0; index < printTotalGen; ++index) {
+        regVal = READ_WAVE_GEN(IpuDiRegsPtr, index);
+        OS_INFO("DI0_DW_GEN_%d 0x%08x\n", index, regVal);
+    }
+    // Print out generator value for D0
+    OS_INFO("## Wave Set\n");
+    for (index = 0; index < printTotalGen; ++index) {
+        for (setNumber = 0; setNumber < 4; ++setNumber) {
+            regVal = READ_WAVE_SET(IpuDiRegsPtr, index, setNumber);
+            OS_INFO("DI0_DW_SET%d_%d 0x%08x\n", setNumber, index, regVal);
+        }
+    }
+
+    regVal = IpuRead32(IpuMmioBasePtr, IPU_IPU_PM_OFFSET);
+    OS_INFO("IPU_IPU_PM_OFFSET %x\n", regVal);
+
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_BS_CLKGEN0_OFFSET);
+    OS_INFO("IPU_DIx_BS_CLKGEN0_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_BS_CLKGEN1_OFFSET);
+    OS_INFO("IPU_DIx_BS_CLKGEN1_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SCR_CONF_OFFSET);
+    OS_INFO("IPU_DIx_SCR_CONF_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN0_1_OFFSET);
+    OS_INFO("IPU_DIx_SW_GEN0_1_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN1_1_OFFSET);
+    OS_INFO("IPU_DIx_SW_GEN1_1_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN0_2_OFFSET);
+    OS_INFO("IPU_DIx_SW_GEN0_2_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN1_2_OFFSET);
+    OS_INFO("IPU_DIx_SW_GEN1_2_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN0_3_OFFSET);
+    OS_INFO("IPU_DIx_SW_GEN0_3_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN1_3_OFFSET);
+    OS_INFO("IPU_DIx_SW_GEN1_3_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN0_4_OFFSET);
+    OS_INFO("IPU_DIx_SW_GEN0_4_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN1_4_OFFSET);
+    OS_INFO("IPU_DIx_SW_GEN1_4_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN0_5_OFFSET);
+    OS_INFO("IPU_DIx_SW_GEN0_5_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN1_5_OFFSET);
+    OS_INFO("IPU_DIx_SW_GEN1_5_OFFSET %x\n", regVal);
+
+    for (index = 0; index < 5; ++index) {
+        regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_STP_REP_OFFSET +  (index * 0x4));
+        OS_INFO("IPU_DIx_STP_%d_REP_OFFSET %x\n", index + 1, regVal);
+    }
+
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_SYNC_AS_GEN_OFFSET);
+    OS_INFO("IPU_DIx_SYNC_AS_GEN_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_GENERAL_OFFSET);
+    OS_INFO("IPU_DIx_GENERAL_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_DIx_POL_OFFSET);
+    OS_INFO("IPU_DIx_POL_OFFSET %x\n", regVal);
+    regVal = DiRead32(IpuDiRegsPtr, IPU_IPU_DISP_GEN_OFFSET);
+    OS_INFO("IPU_IPU_DISP_GEN_OFFSET %x\n", regVal);
+    OS_INFO("------------------------------------\n\n");
+}
+
+VOID ConfigureSyncWave (
+    VOID* IpuMmioBasePtr,
+    IPU_DIx_REGS* IpuDiRegsPtr,
+    UINT32 CounterIndex,
+    UINT32 RunValue,
+    UINT32 RunResolution,
+    UINT32 OffsetValue,
+    UINT32 OffsetResolution,
+    UINT32 CounterPolarityGenEn,
+    UINT32 CounterAutoReload,
+    UINT32 CounterClearSelect,
+    UINT32 CounterDown,
+    UINT32 CounterPolarityTriggerSelect,
+    UINT32 CounterPolarityClearSelect,
+    UINT32 CounterUp,
+    UINT32 StepRepeat
+    )
+{
+    IPUx_DIx_SW_GEN0_x_REG diSwGen0Reg;
+    IPUx_DIx_SW_GEN1_x_REG diSwGen1Reg;
+    IPUx_DIx_STP_REP_REG stepRepeatReg;
+
+    OS_ZERO_MEM((void*)&diSwGen0Reg, sizeof(diSwGen0Reg));
+    diSwGen0Reg.dix_offset_resolution = OffsetResolution;
+    diSwGen0Reg.dix_offset_value = OffsetValue;
+    diSwGen0Reg.dix_run_resolution = RunResolution;
+    diSwGen0Reg.dix_run_value_m1 = RunValue;
+
+    DiWrite32(
+        IpuDiRegsPtr,
+        IPU_DIx_SW_GEN0_1_OFFSET + ((CounterIndex - 1) * 0x04),
+        diSwGen0Reg.Reg);
+
+    OS_ZERO_MEM((void*)&diSwGen1Reg, sizeof(diSwGen1Reg));
+    diSwGen1Reg.dix_cnt_up = CounterUp;
+    diSwGen1Reg.dix_cnt_polarity_clr_sel = CounterPolarityClearSelect;
+    diSwGen1Reg.dix_cnt_polarity_trigger_sel = CounterPolarityTriggerSelect;
+    diSwGen1Reg.dix_cnt_down = CounterDown;
+    diSwGen1Reg.dix_cnt_clr_sel = CounterClearSelect;
+    diSwGen1Reg.dix_cnt_auto_reload = CounterAutoReload;
+    diSwGen1Reg.dix_cnt_polarity_gen_en = CounterPolarityGenEn;
+
+    DiWrite32(
+        IpuDiRegsPtr,
+        IPU_DIx_SW_GEN1_1_OFFSET + ((CounterIndex - 1) * 0x04),
+        diSwGen1Reg.Reg);
+
+    {
+        UINT32 stepIndex = (CounterIndex - 1) / 2;
+
+        stepRepeatReg.Reg = IpuRead32(
+            IpuMmioBasePtr,
+            IPU_DI0_STP_REP_OFFSET + (stepIndex * 0x4));
+
+        if (CounterIndex % 2) {
+            stepRepeatReg.dix_step_repeat_2i_minus_1 = StepRepeat;
+        } else {
+            stepRepeatReg.dix_step_repeat_2i = StepRepeat;
+        }
+
+        IpuWrite32(
+            IpuMmioBasePtr,
+            IPU_DI0_STP_REP_OFFSET + (stepIndex * 0x4),
+            stepRepeatReg.Reg);
+    }
+}
+
+OS_STATUS ConfigureDI (
+    DISPLAY_INTERFACE_CONTEXT* DIContextPtr,
+    UINT32 DisplayIndex,
+    DISPLAY_TIMING* DisplayTimingPtr
+    )
+{
+    OS_STATUS status;
+    UINT32 baseDiv;
+    UINT64 diFreq = DisplayTimingPtr->PixelClock;
+    UINT32 hTotal = DisplayTimingPtr->HActive + DisplayTimingPtr->HBlank;
+    UINT32 vTotal = DisplayTimingPtr->VActive + DisplayTimingPtr->VBlank;
+    VOID* ipuMmioBasePtr = DIContextPtr->IpuMmioBasePtr;
+    IPU_DIx_REGS* ipuDiRegsPtr = DIContextPtr->IpuDiRegsPtr;
+
+    status = ImxSetPll5ReferenceRate(DisplayTimingPtr->PixelClock);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_ERROR("Fail to setup PLL5=%r\n", status);
+        goto Exit;
+    }
+
+    // Setup base timer (fundamental timer). The base timer should already
+    // setup to match the pixel clock frequency.
+    // Shift 4 as the bottom 4 bits are fractional
+    baseDiv = (UINT32)((diFreq << 4) / DisplayTimingPtr->PixelClock);
+
+    DiWrite32(ipuDiRegsPtr, IPU_DIx_BS_CLKGEN0_OFFSET, baseDiv);
+
+    // Up is always set to 0. Down is half of the pixel clock period where
+    // the first bit is fraction
+    baseDiv >>= 4;
+
+    DiWrite32(ipuDiRegsPtr, IPU_DIx_BS_CLKGEN1_OFFSET, baseDiv << 16);
+    // Calculate divisor, again this would usually be 1.
+    baseDiv = (UINT32)(diFreq / DisplayTimingPtr->PixelClock);
+
+    // Set up wave, there 12 wave quartet, for now default to the first.
+    // Each wave quartet has 4 set register
+    {
+        IPUx_DIx_DW_SET_REG dixDwSetReg;
+        IPUx_DIx_DW_GEN_REG dixDwGenReg;
+
+        // Set 0 is just a blank signal where up and down is set to 0
+        OS_ZERO_MEM((void*)&dixDwSetReg, sizeof(dixDwSetReg));
+        dixDwSetReg.dix_data_cnt_upx_i = 0;
+        dixDwSetReg.dix_data_cnt_downx_i = 0;
+        WRITE_WAVE_SET(
+            ipuDiRegsPtr,
+            DW_GEN_0,
+            DW_SET_0,
+            dixDwSetReg.Reg);
+
+        // Set 3 is setup to match pixel clock
+        OS_ZERO_MEM((void*)&dixDwSetReg, sizeof(dixDwSetReg));
+        dixDwSetReg.dix_data_cnt_upx_i = 0;
+        dixDwSetReg.dix_data_cnt_downx_i = baseDiv * 2;
+        WRITE_WAVE_SET(
+            ipuDiRegsPtr,
+            DW_GEN_0,
+            DW_SET_3,
+            dixDwSetReg.Reg);
+
+        // All pins blank signal except pin 15
+        // Need to get pin mapping documentation
+        OS_ZERO_MEM((void*)&dixDwGenReg, sizeof(dixDwGenReg));
+        dixDwGenReg.dix_pt_0_i = DW_SET_0;
+        dixDwGenReg.dix_pt_1_i = DW_SET_0;
+        dixDwGenReg.dix_pt_2_i = DW_SET_0;
+        dixDwGenReg.dix_pt_3_i = DW_SET_0;
+        dixDwGenReg.dix_pt_4_i = DW_SET_3;
+        dixDwGenReg.dix_pt_5_i = DW_SET_0;
+        dixDwGenReg.dix_pt_6_i = DW_SET_0;
+        dixDwGenReg.dix_cst_i = DW_SET_0;
+
+        // Reuse the base divisor to determine extra IPU cycles.
+        dixDwGenReg.dix_componnent_size_i = dixDwGenReg.dix_access_size_i =
+            baseDiv - 1;
+        WRITE_WAVE_GEN(ipuDiRegsPtr, DW_GEN_0, dixDwGenReg.Reg);
+    }
+
+    // Spec mention this as number of display rows but display only works
+    // proper if this is setup as vertical total
+    DiWrite32(ipuDiRegsPtr, IPU_DIx_SCR_CONF_OFFSET, vTotal - 1);
+
+    {
+        // Internal HSYNC
+        ConfigureSyncWave(
+            ipuMmioBasePtr,
+            ipuDiRegsPtr,
+            DI_COUNTER_1_INTERNAL_HSYNC, // CounterIndex
+            hTotal - 1,   // Runvalue
+            DI_COUNTER_0_DISPLAY_CLOCK + 1, // RunResolution
+            0,            // OffsetValue
+            0,            // OffsetResolution
+            0,            // CounterPolarityGenEn
+            1,            // CounterAutoReload
+            DI_COUNTER_DISABLED, // CounterClearSelect
+            0,            // CountDown
+            0,            // CounterPolarityTriggerSelect
+            0,            // CounterPolarityClearSelect
+            0,            // CounterUp
+            0);           // StepRepeat
+
+        // Output HSYNC
+        ConfigureSyncWave(
+            ipuMmioBasePtr,
+            ipuDiRegsPtr,
+            DI_COUNTER_2_OUTPUT_HSYNC, // CounterIndex
+            hTotal - 1,   // Runvalue
+            DI_COUNTER_0_DISPLAY_CLOCK + 1, // RunResolution
+            0,            // OffsetValue
+            DI_COUNTER_0_DISPLAY_CLOCK + 1, // OffsetResolution - Display clock
+            1,            // CounterPolarityGenEn
+            1,            // CounterAutoReload
+            DI_COUNTER_DISABLED, // CounterClearSelect
+            DisplayTimingPtr->HSync * 2,    // CountDown
+            1,            // CounterPolarityTriggerSelect
+            0,            // CounterPolarityClearSelect
+            0,            // CounterUp
+            0);           // StepRepeat
+
+        // Output VSYNC
+        ConfigureSyncWave(
+            ipuMmioBasePtr,
+            ipuDiRegsPtr,
+            DI_COUNTER_3_OUTPUT_VSYNC, // CounterIndex
+            vTotal - 1,   // Runvalue
+            DI_COUNTER_1_INTERNAL_HSYNC + 1, // RunResolution - Counter 1
+            0,            // OffsetValue
+            0,            // OffsetResolution
+            1,            // CounterPolarityGenEn
+            1,            // CounterAutoReload
+            DI_COUNTER_DISABLED, // CounterClearSelect
+            DisplayTimingPtr->VSync * 2,    // CountDown
+            2,            // CounterPolarityTriggerSelect
+            0,            // CounterPolarityClearSelect
+            0,            // CounterUp
+            0);           // StepRepeat
+
+        // Active lines
+        ConfigureSyncWave(
+            ipuMmioBasePtr,
+            ipuDiRegsPtr,
+            DI_COUNTER_4_ACTIVE_LINE , // CounterIndex
+            0,            // Runvalue
+            DI_COUNTER_2_OUTPUT_HSYNC + 1, // RunResolution - Counter 2
+            DisplayTimingPtr->VSync + DisplayTimingPtr->VSyncOffset, // Offset
+            DI_COUNTER_2_OUTPUT_HSYNC + 1,// OffsetResolution - Counter 2
+            0,            // CounterPolarityGenEn
+            0,            // CounterAutoReload
+            DI_COUNTER_3_OUTPUT_VSYNC + 1, // CounterClearSelect - Counter 3
+            0,            // CountDown
+            0,            // CounterPolarityTriggerSelect
+            0,            // CounterPolarityClearSelect
+            0,            // CounterUp
+            DisplayTimingPtr->VActive); // StepRepeat repeat for total VActive
+
+        // Active clock
+        ConfigureSyncWave(
+            ipuMmioBasePtr,
+            ipuDiRegsPtr,
+            DI_COUNTER_5_ACTIVE_CLOCK, // CounterIndex
+            0,            // Runvalue
+            DI_COUNTER_0_DISPLAY_CLOCK + 1, // RunResolution - Display clock
+            DisplayTimingPtr->HSync + DisplayTimingPtr->HSyncOffset, // Offset
+            DI_COUNTER_0_DISPLAY_CLOCK + 1, // OffsetResolution - Display clock
+            0,            // CounterPolarityGenEn
+            0,            // CounterAutoReload
+            DI_COUNTER_4_ACTIVE_LINE + 1, // CounterClearSelect - Counter 4
+            0,            // CountDown
+            0,            // CounterPolarityTriggerSelect
+            0,            // CounterPolarityClearSelect
+            0,            // CounterUp
+            DisplayTimingPtr->HActive); // StepRepeat
+    }
+
+    {
+        IPUx_DIx_SYNC_AS_GEN_REG dixSyncAsGenReg;
+
+        OS_ZERO_MEM((void*)&dixSyncAsGenReg, sizeof(dixSyncAsGenReg));
+        // VSYNC is setup as counter 3 above, 0 index based
+        dixSyncAsGenReg.dix_vsync_sel = 3 - 1;
+        // Number of row DI prepares next frame data.
+        // This seem to be the default value.
+        dixSyncAsGenReg.dix_sync_start = 2;
+        DiWrite32(ipuDiRegsPtr, IPU_DIx_SYNC_AS_GEN_OFFSET, dixSyncAsGenReg.Reg);
+    }
+
+    // Setup general register
+    {
+        IPUx_DIx_GENERAL_REG dixGeneralReg;
+
+        OS_ZERO_MEM((void*)&dixGeneralReg, sizeof(dixGeneralReg));
+        // Counter 1 as display line
+        dixGeneralReg.dix_disp_y_sel = DI_COUNTER_1_INTERNAL_HSYNC - 1;
+        // Stop at the next edge of the display clock
+        dixGeneralReg.DIx_CLOCK_STOP_MODE = 0;
+        // The display's clock is stopped after the next VSYNC
+        dixGeneralReg.DIx_DISP_CLOCK_INIT = 0;
+        // IPP_PIN_2 is coming from counter #2
+        dixGeneralReg.dix_mask_sel = 0;
+        // External clock - for not the video PLL
+        dixGeneralReg.dix_vsync_ext = 1;
+        // External clock - for not the video PLL
+        dixGeneralReg.dix_clk_ext = 1;
+        // 4 cycle watch dog based on BSP
+        dixGeneralReg.DIx_WATCHDOG_MODE = 0;
+        // default sync to counter 0
+        dixGeneralReg.dix_sync_count_sel = DI_COUNTER_1_INTERNAL_HSYNC - 1;
+        // In the event of error drive the last component
+        dixGeneralReg.dix_err_treatment = 0;
+        // An internal VSYNC signal asserted 2 lines before the DI's VSYNC
+        dixGeneralReg.dix_erm_vsync_sel = 0;
+
+        switch(DIContextPtr->displayInterface)
+        {
+            case HDMI_DISPLAY:
+                // Zero for HDMI display
+                dixGeneralReg.dix_polarity_disp_clk = 0;
+                dixGeneralReg.dix_polarity_cs1 = 0;
+                dixGeneralReg.dix_polarity_cs0 = 0;
+                dixGeneralReg.dix_polarity_i_1 = 0;
+                break;
+            default:
+                status = OS_STATUS_UNSUPPORTED;
+                OS_ERROR(
+                    "Unsupported display interface %d",
+                    DIContextPtr->displayInterface);
+                goto Exit;
+        }
+
+        DiWrite32(ipuDiRegsPtr, IPU_DIx_GENERAL_OFFSET, dixGeneralReg.Reg);
+    }
+
+    {
+        IPUx_DIx_POL_REG dixPolReg;
+
+        OS_ZERO_MEM((void*)&dixPolReg, sizeof(dixPolReg));
+        // CS0
+        dixPolReg.DIx_CS0_DATA_POLARITY = 1;
+        dixPolReg.dix_cs0_polarity = 0x7F;
+        // CS1
+        dixPolReg.DIx_CS1_DATA_POLARITY = 1;
+        dixPolReg.dix_cs1_polarity = 0x7F;
+        // DRDY
+        dixPolReg.DIx_DRDY_DATA_POLARITY = 0;
+        dixPolReg.dix_drdy_polarity = 0x7F;
+        // Wait
+        dixPolReg.DIx_WAIT_POLARITY = 0;
+        // CS0 byte enable polarity
+        dixPolReg.DIx_CS0_BYTE_EN_POLARITY = 0;
+        // CS1 byte enable polarity
+        dixPolReg.DIx_CS1_BYTE_EN_POLARITY = 0;
+
+        DiWrite32(ipuDiRegsPtr, IPU_DIx_POL_OFFSET, dixPolReg.Reg);
+    }
+
+    {
+        UINT32 dispGenReg;
+
+        dispGenReg = IpuRead32(ipuMmioBasePtr, IPU_IPU_DISP_GEN_OFFSET);
+        dispGenReg &= ~(0x0F << 18);
+        dispGenReg |= (2 << 18);
+        IpuWrite32(ipuMmioBasePtr, IPU_IPU_DISP_GEN_OFFSET, dispGenReg);
+    }
+
+    // Register dump, commented out by default
+#ifdef REGISTER_DUMP
+    DumpBasicDIReg(ipuMmioBasePtr, ipuDiRegsPtr);
+#endif
+
+    status = OS_STATUS_SUCCESS;
+
+Exit:
+    return status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.h
new file mode 100644
index 000000000000..0c8ede1e8fde
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.h
@@ -0,0 +1,182 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _DI_H_
+#define _DI_H_
+
+OS_STATUS ConfigureDI (
+    DISPLAY_INTERFACE_CONTEXT* DIContextPtr,
+    UINT32 DisplayIndex,
+    DISPLAY_TIMING* DisplayTimingPtr
+    );
+
+enum {
+    DW_GEN_0 = 0,
+    DW_GEN_1 = 1,
+    DW_GEN_2 = 2,
+    DW_GEN_3 = 3,
+    DW_GEN_4 = 4,
+    DW_GEN_5 = 5,
+    DW_GEN_6 = 6,
+    DW_GEN_7 = 7,
+    DW_GEN_8 = 8,
+    DW_GEN_9 = 9,
+    DW_GEN_10 = 10,
+    DW_GEN_11 = 11,
+};
+
+enum {
+    DW_SET_0 = 0,
+    DW_SET_1 = 1,
+    DW_SET_2 = 2,
+    DW_SET_3 = 3,
+};
+
+enum {
+    DI_COUNTER_DISABLED = 0,
+    DI_COUNTER_0_DISPLAY_CLOCK = 0,
+    DI_COUNTER_1_INTERNAL_HSYNC = 1,
+    DI_COUNTER_2_OUTPUT_HSYNC = 2,
+    DI_COUNTER_3_OUTPUT_VSYNC = 3,
+    DI_COUNTER_4_ACTIVE_LINE = 4,
+    DI_COUNTER_5_ACTIVE_CLOCK = 5,
+};
+
+#pragma pack(push, 1)
+
+// IPUx_DIx_GENERAL
+typedef union {
+    struct {
+        UINT32 dix_polarity_i_1 : 8;
+        UINT32 dix_polarity_cs0 : 1;
+        UINT32 dix_polarity_cs1 : 1;
+        UINT32 dix_erm_vsync_sel : 1;
+        UINT32 dix_err_treatment : 1;
+        UINT32 dix_sync_count_sel : 4;
+        UINT32 Reserved : 1;
+        UINT32 dix_polarity_disp_clk : 1;
+        UINT32 DIx_WATCHDOG_MODE : 2;
+        UINT32 dix_clk_ext : 1;
+        UINT32 dix_vsync_ext : 1;
+        UINT32 dix_mask_sel : 1;
+        UINT32 DIx_DISP_CLOCK_INIT : 1;
+        UINT32 DIx_CLOCK_STOP_MODE : 4;
+        UINT32 dix_disp_y_sel : 3;
+        UINT32 dix_pin8_pin15_sel : 1;
+    };
+    UINT32 Reg;
+} IPUx_DIx_GENERAL_REG;
+
+// IPUx_DIx_SYNC_AS_GEN
+typedef union {
+    struct {
+        UINT32 dix_sync_start : 12;
+        UINT32 Reserved1 : 1;
+        UINT32 dix_vsync_sel : 3;
+        UINT32 Reserved2 : 12;
+        UINT32 di0_sync_start_en : 1;
+        UINT32 Reserved3 : 3;
+    };
+    UINT32 Reg;
+} IPUx_DIx_SYNC_AS_GEN_REG;
+
+// IPUx_DIx_DW_SET
+typedef union {
+    struct {
+        UINT32 dix_data_cnt_upx_i : 9;
+        UINT32 Reserved1 : 7;
+        UINT32 dix_data_cnt_downx_i : 9;
+        UINT32 Reserved2 : 7;
+    };
+    UINT32 Reg;
+} IPUx_DIx_DW_SET_REG;
+
+// IPUx_DIx_DW_GEN
+typedef union {
+    struct {
+        UINT32 dix_pt_0_i : 2;  // Pin 11
+        UINT32 dix_pt_1_i : 2;  // Pin 12
+        UINT32 dix_pt_2_i : 2;  // Pin 13
+        UINT32 dix_pt_3_i : 2;  // Pin 14
+        UINT32 dix_pt_4_i : 2;  // Pin 15
+        UINT32 dix_pt_5_i : 2;  // Pin 16
+        UINT32 dix_pt_6_i : 2;  // Pin 17
+        UINT32 dix_cst_i : 2;   // Chip Select
+        UINT32 dix_componnent_size_i : 8;
+        UINT32 dix_access_size_i : 8;
+    };
+    UINT32 Reg;
+} IPUx_DIx_DW_GEN_REG;
+
+
+// IPUx_DIx_SW_GEN0_x_REG
+typedef union {
+    struct {
+        UINT32 dix_offset_resolution : 3;
+        UINT32 dix_offset_value : 12;
+        UINT32 Reserved1: 1;
+        UINT32 dix_run_resolution : 3;
+        UINT32 dix_run_value_m1 : 12;
+        UINT32 Reserved2 : 1;
+    };
+    UINT32 Reg;
+} IPUx_DIx_SW_GEN0_x_REG;
+
+// IPUx_DIx_SW_GEN1_x_REG
+typedef union {
+    struct {
+        UINT32 dix_cnt_up : 9;
+        UINT32 dix_cnt_polarity_clr_sel : 3;
+        UINT32 dix_cnt_polarity_trigger_sel : 3;
+        UINT32 Reserved1 : 1;
+        UINT32 dix_cnt_down: 9;
+        UINT32 dix_cnt_clr_sel : 3;
+        UINT32 dix_cnt_auto_reload : 1;
+        UINT32 dix_cnt_polarity_gen_en : 2;
+        UINT32 Reserved2 : 1;
+    };
+    UINT32 Reg;
+} IPUx_DIx_SW_GEN1_x_REG;
+
+// IPUx_DIx_STP_REP
+typedef union {
+    struct {
+        UINT32 dix_step_repeat_2i_minus_1 : 12;
+        UINT32 Reserved1 : 4;
+        UINT32 dix_step_repeat_2i : 12;
+        UINT32 Reserved2 : 4;
+    };
+    UINT32 Reg;
+} IPUx_DIx_STP_REP_REG;
+
+// IPUx_DIx_POL
+typedef union {
+    struct {
+        UINT32 dix_drdy_polarity : 7;
+        UINT32 DIx_DRDY_DATA_POLARITY : 1;
+        UINT32 dix_cs0_polarity : 7;
+        UINT32 DIx_CS0_DATA_POLARITY : 1;
+        UINT32 dix_cs1_polarity : 7;
+        UINT32 DIx_CS1_DATA_POLARITY : 1;
+        UINT32 DIx_CS0_BYTE_EN_POLARITY : 1;
+        UINT32 DIx_CS1_BYTE_EN_POLARITY : 1;
+        UINT32 DIx_WAIT_POLARITY : 1;
+        UINT32 Reserved : 5;
+    };
+    UINT32 Reg;
+} IPUx_DIx_POL_REG;
+
+#pragma pack(pop)
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.c
new file mode 100644
index 000000000000..85f8bd137963
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.c
@@ -0,0 +1,82 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "Osal.h"
+#include <iMXDisplay.h>
+#include "Display.h"
+#include "Edid.h"
+#include "Ddc.h"
+
+OS_STATUS ReadEDID (
+    DISPLAY_CONTEXT* DisplayContextPtr,
+    DISPLAY_INTERFACE DisplayInterface,
+    UINT8* EdidDataPtr,
+    UINT32* EdidDataSizePtr)
+{
+    OS_STATUS status;
+
+    status = IMX6DDCRead(
+        DisplayContextPtr,
+        DisplayInterface,
+        EDID_I2C_ADDRESS,
+        0,
+        EDID_MIN_SIZE,
+        EdidDataPtr);
+    if (status != OS_STATUS_SUCCESS) {
+        goto Exit;
+    }
+
+    status = ValidateEdidData(
+        EdidDataPtr);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_WARNING("Invalid EDID data\n");
+        goto Exit;
+    }
+
+    OS_INFO("EDID initialized\n");
+
+    *EdidDataSizePtr = EDID_MIN_SIZE;
+
+Exit:
+    return status;
+}
+
+OS_STATUS GetEDIDPreferedTiming (
+    UINT8* EdidDataPtr,
+    UINT32 EdidDataSizePtr,
+    DISPLAY_TIMING* PreferedTiming
+)
+{
+    OS_STATUS status;
+    DETAILED_TIMING_DESCRIPTOR* edidPreferedtiming;
+
+    if (EdidDataSizePtr < EDID_MIN_SIZE) {
+        OS_WARNING("Insufficient EDID data\n");
+        status = OS_STATUS_INVALID_PARAM;
+        goto Exit;
+    }
+
+    edidPreferedtiming =
+        (DETAILED_TIMING_DESCRIPTOR*)&EdidDataPtr[EDID_DTD_1_OFFSET];
+
+    status = ConvertDTDToDisplayTiming(edidPreferedtiming, PreferedTiming);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_ERROR("Conversion to display timing failed\n");
+        goto Exit;
+    }
+
+Exit:
+
+    return status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.h
new file mode 100644
index 000000000000..578f938a304d
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.h
@@ -0,0 +1,31 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _EDID_H_
+#define _EDID_H_
+
+OS_STATUS ReadEDID (
+    DISPLAY_CONTEXT* DisplayContextPtr,
+    DISPLAY_INTERFACE DisplayInterface,
+    UINT8* EdidDataPtr,
+    UINT32* EdidDataSizePtr
+    );
+
+OS_STATUS GetEDIDPreferedTiming (
+    UINT8* EdidDataPtr,
+    UINT32 EdidDataSizePtr,
+    DISPLAY_TIMING* PreferedTiming
+    );
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.c
new file mode 100644
index 000000000000..91901ea42b02
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.c
@@ -0,0 +1,608 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "Osal.h"
+
+#include "Display.h"
+#include "Hdmi.h"
+#include "Edid.h"
+
+PLL_MPLL_CONFIG PllMpllGenericConfigSetting[] = {
+    { 13500000,2,8,{ { 3,0,3,3,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 0,0,0, } },  },
+    { 13500000,2,10,{ { 1,4,3,3,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 0,0,0, } },  },
+    { 13500000,2,12,{ { 2,4,3,3,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 0,0,0, } },  },
+    { 13500000,2,16,{ { 3,1,3,2,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 1,0,0, } },  },
+    { 13500000,4,8,{ { 3,1,3,2,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 1,0,0, } },  },
+    { 13500000,4,10,{ { 1,5,3,2,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 1,0,0, } },  },
+    { 13500000,4,12,{ { 2,5,3,2,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 1,0,0, } },  },
+    { 13500000,4,16,{ { 3,2,3,1,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 2,0,0, } },  },
+    { 18000000,3,8,{ { 2,1,3,2,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 1,0,0, } },  },
+    { 18000000,3,16,{ { 2,2,3,1,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 2,0,0, } },  },
+    { 24175000,1,8,{ { 0,0,3,3,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 0,0,0, } },  },
+    { 24175000,1,10,{ { 1,0,3,3,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 0,0,0, } },  },
+    { 24175000,1,12,{ { 2,0,3,3,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 0,0,0, } },  },
+    { 24175000,1,16,{ { 3,0,2,2,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 1,1,0, } },  },
+    { 27000000,1,8,{ { 0,0,3,3,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 0,0,0, } },  },
+    { 27000000,1,10,{ { 1,0,3,3,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 0,0,0, } },  },
+    { 27000000,1,12,{ { 2,0,3,3,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 0,0,0, } },  },
+    { 27000000,1,16,{ { 3,0,2,2,0,0,3,0, } }, { { 4,3,5,4,0, } }, { { 1,0,0, } },  },
+    { 27000000,2,8,{ { 3,0,2,2,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 1,1,0, } },  },
+    { 27000000,2,10,{ { 1,1,3,2,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 1,0,0, } },  },
+    { 27000000,2,12,{ { 2,1,3,2,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 1,0,0, } },  },
+    { 27000000,2,16,{ { 3,1,2,1,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 2,1,0, } },  },
+    { 27000000,4,8,{ { 3,1,2,1,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 2,1,0, } },  },
+    { 27000000,4,10,{ { 1,2,3,1,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 2,0,0, } },  },
+    { 27000000,4,12,{ { 2,2,3,1,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 2,0,0, } },  },
+    { 27000000,4,16,{ { 3,2,2,0,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 3,1,0, } },  },
+    { 36000000,1,8,{ { 0,0,3,3,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 0,0,0, } },  },
+    { 36000000,1,16,{ { 3,0,2,2,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 1,1,0, } },  },
+    { 50350000,1,8,{ { 0,0,2,2,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 1,1,0, } },  },
+    { 50350000,1,10,{ { 1,0,2,2,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 1,1,0, } },  },
+    { 50350000,1,12,{ { 2,0,2,2,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 1,1,0, } },  },
+    { 50350000,1,16,{ { 3,0,1,1,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 50350000,2,8,{ { 3,0,1,1,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 50350000,2,10,{ { 1,1,2,1,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 2,1,0, } },  },
+    { 50350000,2,12,{ { 2,1,2,1,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 2,1,0, } },  },
+    { 50350000,2,16,{ { 3,1,1,0,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 3,2,0, } },  },
+    { 54000000,1,8,{ { 0,0,2,2,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 1,1,0, } },  },
+    { 54000000,1,10,{ { 1,0,2,2,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 1,1,0, } },  },
+    { 54000000,1,12,{ { 2,0,2,2,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 1,1,0, } },  },
+    { 54000000,1,16,{ { 3,0,1,1,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 54000000,2,8,{ { 3,0,1,1,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 54000000,2,10,{ { 1,1,2,1,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 2,1,0, } },  },
+    { 54000000,2,12,{ { 2,1,2,1,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 2,1,0, } },  },
+    { 54000000,2,16,{ { 3,1,1,0,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 3,2,0, } },  },
+    { 58400000,1,8,{ { 0,0,2,2,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 1,1,0, } },  },
+    { 58400000,1,10,{ { 1,0,2,2,0,0,1,0, } }, { { 4,3,3,3,0, } }, { { 1,1,0, } },  },
+    { 58400000,1,12,{ { 2,0,2,2,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 1,1,0, } },  },
+    { 58400000,1,16,{ { 3,0,1,1,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 72000000,1,8,{ { 0,0,2,2,0,0,0,0, } }, { { 4,3,3,3,0, } }, { { 1,1,0, } },  },
+    { 72000000,1,10,{ { 1,0,2,2,0,0,1,0, } }, { { 4,3,3,3,0, } }, { { 1,1,0, } },  },
+    { 72000000,1,12,{ { 2,0,1,1,0,0,2,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 72000000,1,16,{ { 3,0,1,1,0,0,3,0, } }, { { 4,3,3,3,0, } }, { { 2,2,0, } },  },
+    { 74250000,1,8,{ { 0,0,2,2,0,0,0,0, } }, { { 4,3,3,3,0, } }, { { 1,1,0, } },  },
+    { 74250000,1,10,{ { 1,0,1,1,0,0,1,0, } }, { { 4,3,5,5,0, } }, { { 2,2,0, } },  },
+    { 74250000,1,12,{ { 2,0,1,1,0,0,2,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 74250000,1,16,{ { 3,0,1,1,0,0,3,0, } }, { { 4,3,3,3,0, } }, { { 2,2,0, } },  },
+    { 108000000,1,8,{ { 0,0,1,1,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 108000000,1,10,{ { 1,0,1,1,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 108000000,1,12,{ { 2,0,1,1,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 2,2,0, } },  },
+    { 108000000,1,16,{ { 3,0,0,0,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 3,3,0, } },  },
+    { 118800000,1,8,{ { 0,0,1,1,0,0,0,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 118800000,1,10,{ { 1,0,1,1,0,0,1,0, } }, { { 4,3,4,4,0, } }, { { 2,2,0, } },  },
+    { 118800000,1,12,{ { 2,0,1,1,0,0,2,0, } }, { { 4,3,3,3,0, } }, { { 2,2,0, } },  },
+    { 118800000,1,16,{ { 3,0,0,0,0,0,3,0, } }, { { 4,3,4,4,0, } }, { { 3,3,0, } },  },
+    { 144000000,1,8,{ { 0,0,1,1,0,0,0,0, } }, { { 4,3,3,3,0, } }, { { 2,2,0, } },  },
+    { 144000000,1,10,{ { 1,0,0,0,0,0,1,0, } }, { { 4,3,5,5,0, } }, { { 3,3,0, } },  },
+    { 144000000,1,12,{ { 2,0,0,0,0,0,2,0, } }, { { 4,3,4,4,0, } }, { { 3,3,0, } },  },
+    { 144000000,1,16,{ { 3,0,0,0,0,0,3,0, } }, { { 4,3,3,3,0, } }, { { 3,3,0, } },  },
+    { 148500000,1,8,{ { 0,0,1,1,0,0,0,0, } }, { { 4,3,3,3,0, } }, { { 2,2,0, } },  },
+    { 148500000,1,10,{ { 1,0,0,0,0,0,1,0, } }, { { 4,3,5,5,0, } }, { { 3,3,0, } },  },
+    { 148500000,1,12,{ { 2,0,0,0,0,0,2,0, } }, { { 4,3,4,4,0, } }, { { 3,3,0, } },  },
+    { 148500000,1,16,{ { 3,0,0,0,0,0,3,0, } }, { { 4,3,3,3,0, } }, { { 3,3,0, } },  },
+    { 216000000,1,8,{ { 0,0,1,1,0,0,0,0, } }, { { 4,3,3,3,0, } }, { { 2,2,0, } },  },
+    { 216000000,1,10,{ { 1,0,0,0,0,0,1,0, } }, { { 4,3,5,5,0, } }, { { 3,3,0, } },  },
+    { 216000000,1,12,{ { 2,0,0,0,0,0,2,0, } }, { { 4,3,4,4,0, } }, { { 3,3,0, } },  },
+    // Fallback
+    { 65000000,1,8,{ { 0,0,1,1,0,0,0,0, } },{ { 4,3,3,3,0, } },{ { 2,2,0, } }, },
+};
+
+BOOLEAN HDMIPhyPollI2CDone (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    UINT32 TimeOut
+    )
+{
+    BOOLEAN waitResult = FALSE;
+    HDMI_IH_I2CMPHY_STAT0_REG I2cMPhyStat0Reg;
+
+    do {
+        I2cMPhyStat0Reg.Reg = HDMIRead8(HDMI_IH_I2CMPHY_STAT0);
+        if (I2cMPhyStat0Reg.i2cmphydone)
+        {
+            waitResult = TRUE;
+            break;
+        }
+
+        if (--TimeOut == 0)
+        {
+            break;
+        }
+
+        OS_SLEEP(1);
+    } while (I2cMPhyStat0Reg.i2cmphydone == 0);
+
+#if DBG
+    if ((TimeOut == 0) || (I2cMPhyStat0Reg.i2cmphyerror == 1)) {
+        OS_ERROR(
+            "HDMI I2C failed value %x time out %d\n",
+            I2cMPhyStat0Reg.Reg,
+            TimeOut));
+    }
+#endif
+
+    return waitResult;
+}
+
+BOOLEAN HDMIPhyI2cRead (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    UINT8 Addr,
+    UINT16* DataPtr
+    )
+{
+    BOOLEAN readStatus;
+    UINT16 data0, data1;
+    HDMI_IH_I2CMPHY_STAT0_REG I2cmPhyStat0Reg = { { 1, 1, 0 } };
+
+    HDMIWrite8(HDMI_IH_I2CMPHY_STAT0, I2cmPhyStat0Reg.Reg);
+    HDMIWrite8(HDMI_PHY_I2CM_ADDRESS_ADDR, Addr);
+
+    {
+        HDMI_PHY_I2CM_OPERATION_ADDR_REG I2cmOperationReg;
+
+        I2cmOperationReg.Reg = HDMIRead8(HDMI_PHY_I2CM_OPERATION_ADDR);
+        I2cmOperationReg.read = 1;
+        HDMIWrite8(HDMI_PHY_I2CM_OPERATION_ADDR, I2cmOperationReg.Reg);
+    }
+
+    readStatus = HDMIPhyPollI2CDone(HdmiDisplayContextPtr, 1000);
+    if (!readStatus) {
+        OS_ERROR("Fail to read I2c HDMI Phy\n");
+        goto Exit;
+    }
+
+    data0 = HDMIRead8(HDMI_PHY_I2CM_DATAI_0_ADDR);
+    data1 = HDMIRead8(HDMI_PHY_I2CM_DATAI_1_ADDR);
+
+    *DataPtr = data0 | (data1 << 8);
+
+Exit:
+    return readStatus;
+}
+
+BOOLEAN HDMIPhyI2cWrite (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    UINT8 Addr,
+    UINT16 Data
+    )
+{
+    UINT8 data1 = (Data >> 8);
+    UINT8 data0 = (Data & 0x00FF);
+    HDMI_IH_I2CMPHY_STAT0_REG I2cmPhyStat0Reg = { { 1, 1, 0 } };
+
+    HDMIWrite8(HDMI_IH_I2CMPHY_STAT0, I2cmPhyStat0Reg.Reg);
+    HDMIWrite8(HDMI_PHY_I2CM_ADDRESS_ADDR, Addr);
+    HDMIWrite8(HDMI_PHY_I2CM_DATAO_0_ADDR, data0);
+    HDMIWrite8(HDMI_PHY_I2CM_DATAO_1_ADDR, data1);
+
+    {
+        HDMI_PHY_I2CM_OPERATION_ADDR_REG I2cmOperationReg = { { 0, 0, 0, 0 } };
+
+        I2cmOperationReg.write = 1;
+        HDMIWrite8(HDMI_PHY_I2CM_OPERATION_ADDR, I2cmOperationReg.Reg);
+    }
+
+    return HDMIPhyPollI2CDone(HdmiDisplayContextPtr, 1000);
+}
+
+BOOLEAN GetGenericConfigSetting (
+    DISPLAY_TIMING* DisplayTimingPtr,
+    PLL_MPLL_CONFIG** ConfigGenericSettingPPtr
+    )
+{
+    BOOLEAN foundConfig = FALSE;
+    UINT32 settingIndex;
+
+    for (settingIndex = 0;
+         settingIndex < ARRAYSIZE(PllMpllGenericConfigSetting);
+        ++settingIndex) {
+
+        if ((DisplayTimingPtr->PixelClock ==
+                PllMpllGenericConfigSetting[settingIndex].PixelClock) &&
+            (DisplayTimingPtr->PixelRepetition ==
+                PllMpllGenericConfigSetting[settingIndex].PixelRepetition) &&
+            (GetColorDepth(DisplayTimingPtr->PixelFormat) ==
+                PllMpllGenericConfigSetting[settingIndex].ColorDepth)) {
+
+            foundConfig = TRUE;
+            *ConfigGenericSettingPPtr = &PllMpllGenericConfigSetting[settingIndex];
+            break;
+        }
+    }
+
+    // Use the fallback value the last index if no configuration is found
+    if (foundConfig == FALSE) {
+        *ConfigGenericSettingPPtr =
+            &PllMpllGenericConfigSetting[ARRAYSIZE(PllMpllGenericConfigSetting)];
+        foundConfig = TRUE;
+    }
+
+    return foundConfig;
+}
+
+OS_STATUS InitHDMI (
+    DISPLAY_CONTEXT* DisplayContextPtr
+    )
+{
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr =
+        &DisplayContextPtr->DIContext[HDMI_DISPLAY];
+    OS_STATUS status = 0;
+
+    OS_ZERO_MEM(HdmiDisplayContextPtr, sizeof(*HdmiDisplayContextPtr));
+
+    HdmiDisplayContextPtr->MmioBasePtr = (VOID*)OS_MMIO_MAP(HDMI_BASE);
+    if (HdmiDisplayContextPtr->MmioBasePtr == NULL) {
+        OS_ERROR("Fail to map HDMI register\n");
+        goto Exit;
+    }
+
+    // Setup HDMI DDC muxing
+    OS_WRITE32(IOMUXC_SW_MUX_CTL_PAD_KEY_COL3, 0x00000012);
+    OS_WRITE32(IOMUXC_SW_MUX_CTL_PAD_KEY_ROW3, 0x00000012);
+    OS_WRITE32(IOMUXC_HDMI_II2C_CLKIN_SELECT_INPUT, 0x00000001);
+    OS_WRITE32(IOMUXC_HDMI_II2C_DATAIN_SELECT_INPUT, 0x00000001);
+
+    SetHDMIPower(HdmiDisplayContextPtr, TRUE);
+
+    // Mask all HDMI PHY interrupt
+    HDMIWrite8(HDMI_PHY_MASK0, 0xFF);
+
+    status = ReadEDID(
+        DisplayContextPtr,
+        HDMI_DISPLAY,
+        HdmiDisplayContextPtr->EdidData,
+        &HdmiDisplayContextPtr->EdidDataSize);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_WARNING("Fail to read HDMI EDID data\n");
+        status = OS_STATUS_SUCCESS;
+    }
+
+    status = GetPreferedTiming(
+        HdmiDisplayContextPtr->EdidData,
+        HdmiDisplayContextPtr->EdidDataSize,
+        &HdmiDisplayContextPtr->PreferedTiming);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_ERROR("Fail to retrieve HDMI prefered timing\n");
+        goto Exit;
+    }
+
+    if ((HdmiDisplayContextPtr->PreferedTiming.HActive == 1920) &&
+        (HdmiDisplayContextPtr->PreferedTiming.VActive == 1080)) {
+        HdmiDisplayContextPtr->PreferedTiming.HBlank -= 6;
+    }
+
+Exit:
+    return status;
+}
+
+OS_STATUS SetHDMIPower (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    BOOLEAN PowerState
+    )
+{
+    HDMI_PHY_CONF0_REG CurrentHDMIPhyConf0;
+
+    CurrentHDMIPhyConf0.Reg = HDMIRead8(HDMI_PHY_CONF0);
+    if (PowerState) {
+        // Setup PHY
+        CurrentHDMIPhyConf0.PDZ = 1;
+        CurrentHDMIPhyConf0.ENTMDS = 1;
+        CurrentHDMIPhyConf0.gen2_pddq = 1;
+        CurrentHDMIPhyConf0.gen2_txpwron = 1;
+        CurrentHDMIPhyConf0.seldataenpol = 1;
+        CurrentHDMIPhyConf0.seldipif = 0;
+    } else {
+        // Just power down PHY for shutdown
+        CurrentHDMIPhyConf0.PDZ = 0;
+    }
+
+    HDMIWrite8(HDMI_PHY_CONF0, CurrentHDMIPhyConf0.Reg);
+
+    OS_SLEEP(3);
+
+    return OS_STATUS_SUCCESS;
+}
+
+OS_STATUS SetHDMIPhy (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    DISPLAY_TIMING* Timings
+    )
+{
+    OS_STATUS status;
+    HDMI_PHY_CONF0_REG CurrentHDMIPhyConf0;
+    PLL_MPLL_CONFIG*  pllMpllConfig;
+
+    // Disable Audio
+    {
+        HDMI_FC_AUDSCONF_REG fcAudsConf;
+
+        fcAudsConf.Reg = HDMIRead8(HDMI_FC_AUDSCONF);
+        fcAudsConf.aud_packet_layout = 0;
+        HDMIWrite8(HDMI_FC_AUDSCONF, fcAudsConf.Reg);
+    }
+
+    // Minimum PCLK period / frequency (pixel repetition) : 74 ns / 13.5 MHz
+    // Minimum PCLK period / frequency (no pixel repetition) : 39.7 ns / 24.175 MHz
+    if(Timings->PixelClock < 13500000) {
+        OS_ERROR("Unsupported pixel clock %d\n", Timings->PixelClock);
+        status = OS_STATUS_INVALID_PARAM;
+        goto Exit;
+    }
+
+    if (GetGenericConfigSetting(Timings, &pllMpllConfig) == FALSE) {
+        OS_ERROR("No compatible generic config found\n");
+        status = OS_STATUS_UNSUPPORTED;
+        goto Exit;
+    }
+
+    // Color Space Converter : Not used in UEFI
+    {
+        HDMI_MC_CLKDIS_REG McClkdis;
+
+        McClkdis.Reg = HDMIRead8(HDMI_MC_CLKDIS);
+
+        // Disable CEC, color converter, audio & pixel repitition
+        McClkdis.cecclk_disable = 1;
+        McClkdis.cscclk_disable = 1;
+        McClkdis.audclk_disable = 1;
+        McClkdis.prepclk_disable = 1;
+        McClkdis.hdcpclk_disable = 1;
+        McClkdis.tmdsclk_disable = 0;
+        McClkdis.pixelclk_disable = 0;
+
+        HDMIWrite8(HDMI_MC_CLKDIS, McClkdis.Reg);
+    }
+
+    // Power down the PHY
+    // To set the HDMI_PHY in Power-down mode, set the TX_PWRON signal to 1'b0
+    // and the PDDQ signal to 1'b1. To power up the HDMI 3D Tx PHY and place it
+    // in Active mode, set TX_PWRON to 1'b1 and PDDQ to 1'b0. Any configuration
+    // programmed on the HDMI_PHY must be done in Power-down mode.
+    CurrentHDMIPhyConf0.Reg = HDMIRead8(HDMI_PHY_CONF0);
+    CurrentHDMIPhyConf0.gen2_txpwron = 0;
+    CurrentHDMIPhyConf0.gen2_pddq = 1;
+    HDMIWrite8(HDMI_PHY_CONF0, CurrentHDMIPhyConf0.Reg);
+
+    // Let's reset the PHY to a well defined state based on spec.
+    // The PHY_RESET signal is used to place the digital section of the IP in
+    // a well - defined state
+    {
+        HDMI_MC_PHYRSTZ_REG phyRstzReg;
+        HDMI_MC_HEACPHY_RST_REG heacphyRst;
+
+        phyRstzReg.Reg = HDMIRead8(HDMI_MC_PHYRSTZ);
+        heacphyRst.Reg = HDMIRead8(HDMI_MC_HEACPHY_RST);
+
+        phyRstzReg.phyrstz = 1;
+        HDMIWrite8(HDMI_MC_PHYRSTZ, phyRstzReg.Reg);
+        phyRstzReg.phyrstz = 0;
+        OS_SLEEP(10);
+        HDMIWrite8(HDMI_MC_PHYRSTZ, phyRstzReg.Reg);
+
+        // Even though we dont currently support this, reset the ethernet audio
+        // control too
+        heacphyRst.heacphyrst = 1;
+        HDMIWrite8(HDMI_MC_HEACPHY_RST, heacphyRst.Reg);
+    }
+
+    // Program clock
+    // PLL / MPLL Operation
+    // The PLL / MPLL can be configured in Coherent mode or Non - Coherent mode (default).In
+    //  Coherent mode, the TMDS clock is the MPLL feedback clock, which is coherent with the
+    //  MPLL's high-speed output clock, because both clocks are shaped by the MPLL response.
+    //  In Non - Coherent mode, the TMDS clock is the MPLL reference clock, which is not
+    //  coherent with the MPLL's high-speed output clock.
+    if (HDMIPhyI2cWrite(
+            HdmiDisplayContextPtr,
+            HDMI_PHY_CPCE_CTRL,
+            pllMpllConfig->HdmiPhyCpceCtrl.Reg) == 0) {
+        OS_ERROR("Fail to write to HDMI_PHY_CPCE_CTRL %x\n",
+            pllMpllConfig->HdmiPhyCpceCtrl.Reg);
+        status = OS_STATUS_DEVICE_ERROR;
+        goto Exit;
+    }
+
+    if (HDMIPhyI2cWrite(
+            HdmiDisplayContextPtr,
+            HDMI_PHY_CURRCTRL,
+            pllMpllConfig->HdmiPhyCurrctrl.Reg) == 0) {
+        OS_ERROR("Fail to write to HDMI_PHY_CURRCTRL\n");
+        status = OS_STATUS_DEVICE_ERROR;
+        goto Exit;
+    };
+
+    if (HDMIPhyI2cWrite(
+            HdmiDisplayContextPtr,
+            HDMI_PHY_GMPCTRL,
+            pllMpllConfig->HdmiPhyGmpctrl.Reg) == 0) {
+        OS_ERROR("Fail to write to HDMI_PHY_GMPCTRL\n");
+        status = OS_STATUS_DEVICE_ERROR;
+        goto Exit;
+    }
+
+    // Maintaining the order of phy register writes
+    if (HDMIPhyI2cWrite(
+            HdmiDisplayContextPtr,
+            HDMI_PHY_PLLPHBYCTRL,
+            0x0000) == 0) {
+        OS_ERROR("Fail to write to HDMI_PHY_PLLPHBYCTRL\n");
+        status = OS_STATUS_DEVICE_ERROR;
+        goto Exit;
+    }
+
+    // Coherent  mode
+    if (HDMIPhyI2cWrite(
+            HdmiDisplayContextPtr,
+            HDMI_PHY_MSM_CTRL,
+            0x0006) == 0) {
+        OS_ERROR("Fail to write to HDMI_PHY_MSM_CTRL\n");
+        status = OS_STATUS_DEVICE_ERROR;
+        goto Exit;
+    }
+
+    // Resistance value 133.33 ohm
+    if (HDMIPhyI2cWrite(
+            HdmiDisplayContextPtr,
+            HDMI_PHY_TXTERM,
+            0x0005) == 0) {
+        OS_ERROR("Fail to write to HDMI_PHY_TXTERM\n");
+        status = OS_STATUS_DEVICE_ERROR;
+        goto Exit;
+    }
+
+    // Enable clock symbol
+    if (HDMIPhyI2cWrite(
+            HdmiDisplayContextPtr,
+            HDMI_PHY_CKSYMTXCTRL,
+            0x8009) == 0) {
+        OS_ERROR("Fail to write to HDMI_PHY_CKSYMTXCTRL\n");
+        status = OS_STATUS_DEVICE_ERROR;
+        goto Exit;
+    }
+
+    if (HDMIPhyI2cWrite(
+            HdmiDisplayContextPtr,
+            HDMI_PHY_VLEVCTRL,
+            0x0210) == 0) {
+        OS_ERROR("Fail to write to HDMI_PHY_VLEVCTRL\n");
+        status = OS_STATUS_DEVICE_ERROR;
+        goto Exit;
+    }
+
+    // Enable override
+    if (HDMIPhyI2cWrite(
+        HdmiDisplayContextPtr,
+            HDMI_PHY_CKCALCTRL,
+            0x8000) == 0) {
+        OS_ERROR("Fail to write to HDMI_PHY_CKCALCTRL\n");
+        status = OS_STATUS_DEVICE_ERROR;
+        goto Exit;
+    }
+
+    CurrentHDMIPhyConf0.gen2_txpwron = 1;
+    CurrentHDMIPhyConf0.gen2_pddq = 0;
+    HDMIWrite8(HDMI_PHY_CONF0, CurrentHDMIPhyConf0.Reg);
+
+    {
+        HDMI_PHY_STAT0_REG phyStat0;
+        UINT32 poolTimeOut = 5;
+
+        status = OS_STATUS_DEVICE_ERROR;
+
+        do {
+            phyStat0.Reg = HDMIRead8(HDMI_PHY_STAT0);
+
+            if (!phyStat0.TX_PHY_LOCK) {
+                status = OS_STATUS_SUCCESS;
+                break;
+            }
+
+            OS_SLEEP(1000);
+            --poolTimeOut;
+        } while (poolTimeOut);
+
+        if (poolTimeOut == 0) {
+            OS_ERROR("TX PHY remain unlock\n");
+        }
+    }
+
+Exit:
+    return status;
+}
+
+OS_STATUS SetHDMIDisplay (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    DISPLAY_TIMING* Timings
+    )
+{
+    OS_STATUS status;
+
+    status = SetHDMIPhy(HdmiDisplayContextPtr, Timings);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_ERROR("SetHDMIPhy failed\n");
+        goto Exit;
+    }
+
+Exit:
+    return status;
+}
+
+VOID SetDDCSpeed (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    DDC_MODE mode
+    )
+{
+    HDMIWrite8(HDMI_I2CM_DIV, mode);
+}
+
+OS_STATUS HDMIDDCRead (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    UINT8 SlaveAddress,
+    UINT8 RegisterAddress,
+    UINT32 ReadSize,
+    DDC_MODE DDCMode,
+    UINT8* DataReadPtr
+    )
+{
+    OS_STATUS status;
+    UINT32 AddrCount;
+    UINT8* CurrentDataReadPtr = DataReadPtr;
+
+    // Setup EDID transaction and loop through all byte request
+    SetDDCSpeed(HdmiDisplayContextPtr, DDCMode);
+
+    HDMIWrite8(HDMI_IH_I2CM_STAT0, I2C_MASTER_ERROR | I2C_MASTER_DONE);
+    HDMIWrite8(HDMI_I2CM_SLAVE, SlaveAddress);
+
+    for (AddrCount = 0; AddrCount < ReadSize; ++AddrCount) {
+        UINT32 i2CTimeOut = 1000;
+
+        HDMIWrite8(HDMI_I2CM_ADDRESS, (UINT8)( RegisterAddress + AddrCount));
+        HDMIWrite8(HDMI_I2CM_SEGADDR, 0x00);
+        HDMIWrite8(HDMI_I2CM_OPERATION, DDC_READ_OPERATION);
+
+        // Poll for completion
+        UINT8 i2CMIntStatus = HDMIRead8(HDMI_IH_I2CM_STAT0);
+
+        while ((i2CMIntStatus == 0) && (i2CTimeOut)) {
+            i2CMIntStatus = HDMIRead8(HDMI_IH_I2CM_STAT0);
+            --i2CTimeOut;
+        }
+
+        if (i2CTimeOut == 0) {
+            status = OS_STATUS_DEVICE_ERROR;
+            OS_ERROR("Timeout waiting for interrupt 0x%02x\n", i2CMIntStatus);
+            goto Exit;
+        }
+
+        if (i2CMIntStatus & I2C_MASTER_ERROR) {
+            status = OS_STATUS_DEVICE_ERROR;
+            OS_ERROR("Failed to read with DDC 0x%02x\n", i2CMIntStatus);
+            goto Exit;
+        } else if (i2CMIntStatus & I2C_MASTER_DONE) {
+            *CurrentDataReadPtr = HDMIRead8(HDMI_I2CM_DATAI);
+            CurrentDataReadPtr++;
+        } else {
+            status = OS_STATUS_DEVICE_ERROR;
+            OS_ERROR("Failed to read DDC unknown status 0x%02x\n", i2CMIntStatus);
+            goto Exit;
+        }
+
+        HDMIWrite8(HDMI_IH_I2CM_STAT0, 0xFF);
+    }
+
+    status = OS_STATUS_SUCCESS;
+
+Exit:
+    return status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.h
new file mode 100644
index 000000000000..f186f57105f7
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.h
@@ -0,0 +1,537 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _HDMI_H_
+#define _HDMI_H_
+
+#define HDMIRead8(a) \
+            OS_READ8((UINT32)HdmiDisplayContextPtr->MmioBasePtr + a)
+
+#define HDMIWrite8(a, b) \
+            OS_WRITE8((UINT32)HdmiDisplayContextPtr->MmioBasePtr + a, b)
+
+
+// HDMI Register Base Address
+#define HDMI_BASE 0x00120000
+
+// Interrupt Register Offset
+#define HDMI_IH_FC_STAT0                0x0100
+#define HDMI_IH_FC_STAT1                0x0101
+#define HDMI_IH_FC_STAT2                0x0102
+#define HDMI_IH_AS_STAT0                0x0103
+#define HDMI_IH_PHY_STAT0               0x0104
+#define HDMI_IH_I2CM_STAT0              0x0105
+#define HDMI_IH_CEC_STAT0               0x0106
+#define HDMI_IH_VP_STAT0                0x0107
+#define HDMI_IH_I2CMPHY_STAT0           0x0108
+#define HDMI_IH_AHBDMAAUD_STAT0         0x0180
+#define HDMI_IH_MUTE_FC_STAT1           0x0181
+#define HDMI_IH_MUTE_FC_STAT2           0x0182
+#define HDMI_IH_MUTE_AS_STAT0           0x0183
+#define HDMI_IH_MUTE_PHY_STAT0          0x0184
+#define HDMI_IH_MUTE_I2CM_STAT0         0x0185
+#define HDMI_IH_MUTE_CEC_STAT0          0x0186
+#define HDMI_IH_MUTE_VP_STAT0           0x0187
+#define HDMI_IH_MUTE_I2CMPHY_STAT0      0x0188
+#define HDMI_IH_MUTE_AHBDMAAUD_STAT0    0x0189
+#define HDMI_IH_MUTE                    0x01FF
+
+#define HDMI_FC_INVIDCONF               0x1000
+#define HDMI_FC_INHACTV0                0x1001
+#define HDMI_FC_INHACTV1                0x1002
+#define HDMI_FC_INHBLANK0               0x1003
+#define HDMI_FC_INHBLANK1               0x1004
+#define HDMI_FC_INVACTV0                0x1005
+#define HDMI_FC_INVACTV1                0x1006
+#define HDMI_FC_INVBLANK                0x1007
+#define HDMI_FC_HSYNCINDELAY0           0x1008
+#define HDMI_FC_HSYNCINDELAY1           0x1009
+#define HDMI_FC_HSYNCINWIDTH0           0x100A
+#define HDMI_FC_HSYNCINWIDTH1           0x100B
+#define HDMI_FC_VSYNCINDELAY            0x100C
+#define HDMI_FC_VSYNCINWIDTH            0x100D
+#define HDMI_FC_INFREQ0                 0x100E
+#define HDMI_FC_INFREQ1                 0x100F
+#define HDMI_FC_INFREQ2                 0x1010
+#define HDMI_FC_CTRLDUR                 0x1011
+#define HDMI_FC_EXCTRLDUR               0x1012
+#define HDMI_FC_EXCTRLSPAC              0x1013
+#define HDMI_FC_CH0PREAM                0x1014
+#define HDMI_FC_CH1PREAM                0x1015
+#define HDMI_FC_CH2PREAM                0x1016
+#define HDMI_FC_AVICONF3                0x1017
+#define HDMI_FC_GCP                     0x1018
+#define HDMI_FC_AVICONF0                0x1019
+#define HDMI_FC_AVICONF1                0x101A
+#define HDMI_FC_AVICONF2                0x101B
+#define HDMI_FC_AVIVID                  0x101C
+#define HDMI_FC_AVIETB0                 0x101D
+#define HDMI_FC_AVIETB1                 0x101E
+#define HDMI_FC_AVISBB0                 0x101F
+#define HDMI_FC_AVISBB1                 0x1020
+#define HDMI_FC_AVIELB0                 0x1021
+#define HDMI_FC_AVIELB1                 0x1022
+#define HDMI_FC_AVISRB0                 0x1023
+#define HDMI_FC_AVISRB1                 0x1024
+#define HDMI_FC_AUDICONF0               0x1025
+#define HDMI_FC_AUDICONF1               0x1026
+#define HDMI_FC_AUDICONF2               0x1027
+#define HDMI_FC_AUDICONF3               0x1028
+#define HDMI_FC_VSDIEEEID0              0x1029
+#define HDMI_FC_VSDSIZE                 0x102A
+#define HDMI_FC_VSDIEEEID1              0x1030
+#define HDMI_FC_VSDIEEEID2              0x1031
+#define HDMI_FC_VSDPAYLOAD0             0x1032
+#define HDMI_FC_VSDPAYLOAD1             0x1033
+#define HDMI_FC_VSDPAYLOAD2             0x1034
+#define HDMI_FC_VSDPAYLOAD3             0x1035
+#define HDMI_FC_VSDPAYLOAD4             0x1036
+#define HDMI_FC_VSDPAYLOAD5             0x1037
+#define HDMI_FC_VSDPAYLOAD6             0x1038
+#define HDMI_FC_VSDPAYLOAD7             0x1039
+#define HDMI_FC_VSDPAYLOAD8             0x103A
+#define HDMI_FC_VSDPAYLOAD9             0x103B
+#define HDMI_FC_VSDPAYLOAD10            0x103C
+#define HDMI_FC_VSDPAYLOAD11            0x103D
+#define HDMI_FC_VSDPAYLOAD12            0x103E
+#define HDMI_FC_VSDPAYLOAD13            0x103F
+#define HDMI_FC_VSDPAYLOAD14            0x1040
+#define HDMI_FC_VSDPAYLOAD15            0x1041
+#define HDMI_FC_VSDPAYLOAD16            0x1042
+#define HDMI_FC_VSDPAYLOAD17            0x1043
+#define HDMI_FC_VSDPAYLOAD18            0x1044
+#define HDMI_FC_VSDPAYLOAD19            0x1045
+#define HDMI_FC_VSDPAYLOAD20            0x1046
+#define HDMI_FC_VSDPAYLOAD21            0x1047
+#define HDMI_FC_VSDPAYLOAD22            0x1048
+#define HDMI_FC_VSDPAYLOAD23            0x1049
+#define HDMI_FC_SPDVENDORNAME0          0x104A
+#define HDMI_FC_SPDVENDORNAME1          0x104B
+#define HDMI_FC_SPDVENDORNAME2          0x104C
+#define HDMI_FC_SPDVENDORNAME3          0x104D
+#define HDMI_FC_SPDVENDORNAME4          0x104E
+#define HDMI_FC_SPDVENDORNAME5          0x104F
+#define HDMI_FC_SPDVENDORNAME6          0x1050
+#define HDMI_FC_SPDVENDORNAME7          0x1051
+#define HDMI_FC_SDPPRODUCTNAME0         0x1052
+#define HDMI_FC_SDPPRODUCTNAME1         0x1053
+#define HDMI_FC_SDPPRODUCTNAME2         0x1054
+#define HDMI_FC_SDPPRODUCTNAME3         0x1055
+#define HDMI_FC_SDPPRODUCTNAME4         0x1056
+#define HDMI_FC_SDPPRODUCTNAME5         0x1057
+#define HDMI_FC_SDPPRODUCTNAME6         0x1058
+#define HDMI_FC_SDPPRODUCTNAME7         0x1059
+#define HDMI_FC_SDPPRODUCTNAME8         0x105A
+#define HDMI_FC_SDPPRODUCTNAME9         0x105B
+#define HDMI_FC_SDPPRODUCTNAME10        0x105C
+#define HDMI_FC_SDPPRODUCTNAME11        0x105D
+#define HDMI_FC_SDPPRODUCTNAME12        0x105E
+#define HDMI_FC_SDPPRODUCTNAME13        0x105F
+#define HDMI_FC_SDPPRODUCTNAME14        0x1060
+#define HDMI_FC_SPDPRODUCTNAME15        0x1061
+#define HDMI_FC_SPDDEVICEINF            0x1062
+#define HDMI_FC_AUDSCONF                0x1063
+#define HDMI_FC_AUDSSTAT                0x1064
+#define HDMI_FC_AUDSV                   0x1065
+#define HDMI_FC_AUDSU                   0x1066
+#define HDMI_FC_AUDSCHNLS0              0x1067
+#define HDMI_FC_AUDSCHNLS1              0x1068
+#define HDMI_FC_AUDSCHNLS2              0x1069
+#define HDMI_FC_AUDSCHNLS3              0x106A
+#define HDMI_FC_AUDSCHNLS4              0x106B
+#define HDMI_FC_AUDSCHNLS5              0x106C
+#define HDMI_FC_AUDSCHNLS6              0x106D
+#define HDMI_FC_AUDSCHNLS7              0x106E
+#define HDMI_FC_AUDSCHNLS8              0x106F
+#define HDMI_FC_DATACH0FILL             0x1070
+#define HDMI_FC_DATACH1FILL             0x1071
+#define HDMI_FC_DATACH2FILL             0x1072
+#define HDMI_FC_CTRLQHIGH               0x1073
+#define HDMI_FC_CTRLQLOW                0x1074
+#define HDMI_FC_ACP0                    0x1075
+#define HDMI_FC_ACP28                   0x1076
+#define HDMI_FC_ACP27                   0x1077
+#define HDMI_FC_ACP26                   0x1078
+#define HDMI_FC_ACP25                   0x1079
+#define HDMI_FC_ACP24                   0x107A
+#define HDMI_FC_ACP23                   0x107B
+#define HDMI_FC_ACP22                   0x107C
+#define HDMI_FC_ACP21                   0x107D
+#define HDMI_FC_ACP20                   0x107E
+#define HDMI_FC_ACP19                   0x107F
+#define HDMI_FC_ACP18                   0x1080
+#define HDMI_FC_ACP17                   0x1081
+#define HDMI_FC_ACP16                   0x1082
+#define HDMI_FC_ACP15                   0x1083
+#define HDMI_FC_ACP14                   0x1084
+#define HDMI_FC_ACP13                   0x1085
+#define HDMI_FC_ACP12                   0x1086
+#define HDMI_FC_ACP11                   0x1087
+#define HDMI_FC_ACP10                   0x1088
+#define HDMI_FC_ACP9                    0x1089
+#define HDMI_FC_ACP8                    0x108A
+#define HDMI_FC_ACP7                    0x108B
+#define HDMI_FC_ACP6                    0x108C
+#define HDMI_FC_ACP5                    0x108D
+#define HDMI_FC_ACP4                    0x108E
+#define HDMI_FC_ACP3                    0x108F
+#define HDMI_FC_ACP2                    0x1090
+#define HDMI_FC_ACP1                    0x1091
+#define HDMI_FC_ISCR1_0                 0x1092
+#define HDMI_FC_ISCR1_16                0x1093
+#define HDMI_FC_ISCR1_15                0x1094
+#define HDMI_FC_ISCR1_14                0x1095
+#define HDMI_FC_ISCR1_13                0x1096
+#define HDMI_FC_ISCR1_12                0x1097
+#define HDMI_FC_ISCR1_11                0x1098
+#define HDMI_FC_ISCR1_10                0x1099
+#define HDMI_FC_ISCR1_9                 0x109A
+#define HDMI_FC_ISCR1_8                 0x109B
+#define HDMI_FC_ISCR1_7                 0x109C
+#define HDMI_FC_ISCR1_6                 0x109D
+#define HDMI_FC_ISCR1_5                 0x109E
+#define HDMI_FC_ISCR1_4                 0x109F
+#define HDMI_FC_ISCR1_3                 0x10A0
+#define HDMI_FC_ISCR1_2                 0x10A1
+#define HDMI_FC_ISCR1_1                 0x10A2
+#define HDMI_FC_ISCR2_15                0x10A3
+#define HDMI_FC_ISCR2_14                0x10A4
+#define HDMI_FC_ISCR2_13                0x10A5
+#define HDMI_FC_ISCR2_12                0x10A6
+#define HDMI_FC_ISCR2_11                0x10A7
+#define HDMI_FC_ISCR2_10                0x10A8
+#define HDMI_FC_ISCR2_9                 0x10A9
+#define HDMI_FC_ISCR2_8                 0x10AA
+#define HDMI_FC_ISCR2_7                 0x10AB
+#define HDMI_FC_ISCR2_6                 0x10AC
+#define HDMI_FC_ISCR2_5                 0x10AD
+#define HDMI_FC_ISCR2_4                 0x10AE
+#define HDMI_FC_ISCR2_3                 0x10AF
+#define HDMI_FC_ISCR2_2                 0x10B0
+#define HDMI_FC_ISCR2_1                 0x10B1
+#define HDMI_FC_ISCR2_0                 0x10B2
+#define HDMI_FC_DATAUTO0                0x10B3
+#define HDMI_FC_DATAUTO1                0x10B4
+#define HDMI_FC_DATAUTO2                0x10B5
+#define HDMI_FC_DATMAN                  0x10B6
+#define HDMI_FC_DATAUTO3                0x10B7
+#define HDMI_FC_RDRB0                   0x10B8
+#define HDMI_FC_RDRB1                   0x10B9
+#define HDMI_FC_RDRB2                   0x10BA
+#define HDMI_FC_RDRB3                   0x10BB
+#define HDMI_FC_RDRB4                   0x10BC
+#define HDMI_FC_RDRB5                   0x10BD
+#define HDMI_FC_RDRB6                   0x10BE
+#define HDMI_FC_RDRB7                   0x10BF
+#define HDMI_FC_STAT0                   0x10D0
+#define HDMI_FC_INT0                    0x10D1
+#define HDMI_FC_MASK0                   0x10D2
+#define HDMI_FC_POL0                    0x10D3
+#define HDMI_FC_STAT1                   0x10D4
+#define HDMI_FC_INT1                    0x10D5
+#define HDMI_FC_MASK1                   0x10D6
+#define HDMI_FC_POL1                    0x10D7
+#define HDMI_FC_STAT2                   0x10D8
+#define HDMI_FC_INT2                    0x10D9
+#define HDMI_FC_MASK2                   0x10DA
+#define HDMI_FC_POL2                    0x10DB
+#define HDMI_FC_PRCONF                  0x10E0
+
+// HDMI PHY Register Offset
+#define HDMI_PHY_CONF0                      0x3000
+#define HDMI_PHY_TST0                       0x3001
+#define HDMI_PHY_TST1                       0x3002
+#define HDMI_PHY_TST2                       0x3003
+#define HDMI_PHY_STAT0                      0x3004
+#define HDMI_PHY_INT0                       0x3005
+#define HDMI_PHY_MASK0                      0x3006
+#define HDMI_PHY_POL0                       0x3007
+#define HDMI_PHY_I2CM_SLAVE_ADDR            0x3020
+#define HDMI_PHY_I2CM_ADDRESS_ADDR          0x3021
+#define HDMI_PHY_I2CM_DATAO_1_ADDR          0x3022
+#define HDMI_PHY_I2CM_DATAO_0_ADDR          0x3023
+#define HDMI_PHY_I2CM_DATAI_1_ADDR          0x3024
+#define HDMI_PHY_I2CM_DATAI_0_ADDR          0x3025
+#define HDMI_PHY_I2CM_OPERATION_ADDR        0x3026
+#define HDMI_PHY_I2CM_INT_ADDR              0x3027
+#define HDMI_PHY_I2CM_CTLINT_ADDR           0x3028
+#define HDMI_PHY_I2CM_DIV_ADDR              0x3029
+#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR         0x302a
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR    0x302b
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR    0x302c
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR    0x302d
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR    0x302e
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR    0x302f
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR    0x3030
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR    0x3031
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR    0x3032
+
+// Main Controller Registers
+#define HDMI_MC_CLKDIS          0x4001
+#define HDMI_MC_SWRSTZ          0x4002
+#define HDMI_MC_OPCTRL          0x4003
+#define HDMI_MC_FLOWCTRL        0x4004
+#define HDMI_MC_PHYRSTZ         0x4005
+#define HDMI_MC_LOCKONCLOCK     0x4006
+#define HDMI_MC_HEACPHY_RST     0x4007
+
+// HDMI_PHY absolute address
+#define HDMI_PHY_PWRCTRL        0x00
+#define HDMI_PHY_SERDIVCTRL     0x01
+#define HDMI_PHY_SERCKCTRL      0x02
+#define HDMI_PHY_SERCKKILLCTRL  0x03
+#define HDMI_PHY_TXRESCTRL      0x04
+#define HDMI_PHY_CKCALCTRL      0x05
+#define HDMI_PHY_CPCE_CTRL      0x06
+#define HDMI_PHY_TXCLKMEASCTRL  0x07
+#define HDMI_PHY_TXMEASCTRL     0x08
+#define HDMI_PHY_CKSYMTXCTRL    0x09
+#define HDMI_PHY_CMPSEQCTRL     0x0A
+#define HDMI_PHY_CMPPWRCTRL     0x0B
+#define HDMI_PHY_CMPMODECTRL    0x0C
+#define HDMI_PHY_MEASCTRL       0x0D
+#define HDMI_PHY_VLEVCTRL       0x0E
+#define HDMI_PHY_D2ACTRL        0x0F
+#define HDMI_PHY_CURRCTRL       0x10
+#define HDMI_PHY_DRVANACTRL     0x11
+#define HDMI_PHY_PLLMEASCTRL    0x12
+#define HDMI_PHY_PLLPHBYCTRL    0x13
+#define HDMI_PHY_GRP_CTRL       0x14
+#define HDMI_PHY_GMPCTRL        0x15
+#define HDMI_PHY_MPLLMEASCTRL   0x16
+#define HDMI_PHY_MSM_CTRL       0x17
+#define HDMI_PHY_SCRPB_STATUS   0x18
+#define HDMI_PHY_TXTERM         0x19
+#define HDMI_PHY_PTRPT_ENBL     0x1A
+#define HDMI_PHY_PATTERNGEN     0x1B
+#define HDMI_PHY_SDCAP_MODE     0x1C
+#define HDMI_PHY_SCOPEMODE      0x1D
+#define HDMI_PHY_DIGTXMODE      0x1E
+#define HDMI_PHY_STR_STATUS     0x1F
+#define HDMI_PHY_SCOPECNT0      0x20
+#define HDMI_PHY_SCOPECNT1      0x21
+#define HDMI_PHY_SCOPECNT2      0x22
+#define HDMI_PHY_SCOPECNTCLK    0x23
+#define HDMI_PHY_SCOPESAMPLE    0x24
+#define HDMI_PHY_SCOPECNTMSB01  0x25
+#define HDMI_PHY_SCOPECNTMSB2CK 0x26
+
+// Register struct
+
+#pragma pack(push, 1)
+
+// HDMI_PHY_CONF0 0x0100
+typedef union {
+    struct {
+        UINT8 seldipif : 1;
+        UINT8 seldataenpol : 1;
+        UINT8 gen2_enhpdrxsense : 1;
+        UINT8 gen2_txpwron : 1;
+        UINT8 gen2_pddq : 1;
+        UINT8 sparectrl : 1;
+        UINT8 ENTMDS : 1;
+        UINT8 PDZ : 1;
+    };
+    UINT8 Reg;
+}  HDMI_PHY_CONF0_REG;
+
+// HDMI_IH_I2CMPHY_STAT0 0x0108
+typedef union {
+    struct {
+        UINT8 i2cmphyerror : 1;
+        UINT8 i2cmphydone : 1;
+        UINT8 reserved : 6;
+    };
+    UINT8 Reg;
+}  HDMI_IH_I2CMPHY_STAT0_REG;
+
+// HDMI_FC_AUDSCONF 0x01063
+typedef union {
+    struct {
+        UINT8 aud_packet_layout : 1;
+        UINT8 reserved : 4;
+        UINT8 aud_packet_sampfit : 4;
+    };
+    UINT8 Reg;
+}  HDMI_FC_AUDSCONF_REG;
+
+// HDMI_PHY_STAT0 0x3004
+typedef union {
+    struct {
+        UINT8 TX_PHY_LOCK : 1;
+        UINT8 HPD : 1;
+        UINT8 reserved : 2;
+        UINT8 RX_SENSE0 : 1;
+        UINT8 RX_SENSE1 : 1;
+        UINT8 RX_SENSE2 : 1;
+        UINT8 RX_SENSE3 : 1;
+    };
+    UINT8 Reg;
+
+}  HDMI_PHY_STAT0_REG;
+
+// HDMI_PHY_I2CM_OPERATION_ADDR 0x3026
+typedef union {
+    struct {
+        UINT8 read : 1;
+        UINT8 reserved0 : 3;
+        UINT8 write : 1;
+        UINT8 reserved1 : 3;
+    };
+    UINT8 Reg;
+}  HDMI_PHY_I2CM_OPERATION_ADDR_REG;
+
+// HDMI_MC_CLKDIS 0x4001
+typedef union {
+    struct {
+        UINT8 pixelclk_disable : 1;
+        UINT8 tmdsclk_disable : 1;
+        UINT8 prepclk_disable : 1;
+        UINT8 audclk_disable : 1;
+        UINT8 cscclk_disable : 1;
+        UINT8 cecclk_disable : 1;
+        UINT8 hdcpclk_disable : 1;
+        UINT8 reserved : 1;
+    };
+    UINT8 Reg;
+} HDMI_MC_CLKDIS_REG;
+
+// HDMI_MC_PHYRSTZ 0x4005
+typedef union {
+    struct {
+        UINT8 phyrstz : 1;
+        UINT8 reserved : 7;
+    };
+    UINT8 Reg;
+}  HDMI_MC_PHYRSTZ_REG;
+
+// HDMI_MC_HEACPHY_RST 0x4007
+typedef union {
+    struct {
+        UINT8 heacphyrst : 1;
+        UINT8 reserved : 7;
+    };
+    UINT8 Reg;
+}  HDMI_MC_HEACPHY_RST_REG;
+
+// HDMI PHY : HDMI_PHY_CPCE_CTRL 0x06
+typedef union {
+    struct {
+        UINT16 clr_dpth : 2;
+        UINT16 pixel_rep : 3;
+        UINT16 pll_n_cntrl : 2;
+        UINT16 mpll_n_cntrl : 2;
+        UINT16 ck_edgerate : 2;
+        UINT16 tx_edgerate : 2;
+        UINT16 prep_div : 2;
+        UINT16 reserved : 1;
+    };
+    UINT16 Reg;
+}  HDMI_PHY_CPCE_CTRL_REG;
+
+// HDMI PHY : HDMI_PHY_CURRCTRL 0x10
+typedef union {
+    struct {
+        UINT16 pll_int_cntrl : 3;
+        UINT16 pll_prop_cntrl : 3;
+        UINT16 mpll_int_cntrl : 3;
+        UINT16 mpll_prop_cntrl : 3;
+        UINT16 reserved : 4;
+    };
+    UINT16 Reg;
+}  HDMI_PHY_CURRCTRL_REG;
+
+// HDMI PHY : HDMI_PHY_GMPCTRL 0x15
+typedef union {
+    struct {
+        UINT16 mpll_gmp_cntrl : 2;
+        UINT16 pll_gmp_cntrl : 2;
+        UINT16 reserved : 12;
+    };
+    UINT16 Reg;
+}  HDMI_PHY_GMPCTRL_REG;
+
+#pragma pack(pop)
+
+// HDMI DDC offset
+#define HDMI_I2CM_SLAVE                 0x7E00
+#define HDMI_I2CM_ADDRESS               0x7E01
+#define HDMI_I2CM_DATAO                 0x7E02
+#define HDMI_I2CM_DATAI                 0x7E03
+#define HDMI_I2CM_OPERATION             0x7E04
+#define HDMI_I2CM_INT                   0x7E05
+#define HDMI_I2CM_CTLINT                0x7E06
+#define HDMI_I2CM_DIV                   0x7E07
+#define HDMI_I2CM_SEGADDR               0x7E08
+#define HDMI_I2CM_SOFTRSTZ              0x7E09
+#define HDMI_I2CM_SEGPTR                0x7E0A
+#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR    0x7E0B
+#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR    0x7E0C
+#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR    0x7E0D
+#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR    0x7E0E
+#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR    0x7E0F
+#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR    0x7E10
+#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR    0x7E11
+#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR    0x7E12
+
+// DDC Interrupt status
+#define I2C_MASTER_ERROR                0x01
+#define I2C_MASTER_DONE                 0x02
+
+// HDMI bit configuration
+typedef enum
+{
+    DDC_READ_OPERATION = 0x01,
+    DDC_READ_EXT_OPERATION = 0x02,
+    DDC_WRITE_OPERATION = 0x10,
+}DDC_OPERATION;
+
+typedef enum
+{
+    HDMI_DDC_STANDARD_MODE = 0x00,
+    HDMI_DDC_FAST_MODE = 0x04,
+}DDC_MODE;
+
+typedef struct _PLL_MPLL_CONFIG {
+    UINT32 PixelClock;
+    UINT8 PixelRepetition;
+    UINT8 ColorDepth;
+    HDMI_PHY_CPCE_CTRL_REG HdmiPhyCpceCtrl;
+    HDMI_PHY_CURRCTRL_REG HdmiPhyCurrctrl;
+    HDMI_PHY_GMPCTRL_REG HdmiPhyGmpctrl;
+}PLL_MPLL_CONFIG, *PPLL_MPLL_CONFIG;
+
+OS_STATUS InitHDMI (
+    DISPLAY_CONTEXT* DisplayContextPtr
+    );
+
+OS_STATUS SetHDMIPower (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    BOOLEAN PowerState
+    );
+
+OS_STATUS SetHDMIDisplay (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    DISPLAY_TIMING* Timings
+    );
+
+OS_STATUS HDMIDDCRead (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    UINT8 SlaveAddress,
+    UINT8 RegisterAddress,
+    UINT32 ReadSize,
+    DDC_MODE DDCMode,
+    UINT8* DataReadPtr);
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.c
new file mode 100644
index 000000000000..7e5d575922a2
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.c
@@ -0,0 +1,83 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright 2018 NXP
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "Osal.h"
+#include "Display.h"
+#include "IoMux.h"
+
+OS_STATUS SetupDisplayMux (
+    DISPLAY_CONTEXT* DisplayContextPtr
+    )
+{
+    OS_STATUS status;
+    DISPLAY_MODE displayMode = DisplayContextPtr->DisplayConfig.DisplayMode;
+    DISPLAY_INTERFACE* displayInterface =
+        DisplayContextPtr->DisplayConfig.DIOrder;
+    UINT32 regGPR3, sourceMask, sourceVal, dIIndex;
+    volatile IMX_IOMUXC_GPR_REGISTERS* ioMuxcGprRegisters =
+        DisplayContextPtr->IoMuxMmioBasePtr;
+
+    regGPR3 =
+        OS_READ32(&ioMuxcGprRegisters->GPR3);
+
+    regGPR3 &= ~(HDMI_MUX_CTL_MASK |
+                 MIPI_MUX_CTL_MASK |
+                 LVDS0_MUX_CTL_MASK |
+                 LVDS1_MUX_CTL_MASK);
+
+    OS_WRITE32(
+        &ioMuxcGprRegisters->GPR3,
+        regGPR3);
+
+    for (dIIndex = 0; dIIndex < (UINT32)displayMode; ++dIIndex) {
+        regGPR3 =
+            OS_READ32(&ioMuxcGprRegisters->GPR3);
+
+        switch (displayInterface[dIIndex])
+        {
+        case HDMI_DISPLAY:
+            sourceMask = HDMI_MUX_CTL_MASK;
+            sourceVal = dIIndex << HDMI_MUX_CTL_OFFSET;
+            break;
+        case MIPI_DISPLAY:
+            sourceMask = MIPI_MUX_CTL_MASK;
+            sourceVal = dIIndex << MIPI_MUX_CTL_OFFSET;
+            break;
+        case LVDS0_DISPLAY:
+            sourceMask = LVDS0_MUX_CTL_MASK;
+            sourceVal = dIIndex << LVDS0_MUX_CTL_OFFSET;
+            break;
+        case LVDS1_DISPLAY:
+            sourceMask = LVDS1_MUX_CTL_MASK;
+            sourceVal = dIIndex << LVDS1_MUX_CTL_OFFSET;
+            break;
+        default:
+            status = OS_STATUS_UNSUPPORTED;
+            goto Exit;
+        }
+
+        regGPR3 &= ~sourceMask;
+        regGPR3 |= sourceVal;
+
+        OS_WRITE32(
+            &ioMuxcGprRegisters->GPR3,
+            regGPR3);
+    }
+
+    status = OS_STATUS_SUCCESS;
+
+Exit:
+    return status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.h
new file mode 100644
index 000000000000..5755b03ef8db
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.h
@@ -0,0 +1,31 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _IO_MUX_H_
+#define _IO_MUX_H_
+
+#define HDMI_MUX_CTL_OFFSET         2
+#define HDMI_MUX_CTL_MASK           0x000C
+#define MIPI_MUX_CTL_OFFSET         4
+#define MIPI_MUX_CTL_MASK           0x0030
+#define LVDS0_MUX_CTL_OFFSET        6
+#define LVDS0_MUX_CTL_MASK          0x00C0
+#define LVDS1_MUX_CTL_OFFSET        8
+#define LVDS1_MUX_CTL_MASK          0x0300
+
+OS_STATUS SetupDisplayMux (
+    DISPLAY_CONTEXT* DisplayContextPtr
+    );
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ipu.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ipu.h
new file mode 100644
index 000000000000..7fdb118c99be
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ipu.h
@@ -0,0 +1,236 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _IPU_H_
+#define _IPU_H_
+
+#define IPU1_BASE      0x02600000
+#define IPU2_BASE      0x02A00000
+
+#define IpuRead32(IPU_BASE, OFFSET) \
+            OS_READ32(((unsigned char*)IPU_BASE + OFFSET))
+
+#define IpuWrite32(IPU_BASE, OFFSET, VALUE) \
+            OS_WRITE32(((unsigned char*)IPU_BASE + OFFSET), VALUE)
+
+#define DiRead32(DI_BASE, OFFSET) \
+            OS_READ32(((unsigned char*)DI_BASE + OFFSET))
+
+#define DiWrite32(DI_BASE, OFFSET, VALUE) \
+            OS_WRITE32(((unsigned char*)DI_BASE + OFFSET), VALUE)
+
+// IPU Registers
+#define IPU_IPU_CONF_OFFSET                     0x00000000
+#define IPU_SISG_CTRL0_OFFSET                   0x00000004
+#define IPU_SISG_CTRL1_OFFSET                   0x00000008
+#define IPU_SISG_SET_OFFSET                     0x0000000C
+#define IPU_SISG_CLR_OFFSET                     0x00000024
+#define IPU_IPU_INT_CTRL_1_OFFSET               0x0000003C
+#define IPU_IPU_INT_CTRL_2_OFFSET               0x00000040
+#define IPU_IPU_INT_CTRL_3_OFFSET               0x00000044
+#define IPU_IPU_INT_CTRL_4_OFFSET               0x00000048
+#define IPU_IPU_INT_CTRL_5_OFFSET               0x0000004C
+#define IPU_IPU_INT_CTRL_6_OFFSET               0x00000050
+#define IPU_IPU_INT_CTRL_7_OFFSET               0x00000054
+#define IPU_IPU_INT_CTRL_8_OFFSET               0x00000058
+#define IPU_IPU_INT_CTRL_9_OFFSET               0x0000005C
+#define IPU_IPU_INT_CTRL_10_OFFSET              0x00000060
+#define IPU_IPU_INT_CTRL_11_OFFSET              0x00000064
+#define IPU_IPU_INT_CTRL_12_OFFSET              0x00000068
+#define IPU_IPU_INT_CTRL_13_OFFSET              0x0000006C
+#define IPU_IPU_INT_CTRL_14_OFFSET              0x00000070
+#define IPU_IPU_INT_CTRL_15_OFFSET              0x00000074
+#define IPU_IPU_SDMA_EVENT_1_OFFSET             0x00000078
+#define IPU_IPU_SDMA_EVENT_2_OFFSET             0x0000007C
+#define IPU_IPU_SDMA_EVENT_3_OFFSET             0x00000080
+#define IPU_IPU_SDMA_EVENT_4_OFFSET             0x00000084
+#define IPU_IPU_SDMA_EVENT_7_OFFSET             0x00000088
+#define IPU_IPU_SDMA_EVENT_8_OFFSET             0x0000008C
+#define IPU_IPU_SDMA_EVENT_11_OFFSET            0x00000090
+#define IPU_IPU_SDMA_EVENT_12_OFFSET            0x00000094
+#define IPU_IPU_SDMA_EVENT_13_OFFSET            0x00000098
+#define IPU_IPU_SDMA_EVENT_14_OFFSET            0x0000009C
+#define IPU_IPU_SRM_PRI1_OFFSET                 0x000000A0
+#define IPU_IPU_SRM_PRI2_OFFSET                 0x000000A4
+#define IPU_IPU_FS_PROC_FLOW1_OFFSET            0x000000A8
+#define IPU_IPU_FS_PROC_FLOW2_OFFSET            0x000000AC
+#define IPU_IPU_FS_PROC_FLOW3_OFFSET            0x000000B0
+#define IPU_IPU_FS_DISP_FLOW1_OFFSET            0x000000B4
+#define IPU_IPU_FS_DISP_FLOW2_OFFSET            0x000000B8
+#define IPU_IPU_SKIP_OFFSET                     0x000000BC
+#define IPU_IPU_DISP_ALT_CONF_OFFSET            0x000000C0
+#define IPU_IPU_DISP_GEN_OFFSET                 0x000000C4
+#define IPU_IPU_DISP_ALT1_OFFSET                0x000000C8
+#define IPU_IPU_DISP_ALT2_OFFSET                0x000000CC
+#define IPU_IPU_DISP_ALT3_OFFSET                0x000000D0
+#define IPU_IPU_DISP_ALT4_OFFSET                0x000000D4
+#define IPU_IPU_SNOOP_OFFSET                    0x000000D8
+#define IPU_IPU_MEM_RST_OFFSET                  0x000000DC
+#define IPU_IPU_PM_OFFSET                       0x000000E0
+#define IPU_IPU_GPR_OFFSET                      0x000000E4
+#define IPU_IPU_INT_STAT_1_OFFSET               0x000000E8
+#define IPU_IPU_INT_STAT_2_OFFSET               0x000000EC
+#define IPU_IPU_INT_STAT_3_OFFSET               0x000000F0
+#define IPU_IPU_INT_STAT_4_OFFSET               0x000000F4
+#define IPU_IPU_INT_STAT_5_OFFSET               0x000000F8
+#define IPU_IPU_INT_STAT_6_OFFSET               0x000000FC
+#define IPU_IPU_INT_STAT_7_OFFSET               0x00000100
+#define IPU_IPU_INT_STAT_8_OFFSET               0x00000104
+#define IPU_IPU_INT_STAT_9_OFFSET               0x00000108
+#define IPU_IPU_INT_STAT_10_OFFSET              0x0000010C
+#define IPU_IPU_INT_STAT_11_OFFSET              0x00000110
+#define IPU_IPU_INT_STAT_12_OFFSET              0x00000114
+#define IPU_IPU_INT_STAT_13_OFFSET              0x00000118
+#define IPU_IPU_INT_STAT_14_OFFSET              0x0000011C
+#define IPU_IPU_INT_STAT_15_OFFSET              0x00000120
+#define IPU_IPU_CUR_BUF_0_OFFSET                0x00000124
+#define IPU_IPU_CUR_BUF_1_OFFSET                0x00000128
+#define IPU_IPU_ALT_CUR_BUF_0_OFFSET            0x0000012C
+#define IPU_IPU_ALT_CUR_BUF_1_OFFSET            0x00000130
+#define IPU_IPU_SRM_STAT_OFFSET                 0x00000134
+#define IPU_IPU_PROC_TASKS_STAT_OFFSET          0x00000138
+#define IPU_IPU_DISP_TASKS_STAT_OFFSET          0x0000013C
+#define IPU_IPU_CH_BUF0_RDY0_OFFSET             0x00000140
+#define IPU_IPU_CH_BUF0_RDY1_OFFSET             0x00000144
+#define IPU_IPU_CH_BUF1_RDY0_OFFSET             0x00000148
+#define IPU_IPU_CH_BUF1_RDY1_OFFSET             0x0000014C
+#define IPU_IPU_CH_DB_MODE_SEL0_OFFSET          0x00000150
+#define IPU_IPU_CH_DB_MODE_SEL1_OFFSET          0x00000154
+#define IPU_IPU_ALT_CH_BUF0_RDY0_OFFSET         0x00000158
+#define IPU_IPU_ALT_CH_BUF0_RDY1_OFFSET         0x0000015C
+#define IPU_IPU_ALT_CH_BUF1_RDY0_OFFSET         0x00000160
+#define IPU_IPU_ALT_CH_BUF1_RDY1_OFFSET         0x00000164
+#define IPU_IPU_ALT_CH_DB_MODE_SEL0_OFFSET      0x00000168
+#define IPU_IPU_ALT_CH_DB_MODE_SEL1_OFFSET      0x0000016C
+#define CSP_IPUV3_CPMEM_REGS_OFFSET             0x00100000
+
+// IPU DIx Registers
+#define IPU_DIx_GENERAL_OFFSET                  0x00000000
+#define IPU_DIx_BS_CLKGEN0_OFFSET               0x00000004
+#define IPU_DIx_BS_CLKGEN1_OFFSET               0x00000008
+#define IPU_DIx_SW_GEN0_1_OFFSET                0x0000000C
+#define IPU_DIx_SW_GEN0_2_OFFSET                0x00000010
+#define IPU_DIx_SW_GEN0_3_OFFSET                0x00000014
+#define IPU_DIx_SW_GEN0_4_OFFSET                0x00000018
+#define IPU_DIx_SW_GEN0_5_OFFSET                0x0000001C
+#define IPU_DIx_SW_GEN0_6_OFFSET                0x00000020
+#define IPU_DIx_SW_GEN0_7_OFFSET                0x00000024
+#define IPU_DIx_SW_GEN0_8_OFFSET                0x00000028
+#define IPU_DIx_SW_GEN0_9_OFFSET                0x0000002C
+#define IPU_DIx_SW_GEN1_1_OFFSET                0x00000030
+#define IPU_DIx_SW_GEN1_2_OFFSET                0x00000034
+#define IPU_DIx_SW_GEN1_3_OFFSET                0x00000038
+#define IPU_DIx_SW_GEN1_4_OFFSET                0x0000003C
+#define IPU_DIx_SW_GEN1_5_OFFSET                0x00000040
+#define IPU_DIx_SW_GEN1_6_OFFSET                0x00000044
+#define IPU_DIx_SW_GEN1_7_OFFSET                0x00000048
+#define IPU_DIx_SW_GEN1_8_OFFSET                0x0000004C
+#define IPU_DIx_SW_GEN1_9_OFFSET                0x00000050
+#define IPU_DIx_SYNC_AS_GEN_OFFSET              0x00000054
+#define IPU_DIx_DW_GEN_OFFSET                   0x00000058
+#define IPU_DIx_DW_SET0_OFFSET                  0x00000088
+#define IPU_DIx_DW_SET1_OFFSET                  0x000000B8
+#define IPU_DIx_DW_SET2_OFFSET                  0x000000E8
+#define IPU_DIx_DW_SET3_OFFSET                  0x00000118
+#define IPU_DIx_STP_REP_OFFSET                  0x00000148
+#define IPU_DIx_STP_REP_9_OFFSET                0x00000158
+#define IPU_DIx_SER_CONF_OFFSET                 0x0000015C
+#define IPU_DIx_SSC_OFFSET                      0x00000160
+#define IPU_DIx_POL_OFFSET                      0x00000164
+#define IPU_DIx_AW0_OFFSET                      0x00000168
+#define IPU_DIx_AW1_OFFSET                      0x0000016C
+#define IPU_DIx_SCR_CONF_OFFSET                 0x00000170
+#define IPU_DIx_STAT_OFFSET                     0x00000174
+
+// IPU IDMAC Registers
+#define IPU_IDMAC_LOCK_EN_1                     0x00008024
+#define IPU_IDMAC_LOCK_EN_2                     0x00008028
+
+// IPU DI0 Registers
+#define IPU_DI0_GENERAL_OFFSET                  0x00040000
+#define IPU_DI0_BS_CLKGEN0_OFFSET               0x00040004
+#define IPU_DI0_BS_CLKGEN1_OFFSET               0x00040008
+#define IPU_DI0_SW_GEN0_1_OFFSET                0x0004000C
+#define IPU_DI0_SW_GEN0_2_OFFSET                0x00040010
+#define IPU_DI0_SW_GEN0_3_OFFSET                0x00040014
+#define IPU_DI0_SW_GEN0_4_OFFSET                0x00040018
+#define IPU_DI0_SW_GEN0_5_OFFSET                0x0004001C
+#define IPU_DI0_SW_GEN0_6_OFFSET                0x00040020
+#define IPU_DI0_SW_GEN0_7_OFFSET                0x00040024
+#define IPU_DI0_SW_GEN0_8_OFFSET                0x00040028
+#define IPU_DI0_SW_GEN0_9_OFFSET                0x0004002C
+#define IPU_DI0_SW_GEN1_1_OFFSET                0x00040030
+#define IPU_DI0_SW_GEN1_2_OFFSET                0x00040034
+#define IPU_DI0_SW_GEN1_3_OFFSET                0x00040038
+#define IPU_DI0_SW_GEN1_4_OFFSET                0x0004003C
+#define IPU_DI0_SW_GEN1_5_OFFSET                0x00040040
+#define IPU_DI0_SW_GEN1_6_OFFSET                0x00040044
+#define IPU_DI0_SW_GEN1_7_OFFSET                0x00040048
+#define IPU_DI0_SW_GEN1_8_OFFSET                0x0004004C
+#define IPU_DI0_SW_GEN1_9_OFFSET                0x00040050
+#define IPU_DI0_SYNC_AS_GEN_OFFSET              0x00040054
+#define IPU_DI0_DW_GEN_OFFSET                   0x00040058
+#define IPU_DI0_DW_SET0_OFFSET                  0x00040088
+#define IPU_DI0_DW_SET1_OFFSET                  0x000400B8
+#define IPU_DI0_DW_SET2_OFFSET                  0x000400E8
+#define IPU_DI0_DW_SET3_OFFSET                  0x00040118
+#define IPU_DI0_STP_REP_OFFSET                  0x00040148
+#define IPU_DI0_STP_REP_9_OFFSET                0x00040158
+#define IPU_DI0_SER_CONF_OFFSET                 0x0004015C
+#define IPU_DI0_SSC_OFFSET                      0x00040160
+#define IPU_DI0_POL_OFFSET                      0x00040164
+#define IPU_DI0_AW0_OFFSET                      0x00040168
+#define IPU_DI0_AW1_OFFSET                      0x0004016C
+#define IPU_DI0_SCR_CONF_OFFSET                 0x00040170
+#define IPU_DI0_STAT_OFFSET                     0x00040174
+
+// IPU DI1 Registers
+#define IPU_DI1_GENERAL_OFFSET                  0x00048000
+#define IPU_DI1_BS_CLKGEN0_OFFSET               0x00048004
+#define IPU_DI1_BS_CLKGEN1_OFFSET               0x00048008
+#define IPU_DI1_SW_GEN0_1_OFFSET                0x0004800C
+#define IPU_DI1_SW_GEN0_2_OFFSET                0x00048010
+#define IPU_DI1_SW_GEN0_3_OFFSET                0x00048014
+#define IPU_DI1_SW_GEN0_4_OFFSET                0x00048018
+#define IPU_DI1_SW_GEN0_5_OFFSET                0x0004801C
+#define IPU_DI1_SW_GEN0_6_OFFSET                0x00048020
+#define IPU_DI1_SW_GEN0_7_OFFSET                0x00048024
+#define IPU_DI1_SW_GEN0_8_OFFSET                0x00048028
+#define IPU_DI1_SW_GEN0_9_OFFSET                0x0004802C
+#define IPU_DI1_SW_GEN1_1_OFFSET                0x00048030
+#define IPU_DI1_SW_GEN1_2_OFFSET                0x00048034
+#define IPU_DI1_SW_GEN1_3_OFFSET                0x00048038
+#define IPU_DI1_SW_GEN1_4_OFFSET                0x0004803C
+#define IPU_DI1_SW_GEN1_5_OFFSET                0x00048040
+#define IPU_DI1_SW_GEN1_6_OFFSET                0x00048044
+#define IPU_DI1_SW_GEN1_7_OFFSET                0x00048048
+#define IPU_DI1_SW_GEN1_8_OFFSET                0x0004804C
+#define IPU_DI1_SW_GEN1_9_OFFSET                0x00048050
+#define IPU_DI1_SYNC_AS_GEN_OFFSET              0x00048054
+#define IPU_DI1_DW_GEN_OFFSET                   0x00048058
+#define IPU_DI1_DW_SET0_OFFSET                  0x00048088
+#define IPU_DI1_DW_SET1_OFFSET                  0x000480B8
+#define IPU_DI1_DW_SET2_OFFSET                  0x000480E8
+#define IPU_DI1_DW_SET3_OFFSET                  0x00048118
+#define IPU_DI1_STP_REP_OFFSET                  0x00048148
+#define IPU_DI1_STP_REP_9_OFFSET                0x00048158
+#define IPU_DI1_SER_CONF_OFFSET                 0x0004815C
+#define IPU_DI1_SSC_OFFSET                      0x00048160
+#define IPU_DI1_POL_OFFSET                      0x00048164
+#define IPU_DI1_AW0_OFFSET                      0x00048168
+#define IPU_DI1_AW1_OFFSET                      0x0004816C
+#define IPU_DI1_SCR_CONF_OFFSET                 0x00048170
+#define IPU_DI1_STAT_OFFSET                     0x00048174
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.c
new file mode 100644
index 000000000000..325e81974888
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.c
@@ -0,0 +1,81 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright 2018 NXP
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "Osal.h"
+#include "Display.h"
+#include "Lvds.h"
+#include "Edid.h"
+
+OS_STATUS InitLVDS (
+    DISPLAY_CONTEXT* DisplayContextPtr
+    )
+{
+    DISPLAY_INTERFACE_CONTEXT* LvdsDisplayContextPtr = &DisplayContextPtr->DIContext[LVDS0_DISPLAY];
+    OS_STATUS status = 0;
+
+    OS_ZERO_MEM(LvdsDisplayContextPtr, sizeof(*LvdsDisplayContextPtr));
+
+    LvdsDisplayContextPtr->MmioBasePtr = (VOID*)OS_MMIO_MAP(LDB_BASE);
+    if (LvdsDisplayContextPtr->MmioBasePtr == NULL) {
+        OS_ERROR("Fail to map LDB register\n");
+        goto Exit;
+    }
+
+
+    // LVDS CH1 enabled, routed to DI0; ipu_di01_vsync_active_low
+    {
+
+
+        LDB_CTRL_REG LdbCtrlReg;
+        LdbCtrlReg.Reg = LVDSRead32(LDB_CTRL);
+        LdbCtrlReg.ch0_mode = 1;
+        LdbCtrlReg.ch1_mode = 1;
+        LdbCtrlReg.di0_vs_polarity = 1;
+        LdbCtrlReg.di1_vs_polarity = 1;
+        LVDSWrite32(LDB_CTRL, LdbCtrlReg.Reg);
+    }
+
+    // No EDID available
+    LvdsDisplayContextPtr->EdidDataSize = 0;
+
+    status = GetPreferedTiming(
+        LvdsDisplayContextPtr->EdidData,
+        LvdsDisplayContextPtr->EdidDataSize,
+        &LvdsDisplayContextPtr->PreferedTiming);
+    if (status != OS_STATUS_SUCCESS) {
+        OS_ERROR("Fail to retrieve LVDS prefered timing\n");
+        goto Exit;
+    }
+
+Exit:
+    return status;
+}
+
+OS_STATUS SetLVDSPower (
+    DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr,
+    BOOLEAN PowerState
+    )
+{
+    return OS_STATUS_UNSUPPORTED;
+}
+
+OS_STATUS SetLVDSDisplay (
+    DISPLAY_INTERFACE_CONTEXT* LvdsDisplayContextPtr,
+    DISPLAY_TIMING* Timings
+    )
+{
+    return OS_STATUS_UNSUPPORTED;
+}
+
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.h
new file mode 100644
index 000000000000..f98b4aac0061
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.h
@@ -0,0 +1,72 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright 2018 NXP
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _LVDS_H_
+#define _LVDS_H_
+
+#define LVDSRead32(a) \
+            OS_READ32((UINT32)LvdsDisplayContextPtr->MmioBasePtr + (a))
+
+#define LVDSWrite32(a, b) \
+            OS_WRITE32((UINT32)LvdsDisplayContextPtr->MmioBasePtr + (a), (b))
+
+// LDB Register Base Address
+#define LDB_BASE 0x020E0008
+
+// LDB Control Register offset
+#define LDB_CTRL    0
+
+// Register struct
+
+#pragma pack(push, 1)
+
+// LDB_CTRL_REG
+typedef union {
+    struct {
+        UINT32 ch0_mode : 2;
+        UINT32 ch1_mode : 2;
+        UINT32 split_mode_en : 1;
+        UINT32 data_width_ch0 : 1;
+        UINT32 bit_mapping_ch0 : 1;
+        UINT32 data_width_ch1 : 1;
+        UINT32 bit_mapping_ch1 : 1;
+        UINT32 di0_vs_polarity : 1;
+        UINT32 di1_vs_polarity : 1;
+        UINT32 Reserved11_15 : 5;
+        UINT32 lvds_clk_shift : 3;
+        UINT32 Reserved19 : 1;
+        UINT32 counter_reset_val : 2;
+        UINT32 Reserved22_31 : 10;
+    };
+    UINT32 Reg;
+}  LDB_CTRL_REG;
+
+#pragma pack(pop)
+
+OS_STATUS InitLVDS (
+    DISPLAY_CONTEXT* DisplayContextPtr
+    );
+
+OS_STATUS SetLVDSPower (
+    DISPLAY_INTERFACE_CONTEXT* LvdsDisplayContextPtr,
+    BOOLEAN PowerState
+    );
+
+OS_STATUS SetLVDSDisplay (
+    DISPLAY_INTERFACE_CONTEXT* LvdsDisplayContextPtr,
+    DISPLAY_TIMING* Timings
+    );
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.c
new file mode 100644
index 000000000000..664f9e008f1c
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.c
@@ -0,0 +1,38 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "Osal.h"
+#include "Display.h"
+#include "Ipu.h"
+
+OS_STATUS UefiAllocContiguousMemory (
+    UINT32 AllocSize,
+    VOID** MemoryPointer)
+{
+    OS_STATUS status;
+
+    *MemoryPointer = NULL;
+
+    *MemoryPointer = AllocateRuntimePool(AllocSize);
+    if (*MemoryPointer == NULL) {
+        OS_ERROR("AllocateRuntimePool failed\n");
+        status = OS_STATUS_INSUFFICIENT_RESOURCE;
+        goto Exit;
+    }
+
+    status = OS_STATUS_SUCCESS;
+
+Exit:
+    return status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.h b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.h
new file mode 100644
index 000000000000..7719b0a1bddb
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.h
@@ -0,0 +1,74 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _OSAL_H_
+#define _OSAL_H_
+
+// OS abstraction header
+
+#ifdef WIN32 // Windows
+
+#else // UEFI
+
+#include <Uefi.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+// UEFI only headers
+#include <iMX6.h>
+#include <iMXDisplay.h>
+#include <iMX6ClkPwr.h>
+
+#define OS_READ8(ADDRESS)  MmioRead8(ADDRESS)
+#define OS_WRITE8(ADDRESS, VALUE)  MmioWrite8(ADDRESS, VALUE)
+#define OS_READ32(ADDRESS)  MmioRead32((UINT32)ADDRESS)
+#define OS_WRITE32(ADDRESS, VALUE)  MmioWrite32((UINT32)ADDRESS, VALUE)
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(__array__) (sizeof((__array__))/sizeof((__array__[0])))
+#endif
+
+#define OS_STATUS                           EFI_STATUS
+#define OS_STATUS_SUCCESS                   EFI_SUCCESS
+#define OS_STATUS_INVALID_PARAM             EFI_INVALID_PARAMETER
+#define OS_STATUS_DEVICE_ERROR              EFI_DEVICE_ERROR
+#define OS_STATUS_UNSUPPORTED               EFI_UNSUPPORTED
+#define OS_STATUS_INSUFFICIENT_RESOURCE     EFI_OUT_OF_RESOURCES
+
+OS_STATUS UefiAllocContiguousMemory (
+    UINT32 AllocSize,
+    VOID** MemoryPointer
+    );
+
+#define OS_MMIO_MAP(PHYSICAL_ADDRESS)           PHYSICAL_ADDRESS
+#define OS_SLEEP(MILISECOND)                    gBS->Stall(MILISECOND)
+#define OS_ALLOC_CONTIGUOUS_MEMORY(ALLOC_SIZE, MEMORY_POINTER) \
+            UefiAllocContiguousMemory(ALLOC_SIZE, (VOID**) MEMORY_POINTER)
+#define OS_VIRT_TO_PHY_ADDR(VIRT_ADDR)          (VIRT_ADDR)
+#define OS_MEM_COPY(DEST, SRC, SIZE)            CopyMem(DEST, SRC, SIZE)
+#define OS_ZERO_MEM(VIRT_ADDR, SIZE)            ZeroMem(VIRT_ADDR, SIZE)
+
+#define OS_LOG_FMT_HELPER(FMT, ...) \
+    "iMX6Gop:" FMT "%a", __VA_ARGS__
+
+#define OS_INFO(...) DEBUG((DEBUG_INFO, OS_LOG_FMT_HELPER(__VA_ARGS__, "")))
+#define OS_WARNING(...) DEBUG((DEBUG_WARN, OS_LOG_FMT_HELPER(__VA_ARGS__, "")))
+#define OS_ERROR(...) DEBUG((DEBUG_ERROR, OS_LOG_FMT_HELPER(__VA_ARGS__, "")))
+
+#endif
+
+#endif
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/iMX6GOP.inf b/Silicon/NXP/iMX6Pkg/Drivers/GOP/iMX6GOP.inf
new file mode 100644
index 000000000000..49e4788c0781
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/iMX6GOP.inf
@@ -0,0 +1,71 @@
+#/** @file
+#
+#  Copyright (c) 2011, ARM Ltd. All rights reserved.<BR>
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = iMX6GOPDxe
+  FILE_GUID                      = E68088EF-D1A4-4336-C1DB-4D3A204730A6
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = VideoiMX6DxeInitialize
+
+[Sources.common]
+  iMXVideoDxe.c
+  Osal.c
+  Ddc.c
+  Display.c
+  Hdmi.c
+  Lvds.c
+  Edid.c
+  DisplayInterface.c
+  DisplayController.c
+  CPMem.c
+  IoMux.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Silicon/NXP/iMX6Pkg/iMX6Pkg.dec
+
+[LibraryClasses]
+  ArmLib
+  UefiLib
+  BaseLib
+  DebugLib
+  TimerLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  IoLib
+  BaseMemoryLib
+  iMX6ClkPwrLib
+  iMXDisplayLib
+
+[Protocols]
+  gEfiDevicePathProtocolGuid                    # Produced
+  gEfiGraphicsOutputProtocolGuid                # Produced
+  gEfiEdidDiscoveredProtocolGuid                # Produced
+  gEfiEdidActiveProtocolGuid                    # Produced
+  gEfiDevicePathToTextProtocolGuid
+
+[Pcd]
+  giMX6TokenSpaceGuid.PcdFrameBufferBase
+  giMX6TokenSpaceGuid.PcdFrameBufferSize
+  giMX6TokenSpaceGuid.PcdLvdsEnable
+
+[Depex]
+  gEfiCpuArchProtocolGuid AND gEfiTimerArchProtocolGuid
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/iMXVideoDxe.c b/Silicon/NXP/iMX6Pkg/Drivers/GOP/iMXVideoDxe.c
new file mode 100644
index 000000000000..f65c0df8f148
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/iMXVideoDxe.c
@@ -0,0 +1,488 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright 2018 NXP
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/EmbeddedExternalDevice.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/EdidDiscovered.h>
+#include <Protocol/EdidActive.h>
+
+#include "Osal.h"
+#include "Display.h"
+#include "Hdmi.h"
+#include "Lvds.h"
+
+#define PIXEL_BYTES 4
+
+typedef struct {
+    VENDOR_DEVICE_PATH Mmc;
+    EFI_DEVICE_PATH End;
+} VID_DEVICE_PATH;
+
+DISPLAY_TIMING const FullHDTiming =
+{
+    148500000,  // Full 1080p HD PixelClock
+    1920,       // HActive
+    280,        // HBlank
+    1080,       // VActive
+    45,         // VBlank
+    44,         // HSync
+    5,          // VSync
+    88,         // HSyncOffset;
+    4,          // VSyncOffset;
+    1920,       // HImageSize
+    1080,       // VImageSize
+    0,          // HBorder
+    0,          // VBorder
+    30,         // EdidFlags
+    0,          // Flags
+    1,          // PixelRepetition
+    32,         // Bpp
+    PIXEL_FORMAT_BGRA32,       // PixelFormat
+};
+
+EFI_STATUS
+EFIAPI
+VidGopQueryMode(
+    IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+    IN UINT32 ModeNumber,
+    OUT UINTN *SizeOfInfo,
+    OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+    );
+
+EFI_STATUS
+VidGopSetMode(
+    IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+    IN UINT32 ModeNumber
+    );
+
+EFI_STATUS
+VidGopBlt(
+    IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+    IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
+    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
+    );
+
+//--------------------------------------------------------------------- Globals.
+
+static VID_DEVICE_PATH g_VidDevicePath =
+{
+    {
+        {
+            HARDWARE_DEVICE_PATH,
+            HW_VENDOR_DP,
+            {
+                (UINT8)sizeof(VENDOR_DEVICE_PATH),
+                (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
+            }
+        },
+        {
+            0xa6b94ebe,
+            0x5ba3,
+            0x44b0,
+            { 0x95, 0x92, 0xdc, 0x04, 0x5e, 0xb8, 0xf8, 0x9e }
+        }
+    },
+    {
+        END_DEVICE_PATH_TYPE,
+        END_ENTIRE_DEVICE_PATH_SUBTYPE,
+        {
+            sizeof(EFI_DEVICE_PATH_PROTOCOL),
+            0
+        }
+    }
+};
+
+static EFI_GRAPHICS_OUTPUT_MODE_INFORMATION g_VidGopModeInfo;
+static EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE g_VidGopMode;
+
+static EFI_GRAPHICS_OUTPUT_PROTOCOL g_VidGop =
+{
+    VidGopQueryMode, // QueryMode
+    VidGopSetMode,   // SetMode
+    VidGopBlt,       // Blt
+    &g_VidGopMode    // Mode
+};
+
+EFI_EDID_DISCOVERED_PROTOCOL g_EdidDiscovered = {
+    0,
+    NULL
+};
+
+EFI_EDID_ACTIVE_PROTOCOL g_EdidActive = {
+    0,
+    NULL
+};
+
+DISPLAY_CONTEXT* DisplayContextPtr;
+
+DISPLAY_INTERFACE DisplayDevice;
+
+EFI_STATUS
+VideoiMX6DxeInitialize (
+    IN EFI_HANDLE       ImageHandle,
+    IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+    EFI_STATUS status;
+    UINT32 ReservedDisplayMemorySize;
+    UINT32 RequestedDisplayMemorySize;
+    DEBUG((DEBUG_INFO,"++VideoiMX6DxeInitialize()\r\n"));
+
+       ReservedDisplayMemorySize = FixedPcdGet32(PcdFrameBufferSize);
+
+    if (FeaturePcdGet(PcdLvdsEnable)) {
+        DisplayDevice = LVDS0_DISPLAY;
+    } else {
+        DisplayDevice = HDMI_DISPLAY;
+    }
+
+    status = InitDisplay(&DisplayContextPtr);
+    if (EFI_ERROR(status)) {
+        DEBUG(
+            (DEBUG_ERROR,
+            "VideoiMX6DxeInitialize: Fail to init display, status=%r\n",
+            status));
+        goto Exit;
+    }
+
+    DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize - Allocate frame buffer\r\n"));
+    // To allocate frame buffer dynamically, there isn`t a built in graphic memory
+    // manager for UEFI, so we are allocating frame buffer manually. Currently only
+    // support single display, so allocate single(1) frame buffer
+    {
+        // Allocate frame buffer
+        DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width =
+            DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming.HActive;
+        DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height =
+            DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming.VActive;
+        DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp =
+            DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming.Bpp;
+        DisplayContextPtr->DisplayConfig.DisplaySurface[0].PixelFormat =
+            DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming.PixelFormat;
+
+        // iMX6 UEFI reserves display memory for fullHD buffer size.
+        // PcdFrameBufferSize=800000h or 8388608 bytes - 1920x1080x4 bytes
+        // to prevent larger displays overrun our reserved memory size, cap display resolution to fullHD
+        // NOTE: for displays which do not have supported 1920x1080 mode may cause poor or missing picture
+
+        RequestedDisplayMemorySize=DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width *
+            DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height *
+            (DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp/8);
+
+        DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize: Display Memory: Needed=%d, Available=%d\r\n",RequestedDisplayMemorySize,
+            ReservedDisplayMemorySize));
+
+        if (RequestedDisplayMemorySize > ReservedDisplayMemorySize) {
+            DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize WARNING. Display resolution needs more video memory than reserved by %d bytes\r\n",
+                RequestedDisplayMemorySize - ReservedDisplayMemorySize));
+            DEBUG((DEBUG_ERROR,"VideoiMX6DxeInitialize - display horizontal resolution too big. Cap to HD 1080p\r\n"));
+
+            DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width = FullHDTiming.HActive;
+            DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height = FullHDTiming.VActive;
+            DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp = FullHDTiming.Bpp;
+
+             OS_MEM_COPY(&DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming,
+                    &FullHDTiming, sizeof(DISPLAY_TIMING));
+        }
+
+        DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize - allocating frame buffer... \r\n"));
+        status = AllocateFrameBuffer(
+            &DisplayContextPtr->DisplayConfig.DisplaySurface[0]);
+        if (EFI_ERROR(status)) {
+            DEBUG(
+                (DEBUG_ERROR,
+                "VideoiMX6DxeInitialize: Fail to allocate fb, status=%r\n",
+                status));
+            goto Exit;
+        };
+
+        DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize - Initialize the frame buffer to black\r\n"));
+        // Initialize the frame buffer to black
+        SetMem32(
+            (void*)DisplayContextPtr->DisplayConfig.DisplaySurface[0].PhyAddr,
+            DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width *
+                DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height * 4,
+            0xFF000000);
+
+    }
+
+    DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize - set the display configuration to single HDMI mode\r\n"));
+    // Set the display configuration to single HDMI/LVDS mode
+    {
+        DISPLAY_INTERFACE displayInterfaceOrder[MAX_DISPLAY] = {
+            DisplayDevice,
+            NO_DISPLAY,
+            NO_DISPLAY,
+            NO_DISPLAY,
+        };
+
+        DisplayContextPtr->DisplayConfig.DisplayTiming[0] =
+            DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming;
+
+        status = ApplyDisplayConfig(
+            DisplayContextPtr,
+            SINGLE_MODE,
+            displayInterfaceOrder);
+        if (EFI_ERROR(status)) {
+            DEBUG(
+                (DEBUG_ERROR,
+                "VideoiMX6DxeInitialize: Fail to set display. Exit status=%r\n",
+                status));
+            goto Exit;
+        }
+    }
+
+    g_VidGopModeInfo.Version = 0;
+    g_VidGopModeInfo.HorizontalResolution =
+        DisplayContextPtr->DisplayConfig.DisplayTiming[0].HActive;
+    g_VidGopModeInfo.VerticalResolution =
+        DisplayContextPtr->DisplayConfig.DisplayTiming[0].VActive;
+    g_VidGopModeInfo.PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+
+    OS_ZERO_MEM(
+        &g_VidGopModeInfo.PixelInformation,
+        sizeof(g_VidGopModeInfo.PixelInformation));
+
+    g_VidGopModeInfo.PixelsPerScanLine = g_VidGopModeInfo.HorizontalResolution;
+    g_VidGopMode.MaxMode = 1;
+    g_VidGopMode.Mode = 0;
+    g_VidGopMode.Info = &g_VidGopModeInfo;
+    g_VidGopMode.SizeOfInfo = sizeof(g_VidGopModeInfo);
+    g_VidGopMode.FrameBufferBase =
+        (EFI_PHYSICAL_ADDRESS)
+            DisplayContextPtr->DisplayConfig.DisplaySurface[0].PhyAddr;
+    g_VidGopMode.FrameBufferSize =
+        g_VidGopModeInfo.HorizontalResolution *
+            g_VidGopModeInfo.VerticalResolution *
+            (DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp / 8);
+
+    DisplayContextPtr->DisplayConfig.OsHandle[0] = (UINT32)&ImageHandle;
+
+    status = gBS->InstallMultipleProtocolInterfaces(
+        &ImageHandle,
+        &gEfiGraphicsOutputProtocolGuid,
+        &g_VidGop,
+        &gEfiDevicePathProtocolGuid,
+        &g_VidDevicePath,
+        NULL);
+    if (EFI_ERROR(status)) {
+        DEBUG(
+            (DEBUG_ERROR,
+            "VideoiMX6DxeInitialize: Fail to install protocol, status=%r\n",
+            status));
+        goto Exit;
+    }
+
+Exit:
+    DEBUG((DEBUG_INFO,"--VideoiMX6DxeInitialize()=%Xh\r\n",status));
+    return status;
+}
+
+//---------------------------------------------------------------- GOP routines.
+
+EFI_STATUS
+EFIAPI
+VidGopQueryMode (
+    IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+    IN UINT32 ModeNumber,
+    OUT UINTN *SizeOfInfo,
+    OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+    )
+{
+    EFI_STATUS status;
+    EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *outputMode;
+
+    if (FeaturePcdGet(PcdLvdsEnable)) {
+        DisplayDevice = LVDS0_DISPLAY;
+    } else {
+        DisplayDevice = HDMI_DISPLAY;
+    }
+
+
+    g_EdidDiscovered.SizeOfEdid =
+        DisplayContextPtr->DIContext[DisplayDevice].EdidDataSize;
+    g_EdidDiscovered.Edid =
+        DisplayContextPtr->DIContext[DisplayDevice].EdidData;
+    g_EdidActive.SizeOfEdid =
+        DisplayContextPtr->DIContext[DisplayDevice].EdidDataSize;
+    g_EdidActive.Edid =
+        DisplayContextPtr->DIContext[DisplayDevice].EdidData;
+
+    status = gBS->InstallMultipleProtocolInterfaces(
+        (EFI_HANDLE)DisplayContextPtr->DisplayConfig.OsHandle[0],
+        &gEfiEdidDiscoveredProtocolGuid,
+        &g_EdidDiscovered,
+        &gEfiEdidActiveProtocolGuid,
+        &g_EdidActive,
+        NULL);
+    if (EFI_ERROR(status)) {
+        DEBUG(
+            (DEBUG_ERROR,
+            "Fail to install EDID discover and active protocol status=%r\n",
+            status));
+    }
+
+    if (ModeNumber != 0) {
+        DEBUG((DEBUG_ERROR, "VidGopQueryMode: Saw request to query mode %d\n", ModeNumber));
+        status = EFI_INVALID_PARAMETER;
+        goto Exit;
+    }
+
+    outputMode = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *)
+        AllocatePool (sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+    if (outputMode == NULL) {
+        status = EFI_OUT_OF_RESOURCES;
+        goto Exit;
+    }
+
+    outputMode->Version = 0;
+    outputMode->HorizontalResolution = g_VidGopModeInfo.HorizontalResolution;
+    outputMode->VerticalResolution = g_VidGopModeInfo.VerticalResolution;
+    outputMode->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+
+    outputMode->PixelsPerScanLine = g_VidGopModeInfo.HorizontalResolution;
+    *SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+    *Info = outputMode;
+
+    status = EFI_SUCCESS;
+
+Exit:
+    return status;
+}
+
+EFI_STATUS
+VidGopSetMode (
+    IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+    IN UINT32 ModeNumber
+    )
+{
+    OS_STATUS status;
+
+    if (ModeNumber != 0) {
+        DEBUG((DEBUG_ERROR, "VidGopSetMode: Saw request to set mode to %d\n", ModeNumber));
+        status = OS_STATUS_UNSUPPORTED;
+        goto Exit;
+    }
+
+    status = OS_STATUS_SUCCESS;
+
+Exit:
+    return status;
+}
+
+EFI_STATUS
+VidGopBlt (
+    IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+    IN OUT 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
+    )
+{
+    UINT32 *frameBuffer;
+    UINT32 frameWidth;
+    UINT32 frameOffset;
+    UINT32 bufferOffset;
+    UINT32 bufferWidth;
+    UINT32 i;
+
+    frameBuffer = (UINT32 *) (UINTN) g_VidGopMode.FrameBufferBase;
+    frameWidth = g_VidGopModeInfo.HorizontalResolution;
+
+    if (Delta == 0) {
+        bufferWidth = Width;
+    } else {
+        bufferWidth = Delta / PIXEL_BYTES;
+    }
+
+    if (BltOperation == EfiBltVideoFill) {
+
+        frameOffset = frameWidth * DestinationY + DestinationX;
+        for (i = DestinationY; i < DestinationY + Height; i++) {
+            SetMem32(frameBuffer + frameOffset,
+                     Width * PIXEL_BYTES,
+                     *(UINT32 *)BltBuffer
+                     );
+            frameOffset += frameWidth;
+        }
+    } else if (BltOperation == EfiBltVideoToBltBuffer) {
+
+        frameOffset = frameWidth * SourceY + SourceX;
+        bufferOffset = bufferWidth * DestinationY + DestinationX;
+
+        for (i = SourceY; i < SourceY + Height; i++) {
+            CopyMem(BltBuffer + bufferOffset,
+                    frameBuffer + frameOffset,
+                    Width * PIXEL_BYTES);
+            frameOffset += frameWidth;
+            bufferOffset += bufferWidth;
+        }
+    } else if (BltOperation == EfiBltBufferToVideo) {
+
+        frameOffset = frameWidth * DestinationY + DestinationX;
+        bufferOffset = bufferWidth * SourceY + SourceX;
+
+        for (i = SourceY; i < SourceY + Height; i++) {
+            CopyMem(frameBuffer + frameOffset,
+                    BltBuffer + bufferOffset,
+                    Width * PIXEL_BYTES);
+            frameOffset += frameWidth;
+            bufferOffset += bufferWidth;
+        }
+
+    } else if (BltOperation == EfiBltVideoToVideo) {
+
+        frameOffset = frameWidth * DestinationY + DestinationX;
+        bufferOffset = frameWidth * SourceY + SourceX;
+
+        for (i = SourceY; i < SourceY + Height; i++) {
+            CopyMem(frameBuffer + frameOffset,
+                    frameBuffer + bufferOffset,
+                    Width * PIXEL_BYTES);
+            frameOffset += frameWidth;
+            bufferOffset += frameWidth;
+        }
+
+    } else {
+        DEBUG((DEBUG_ERROR, "VideoDxe:VidGopBlt not impl %d\n", BltOperation));
+        return EFI_INVALID_PARAMETER;
+    }
+
+    return EFI_SUCCESS;
+}
-- 
2.16.2.gvfs.1.33.gf5370f1



  parent reply	other threads:[~2018-07-20  6:34 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-20  6:33 [PATCH edk2-platforms 00/13] Silicon/NXP: Import NXP i.MX6 Package Chris Co
2018-07-20  6:33 ` [PATCH edk2-platforms 01/13] Silicon/NXP: Add i.MX6 SoC header files Chris Co
2018-07-20  6:33 ` [PATCH edk2-platforms 02/13] Silicon/NXP: Add i.MX6 GPT and EPIT timer headers Chris Co
2018-07-20  6:33 ` [PATCH edk2-platforms 03/13] Silicon/NXP: Add iMX6Pkg dec Chris Co
2018-07-20  6:33 ` [PATCH edk2-platforms 04/13] Silicon/NXP: Add i.MX6 Timer DXE driver Chris Co
2018-07-20  6:33 ` [PATCH edk2-platforms 05/13] Silicon/NXP: Add i.MX6 GPT Timer library Chris Co
2018-07-20  6:33 ` [PATCH edk2-platforms 06/13] Silicon/NXP: Add i.MX6 USB Phy Library Chris Co
2018-07-20  6:33 ` [PATCH edk2-platforms 07/13] Silicon/NXP: Add i.MX6 I/O MUX library Chris Co
2018-07-20  6:33 ` [PATCH edk2-platforms 08/13] Silicon/NXP: Add i.MX6 Clock Library Chris Co
2018-07-20  6:33 ` [PATCH edk2-platforms 09/13] Silicon/NXP: Add i.MX6 ACPI tables Chris Co
2018-07-20  6:33 ` [PATCH edk2-platforms 10/13] Silicon/NXP: Add i.MX6 Board init library Chris Co
2018-07-20  6:34 ` [PATCH edk2-platforms 11/13] Silicon/NXP: Add i.MX6 PCIe DXE driver Chris Co
2018-07-20  6:34 ` Chris Co [this message]
2018-07-20  6:34 ` [PATCH edk2-platforms 13/13] Silicon/NXP: Add i.MX6 common dsc and fdf files Chris Co

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20180720063328.26856-13-christopher.co@microsoft.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

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

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