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 22/27] Silicon/NXP: Add i.MX6 GOP driver
Date: Fri, 21 Sep 2018 08:26:15 +0000 [thread overview]
Message-ID: <20180921082542.35768-23-christopher.co@microsoft.com> (raw)
In-Reply-To: <20180921082542.35768-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/GopDxe/CPMem.c | 423 +++++++++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/CPMem.h | 277 +++++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ddc.c | 69 ++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ddc.h | 28 +
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Display.c | 455 ++++++++++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Display.h | 175 +++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayController.c | 399 ++++++++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayController.h | 331 +++++++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayInterface.c | 458 ++++++++++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayInterface.h | 195 +++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Edid.c | 96 +++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Edid.h | 33 +
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.c | 475 ++++++++++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.h | 20 +
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.inf | 70 ++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Hdmi.c | 761 ++++++++++++++++++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Hdmi.h | 529 ++++++++++++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/IoMux.c | 88 +++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/IoMux.h | 32 +
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ipu.h | 236 ++++++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Lvds.c | 93 +++
Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Lvds.h | 67 ++
22 files changed, 5310 insertions(+)
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/CPMem.c b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/CPMem.c
new file mode 100644
index 000000000000..a8ab78128719
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/CPMem.c
@@ -0,0 +1,423 @@
+/** @file
+*
+* Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <iMX6.h>
+#include <iMX6ClkPwr.h>
+#include <iMXDisplay.h>
+
+#include "Display.h"
+#include "CPMem.h"
+#include "GopDxe.h"
+#include "Ipu.h"
+
+CPMEM_PARAM *CpMemParamBasePtr = (CPMEM_PARAM *)(IPU1_BASE + CSP_IPUV3_CPMEM_REGS_OFFSET);
+
+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,
+};
+
+#ifdef DEBUG
+VOID
+DumpCpmemParamPack (
+ IN CPMEM_PARAM *ParamPtr
+ )
+{
+ DEBUG ((DEBUG_VERBOSE, "%a: --WORD0--\n", __FUNCTION__));
+ DEBUG ((DEBUG_VERBOSE, "%a: XVVirtualCoordinate 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.XVVirtualCoordinate));
+ DEBUG ((DEBUG_VERBOSE, "%a: YVVirtualCoordinate 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.YVVirtualCoordinate));
+ DEBUG ((DEBUG_VERBOSE, "%a: XBinnerBlockCoordinate 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.XBinnerBlockCoordinate));
+ DEBUG ((DEBUG_VERBOSE, "%a: YBinnerBlockCoordinate 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.YBinnerBlockCoordinate));
+ DEBUG ((DEBUG_VERBOSE, "%a: NewSubBlock 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.NewSubBlock));
+ DEBUG ((DEBUG_VERBOSE, "%a: CurrentField 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.CurrentField));
+ DEBUG ((DEBUG_VERBOSE, "%a: ScrollXCounter 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ScrollXCounter));
+ DEBUG ((DEBUG_VERBOSE, "%a: ScrollYCounter 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ScrollYCounter));
+ DEBUG ((DEBUG_VERBOSE, "%a: NumberOfScroll 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.NumberOfScroll));
+ DEBUG ((DEBUG_VERBOSE, "%a: ScrollDeltaX 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ScrollDeltaX));
+ DEBUG ((DEBUG_VERBOSE, "%a: ScrollMax 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ScrollMax));
+ DEBUG ((DEBUG_VERBOSE, "%a: ScrollingConfiguration 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ScrollingConfiguration));
+ DEBUG ((DEBUG_VERBOSE, "%a: ScrollingEnable 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ScrollingEnable));
+ DEBUG ((DEBUG_VERBOSE, "%a: ScrollDeltaY 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ScrollDeltaY));
+ DEBUG ((DEBUG_VERBOSE, "%a: ScrollHorizontalDirection 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ScrollHorizontalDirection));
+ DEBUG ((DEBUG_VERBOSE, "%a: ScrollVerticalDirection 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ScrollVerticalDirection));
+ DEBUG ((DEBUG_VERBOSE, "%a: BitsPerPixel 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.BitsPerPixel));
+ DEBUG ((DEBUG_VERBOSE, "%a: DecodeAddressSelect 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.DecodeAddressSelect));
+ DEBUG ((DEBUG_VERBOSE, "%a: AccessDimension 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.AccessDimension));
+ DEBUG ((DEBUG_VERBOSE, "%a: ScanOrder 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ScanOrder));
+ DEBUG ((DEBUG_VERBOSE, "%a: BandMode 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.BandMode));
+ DEBUG ((DEBUG_VERBOSE, "%a: BlockMode 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.BlockMode));
+ DEBUG ((DEBUG_VERBOSE, "%a: Rotation 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.Rotation));
+ DEBUG ((DEBUG_VERBOSE, "%a: HorizontalFlip 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.HorizontalFlip));
+ DEBUG ((DEBUG_VERBOSE, "%a: VerticalFlip 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.VerticalFlip));
+ DEBUG ((DEBUG_VERBOSE, "%a: ThresholdEnable 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ThresholdEnable));
+ DEBUG ((DEBUG_VERBOSE, "%a: ConditionalAccessPolarity 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ConditionalAccessPolarity));
+ DEBUG ((DEBUG_VERBOSE, "%a: ConditionalAccessEnable 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.ConditionalAccessEnable));
+ DEBUG ((DEBUG_VERBOSE, "%a: FrameWidth 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.FrameWidth));
+ DEBUG ((DEBUG_VERBOSE, "%a: FrameHeight 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.FrameHeight));
+ DEBUG ((DEBUG_VERBOSE, "%a: EndOfLineInterrupt 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word0Pack.EndOfLineInterrupt));
+
+ DEBUG ((DEBUG_VERBOSE, "%a: --WORD1--\n", __FUNCTION__));
+ DEBUG ((DEBUG_VERBOSE, "%a: ExtMemBuffer0Address 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.ExtMemBuffer0Address));
+ DEBUG ((DEBUG_VERBOSE, "%a: ExtMemBuffer1Address 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.ExtMemBuffer1Address));
+ DEBUG ((DEBUG_VERBOSE, "%a: InterlaceOffset 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.InterlaceOffset));
+ DEBUG ((DEBUG_VERBOSE, "%a: NumberOfPixelsInWholeBurstAccess 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.NumberOfPixelsInWholeBurstAccess));
+ DEBUG ((DEBUG_VERBOSE, "%a: PixelFormatSelect 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.PixelFormatSelect));
+ DEBUG ((DEBUG_VERBOSE, "%a: AlphaUsed 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.AlphaUsed));
+ DEBUG ((DEBUG_VERBOSE, "%a: AlphaChannelMapping 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.AlphaChannelMapping));
+ DEBUG ((DEBUG_VERBOSE, "%a: AxiId 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.AxiId));
+ DEBUG ((DEBUG_VERBOSE, "%a: Threshold 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.Threshold));
+ DEBUG ((DEBUG_VERBOSE, "%a: StrideLine 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.StrideLine));
+ DEBUG ((DEBUG_VERBOSE, "%a: Width0 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.Width0));
+ DEBUG ((DEBUG_VERBOSE, "%a: Width1 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.Width1));
+ DEBUG ((DEBUG_VERBOSE, "%a: Width2 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.Width2));
+ DEBUG ((DEBUG_VERBOSE, "%a: Width3 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.Width3));
+ DEBUG ((DEBUG_VERBOSE, "%a: Offset0 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.Offset0));
+ DEBUG ((DEBUG_VERBOSE, "%a: Offset1 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.Offset1));
+ DEBUG ((DEBUG_VERBOSE, "%a: Offset2 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.Offset2));
+ DEBUG ((DEBUG_VERBOSE, "%a: Offset3 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.Offset3));
+ DEBUG ((DEBUG_VERBOSE, "%a: SelectSXSYSet 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.SelectSXSYSet));
+ DEBUG ((DEBUG_VERBOSE, "%a: ConditionalReadEnable 0x%08x\n", __FUNCTION__,
+ ParamPtr->Word1Pack.ConditionalReadEnable));
+}
+
+VOID
+DumpBasicCpmemReg (
+ IN CPMEM_PARAM *pCpmemChannel
+ )
+{
+ DEBUG ((DEBUG_VERBOSE, "%a: ---------- CPMEM Register Dump ----------\n",
+ __FUNCTION__));
+ DEBUG ((DEBUG_VERBOSE, "%a: CPMEM\n", __FUNCTION__));
+ DEBUG ((DEBUG_VERBOSE, "%a: IDMAC_CHANNEL_DP_PRIMARY_FLOW_MAIN_PLANE\n",
+ __FUNCTION__));
+ DumpCpmemParamPack (pCpmemChannel);
+ DEBUG ((DEBUG_VERBOSE, "%a: ------------------------------------\n",
+ __FUNCTION__));
+}
+#endif /* DEBUG */
+
+// Enable IDMAC lock setting, which optimises memory accesses and reduces
+// power consumption
+VOID
+SetIdmacLockEn (
+ IN DISPLAY_INTERFACE_CONTEXT *DisplayInterfaceContextPtr,
+ IN UINT32 Channel,
+ IN UINT32 Setting
+ )
+{
+ UINT32 i;
+ UINTN LockReg;
+ UINT32 Shift;
+ UINT32 Value;
+
+ Shift = -1;
+
+ for (i = 0; i < ARRAYSIZE (ChannelMap); i += 2) {
+ if (ChannelMap[i] == Channel) {
+ Shift = ChannelMap[i + 1];
+ break;
+ }
+ }
+
+ if (Shift == -1) {
+ DEBUG ((DEBUG_WARN, "%a: Channel %d does not have lock bits\n",
+ __FUNCTION__, Channel));
+ return;
+ }
+
+ if (Channel < 29) {
+ LockReg = (UINTN)DisplayInterfaceContextPtr->IpuMmioBasePtr + IPU_IDMAC_LOCK_EN_1;
+ } else {
+ LockReg = (UINTN)DisplayInterfaceContextPtr->IpuMmioBasePtr + IPU_IDMAC_LOCK_EN_2;
+ }
+
+ Value = MmioRead32 ((UINT32)LockReg);
+ Value &= ~(0x3 << Shift);
+ Value |= (Setting & 0x3) << Shift;
+ MmioWrite32 ((UINT32)LockReg, Value);
+}
+
+EFI_STATUS
+ConfigureCpmemFrameBuffer (
+ IN DISPLAY_INTERFACE_CONTEXT *DisplayInterfaceContextPtr,
+ IN UINT32 Channel,
+ IN SURFACE_INFO *FrameBufferPtr
+ )
+{
+ CPMEM_PARAM *pCpmemChannel;
+ EFI_STATUS Status;
+ CPMEM_WORD0_PACKED_REG CpmemWord0PackedReg;
+ CPMEM_WORD1_PACKED_REG CpmemWord1PackedReg;
+ CPMEM_DEC_SEL DecodeAddressSelect;
+ UINT32 PixelBurst;
+ CPMEM_PFS_PACKED PixelFormatSelector;
+ UINT32 Width0;
+ UINT32 Width1;
+ UINT32 Width2;
+ UINT32 Width3;
+ UINT32 Offset0;
+ UINT32 Offset1;
+ UINT32 Offset2;
+ UINT32 Offset3;
+ UINT32 BytesPerPixel;
+
+ pCpmemChannel = DisplayInterfaceContextPtr->CpMemParamBasePtr;
+ Status = EFI_SUCCESS;
+ PixelBurst = 1;
+ DecodeAddressSelect = CPMEM_DEC_SEL_0_15; // Only applicable for 4 bpp
+ ZeroMem (&CpmemWord0PackedReg, sizeof (CpmemWord0PackedReg));
+ ZeroMem (&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 = EFI_UNSUPPORTED;
+ break;
+ }
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ switch (FrameBufferPtr->Bpp) {
+ case 8:
+ Width0 = 0;
+ Width1 = 0;
+ Width2 = 0;
+ Width3 = 0;
+ break;
+ case 32:
+ if (PixelFormatSelector == CPMEM_PFS_RGB) {
+ Width0 = 7;
+ Width1 = 7;
+ Width2 = 7;
+ Width3 = 7;
+ } else {
+ Width0 = 0;
+ Width1 = 0;
+ Width2 = 0;
+ Width3 = 0;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ if (EFI_ERROR (Status)) {
+ 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;
+
+ // Finally write into cpmem IDMAC channel
+ pCpmemChannel = (pCpmemChannel + Channel);
+
+ CopyMem (
+ &pCpmemChannel->Word0Pack,
+ &CpmemWord0PackedReg,
+ sizeof (pCpmemChannel->Word0Pack)
+ );
+
+ CopyMem (
+ &pCpmemChannel->Word1Pack,
+ &CpmemWord1PackedReg,
+ sizeof (pCpmemChannel->Word1Pack)
+ );
+
+ // IDMAC will generate 8 AXI bursts upon assertion of the DMA request
+ // This significantly reduces memory activity and power consumption
+ SetIdmacLockEn (DisplayInterfaceContextPtr, Channel, 0x3);
+
+#ifdef DEBUG
+ DumpBasicCpmemReg (pCpmemChannel);
+#endif /* DEBUG */
+
+Exit:
+ return Status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/CPMem.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/CPMem.h
new file mode 100644
index 000000000000..06e96538f2d1
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/CPMem.h
@@ -0,0 +1,277 @@
+/** @file
+*
+* Copyright (c) 2018 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)
+
+EFI_STATUS
+ConfigureCpmemFrameBuffer (
+ IN DISPLAY_INTERFACE_CONTEXT *DisplayInterfaceContextPtr,
+ IN UINT32 Channel,
+ IN SURFACE_INFO *FrameBufferPtr
+ );
+
+#endif /* _CPMEM_H_ */
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ddc.c b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ddc.c
new file mode 100644
index 000000000000..30b737b2f4f5
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ddc.c
@@ -0,0 +1,69 @@
+/** @file
+*
+* Copyright (c) 2018 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/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <iMX6.h>
+#include <iMX6ClkPwr.h>
+#include <iMXDisplay.h>
+
+#include "Display.h"
+#include "Edid.h"
+#include "Ddc.h"
+#include "Hdmi.h"
+#include "Lvds.h"
+
+EFI_STATUS
+Imx6DdcRead (
+ IN DISPLAY_CONTEXT *DisplayContextPtr,
+ IN DISPLAY_INTERFACE_TYPE DisplayInterface,
+ IN UINT8 SlaveAddress,
+ IN UINT8 RegisterAddress,
+ IN UINT32 ReadSize,
+ IN UINT8 *DataReadPtr
+ )
+{
+ EFI_STATUS Status;
+
+ switch (DisplayInterface) {
+ case HdmiDisplay:
+ Status = HdmiDdcRead (
+ &DisplayContextPtr->DiContext[HdmiDisplay],
+ SlaveAddress,
+ RegisterAddress,
+ ReadSize,
+ HDMI_DDC_STANDARD_MODE,
+ DataReadPtr
+ );
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: HdmiDdcRead failed\n", __FUNCTION__));
+ }
+ break;
+ case MipiDisplay:
+ case Lvds0Display:
+ case Lvds1Display:
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ return Status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ddc.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ddc.h
new file mode 100644
index 000000000000..5a10f3d0c26c
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ddc.h
@@ -0,0 +1,28 @@
+/** @file
+*
+* Copyright (c) 2018 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_
+
+EFI_STATUS
+Imx6DdcRead (
+ IN DISPLAY_CONTEXT *DisplayContextPtr,
+ IN DISPLAY_INTERFACE_TYPE DisplayInterface,
+ IN UINT8 SlaveAddress,
+ IN UINT8 RegisterAddress,
+ IN UINT32 ReadSize,
+ IN UINT8 *DataReadPtr
+ );
+
+#endif /* _DDC_H_ */
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Display.c b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Display.c
new file mode 100644
index 000000000000..334e7362d3b8
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Display.c
@@ -0,0 +1,455 @@
+/** @file
+*
+* Copyright (c) 2018 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/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <iMX6.h>
+#include <iMX6ClkPwr.h>
+#include <iMXDisplay.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
+};
+
+EFI_STATUS
+GetPreferredTiming (
+ IN UINT8 *EdidDataPtr,
+ IN UINT32 EdidDataSize,
+ IN DISPLAY_TIMING *PreferredTimingPtr
+ )
+{
+ EFI_STATUS Status;
+
+ if (FeaturePcdGet (PcdLvdsEnable)) {
+ *PreferredTimingPtr = Hannstar_XGA;
+ Status = EFI_SUCCESS;
+ } else {
+ Status = GetEdidPreferredTiming (EdidDataPtr, EdidDataSize, PreferredTimingPtr);
+ if (Status != EFI_SUCCESS) {
+ // If EDID is unavailable use the default timing
+ Status = EFI_SUCCESS;
+ *PreferredTimingPtr = DefaultTiming;
+ DEBUG ((DEBUG_WARN,
+ "%a: EDID data not available, falling back to default timing\n",
+ __FUNCTION__));
+ }
+ }
+
+ // Only support 8 bit per pixel and no pixel repetition for now
+ PreferredTimingPtr->PixelRepetition = 1;
+ PreferredTimingPtr->PixelFormat = PIXEL_FORMAT_BGRA32;
+ PreferredTimingPtr->Bpp = 32;
+
+#ifdef DEBUG
+ PrintDisplayTiming ("Preferred Timing", PreferredTimingPtr);
+#endif /* DEBUG */
+ DEBUG ((DEBUG_WARN, "%a: --GetPreferredTiming\n", __FUNCTION__));
+ return Status;
+}
+
+EFI_STATUS
+InitDisplay (
+ IN DISPLAY_CONTEXT **DisplayConfigPPtr
+ )
+{
+ DISPLAY_CONTEXT *pTempDisplayContext;
+ DISPLAY_INTERFACE_TYPE DisplayCounter;
+ EFI_STATUS Status;
+
+ pTempDisplayContext = AllocateRuntimePool (sizeof (*pTempDisplayContext));
+ if (pTempDisplayContext == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to allocate display context\n", __FUNCTION__));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ ZeroMem (pTempDisplayContext, sizeof (*pTempDisplayContext));
+
+ pTempDisplayContext->IoMuxMmioBasePtr = (VOID *)IOMUXC_GPR_BASE_ADDRESS;
+ if (pTempDisplayContext->IoMuxMmioBasePtr == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to map IO Mux register\n", __FUNCTION__));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ pTempDisplayContext->IpuMmioBasePtr[IPU1] = (VOID *)IPU1_BASE;
+ if (pTempDisplayContext->IoMuxMmioBasePtr == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to map IPU1 IO Mux register\n", __FUNCTION__));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+#if !defined(CPU_IMX6SDL)
+ pTempDisplayContext->IpuMmioBasePtr[IPU2] = (VOID *)IPU2_BASE;
+ if (pTempDisplayContext->IoMuxMmioBasePtr == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to map IPU2 IO Mux register\n", __FUNCTION__));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+#endif
+ for (DisplayCounter = HdmiDisplay; DisplayCounter < DisplayTypeMax; ++DisplayCounter) {
+ pTempDisplayContext->DiContext[DisplayCounter].displayInterface =
+ DisplayCounter;
+ }
+
+ if (FeaturePcdGet (PcdLvdsEnable)) {
+ Status = InitLvds (pTempDisplayContext);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to intialize LVDS\n", __FUNCTION__));
+ goto Exit;
+ }
+ } else {
+ Status = InitHdmi (pTempDisplayContext);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to intialize HDMI\n", __FUNCTION__));
+ goto Exit;
+ }
+ }
+
+ *DisplayConfigPPtr = pTempDisplayContext;
+
+Exit:
+ return Status;
+}
+
+EFI_STATUS
+ValidateDisplayConfig (
+ IN DISPLAY_CONTEXT *DisplayContextPtr,
+ IN DISPLAY_MODE DisplayMode,
+ IN DISPLAY_INTERFACE_TYPE *DiOrder
+ )
+{
+ DISPLAY_INTERFACE_TYPE DisplayDevice;
+ EFI_STATUS Status;
+
+ if (FeaturePcdGet (PcdLvdsEnable)) {
+ DisplayDevice = Lvds0Display;
+ } else {
+ DisplayDevice = HdmiDisplay;
+ }
+
+ // Currently only support single display mode on HDMI/LVDS
+ if (DisplayMode != SINGLE_MODE && DiOrder[0] != DisplayDevice) {
+ Status = EFI_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 = EFI_SUCCESS;
+
+Exit:
+ return Status;
+}
+
+EFI_STATUS
+SetDisplayConfig (
+ IN OUT DISPLAY_CONTEXT *DisplayContextPtr,
+ IN DISPLAY_MODE DisplayMode,
+ IN DISPLAY_INTERFACE_TYPE *DiOrder
+ )
+{
+ DISPLAY_INTERFACE_CONTEXT *pDisplayInterfaceContext;
+ DISPLAY_INTERFACE_INDEX DisplayInterfaceIndex;
+ UINT32 DisplayInterfaceOffset[DisplayInterfaceMax];
+ UINT32 DisplayModeIndex;
+ IPU_INDEX IpuIndex;
+ EFI_STATUS Status;
+
+ DisplayInterfaceOffset[0] = IPU_DISPLAY_INTERFACE_0_OFFSET;
+ DisplayInterfaceOffset[1] = IPU_DISPLAY_INTERFACE_1_OFFSET;
+ Status = ValidateDisplayConfig (DisplayContextPtr, DisplayMode, DiOrder);
+ if (Status != EFI_SUCCESS) {
+ DisplayContextPtr->DisplayConfig.DisplayMode = UNKNOWN_MODE;
+ ZeroMem (
+ DisplayContextPtr->DisplayConfig.DiOrder,
+ sizeof (DisplayContextPtr->DisplayConfig.DiOrder)
+ );
+ DEBUG ((DEBUG_ERROR, "%a: Unsupported display configuration\n", __FUNCTION__));
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ DisplayContextPtr->DisplayConfig.DisplayMode = DisplayMode;
+ ZeroMem (
+ DisplayContextPtr->DisplayConfig.DiOrder,
+ sizeof (DisplayContextPtr->DisplayConfig.DiOrder)
+ );
+
+ // Assigning display interface in order. Require mode information on IPU
+ // and Display Interface valid combination
+ DisplayModeIndex = 0;
+ for (IpuIndex = IPU1; IpuIndex < IPU_TOTAL; IpuIndex++) {
+ for (DisplayInterfaceIndex = DisplayInterface0;
+ DisplayInterfaceIndex < DisplayInterfaceMax;
+ DisplayInterfaceIndex++)
+ {
+ if (DisplayModeIndex >= (UINT32)DisplayMode) {
+ break;
+ }
+ DisplayModeIndex++;
+
+ DisplayContextPtr->DisplayConfig.DiOrder[DisplayInterfaceIndex] =
+ DiOrder[DisplayInterfaceIndex];
+ pDisplayInterfaceContext =
+ &DisplayContextPtr->DiContext[DiOrder[DisplayInterfaceIndex]];
+ pDisplayInterfaceContext->IpuMmioBasePtr =
+ DisplayContextPtr->IpuMmioBasePtr[IpuIndex];
+ pDisplayInterfaceContext->IpuDiRegsPtr =
+ (IPU_DIx_REGS *)(((UINTN)DisplayContextPtr->IpuMmioBasePtr[IpuIndex]) +
+ DisplayInterfaceOffset[DisplayInterfaceIndex]);
+ pDisplayInterfaceContext->CpMemParamBasePtr =
+ (VOID *)(((UINTN)pDisplayInterfaceContext->IpuMmioBasePtr) +
+ CSP_IPUV3_CPMEM_REGS_OFFSET);
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+Exit:
+ return Status;
+}
+
+EFI_STATUS
+ApplyDisplayConfig (
+ IN OUT DISPLAY_CONTEXT *DisplayContextPtr,
+ IN DISPLAY_MODE DisplayMode,
+ IN DISPLAY_INTERFACE_TYPE *DiOrder
+ )
+{
+ DISPLAY_TIMING *pCurrentDisplayTiming;
+ DISPLAY_CONFIG *pDisplayConfig;
+ DISPLAY_INTERFACE_CONTEXT *pDisplayInterfaceContext;
+ UINT32 CurrentDisplayInterface;
+ UINT32 DisplayModeIndex;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ pDisplayConfig = &DisplayContextPtr->DisplayConfig;
+ Status = SetDisplayConfig (DisplayContextPtr, DisplayMode, DiOrder);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Fail to set display configuration %d\n",
+ __FUNCTION__, DisplayMode));
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ // Setup muxing first before configuring DI and DC
+ Status = SetupDisplayMux (DisplayContextPtr);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: SetDisplayMux failed \n", __FUNCTION__));
+ goto Exit;
+ }
+
+ for (DisplayModeIndex = 0;
+ DisplayModeIndex < (UINT32)pDisplayConfig->DisplayMode;
+ ++DisplayModeIndex)
+ {
+ CurrentDisplayInterface = pDisplayConfig->DiOrder[DisplayModeIndex];
+ pDisplayInterfaceContext = &DisplayContextPtr->DiContext[CurrentDisplayInterface];
+ pCurrentDisplayTiming = &pDisplayConfig->DisplayTiming[DisplayModeIndex];
+
+ Status = ConfigureDisplayControllerChannel (
+ pDisplayInterfaceContext,
+ CurrentDisplayInterface,
+ DisplayModeIndex,
+ pCurrentDisplayTiming
+ );
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR,
+ "%a:ConfigureDisplayControllerChannel fail display %d index %d\n",
+ __FUNCTION__, CurrentDisplayInterface, DisplayModeIndex));
+ goto Exit;
+ }
+
+ Status = ConfigureDisplayInterface (
+ pDisplayInterfaceContext,
+ DisplayModeIndex,
+ pCurrentDisplayTiming
+ );
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to configure DI\n", __FUNCTION__));
+ goto Exit;
+ }
+
+ switch (CurrentDisplayInterface) {
+ case HdmiDisplay:
+ Status = SetHdmiDisplay (pDisplayInterfaceContext, pCurrentDisplayTiming);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to set HDMI timing\n", __FUNCTION__));
+ goto Exit;
+ }
+ break;
+ case Lvds0Display:
+ case Lvds1Display:
+ break;
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = ConfigureFrameBuffer (
+ pDisplayInterfaceContext,
+ &pDisplayConfig->DisplaySurface[DisplayModeIndex]
+ );
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Fail to configure frame buffer (%d)\n",
+ __FUNCTION__, DisplayModeIndex));
+ goto Exit;
+ }
+ }
+
+Exit:
+ return Status;
+}
+
+EFI_STATUS
+AllocateFrameBuffer (
+ IN OUT SURFACE_INFO *SurfaceInfoPtr
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "%a: Enter\n", __FUNCTION__));
+ if ((SurfaceInfoPtr->Width == 0) || (SurfaceInfoPtr->Height == 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ DEBUG ((DEBUG_INFO, "%a: Frame Buffer AddrP=%Xh\n",
+ __FUNCTION__, FixedPcdGet32 (PcdFrameBufferBase)));
+ DEBUG ((DEBUG_INFO, "%a: Frame Buffer Size=%Xh\n",
+ __FUNCTION__, FixedPcdGet32 (PcdFrameBufferSize)));
+
+ SurfaceInfoPtr->VirtAddrPtr = (VOID *)(UINTN)FixedPcdGet32 (PcdFrameBufferBase);
+ SurfaceInfoPtr->PhyAddr = (UINT32)(SurfaceInfoPtr->VirtAddrPtr);
+ SurfaceInfoPtr->Pitch = SurfaceInfoPtr->Width;
+
+ DEBUG ((DEBUG_INFO,
+ "%a: Allocate FB PhyAddr %x VirtAddr %x\n",
+ __FUNCTION__, SurfaceInfoPtr->PhyAddr, SurfaceInfoPtr->VirtAddrPtr));
+
+ Status = EFI_SUCCESS;
+
+Exit:
+ DEBUG ((DEBUG_INFO, "%a: Exit = %Xh\n",
+ __FUNCTION__, Status));
+ return Status;
+}
+
+EFI_STATUS
+ConfigureFrameBuffer (
+ IN DISPLAY_INTERFACE_CONTEXT *DisplayInterfaceContextPtr,
+ IN SURFACE_INFO *FrameBufferPtr
+ )
+{
+ EFI_STATUS Status;
+
+ // Only support single display for now
+ Status = ConfigureCpmemFrameBuffer (
+ DisplayInterfaceContextPtr,
+ IDMAC_CHANNEL_DP_PRIMARY_FLOW_MAIN_PLANE,
+ FrameBufferPtr
+ );
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to configure CPMEM\n", __FUNCTION__));
+ goto Exit;
+ }
+
+Exit:
+ return Status;
+}
+
+UINT32
+GetColorDepth (
+ IN PIXEL_FORMAT PixelFormat
+ )
+{
+ UINT32 BitDepth;
+
+ switch (PixelFormat) {
+ case PIXEL_FORMAT_ARGB32:
+ case PIXEL_FORMAT_BGRA32:
+ BitDepth = 8;
+ break;
+ default:
+ BitDepth = 0;
+ break;
+ }
+
+ return BitDepth;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Display.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Display.h
new file mode 100644
index 000000000000..cbcea1219743
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Display.h
@@ -0,0 +1,175 @@
+/** @file
+*
+* Copyright (c) 2018 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 {
+ DisplayInterface0,
+ DisplayInterface1,
+ DisplayInterfaceMax,
+} DISPLAY_INTERFACE_INDEX;
+
+typedef enum {
+ HdmiDisplay,
+ MipiDisplay,
+ Lvds0Display,
+ Lvds1Display,
+ DisplayTypeMax, // Only 4 display types supported by IPU
+ NoDisplayType = DisplayTypeMax,
+} DISPLAY_INTERFACE_TYPE;
+
+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_TYPE displayInterface;
+
+ VOID *MmioBasePtr;
+ VOID *IpuMmioBasePtr;
+ VOID *CpMemParamBasePtr;
+ IPU_DIx_REGS *IpuDiRegsPtr;
+ UINT32 EdidDataSize;
+ UINT8 EdidData[256];
+ DISPLAY_TIMING PreferredTiming;
+} DISPLAY_INTERFACE_CONTEXT, *PDISPLAY_INTERFACE_CONTEXT;
+
+typedef struct _DISPLAY_CONFIG {
+ DISPLAY_MODE DisplayMode;
+ DISPLAY_INTERFACE_TYPE DiOrder[DisplayTypeMax];
+ SURFACE_INFO DisplaySurface[DisplayTypeMax];
+ DISPLAY_TIMING DisplayTiming[DisplayTypeMax];
+ UINT32 OsHandle[DisplayTypeMax];
+} DISPLAY_CONFIG, *PDISPLAY_CONFIG;
+
+typedef struct _DISPLAY_CONTEXT {
+ DISPLAY_CONFIG DisplayConfig;
+ VOID *IoMuxMmioBasePtr;
+ VOID *IpuMmioBasePtr[IPU_TOTAL];
+ DISPLAY_INTERFACE_CONTEXT DiContext[DisplayTypeMax];
+} DISPLAY_CONTEXT, *PDISPLAY_CONTEXT;
+
+extern DISPLAY_TIMING DefaultTiming;
+
+EFI_STATUS
+GetPreferredTiming (
+ IN UINT8 *EdidDataPtr,
+ IN UINT32 EdidDataSize,
+ IN DISPLAY_TIMING *PreferredTimingPtr
+ );
+
+EFI_STATUS
+InitDisplay (
+ IN DISPLAY_CONTEXT **DisplayConfigPPtr
+ );
+
+EFI_STATUS
+ValidateDisplayConfig (
+ IN DISPLAY_CONTEXT *DisplayContextPtr,
+ IN DISPLAY_MODE DisplayMode,
+ IN DISPLAY_INTERFACE_TYPE *DiOrder
+ );
+
+EFI_STATUS
+SetDisplayConfig (
+ IN OUT DISPLAY_CONTEXT *DisplayContextPtr,
+ IN DISPLAY_MODE DisplayMode,
+ IN DISPLAY_INTERFACE_TYPE *DiOrder
+ );
+
+EFI_STATUS
+ApplyDisplayConfig (
+ IN OUT DISPLAY_CONTEXT *DisplayContextPtr,
+ IN DISPLAY_MODE DisplayMode,
+ IN DISPLAY_INTERFACE_TYPE *DiOrder
+ );
+
+EFI_STATUS
+AllocateFrameBuffer (
+ IN OUT SURFACE_INFO *SurfaceInfoPtr
+ );
+
+EFI_STATUS
+ConfigureFrameBuffer (
+ IN DISPLAY_INTERFACE_CONTEXT *DisplayInterfaceContextPtr,
+ IN SURFACE_INFO *FrameBufferPtr
+ );
+
+UINT32
+GetColorDepth (
+ IN PIXEL_FORMAT PixelFormat
+ );
+
+#endif /* _DISPLAY_H_ */
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayController.c b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayController.c
new file mode 100644
index 000000000000..7a5fc7e3d6c3
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayController.c
@@ -0,0 +1,399 @@
+/** @file
+*
+* Copyright (c) 2018 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/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <iMX6.h>
+#include <iMX6ClkPwr.h>
+#include <iMXDisplay.h>
+
+#include "Ipu.h"
+#include "Display.h"
+#include "DisplayController.h"
+#include "DisplayInterface.h"
+
+#ifdef DEBUG
+VOID
+DumpBasicDisplayControllerReg (
+ IN VOID *IpuMmioBasePtr
+ )
+{
+ UINT32 Counter;
+ UINT32 Index;
+ UINT32 RegVal;
+
+ DEBUG ((DEBUG_VERBOSE, "%a: ------- DC Register Dump -------\n", __FUNCTION__));
+
+ DEBUG ((DEBUG_VERBOSE, "%a: ## Configuration\n\n", __FUNCTION__));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_WR_CH_CONF_5_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_WR_CH_CONF_1_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_WR_CH_CONF_1_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_DISP_CONF1_0_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_DISP_CONF1_0_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_DISP_CONF1_1_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_DISP_CONF1_1_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_DISP_CONF1_2_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_DISP_CONF1_2_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_DISP_CONF1_3_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_DISP_CONF1_3_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_DISP_CONF2_0_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_DISP_CONF2_0_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_GEN_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_GEN_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+
+ DEBUG ((DEBUG_VERBOSE, "%a: ## Bus MAPPING\n\n", __FUNCTION__));
+ {
+ for (Counter = 0, Index = 0; Index < 26; Counter += 4, ++Index) {
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_MAP_CONF_0_OFFSET + Counter);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_MAP_CONF_%d %x\n",
+ __FUNCTION__, Index, RegVal));
+ }
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "%a: ## Channel MicroCode setup\n\n", __FUNCTION__));
+ // Only print out channel 5 as we only support single mode for now
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_RL0_CH_5_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_RL0_CH_5_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_RL1_CH_5_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_RL1_CH_5_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_RL2_CH_5_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_RL2_CH_5_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_RL3_CH_5_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_RL3_CH_5_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (IpuMmioBasePtr, IPU_DC_RL4_CH_5_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_RL4_CH_5_OFFSET %x\n",
+ __FUNCTION__, RegVal));
+
+ DEBUG ((DEBUG_VERBOSE, "%a: ## MicroCode\n\n", __FUNCTION__));
+ // There are 256 template, only print out the first 10
+ for (Counter = 0, Index = 0; Index < 10; Counter += 8, ++Index) {
+ DEBUG ((DEBUG_VERBOSE, "%a: (%d)\n", __FUNCTION__, Index));
+ RegVal = IpuRead32 (
+ IpuMmioBasePtr,
+ IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + Counter);
+ DEBUG ((DEBUG_VERBOSE, "%a: - %8x\n", __FUNCTION__, RegVal));
+ RegVal = IpuRead32 (
+ IpuMmioBasePtr,
+ IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + Counter + 4);
+ DEBUG ((DEBUG_VERBOSE, "%a: %8x -\n", __FUNCTION__, RegVal));
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "%a: ---------------------------\n\n", __FUNCTION__));
+}
+#endif /* DEBUG */
+
+EFI_STATUS
+WriteWrodCommand (
+ IN VOID *IpuMmioBasePtr,
+ IN UINT32 MicroCodeAddr,
+ IN UINT32 Data,
+ IN UINT32 Mapping,
+ IN UINT32 WaveForm,
+ IN UINT32 GlueLogic,
+ IN UINT32 Sync
+ )
+{
+ UINT32 MicroCodeAddrOffset;
+ DISPLAY_CONTROLLER_WROD_COMMAND WrodCommand;
+
+
+ MicroCodeAddrOffset = IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + (MicroCodeAddr * 8);
+ ZeroMem ((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 EFI_SUCCESS;
+}
+
+EFI_STATUS
+SetDisplayControllerChannelState (
+ IN VOID *IpuMmioBasePtr,
+ IN 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 EFI_SUCCESS;
+}
+
+EFI_STATUS
+ConfigureDisplayControllerChannel (
+ IN DISPLAY_INTERFACE_CONTEXT *DisplayInterfaceContextPtr,
+ IN DISPLAY_INTERFACE_TYPE DisplayInterface,
+ IN UINT32 DisplayIndex,
+ IN DISPLAY_TIMING *DisplayTimingPtr
+ )
+{
+ VOID *pIpuMmioBase;
+ DC_MAP_CONF_OFFSET_MASK_REG DcConfOffsetMaskReg;
+ IPUx_DC_MAP_CONF_MAP_REG DcMapConf0Reg;
+ IPU_DC_RL0_CH_5_REG DcRl0Ch5Reg;
+ IPU_DC_RL2_CH_5_REG DcRl2Ch5Reg;
+ IPU_DC_RL4_CH_5_REG DcRl4Ch5Reg;
+ IPUx_DC_DISP_CONF1_REG DisplayConfig1Reg;
+ IPUx_IPU_DC_GEN_REG DisplayControllerGenReg;
+ UINT32 Mask0;
+ UINT32 Mask1;
+ UINT32 Mask2;
+ UINT32 Offset0;
+ UINT32 Offset1;
+ UINT32 Offset2;
+ EFI_STATUS Status;
+ IPU_DC_WR_CH_CONF_5_REG WrChConfigReg;
+
+ pIpuMmioBase = DisplayInterfaceContextPtr->IpuMmioBasePtr;
+ Status = EFI_SUCCESS;
+
+ ZeroMem ((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 (pIpuMmioBase, IPU_DC_WR_CH_CONF_5_OFFSET, WrChConfigReg.Reg);
+ // Start address of memory always 0
+ IpuWrite32 (pIpuMmioBase, IPU_DC_WR_CH_ADDR_5_OFFSET, 0);
+
+ ZeroMem ((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 (pIpuMmioBase, IPU_DC_WR_CH_CONF_1_OFFSET, WrChConfigReg.Reg);
+ IpuWrite32 (pIpuMmioBase, IPU_DC_WR_CH_ADDR_1_OFFSET, 0);
+
+ DisplayConfig1Reg.DISP_TYP = 0x02; // What is byte_enabled
+ DisplayConfig1Reg.ADDR_INCREMENT = 0; // Increase by 1 byte
+ DisplayConfig1Reg.ADDR_BE_L_INC = 0;
+ DisplayConfig1Reg.MCU_ACC_LB_MASK_3 = 0;
+ DisplayConfig1Reg.DISP_RD_VALUE_PTR = 0;
+ IpuWrite32 (pIpuMmioBase, IPU_DC_DISP_CONF1_0_OFFSET, DisplayConfig1Reg.Reg);
+
+ // Set stride
+ IpuWrite32 (pIpuMmioBase, IPU_DC_DISP_CONF2_0_OFFSET, DisplayTimingPtr->VActive);
+
+ // Setup general register. Channel 5 is the main channel.
+ DisplayControllerGenReg.Sync_1_6 = 2; // Sync flow
+ DisplayControllerGenReg.MASK_EN = 0; // Disable masking
+ DisplayControllerGenReg.MASK4CHAN_5 = 0; // Ignore as mask is disabled
+ DisplayControllerGenReg.SYNC_PRIORITY_5 = 1; // Higher sync priority for channel 5
+ DisplayControllerGenReg.SYNC_PRIORITY_1 = 0; // Lower sync priority
+ DisplayControllerGenReg.DC_CH5_TYPE = 0; // Normal mode, sync flow through channel 5
+ DisplayControllerGenReg.DC_BK_EN = 0; // No cursor support
+ DisplayControllerGenReg.DC_BKDIV = 0; // No cursor support
+ IpuWrite32 (pIpuMmioBase, IPU_DC_GEN_OFFSET, DisplayControllerGenReg.Reg);
+
+ // Do not use any user event
+ IpuWrite32 (pIpuMmioBase, IPU_DC_UGDE0_0_OFFSET, 0);
+ IpuWrite32 (pIpuMmioBase, IPU_DC_UGDE1_0_OFFSET, 0);
+ IpuWrite32 (pIpuMmioBase, IPU_DC_UGDE2_0_OFFSET, 0);
+ IpuWrite32 (pIpuMmioBase, IPU_DC_UGDE3_0_OFFSET, 0);
+
+ 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 (pIpuMmioBase, IPU_DC_MAP_CONF_0_OFFSET, DcMapConf0Reg.Reg);
+
+ switch (DisplayInterface) {
+ // PixelFormat RGB24
+ case HdmiDisplay:
+ Mask0 = 0xFF;
+ Mask1 = 0xFF;
+ Mask2 = 0xFF;
+ Offset0 = 7;
+ Offset1 = 15;
+ Offset2 = 23;
+ break;
+ // PixelFormat RGB666
+ case Lvds0Display:
+ case Lvds1Display:
+ Mask0 = 0xFC;
+ Mask1 = 0xFC;
+ Mask2 = 0xFC;
+ Offset0 = 5;
+ Offset1 = 11;
+ Offset2 = 17;
+ break;
+ default:
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ if (EFI_ERROR (Status)) {
+ 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 (pIpuMmioBase, 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 (pIpuMmioBase, IPU_DC_MAP_CONF_16_OFFSET, DcConfOffsetMaskReg.Reg);
+
+ // Setup microcode
+ // New line event point to the first microcode (0)
+ ZeroMem ((VOID *)&DcRl0Ch5Reg, sizeof (DcRl0Ch5Reg));
+ DcRl0Ch5Reg.COD_NL_START_CHAN_5 = 0;
+ DcRl0Ch5Reg.COD_NL_PRIORITY_CHAN_5 = 3;
+ IpuWrite32 (pIpuMmioBase, IPU_DC_RL0_CH_5_OFFSET, DcRl0Ch5Reg.Reg);
+
+ // End of line event point to the second microcode (1)
+ ZeroMem ((VOID *)&DcRl2Ch5Reg, sizeof (DcRl2Ch5Reg));
+ DcRl2Ch5Reg.COD_EOL_START_CHAN_5 = 1;
+ DcRl2Ch5Reg.COD_EOL_PRIORITY_CHAN_5 = 2;
+ IpuWrite32 (pIpuMmioBase, IPU_DC_RL2_CH_5_OFFSET, DcRl2Ch5Reg.Reg);
+
+ // New data event point to the first microcode (2)
+ ZeroMem ((VOID *)&DcRl4Ch5Reg, sizeof (DcRl4Ch5Reg));
+ DcRl4Ch5Reg.COD_NEW_DATA_START_CHAN_5 = 2;
+ DcRl4Ch5Reg.COD_NEW_DATA_PRIORITY_CHAN_5 = 1;
+ IpuWrite32 (pIpuMmioBase, 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 (
+ pIpuMmioBase,
+ 0,
+ 0,
+ 1,
+ DwGen0,
+ 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 (
+ pIpuMmioBase,
+ 1,
+ 0,
+ 1,
+ DwGen0,
+ 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 (
+ pIpuMmioBase,
+ 2,
+ 0,
+ 1,
+ DwGen0,
+ 8,
+ DI_COUNTER_5_ACTIVE_CLOCK
+ );
+
+ // Turn on channel without anti tearing
+ SetDisplayControllerChannelState (
+ DisplayInterfaceContextPtr->IpuMmioBasePtr,
+ PROG_CHAN_TYP_NORMAL
+ );
+
+#ifdef DEBUG
+ DumpBasicDisplayControllerReg (pIpuMmioBase);
+#endif /* DEBUG */
+
+ Status = EFI_SUCCESS;
+
+Exit:
+ return Status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayController.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayController.h
new file mode 100644
index 000000000000..46f0fa66d674
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayController.h
@@ -0,0 +1,331 @@
+/** @file
+*
+* Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _DISPLAY_CONTROLLER_H_
+#define _DISPLAY_CONTROLLER_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;
+
+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;
+ };
+} DISPLAY_CONTROLLER_WROD_COMMAND;
+
+#pragma pack(pop)
+
+EFI_STATUS
+SetDisplayControllerChannelState (
+ IN VOID *IpuMmioBasePtr,
+ IN PROG_CHAN_TYP ChannelType
+ );
+
+EFI_STATUS
+ConfigureDisplayControllerChannel (
+ IN DISPLAY_INTERFACE_CONTEXT *DisplayInterfaceContextPtr,
+ IN DISPLAY_INTERFACE_TYPE DisplayInterface,
+ IN UINT32 DisplayIndex,
+ IN DISPLAY_TIMING *DisplayTimingPtr
+ );
+
+#endif /* _DISPLAY_CONTROLLER_H_ */
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayInterface.c b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayInterface.c
new file mode 100644
index 000000000000..b36d03239652
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayInterface.c
@@ -0,0 +1,458 @@
+/** @file
+*
+* Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <iMX6.h>
+#include <iMX6ClkPwr.h>
+#include <iMXDisplay.h>
+
+#include "Ipu.h"
+#include "Display.h"
+#include "DisplayInterface.h"
+
+#ifdef DEBUG
+VOID
+DumpBasicDisplayInterfaceReg (
+ IN VOID *IpuMmioBasePtr,
+ IN IPU_DIx_REGS *IpuDiRegsPtr
+ )
+{
+ UINT32 index, setNumber, regVal;
+ UINT32 printTotalGen = 8; // Limit printing (max 12)
+
+ DEBUG ((DEBUG_VERBOSE, "%a: ------- DI Register Dump -------\n", __FUNCTION__));
+ // Print out generator value for D0
+ DEBUG ((DEBUG_VERBOSE, "%a: ## Wave Gen\n", __FUNCTION__));
+ for (index = 0; index < printTotalGen; ++index) {
+ regVal = READ_WAVE_GEN (IpuDiRegsPtr, index);
+ DEBUG ((DEBUG_VERBOSE, "%a: DI0_DW_GEN_%d 0x%08x\n",
+ __FUNCTION__, index, regVal));
+ }
+ // Print out generator value for D0
+ DEBUG ((DEBUG_VERBOSE, "%a: ## Wave Set\n", __FUNCTION__));
+ for (index = 0; index < printTotalGen; ++index) {
+ for (setNumber = 0; setNumber < 4; ++setNumber) {
+ regVal = READ_WAVE_SET (IpuDiRegsPtr, index, setNumber);
+ DEBUG ((DEBUG_VERBOSE, "%a: DI0_DW_SET%d_%d 0x%08x\n",
+ __FUNCTION__, setNumber, index, regVal));
+ }
+ }
+
+ regVal = IpuRead32 (IpuMmioBasePtr, IPU_IPU_PM_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_IPU_PM_OFFSET %x\n",
+ __FUNCTION__, regVal));
+
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_BS_CLKGEN0_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_BS_CLKGEN0_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_BS_CLKGEN1_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_BS_CLKGEN1_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SCR_CONF_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SCR_CONF_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN0_1_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN0_1_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN1_1_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN1_1_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN0_2_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN0_2_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN1_2_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN1_2_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN0_3_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN0_3_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN1_3_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN1_3_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN0_4_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN0_4_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN1_4_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN1_4_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN0_5_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN0_5_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN1_5_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN1_5_OFFSET %x\n",
+ __FUNCTION__, regVal));
+
+ for (index = 0; index < 5; ++index) {
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_STP_REP_OFFSET + (index * 0x4));
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_STP_%d_REP_OFFSET %x\n",
+ __FUNCTION__, index + 1, regVal));
+ }
+
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_SYNC_AS_GEN_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SYNC_AS_GEN_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_GENERAL_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_GENERAL_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_DIx_POL_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_POL_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ regVal = DiRead32 (IpuDiRegsPtr, IPU_IPU_DISP_GEN_OFFSET);
+ DEBUG ((DEBUG_VERBOSE, "%a: IPU_IPU_DISP_GEN_OFFSET %x\n",
+ __FUNCTION__, regVal));
+ DEBUG ((DEBUG_VERBOSE, "%a: ------------------------------\n\n", __FUNCTION__));
+}
+#endif /* DEBUG */
+
+VOID
+ConfigureSyncWave (
+ IN VOID *IpuMmioBasePtr,
+ IN IPU_DIx_REGS *IpuDiRegsPtr,
+ IN UINT32 CounterIndex,
+ IN UINT32 RunValue,
+ IN UINT32 RunResolution,
+ IN UINT32 OffsetValue,
+ IN UINT32 OffsetResolution,
+ IN UINT32 CounterPolarityGenEn,
+ IN UINT32 CounterAutoReload,
+ IN UINT32 CounterClearSelect,
+ IN UINT32 CounterDown,
+ IN UINT32 CounterPolarityTriggerSelect,
+ IN UINT32 CounterPolarityClearSelect,
+ IN UINT32 CounterUp,
+ IN UINT32 StepRepeat
+ )
+{
+ IPUx_DIx_SW_GEN0_x_REG DiSwGen0Reg;
+ IPUx_DIx_SW_GEN1_x_REG DiSwGen1Reg;
+ UINT32 StepIndex;
+ IPUx_DIx_STP_REP_REG StepRepeatReg;
+
+ ZeroMem ((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
+ );
+
+ ZeroMem ((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
+ );
+
+ 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
+ );
+}
+
+EFI_STATUS
+ConfigureDisplayInterface (
+ IN DISPLAY_INTERFACE_CONTEXT *DisplayInterfaceContextPtr,
+ IN UINT32 DisplayIndex,
+ IN DISPLAY_TIMING *DisplayTimingPtr
+ )
+{
+ IPU_DIx_REGS *pIpuDiRegs;
+ VOID *pIpuMmioBase;
+ UINT32 BaseDiv;
+ UINT32 DispGenReg;
+ UINT64 DisplayInterfaceFrequency;
+ IPUx_DIx_DW_GEN_REG DixDwGenReg;
+ IPUx_DIx_DW_SET_REG DixDwSetReg;
+ IPUx_DIx_GENERAL_REG DixGeneralReg;
+ IPUx_DIx_POL_REG DixPolReg;
+ IPUx_DIx_SYNC_AS_GEN_REG DixSyncAsGenReg;
+ UINT32 HorizontalLength;
+ EFI_STATUS Status;
+ UINT32 VerticalLength;
+
+ DisplayInterfaceFrequency = DisplayTimingPtr->PixelClock;
+ HorizontalLength = DisplayTimingPtr->HActive + DisplayTimingPtr->HBlank;
+ VerticalLength = DisplayTimingPtr->VActive + DisplayTimingPtr->VBlank;
+ pIpuMmioBase = DisplayInterfaceContextPtr->IpuMmioBasePtr;
+ pIpuDiRegs = DisplayInterfaceContextPtr->IpuDiRegsPtr;
+ Status = EFI_SUCCESS;
+
+ Status = ImxSetPll5ReferenceRate (DisplayTimingPtr->PixelClock);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to setup PLL5=%r\n", __FUNCTION__, 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) ((DisplayInterfaceFrequency << 4) / DisplayTimingPtr->PixelClock);
+ DiWrite32 (pIpuDiRegs, 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 (pIpuDiRegs, IPU_DIx_BS_CLKGEN1_OFFSET, BaseDiv << 16);
+ // Calculate divisor, again this would usually be 1.
+ BaseDiv = (UINT32) (DisplayInterfaceFrequency / DisplayTimingPtr->PixelClock);
+
+ // Set up wave, there 12 wave quartet, for now default to the first.
+ // Each wave quartet has 4 set register
+ // Set 0 is just a blank signal where up and down is set to 0
+ ZeroMem ((VOID *)&DixDwSetReg, sizeof (DixDwSetReg));
+ DixDwSetReg.dix_data_cnt_upx_i = 0;
+ DixDwSetReg.dix_data_cnt_downx_i = 0;
+ WRITE_WAVE_SET (
+ pIpuDiRegs,
+ DwGen0,
+ DwSet0,
+ DixDwSetReg.Reg
+ );
+
+ // Set 3 is setup to match pixel clock
+ ZeroMem ((VOID *)&DixDwSetReg, sizeof (DixDwSetReg));
+ DixDwSetReg.dix_data_cnt_upx_i = 0;
+ DixDwSetReg.dix_data_cnt_downx_i = BaseDiv * 2;
+ WRITE_WAVE_SET (
+ pIpuDiRegs,
+ DwGen0,
+ DwSet3,
+ DixDwSetReg.Reg
+ );
+
+ // All pins blank signal except pin 15
+ ZeroMem ((VOID *)&DixDwGenReg, sizeof (DixDwGenReg));
+ DixDwGenReg.dix_pt_0_i = DwSet0;
+ DixDwGenReg.dix_pt_1_i = DwSet0;
+ DixDwGenReg.dix_pt_2_i = DwSet0;
+ DixDwGenReg.dix_pt_3_i = DwSet0;
+ DixDwGenReg.dix_pt_4_i = DwSet3;
+ DixDwGenReg.dix_pt_5_i = DwSet0;
+ DixDwGenReg.dix_pt_6_i = DwSet0;
+ DixDwGenReg.dix_cst_i = DwSet0;
+ // Reuse the base divisor to determine extra IPU cycles.
+ DixDwGenReg.dix_componnent_size_i = BaseDiv - 1;
+ DixDwGenReg.dix_access_size_i = BaseDiv - 1;
+ WRITE_WAVE_GEN (pIpuDiRegs, DwGen0, DixDwGenReg.Reg);
+
+ // Spec mention this as number of display rows but display only works
+ // properly if this is setup as vertical total
+ DiWrite32 (pIpuDiRegs, IPU_DIx_SCR_CONF_OFFSET, VerticalLength - 1);
+
+ // Internal HSYNC
+ ConfigureSyncWave (
+ pIpuMmioBase,
+ pIpuDiRegs,
+ DI_COUNTER_1_INTERNAL_HSYNC, // CounterIndex
+ HorizontalLength - 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 (
+ pIpuMmioBase,
+ pIpuDiRegs,
+ DI_COUNTER_2_OUTPUT_HSYNC, // CounterIndex
+ HorizontalLength - 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 (
+ pIpuMmioBase,
+ pIpuDiRegs,
+ DI_COUNTER_3_OUTPUT_VSYNC, // CounterIndex
+ VerticalLength - 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 (
+ pIpuMmioBase,
+ pIpuDiRegs,
+ 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 (
+ pIpuMmioBase,
+ pIpuDiRegs,
+ 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
+ );
+
+ ZeroMem ((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.
+ DixSyncAsGenReg.dix_sync_start = 2;
+ DiWrite32 (pIpuDiRegs, IPU_DIx_SYNC_AS_GEN_OFFSET, DixSyncAsGenReg.Reg);
+
+ // Setup general register
+ ZeroMem ((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 (DisplayInterfaceContextPtr->displayInterface) {
+ case HdmiDisplay:
+ // 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 = EFI_UNSUPPORTED;
+ DEBUG ((DEBUG_ERROR, "%a: Unsupported display interface %d\n",
+ __FUNCTION__, DisplayInterfaceContextPtr->displayInterface));
+ break;
+ }
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ DiWrite32 (pIpuDiRegs, IPU_DIx_GENERAL_OFFSET, DixGeneralReg.Reg);
+
+ ZeroMem ((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 (pIpuDiRegs, IPU_DIx_POL_OFFSET, DixPolReg.Reg);
+
+ DispGenReg = IpuRead32 (pIpuMmioBase, IPU_IPU_DISP_GEN_OFFSET);
+ DispGenReg &= ~(0x0F << 18);
+ DispGenReg |= (2 << 18);
+ IpuWrite32 (pIpuMmioBase, IPU_IPU_DISP_GEN_OFFSET, DispGenReg);
+
+#ifdef DEBUG
+ DumpBasicDisplayInterfaceReg (pIpuMmioBase, pIpuDiRegs);
+#endif /* DEBUG */
+
+ Status = EFI_SUCCESS;
+
+Exit:
+ return Status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayInterface.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayInterface.h
new file mode 100644
index 000000000000..786ef1fff5f0
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayInterface.h
@@ -0,0 +1,195 @@
+/** @file
+*
+* Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _DISPLAY_INTERFACE_H_
+#define _DISPLAY_INTERFACE_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)
+
+#define DI_COUNTER_DISABLED 0
+#define DI_COUNTER_0_DISPLAY_CLOCK 0
+#define DI_COUNTER_1_INTERNAL_HSYNC 1
+#define DI_COUNTER_2_OUTPUT_HSYNC 2
+#define DI_COUNTER_3_OUTPUT_VSYNC 3
+#define DI_COUNTER_4_ACTIVE_LINE 4
+#define DI_COUNTER_5_ACTIVE_CLOCK 5
+
+typedef enum {
+ DwGen0,
+ DwGen1,
+ DwGen2,
+ DwGen3,
+ DwGen4,
+ DwGen5,
+ DwGen6,
+ DwGen7,
+ DwGen8,
+ DwGen9,
+ DwGen10,
+ DwGen11,
+ DwGenMax
+} DW_GEN;
+
+typedef enum {
+ DwSet0,
+ DwSet1,
+ DwSet2,
+ DwSet3,
+ DwSetMax
+} DW_SET;
+
+#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)
+
+EFI_STATUS
+ConfigureDisplayInterface (
+ IN DISPLAY_INTERFACE_CONTEXT *DisplayInterfaceContextPtr,
+ IN UINT32 DisplayIndex,
+ IN DISPLAY_TIMING *DisplayTimingPtr
+ );
+
+#endif /* _DISPLAY_INTERFACE_H_ */
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Edid.c b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Edid.c
new file mode 100644
index 000000000000..cc6557a58138
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Edid.c
@@ -0,0 +1,96 @@
+/** @file
+*
+* Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <iMX6.h>
+#include <iMX6ClkPwr.h>
+#include <iMXDisplay.h>
+
+#include "Display.h"
+#include "Edid.h"
+#include "Ddc.h"
+
+EFI_STATUS
+ReadEdid (
+ IN DISPLAY_CONTEXT *DisplayContextPtr,
+ IN DISPLAY_INTERFACE_TYPE DisplayInterface,
+ IN UINT8 *EdidDataPtr,
+ OUT UINT32 *EdidDataSizePtr
+ )
+{
+ EFI_STATUS Status;
+
+ Status = Imx6DdcRead (
+ DisplayContextPtr,
+ DisplayInterface,
+ EDID_I2C_ADDRESS,
+ 0,
+ EDID_MIN_SIZE,
+ EdidDataPtr
+ );
+ if (Status != EFI_SUCCESS) {
+ goto Exit;
+ }
+
+ Status = ValidateEdidData (
+ EdidDataPtr
+ );
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_WARN, "%a: Invalid EDID data\n", __FUNCTION__));
+ goto Exit;
+ }
+
+ DEBUG ((DEBUG_INFO, "%a: EDID initialized\n", __FUNCTION__));
+
+ *EdidDataSizePtr = EDID_MIN_SIZE;
+
+Exit:
+ return Status;
+}
+
+EFI_STATUS
+GetEdidPreferredTiming (
+ IN UINT8 *EdidDataPtr,
+ IN UINT32 EdidDataSizePtr,
+ OUT DISPLAY_TIMING *PreferredTiming
+ )
+{
+ DETAILED_TIMING_DESCRIPTOR *pEdidPreferredTiming;
+ EFI_STATUS Status;
+
+ if (EdidDataSizePtr < EDID_MIN_SIZE) {
+ DEBUG ((DEBUG_WARN, "%a: Insufficient EDID data\n", __FUNCTION__));
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ pEdidPreferredTiming = (DETAILED_TIMING_DESCRIPTOR *)&EdidDataPtr[EDID_DTD_1_OFFSET];
+ Status = ConvertDTDToDisplayTiming (pEdidPreferredTiming, PreferredTiming);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: Conversion to display timing failed\n",
+ __FUNCTION__));
+ goto Exit;
+ }
+
+Exit:
+
+ return Status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Edid.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Edid.h
new file mode 100644
index 000000000000..df714f284deb
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Edid.h
@@ -0,0 +1,33 @@
+/** @file
+*
+* Copyright (c) 2018 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_
+
+EFI_STATUS
+ReadEdid (
+ IN DISPLAY_CONTEXT *DisplayContextPtr,
+ IN DISPLAY_INTERFACE_TYPE DisplayInterface,
+ IN UINT8 *EdidDataPtr,
+ OUT UINT32 *EdidDataSizePtr
+ );
+
+EFI_STATUS
+GetEdidPreferredTiming (
+ IN UINT8 *EdidDataPtr,
+ IN UINT32 EdidDataSizePtr,
+ OUT DISPLAY_TIMING *PreferredTiming
+ );
+
+#endif /* _EDID_H_ */
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.c b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.c
new file mode 100644
index 000000000000..2e990a6b14fb
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.c
@@ -0,0 +1,475 @@
+/** @file
+*
+* Copyright (c) 2018 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 <iMX6.h>
+#include <iMX6ClkPwr.h>
+#include <iMXDisplay.h>
+
+#include "Display.h"
+#include "GopDxe.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
+ );
+
+STATIC VID_DEVICE_PATH 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 VidGopModeInfo;
+STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE VidGopMode;
+
+STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL VidGop = {
+ VidGopQueryMode, // QueryMode
+ VidGopSetMode, // SetMode
+ VidGopBlt, // Blt
+ &VidGopMode // Mode
+};
+
+EFI_EDID_DISCOVERED_PROTOCOL EdidDiscovered = {
+ 0,
+ NULL
+};
+
+EFI_EDID_ACTIVE_PROTOCOL EdidActive = {
+ 0,
+ NULL
+};
+
+DISPLAY_CONTEXT *DisplayContextPtr;
+
+DISPLAY_INTERFACE_TYPE DisplayDevice;
+
+EFI_STATUS
+GopDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ DISPLAY_INTERFACE_TYPE DisplayInterfaceOrder[DisplayTypeMax];
+ UINT32 i;
+ UINT32 RequestedDisplayMemorySize;
+ UINT32 ReservedDisplayMemorySize;
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "%a: Enter \n", __FUNCTION__));
+
+ for (i = 0; i < DisplayTypeMax; i++) {
+ DisplayInterfaceOrder[i] = NoDisplayType;
+ }
+ ReservedDisplayMemorySize = FixedPcdGet32 (PcdFrameBufferSize);
+ if (FeaturePcdGet (PcdLvdsEnable)) {
+ DisplayDevice = Lvds0Display;
+ } else {
+ DisplayDevice = HdmiDisplay;
+ }
+
+ Status = InitDisplay (&DisplayContextPtr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Fail to init display, Status=%r\n", __FUNCTION__,
+ Status));
+ goto Exit;
+ }
+
+ DEBUG ((DEBUG_INFO, "%a: - Allocate frame buffer\n", __FUNCTION__));
+ // 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].PreferredTiming.HActive;
+ DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height =
+ DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming.VActive;
+ DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp =
+ DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming.Bpp;
+ DisplayContextPtr->DisplayConfig.DisplaySurface[0].PixelFormat =
+ DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming.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: Displays which do not have support for 1920x1080 mode may
+ // have poor or missing picture
+ RequestedDisplayMemorySize =
+ DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width *
+ DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height *
+ (DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp / 8);
+
+ DEBUG ((DEBUG_INFO, "%a: Display Memory: Needed=%d, Available=%d\n",
+ __FUNCTION__, RequestedDisplayMemorySize, ReservedDisplayMemorySize));
+
+ if (RequestedDisplayMemorySize > ReservedDisplayMemorySize) {
+ DEBUG ((DEBUG_INFO,
+ "%a: WARNING. Need more video memory than reserved by %d bytes\n",
+ __FUNCTION__, RequestedDisplayMemorySize - ReservedDisplayMemorySize));
+ DEBUG ((DEBUG_ERROR,
+ "%a: - display resolution too big. Cap to HD 1080p\n",
+ __FUNCTION__));
+ DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width = FullHDTiming.HActive;
+ DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height =
+ FullHDTiming.VActive;
+ DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp = FullHDTiming.Bpp;
+ CopyMem (
+ &DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming,
+ &FullHDTiming,
+ sizeof (DISPLAY_TIMING)
+ );
+ }
+
+ DEBUG ((DEBUG_INFO, "%a: - allocating frame buffer... \n",
+ __FUNCTION__));
+ Status = AllocateFrameBuffer (&DisplayContextPtr->DisplayConfig.DisplaySurface[0]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to allocate fb, Status=%r\n",
+ __FUNCTION__, Status));
+ goto Exit;
+ };
+
+ DEBUG ((DEBUG_INFO, "%a: - Initialize the frame buffer to black\n",
+ __FUNCTION__));
+ // 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, "%a: - set display configuration to single HDMI\n",
+ __FUNCTION__));
+ // Set the display configuration to single HDMI/LVDS mode
+ DisplayInterfaceOrder[0] = DisplayDevice;
+ DisplayContextPtr->DisplayConfig.DisplayTiming[0] =
+ DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming;
+
+ Status = ApplyDisplayConfig (
+ DisplayContextPtr,
+ SINGLE_MODE,
+ DisplayInterfaceOrder
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to set display. Exit Status=%r\n",
+ __FUNCTION__, Status));
+ goto Exit;
+ }
+
+ VidGopModeInfo.Version = 0;
+ VidGopModeInfo.HorizontalResolution =
+ DisplayContextPtr->DisplayConfig.DisplayTiming[0].HActive;
+ VidGopModeInfo.VerticalResolution =
+ DisplayContextPtr->DisplayConfig.DisplayTiming[0].VActive;
+ VidGopModeInfo.PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+ ZeroMem (
+ &VidGopModeInfo.PixelInformation,
+ sizeof (VidGopModeInfo.PixelInformation)
+ );
+
+ VidGopModeInfo.PixelsPerScanLine = VidGopModeInfo.HorizontalResolution;
+ VidGopMode.MaxMode = 1;
+ VidGopMode.Mode = 0;
+ VidGopMode.Info = &VidGopModeInfo;
+ VidGopMode.SizeOfInfo = sizeof (VidGopModeInfo);
+ VidGopMode.FrameBufferBase =
+ (EFI_PHYSICAL_ADDRESS) DisplayContextPtr->DisplayConfig.DisplaySurface[0].PhyAddr;
+ VidGopMode.FrameBufferSize =
+ VidGopModeInfo.HorizontalResolution *
+ VidGopModeInfo.VerticalResolution *
+ (DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp / 8);
+ DisplayContextPtr->DisplayConfig.OsHandle[0] = (UINT32)&ImageHandle;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &VidGop,
+ &gEfiDevicePathProtocolGuid,
+ &VidDevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to install protocol, Status=%x\n",
+ __FUNCTION__, Status));
+ goto Exit;
+ }
+
+Exit:
+ DEBUG ((DEBUG_INFO, "%a: Exit = %Xh\n",
+ __FUNCTION__, Status));
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+VidGopQueryMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ )
+{
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *OutputMode;
+ EFI_STATUS Status;
+
+ if (FeaturePcdGet (PcdLvdsEnable)) {
+ DisplayDevice = Lvds0Display;
+ } else {
+ DisplayDevice = HdmiDisplay;
+ }
+
+ EdidDiscovered.SizeOfEdid = DisplayContextPtr->DiContext[DisplayDevice].EdidDataSize;
+ EdidDiscovered.Edid = DisplayContextPtr->DiContext[DisplayDevice].EdidData;
+ EdidActive.SizeOfEdid = DisplayContextPtr->DiContext[DisplayDevice].EdidDataSize;
+ EdidActive.Edid = DisplayContextPtr->DiContext[DisplayDevice].EdidData;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ (EFI_HANDLE)DisplayContextPtr->DisplayConfig.OsHandle[0],
+ &gEfiEdidDiscoveredProtocolGuid,
+ &EdidDiscovered,
+ &gEfiEdidActiveProtocolGuid,
+ &EdidActive,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to install EDID protocols Status=%r\n",
+ __FUNCTION__, Status));
+ }
+
+ if (ModeNumber != 0) {
+ DEBUG ((DEBUG_ERROR, "%a: Saw request to query mode %d\n",
+ __FUNCTION__, 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 = VidGopModeInfo.HorizontalResolution;
+ OutputMode->VerticalResolution = VidGopModeInfo.VerticalResolution;
+ OutputMode->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+ OutputMode->PixelsPerScanLine = 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
+ )
+{
+ EFI_STATUS Status;
+
+ if (ModeNumber != 0) {
+ DEBUG ((DEBUG_ERROR, "%a: Saw request to set mode to %d\n",
+ __FUNCTION__, ModeNumber));
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ Status = EFI_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 BufferOffset;
+ UINT32 BufferWidth;
+ UINT32 FrameOffset;
+ UINT32 FrameWidth;
+ UINT32 i;
+
+ FrameBuffer = (UINT32 *)((UINTN)VidGopMode.FrameBufferBase);
+ FrameWidth = 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, "%a: Not implemented %d\n",
+ __FUNCTION__, BltOperation));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.h
new file mode 100644
index 000000000000..b8622283238f
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.h
@@ -0,0 +1,20 @@
+/** @file
+*
+* Copyright (c) 2018 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 _GOP_DXE_H_
+#define _GOP_DXE_H_
+
+#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
+
+#endif /* _GOP_DXE_H_ */
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.inf b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.inf
new file mode 100644
index 000000000000..9dbe00ae1ab1
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/GopDxe.inf
@@ -0,0 +1,70 @@
+#/** @file
+#
+# Copyright (c) 2011, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2018 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 = 0x0001001A
+ BASE_NAME = GopDxe
+ FILE_GUID = E68088EF-D1A4-4336-C1DB-4D3A204730A6
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = GopDxeInitialize
+
+[Sources.common]
+ CPMem.c
+ Ddc.c
+ Display.c
+ DisplayController.c
+ DisplayInterface.c
+ Edid.c
+ GopDxe.c
+ Hdmi.c
+ IoMux.c
+ Lvds.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/NXP/iMX6Pkg/iMX6Pkg.dec
+
+[LibraryClasses]
+ ArmLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ iMX6ClkPwrLib
+ iMXDisplayLib
+ IoLib
+ TimerLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiDevicePathProtocolGuid # Produced
+ gEfiDevicePathToTextProtocolGuid
+ gEfiEdidActiveProtocolGuid # Produced
+ gEfiEdidDiscoveredProtocolGuid # Produced
+ gEfiGraphicsOutputProtocolGuid # Produced
+
+[Pcd]
+ giMX6TokenSpaceGuid.PcdFrameBufferBase
+ giMX6TokenSpaceGuid.PcdFrameBufferSize
+ giMX6TokenSpaceGuid.PcdLvdsEnable
+
+[Depex]
+ gEfiCpuArchProtocolGuid AND gEfiTimerArchProtocolGuid
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Hdmi.c b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Hdmi.c
new file mode 100644
index 000000000000..fa8fb3ed4aea
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Hdmi.c
@@ -0,0 +1,761 @@
+/** @file
+*
+* Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <iMX6.h>
+#include <iMX6ClkPwr.h>
+#include <iMXDisplay.h>
+
+#include "Display.h"
+#include "GopDxe.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 (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN UINT32 Timeout
+ )
+{
+ HDMI_IH_I2CMPHY_STAT0_REG I2cmphyStat0Reg;
+ BOOLEAN WaitResult;
+
+ WaitResult = FALSE;
+ for (; Timeout > 0; Timeout--) {
+ I2cmphyStat0Reg.Reg = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_IH_I2CMPHY_STAT0
+ );
+ if (I2cmphyStat0Reg.i2cmphydone) {
+ WaitResult = TRUE;
+ break;
+ }
+ gBS->Stall (1);
+ }
+
+#if DEBUG
+ if ((Timeout == 0) || (I2cmphyStat0Reg.i2cmphyerror == 1)) {
+ DEBUG ((DEBUG_ERROR, "%a: HDMI I2C failed value %x time out %d\n",
+ __FUNCTION__, I2cmphyStat0Reg.Reg, Timeout));
+ }
+#endif
+
+ return WaitResult;
+}
+
+BOOLEAN
+HdmiPhyI2cRead (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN UINT8 Addr,
+ OUT UINT16 *DataPtr
+ )
+{
+ UINT16 Data0;
+ UINT16 Data1;
+ HDMI_PHY_I2CM_OPERATION_ADDR_REG I2cmOperationReg;
+ HDMI_IH_I2CMPHY_STAT0_REG I2cmphyStat0Reg;
+ BOOLEAN ReadStatus;
+
+ I2cmphyStat0Reg.i2cmphyerror = 1;
+ I2cmphyStat0Reg.i2cmphydone = 1;
+ I2cmphyStat0Reg.reserved = 0;
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_IH_I2CMPHY_STAT0,
+ I2cmphyStat0Reg.Reg
+ );
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_ADDRESS_ADDR,
+ Addr
+ );
+
+ I2cmOperationReg.Reg = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_PHY_I2CM_OPERATION_ADDR
+ );
+ I2cmOperationReg.read = 1;
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_OPERATION_ADDR,
+ I2cmOperationReg.Reg
+ );
+
+ ReadStatus = HdmiPhyPollI2cDone (HdmiDisplayContextPtr, 1000);
+ if (!ReadStatus) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to read I2c HDMI Phy\n", __FUNCTION__));
+ goto Exit;
+ }
+
+ Data0 = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_PHY_I2CM_DATAI_0_ADDR
+ );
+ Data1 = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_PHY_I2CM_DATAI_1_ADDR
+ );
+ *DataPtr = Data0 | (Data1 << 8);
+
+Exit:
+ return ReadStatus;
+}
+
+BOOLEAN
+HdmiPhyI2cWrite (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN UINT8 Addr,
+ IN UINT16 Data
+ )
+{
+ UINT8 Data0;
+ UINT8 Data1;
+ HDMI_PHY_I2CM_OPERATION_ADDR_REG I2cmOperationReg;
+ HDMI_IH_I2CMPHY_STAT0_REG I2cmphyStat0Reg;
+
+ Data0 = (Data & 0x00FF);
+ Data1 = (Data >> 8);
+ I2cmphyStat0Reg.i2cmphyerror = 1;
+ I2cmphyStat0Reg.i2cmphydone = 1;
+ I2cmphyStat0Reg.reserved = 1;
+ I2cmOperationReg.read = 0;
+ I2cmOperationReg.reserved0 = 0;
+ I2cmOperationReg.write = 0;
+ I2cmOperationReg.reserved1 = 0;
+
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_IH_I2CMPHY_STAT0,
+ I2cmphyStat0Reg.Reg
+ );
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_ADDRESS_ADDR,
+ Addr
+ );
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_DATAO_0_ADDR,
+ Data0
+ );
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_DATAO_1_ADDR,
+ Data1
+ );
+
+ I2cmOperationReg.read = 0;
+ I2cmOperationReg.write = 1;
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_OPERATION_ADDR,
+ I2cmOperationReg.Reg
+ );
+ return HdmiPhyPollI2cDone (HdmiDisplayContextPtr, 1000);
+}
+
+BOOLEAN
+GetGenericConfigSetting (
+ IN DISPLAY_TIMING *DisplayTimingPtr,
+ OUT PLL_MPLL_CONFIG **ConfigGenericSettingPPtr
+ )
+{
+ UINT32 ColorDepth;
+ BOOLEAN FoundConfig;
+ UINT32 SettingIndex;
+
+ FoundConfig = FALSE;
+ ColorDepth = GetColorDepth (DisplayTimingPtr->PixelFormat);
+
+ for (SettingIndex = 0;
+ SettingIndex < ARRAYSIZE (PllMpllGenericConfigSetting);
+ ++SettingIndex)
+ {
+ if ((DisplayTimingPtr->PixelClock ==
+ PllMpllGenericConfigSetting[SettingIndex].PixelClock) &&
+ (DisplayTimingPtr->PixelRepetition ==
+ PllMpllGenericConfigSetting[SettingIndex].PixelRepetition) &&
+ (ColorDepth == 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;
+}
+
+EFI_STATUS
+InitHdmi (
+ IN DISPLAY_CONTEXT *DisplayContextPtr
+ )
+{
+ DISPLAY_INTERFACE_CONTEXT *pHdmiDisplayContext;
+ EFI_STATUS Status;
+
+ pHdmiDisplayContext = &DisplayContextPtr->DiContext[HdmiDisplay];
+ Status = EFI_SUCCESS;
+ ZeroMem (pHdmiDisplayContext, sizeof (*pHdmiDisplayContext));
+
+ pHdmiDisplayContext->MmioBasePtr = (VOID *)HDMI_BASE;
+ if (pHdmiDisplayContext->MmioBasePtr == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to map HDMI register\n", __FUNCTION__));
+ goto Exit;
+ }
+
+ // Setup HDMI DDC muxing
+ MmioWrite32 ((UINT32)IOMUXC_SW_MUX_CTL_PAD_KEY_COL3, 0x00000012);
+ MmioWrite32 ((UINT32)IOMUXC_SW_MUX_CTL_PAD_KEY_ROW3, 0x00000012);
+ MmioWrite32 ((UINT32)IOMUXC_HDMI_II2C_CLKIN_SELECT_INPUT, 0x00000001);
+ MmioWrite32 ((UINT32)IOMUXC_HDMI_II2C_DATAIN_SELECT_INPUT, 0x00000001);
+ SetHdmiPower (pHdmiDisplayContext, TRUE);
+
+ // Mask all HDMI PHY interrupt
+ MmioWrite8 (
+ (UINT32)pHdmiDisplayContext->MmioBasePtr + HDMI_PHY_MASK0,
+ 0xFF
+ );
+
+ Status = ReadEdid (
+ DisplayContextPtr,
+ HdmiDisplay,
+ pHdmiDisplayContext->EdidData,
+ &pHdmiDisplayContext->EdidDataSize
+ );
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_WARN, "%a: Fail to read HDMI EDID data\n", __FUNCTION__));
+ Status = EFI_SUCCESS;
+ }
+
+ Status = GetPreferredTiming (
+ pHdmiDisplayContext->EdidData,
+ pHdmiDisplayContext->EdidDataSize,
+ &pHdmiDisplayContext->PreferredTiming
+ );
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to retrieve HDMI preferred timing\n",
+ __FUNCTION__));
+ goto Exit;
+ }
+
+ if ((pHdmiDisplayContext->PreferredTiming.HActive == 1920) &&
+ (pHdmiDisplayContext->PreferredTiming.VActive == 1080))
+ {
+ pHdmiDisplayContext->PreferredTiming.HBlank -= 6;
+ }
+
+Exit:
+ return Status;
+}
+
+EFI_STATUS
+SetHdmiPower (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN BOOLEAN PowerState
+ )
+{
+ HDMI_PHY_CONF0_REG CurrentHdmiPhyConf0Reg;
+
+ CurrentHdmiPhyConf0Reg.Reg = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_PHY_CONF0
+ );
+ if (PowerState) {
+ // Setup PHY
+ CurrentHdmiPhyConf0Reg.PDZ = 1;
+ CurrentHdmiPhyConf0Reg.ENTMDS = 1;
+ CurrentHdmiPhyConf0Reg.gen2_pddq = 1;
+ CurrentHdmiPhyConf0Reg.gen2_txpwron = 1;
+ CurrentHdmiPhyConf0Reg.seldataenpol = 1;
+ CurrentHdmiPhyConf0Reg.seldipif = 0;
+ } else {
+ // Just power down PHY for shutdown
+ CurrentHdmiPhyConf0Reg.PDZ = 0;
+ }
+
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_CONF0,
+ CurrentHdmiPhyConf0Reg.Reg
+ );
+ gBS->Stall (3);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SetHdmiPhy (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN DISPLAY_TIMING *Timings
+ )
+{
+ PLL_MPLL_CONFIG *pPllMpllConfig;
+ HDMI_PHY_CONF0_REG CurrentHdmiPhyConf0Reg;
+ HDMI_FC_AUDSCONF_REG FcAudsconfReg;
+ HDMI_MC_HEACPHY_RST_REG HeacphyRstReg;
+ HDMI_MC_CLKDIS_REG McClkdisReg;
+ HDMI_MC_PHYRSTZ_REG PhyRstzReg;
+ HDMI_PHY_STAT0_REG PhyStat0Reg;
+ BOOLEAN PhyStatus;
+ UINT32 RetryCount;
+ EFI_STATUS Status;
+
+ // Disable Audio
+ FcAudsconfReg.Reg = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_FC_AUDSCONF
+ );
+ FcAudsconfReg.aud_packet_layout = 0;
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_FC_AUDSCONF,
+ FcAudsconfReg.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) {
+ DEBUG ((DEBUG_ERROR, "%a: Unsupported pixel clock %d\n",
+ __FUNCTION__, Timings->PixelClock));
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (GetGenericConfigSetting (Timings, &pPllMpllConfig) == FALSE) {
+ DEBUG ((DEBUG_ERROR, "%a: No compatible generic config found\n",
+ __FUNCTION__));
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ // Color Space Converter : Not used in UEFI
+ McClkdisReg.Reg = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_MC_CLKDIS
+ );
+ // Disable CEC, color converter, audio & pixel repitition
+ McClkdisReg.cecclk_disable = 1;
+ McClkdisReg.cscclk_disable = 1;
+ McClkdisReg.audclk_disable = 1;
+ McClkdisReg.prepclk_disable = 1;
+ McClkdisReg.hdcpclk_disable = 1;
+ McClkdisReg.tmdsclk_disable = 0;
+ McClkdisReg.pixelclk_disable = 0;
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_MC_CLKDIS,
+ McClkdisReg.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.
+ CurrentHdmiPhyConf0Reg.Reg = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_PHY_CONF0
+ );
+ CurrentHdmiPhyConf0Reg.gen2_txpwron = 0;
+ CurrentHdmiPhyConf0Reg.gen2_pddq = 1;
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_CONF0,
+ CurrentHdmiPhyConf0Reg.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
+ PhyRstzReg.Reg = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_MC_PHYRSTZ
+ );
+ PhyRstzReg.phyrstz = 1;
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_MC_PHYRSTZ,
+ PhyRstzReg.Reg
+ );
+ PhyRstzReg.phyrstz = 0;
+ gBS->Stall (10);
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_MC_PHYRSTZ,
+ PhyRstzReg.Reg
+ );
+
+ HeacphyRstReg.Reg = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_MC_HEACPHY_RST
+ );
+ HeacphyRstReg.heacphyrst = 1;
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_MC_HEACPHY_RST,
+ HeacphyRstReg.Reg
+ );
+
+ // Program clock
+ // PLL / MPLL Operation
+ // The PLL / MPLL can be configured in Coherent mode or NonCoherent 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 NonCoherent mode, the TMDS clock is the MPLL reference clock, which is
+ // not coherent with the MPLL's high-speed output clock.
+ PhyStatus = HdmiPhyI2cWrite (
+ HdmiDisplayContextPtr,
+ HDMI_PHY_CPCE_CTRL,
+ pPllMpllConfig->HdmiPhyCpceCtrl.Reg
+ );
+ if (PhyStatus == FALSE) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_CPCE_CTRL %x\n",
+ __FUNCTION__, pPllMpllConfig->HdmiPhyCpceCtrl.Reg));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ PhyStatus = HdmiPhyI2cWrite (
+ HdmiDisplayContextPtr,
+ HDMI_PHY_CURRCTRL,
+ pPllMpllConfig->HdmiPhyCurrctrl.Reg
+ );
+ if (PhyStatus == FALSE) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_CURRCTRL\n",
+ __FUNCTION__));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ };
+
+ PhyStatus = HdmiPhyI2cWrite (
+ HdmiDisplayContextPtr,
+ HDMI_PHY_GMPCTRL,
+ pPllMpllConfig->HdmiPhyGmpctrl.Reg
+ );
+ if (PhyStatus == FALSE) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_GMPCTRL\n",
+ __FUNCTION__));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ // Maintaining the order of phy register writes
+ PhyStatus = HdmiPhyI2cWrite (
+ HdmiDisplayContextPtr,
+ HDMI_PHY_PLLPHBYCTRL,
+ 0x0000
+ );
+ if (PhyStatus == FALSE) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_PLLPHBYCTRL\n",
+ __FUNCTION__));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ // Coherent mode
+ PhyStatus = HdmiPhyI2cWrite (
+ HdmiDisplayContextPtr,
+ HDMI_PHY_MSM_CTRL,
+ 0x0006
+ );
+ if (PhyStatus == FALSE) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_MSM_CTRL\n",
+ __FUNCTION__));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ // Resistance value 133.33 ohm
+ PhyStatus = HdmiPhyI2cWrite (
+ HdmiDisplayContextPtr,
+ HDMI_PHY_TXTERM,
+ 0x0005
+ );
+ if (PhyStatus == FALSE) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_TXTERM\n",
+ __FUNCTION__));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ // Enable clock symbol
+ PhyStatus = HdmiPhyI2cWrite (
+ HdmiDisplayContextPtr,
+ HDMI_PHY_CKSYMTXCTRL,
+ 0x8009
+ );
+ if (PhyStatus == FALSE) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_CKSYMTXCTRL\n",
+ __FUNCTION__));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ PhyStatus = HdmiPhyI2cWrite (
+ HdmiDisplayContextPtr,
+ HDMI_PHY_VLEVCTRL,
+ 0x0210
+ );
+ if (PhyStatus == FALSE) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_VLEVCTRL\n",
+ __FUNCTION__));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ // Enable override
+ PhyStatus = HdmiPhyI2cWrite (
+ HdmiDisplayContextPtr,
+ HDMI_PHY_CKCALCTRL,
+ 0x8000
+ );
+ if (PhyStatus == FALSE) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_CKCALCTRL\n",
+ __FUNCTION__));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ CurrentHdmiPhyConf0Reg.gen2_txpwron = 1;
+ CurrentHdmiPhyConf0Reg.gen2_pddq = 0;
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_CONF0,
+ CurrentHdmiPhyConf0Reg.Reg
+ );
+
+ Status = EFI_DEVICE_ERROR;
+ for (RetryCount = 5; RetryCount > 0; RetryCount--) {
+ PhyStat0Reg.Reg = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_PHY_STAT0
+ );
+ if (!PhyStat0Reg.TX_PHY_LOCK) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ gBS->Stall (1000);
+ }
+
+ if (RetryCount == 0) {
+ DEBUG ((DEBUG_ERROR, "%a: TX PHY remain unlock\n", __FUNCTION__));
+ }
+
+Exit:
+ return Status;
+}
+
+EFI_STATUS
+SetHdmiDisplay (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN DISPLAY_TIMING *Timings
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SetHdmiPhy (HdmiDisplayContextPtr, Timings);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: SetHdmiPhy failed\n", __FUNCTION__));
+ goto Exit;
+ }
+
+Exit:
+ return Status;
+}
+
+VOID
+SetDdcSpeed (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN DDC_MODE Mode
+ )
+{
+ MmioWrite8 ((UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_I2CM_DIV, Mode);
+}
+
+EFI_STATUS
+HdmiDdcRead (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN UINT8 SlaveAddress,
+ IN UINT8 RegisterAddress,
+ IN UINT32 ReadSize,
+ IN DDC_MODE DDCMode,
+ IN UINT8 *DataReadPtr
+ )
+{
+ UINT8 *pCurrentDataRead;
+ UINT32 AddrCount;
+ UINT8 I2cmIntStatus;
+ UINT32 I2cRetryCount;
+ EFI_STATUS Status;
+
+ pCurrentDataRead = DataReadPtr;
+ Status = EFI_SUCCESS;
+
+ // Setup EDID transaction and loop through all byte request
+ SetDdcSpeed (HdmiDisplayContextPtr, DDCMode);
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_IH_I2CM_STAT0,
+ I2C_MASTER_ERROR | I2C_MASTER_DONE
+ );
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_I2CM_SLAVE,
+ SlaveAddress
+ );
+
+ for (AddrCount = 0; AddrCount < ReadSize; ++AddrCount) {
+ I2cRetryCount = 1000;
+
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_I2CM_ADDRESS,
+ (UINT8) ( RegisterAddress + AddrCount)
+ );
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_I2CM_SEGADDR,
+ 0x00
+ );
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_I2CM_OPERATION,
+ DDC_READ_OPERATION
+ );
+
+ // Poll for completion
+ I2cmIntStatus = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_IH_I2CM_STAT0
+ );
+ for (I2cRetryCount = 1000; I2cRetryCount > 0; I2cRetryCount--) {
+ I2cmIntStatus = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_IH_I2CM_STAT0
+ );
+ if (I2cmIntStatus != 0) {
+ break;
+ }
+ }
+
+ if (I2cRetryCount == 0) {
+ Status = EFI_DEVICE_ERROR;
+ DEBUG ((DEBUG_ERROR, "%a: Timeout waiting for interrupt 0x%02x\n",
+ __FUNCTION__, I2cmIntStatus));
+ goto Exit;
+ }
+
+ if ((I2cmIntStatus & I2C_MASTER_DONE) &&
+ !(I2cmIntStatus & I2C_MASTER_ERROR))
+ {
+ *pCurrentDataRead = MmioRead8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr +
+ HDMI_I2CM_DATAI
+ );
+ pCurrentDataRead++;
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_IH_I2CM_STAT0,
+ I2C_MASTER_ERROR | I2C_MASTER_DONE
+ );
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ DEBUG ((DEBUG_ERROR, "%a: Failed to read with DDC 0x%02x\n",
+ __FUNCTION__, I2cmIntStatus));
+ goto Exit;
+ }
+
+ MmioWrite8 (
+ (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_IH_I2CM_STAT0,
+ I2C_MASTER_ERROR | I2C_MASTER_DONE
+ );
+ }
+
+Exit:
+ return Status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Hdmi.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Hdmi.h
new file mode 100644
index 000000000000..e1b7372bc2e9
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Hdmi.h
@@ -0,0 +1,529 @@
+/** @file
+*
+* Copyright (c) 2018 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_
+
+// 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
+
+// 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;
+
+#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)
+
+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;
+
+EFI_STATUS
+InitHdmi (
+ IN DISPLAY_CONTEXT *DisplayContextPtr
+ );
+
+EFI_STATUS
+SetHdmiPower (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN BOOLEAN PowerState
+ );
+
+EFI_STATUS
+SetHdmiDisplay (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN DISPLAY_TIMING *Timings
+ );
+
+EFI_STATUS
+HdmiDdcRead (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN UINT8 SlaveAddress,
+ IN UINT8 RegisterAddress,
+ IN UINT32 ReadSize,
+ IN DDC_MODE DDCMode,
+ IN UINT8 *DataReadPtr
+ );
+
+#endif /* _HDMI_H_ */
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/IoMux.c b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/IoMux.c
new file mode 100644
index 000000000000..b82fbd2125f5
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/IoMux.c
@@ -0,0 +1,88 @@
+/** @file
+*
+* Copyright (c) 2018 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/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <iMX6.h>
+#include <iMX6ClkPwr.h>
+#include <iMXDisplay.h>
+
+#include "Display.h"
+#include "IoMux.h"
+
+EFI_STATUS
+SetupDisplayMux (
+ IN DISPLAY_CONTEXT *DisplayContextPtr
+ )
+{
+ DISPLAY_INTERFACE_TYPE *pDisplayInterfaceType;
+ volatile IMX_IOMUXC_GPR_REGISTERS *pIomuxcGprReg;
+ UINT32 DisplayInterfaceIndex;
+ DISPLAY_MODE DisplayMode;
+ UINT32 Gpr3Reg;
+ UINT32 SourceMask;
+ UINT32 SourceValue;
+ EFI_STATUS Status;
+
+ pIomuxcGprReg = DisplayContextPtr->IoMuxMmioBasePtr;
+ DisplayMode = DisplayContextPtr->DisplayConfig.DisplayMode;
+ pDisplayInterfaceType = DisplayContextPtr->DisplayConfig.DiOrder;
+ Status = EFI_SUCCESS;
+
+ Gpr3Reg = MmioRead32 ((UINT32)&pIomuxcGprReg->GPR3);
+ Gpr3Reg &= ~(HDMI_MUX_CTL_MASK | MIPI_MUX_CTL_MASK |
+ LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);
+ MmioWrite32 ((UINT32)&pIomuxcGprReg->GPR3, Gpr3Reg);
+
+ for (DisplayInterfaceIndex = 0; DisplayInterfaceIndex < (UINT32)DisplayMode; ++DisplayInterfaceIndex) {
+ Gpr3Reg = MmioRead32 ((UINT32)&pIomuxcGprReg->GPR3);
+ switch (pDisplayInterfaceType[DisplayInterfaceIndex]) {
+ case HdmiDisplay:
+ SourceMask = HDMI_MUX_CTL_MASK;
+ SourceValue = DisplayInterfaceIndex << HDMI_MUX_CTL_OFFSET;
+ break;
+ case MipiDisplay:
+ SourceMask = MIPI_MUX_CTL_MASK;
+ SourceValue = DisplayInterfaceIndex << MIPI_MUX_CTL_OFFSET;
+ break;
+ case Lvds0Display:
+ SourceMask = LVDS0_MUX_CTL_MASK;
+ SourceValue = DisplayInterfaceIndex << LVDS0_MUX_CTL_OFFSET;
+ break;
+ case Lvds1Display:
+ SourceMask = LVDS1_MUX_CTL_MASK;
+ SourceValue = DisplayInterfaceIndex << LVDS1_MUX_CTL_OFFSET;
+ break;
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Gpr3Reg &= ~SourceMask;
+ Gpr3Reg |= SourceValue;
+ MmioWrite32 ((UINT32)&pIomuxcGprReg->GPR3, Gpr3Reg);
+ }
+
+ return Status;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/IoMux.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/IoMux.h
new file mode 100644
index 000000000000..4946ab293ae5
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/IoMux.h
@@ -0,0 +1,32 @@
+/** @file
+*
+* Copyright (c) 2018 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
+
+EFI_STATUS
+SetupDisplayMux (
+ IN DISPLAY_CONTEXT *DisplayContextPtr
+ );
+
+#endif /* _IO_MUX_H_ */
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ipu.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ipu.h
new file mode 100644
index 000000000000..00d20c881b67
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Ipu.h
@@ -0,0 +1,236 @@
+/** @file
+*
+* Copyright (c) 2018 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) \
+ MmioRead32((UINT32)((UINT8 *)IPU_BASE + OFFSET))
+
+#define IpuWrite32(IPU_BASE, OFFSET, VALUE) \
+ MmioWrite32((UINT32)((UINT8 *)IPU_BASE + OFFSET), VALUE)
+
+#define DiRead32(DI_BASE, OFFSET) \
+ MmioRead32((UINT32)((UINT8 *)DI_BASE + OFFSET))
+
+#define DiWrite32(DI_BASE, OFFSET, VALUE) \
+ MmioWrite32((UINT32)((UINT8 *)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 DisplayInterface0 Registers
+#define IPU_DISPLAY_INTERFACE_0_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 DisplayInterface1 Registers
+#define IPU_DISPLAY_INTERFACE_1_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 /* _IPU_H_ */
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Lvds.c b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Lvds.c
new file mode 100644
index 000000000000..e6eb3b31bb07
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Lvds.c
@@ -0,0 +1,93 @@
+/** @file
+*
+* Copyright (c) 2018 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/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <iMX6.h>
+#include <iMX6ClkPwr.h>
+#include <iMXDisplay.h>
+
+#include "Display.h"
+#include "Lvds.h"
+#include "Edid.h"
+
+EFI_STATUS
+InitLvds (
+ IN DISPLAY_CONTEXT *DisplayContextPtr
+ )
+{
+ DISPLAY_INTERFACE_CONTEXT *pLvdsDisplayContext;
+ EFI_STATUS Status;
+ LDB_CTRL_REG LdbCtrlReg;
+
+ Status = EFI_SUCCESS;
+ pLvdsDisplayContext = &DisplayContextPtr->DiContext[Lvds0Display];
+ ZeroMem (pLvdsDisplayContext, sizeof (*pLvdsDisplayContext));
+
+ pLvdsDisplayContext->MmioBasePtr = (VOID *)LDB_BASE;
+ if (pLvdsDisplayContext->MmioBasePtr == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to map LDB register\n", __FUNCTION__));
+ goto Exit;
+ }
+
+ // LVDS CH1 enabled, routed to DisplayInterface0; ipu_di01_vsync_active_low
+ LdbCtrlReg.Reg = MmioRead32 ((UINT32)pLvdsDisplayContext->MmioBasePtr + LDB_CTRL);
+ LdbCtrlReg.ch0_mode = 1;
+ LdbCtrlReg.ch1_mode = 1;
+ LdbCtrlReg.di0_vs_polarity = 1;
+ LdbCtrlReg.di1_vs_polarity = 1;
+ MmioWrite32 ((UINT32)pLvdsDisplayContext->MmioBasePtr + LDB_CTRL, LdbCtrlReg.Reg);
+
+ // No EDID available
+ pLvdsDisplayContext->EdidDataSize = 0;
+
+ Status = GetPreferredTiming (
+ pLvdsDisplayContext->EdidData,
+ pLvdsDisplayContext->EdidDataSize,
+ &pLvdsDisplayContext->PreferredTiming
+ );
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to retrieve LVDS preferred timing\n",
+ __FUNCTION__));
+ goto Exit;
+ }
+
+Exit:
+ return Status;
+}
+
+EFI_STATUS
+SetLvdsPower (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN BOOLEAN PowerState
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+SetLvdsDisplay (
+ IN DISPLAY_INTERFACE_CONTEXT *pLvdsDisplayContext,
+ IN DISPLAY_TIMING *Timings
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Lvds.h b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Lvds.h
new file mode 100644
index 000000000000..b45201fb45fc
--- /dev/null
+++ b/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Lvds.h
@@ -0,0 +1,67 @@
+/** @file
+*
+* Copyright (c) 2018 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_
+
+// LDB Register Base Address
+#define LDB_BASE 0x020E0008
+
+// LDB Control Register offset
+#define LDB_CTRL 0
+
+#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)
+
+EFI_STATUS
+InitLvds (
+ IN DISPLAY_CONTEXT *DisplayContextPtr
+ );
+
+EFI_STATUS
+SetLvdsPower (
+ IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr,
+ IN BOOLEAN PowerState
+ );
+
+EFI_STATUS
+SetLvdsDisplay (
+ IN DISPLAY_INTERFACE_CONTEXT *LvdsDisplayContextPtr,
+ IN DISPLAY_TIMING *Timings
+ );
+
+#endif /* _LVDS_H_ */
--
2.16.2.gvfs.1.33.gf5370f1
next prev parent reply other threads:[~2018-09-21 8:26 UTC|newest]
Thread overview: 75+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-09-21 8:25 [PATCH edk2-platforms 00/27] Import Hummingboard Edge platform for Windows IoT Core Chris Co
2018-09-21 8:25 ` [PATCH edk2-platforms 01/27] Platform/Microsoft: Add OpteeClientPkg dec Chris Co
2018-10-31 20:43 ` Leif Lindholm
2018-11-01 10:55 ` Sumit Garg
2018-11-02 0:41 ` Chris Co
2018-11-02 5:24 ` Sumit Garg
2018-11-02 23:55 ` Chris Co
2018-11-05 10:07 ` Sumit Garg
2018-11-06 1:53 ` Chris Co
2018-11-06 11:09 ` Sumit Garg
2018-09-21 8:25 ` [PATCH edk2-platforms 02/27] Platform/Microsoft: Add SdMmc Dxe Driver Chris Co
2018-09-21 8:25 ` [PATCH edk2-platforms 03/27] Platform/Microsoft: Add MsPkg Chris Co
2018-10-31 21:00 ` Leif Lindholm
2018-09-21 8:25 ` [PATCH edk2-platforms 04/27] Silicon/NXP: Add iMXPlatformPkg dec Chris Co
2018-09-21 8:25 ` [PATCH edk2-platforms 05/27] Silicon/NXP: Add UART library support for i.MX platforms Chris Co
2018-11-01 8:59 ` Leif Lindholm
2018-11-02 1:46 ` Chris Co
2018-09-21 8:25 ` [PATCH edk2-platforms 06/27] Silicon/NXP: Add I2C " Chris Co
2018-11-01 17:53 ` Leif Lindholm
2018-09-21 8:25 ` [PATCH edk2-platforms 07/27] Silicon/NXP: Add i.MX display library support Chris Co
2018-11-01 18:05 ` Leif Lindholm
2018-11-29 0:55 ` Chris Co
2018-09-21 8:25 ` [PATCH edk2-platforms 08/27] Silicon/NXP: Add Virtual RTC support for i.MX platform Chris Co
2018-12-15 13:26 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 10/27] Silicon/NXP: Add iMX6Pkg dec Chris Co
2018-11-01 18:25 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 09/27] Silicon/NXP: Add headers for SoC-specific i.MX packages to use Chris Co
2018-11-01 18:20 ` Leif Lindholm
2018-12-01 0:22 ` Chris Co
2018-12-03 9:42 ` Leif Lindholm
2018-12-04 1:44 ` Chris Co
2018-12-04 9:33 ` Ard Biesheuvel
2018-12-04 12:22 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 11/27] Silicon/NXP: Add i.MX6 SoC header files Chris Co
2018-12-13 17:11 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 12/27] Silicon/NXP: Add i.MX6 I/O MUX library Chris Co
2018-11-08 18:00 ` Leif Lindholm
2018-12-04 1:41 ` Chris Co
2018-09-21 8:26 ` [PATCH edk2-platforms 13/27] Silicon/NXP: Add support for iMX SDHC Chris Co
2018-12-05 10:31 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 14/27] Silicon/NXP: Add i.MX6 GPT and EPIT timer headers Chris Co
2018-11-08 18:14 ` Leif Lindholm
2018-12-04 2:06 ` Chris Co
2018-12-04 12:58 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 15/27] Silicon/NXP: Add i.MX6 GPT Timer library Chris Co
2018-12-13 17:26 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 16/27] Silicon/NXP: Add i.MX6 Timer DXE driver Chris Co
2018-12-13 17:33 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 17/27] Silicon/NXP: Add i.MX6 USB Phy Library Chris Co
2018-12-14 17:10 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 18/27] Silicon/NXP: Add i.MX6 Clock Library Chris Co
2018-12-14 18:12 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 19/27] Silicon/NXP: Add i.MX6 ACPI tables Chris Co
2018-12-14 19:53 ` Leif Lindholm
2018-12-17 11:14 ` Ard Biesheuvel
2019-01-08 21:43 ` Chris Co
2019-01-29 14:09 ` Ard Biesheuvel
2018-09-21 8:26 ` [PATCH edk2-platforms 20/27] Silicon/NXP: Add i.MX6 Board init library Chris Co
2018-12-14 20:12 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 21/27] Silicon/NXP: Add i.MX6 PCIe DXE driver Chris Co
2018-12-14 21:59 ` Leif Lindholm
2018-09-21 8:26 ` Chris Co [this message]
2018-12-14 22:37 ` [PATCH edk2-platforms 22/27] Silicon/NXP: Add i.MX6 GOP driver Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 23/27] Silicon/NXP: Add i.MX6 Smbios Driver Chris Co
2018-12-14 23:07 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 24/27] Silicon/NXP: Add i.MX6 common dsc and fdf files Chris Co
2018-12-14 23:36 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 25/27] Platform/Solidrun: Add Hummingboard Peripheral Initialization Chris Co
2018-12-15 12:12 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 26/27] Platform/SolidRun: Add i.MX 6Quad Hummingboard Edge ACPI tables Chris Co
2018-12-15 12:19 ` Leif Lindholm
2018-09-21 8:26 ` [PATCH edk2-platforms 27/27] Platform/Solidrun: Add i.MX 6Quad Hummingboard Edge dsc and fdf files Chris Co
2018-12-15 12:28 ` Leif Lindholm
2018-12-15 13:32 ` [PATCH edk2-platforms 00/27] Import Hummingboard Edge platform for Windows IoT Core Leif Lindholm
2018-12-19 18:28 ` 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=20180921082542.35768-23-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