From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.38.112; helo=nam02-bl2-obe.outbound.protection.outlook.com; envelope-from=christopher.co@microsoft.com; receiver=edk2-devel@lists.01.org Received: from NAM02-BL2-obe.outbound.protection.outlook.com (mail-bl2nam02on0112.outbound.protection.outlook.com [104.47.38.112]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id DB29C2115412E for ; Fri, 21 Sep 2018 01:26:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=aJc/grOIiPhW0GZ+9GW6C580iL6k3JAazPXa/ANwAUg=; b=dsWxVbIHzrod++/ljS9aDAIhLw1rtj1kRg2IvdKUeB5su3xpK125buRDfXJVLo4OPsXVyTEnWFK/yaEnMUwR0QsNRxLWsJXt+/K24n1Dyb5oGFU+SU8XPaUUlr2HDkdsP6PUr7FR7ep+I7AqiLbIBfR/1CvsLu+RuGSy0QB1Q90= Received: from DM5PR2101MB1128.namprd21.prod.outlook.com (52.132.133.20) by DM5PR2101MB0727.namprd21.prod.outlook.com (10.167.110.39) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1185.6; Fri, 21 Sep 2018 08:26:15 +0000 Received: from DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::81f8:300e:d90:d49]) by DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::81f8:300e:d90:d49%3]) with mapi id 15.20.1164.008; Fri, 21 Sep 2018 08:26:15 +0000 From: Chris Co To: "edk2-devel@lists.01.org" CC: Ard Biesheuvel , Leif Lindholm , Michael D Kinney Thread-Topic: [PATCH edk2-platforms 22/27] Silicon/NXP: Add i.MX6 GOP driver Thread-Index: AQHUUYTDcNYz+AHEvkiwUFa0y0Uvlg== Date: Fri, 21 Sep 2018 08:26:15 +0000 Message-ID: <20180921082542.35768-23-christopher.co@microsoft.com> References: <20180921082542.35768-1-christopher.co@microsoft.com> In-Reply-To: <20180921082542.35768-1-christopher.co@microsoft.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: MWHPR17CA0054.namprd17.prod.outlook.com (2603:10b6:300:93::16) To DM5PR2101MB1128.namprd21.prod.outlook.com (2603:10b6:4:a8::20) x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [2001:4898:80e8:8:388a:edc9:7085:c18] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DM5PR2101MB0727; 6:8yV/BIFjwwXHQ19WlMblTFIITDPgXnAJGs7ROSUPGAmn2Lu6kxTDTEF1pbTBWVosWTVB29wpbRknB9yy+kopIewuf8kBKnwMhoIwpN83odnlLODXIoqN7IkI8yuQU54jBc7FjGDNhfMWVuRGAB1ezGx/EAUnVN6EsuwIvo3H1sjjhTYtOB1XgNWmu169VPgIywl0XDXRcKQsZTIOp2aetmSjEjRes9h/6LSbBOAjbr0aKLdlPs3opqjs7IV8WfRhkTsBHkIXOYt04GmmGkH5eru9h0t5szAxE1wkIhvZAKIwSIPAFzlvgVD9w0WId5p58rgvU7G5Ah1qxwun/7bp+LeMZ9U+QsEhrwA3mXXBM7TW98kkSWRxSk2n6nLoiwo1jvDxnCtVfxr1ndD9HTAv/Om4g3T9Rp1J9VYQVac1RSxTzqDbnHPAd3uHhHfX7qJsnq1tlwKKwcNPLYsnQwnGXQ==; 5:0irX7WlPLuTOYksQEk1hwao+GAVkvGGq9OdLvDLlZUM4o+ZSQuLnB47DfmBKcnKq8E+QTXnX9jS+ztYm6gdmEMPfzTn+fwfX3NSXEu1PhC6WJKqOsymaucHWW6AtkRJ2xdm9/iuAWHOdVV5iHVIDYGuXMEvprdRa264jSlTdvMM=; 7:apEsXqdpS4DNMgNej2F7fBqr9uXPFZcNidJ6CH7JE99rHeW5Hh1SlcjhG5NlOwtrxgvqqcjDUV3dNVSRuLP8pL3D6/pqmKvkheux7FOcyJPJVWAmvThzWT/y3vvBpESIoitIA7xx1/VzBqzRrRqdhXyU3FFl2j2rwy83lsSWE1huA+58MofNZ0RCV2z0CFZXxKQr7/9Xw4GoMSJj2xRgb/ak3RG9woMrH06vbjvX8IC4fRx+Wl0uo3dHcK0D6b0D x-ms-office365-filtering-correlation-id: d307ef0c-a5cb-4429-11b1-08d61f9be509 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989299)(4534165)(4627221)(201703031133081)(201702281549075)(8990200)(5600074)(711020)(4618075)(2017052603328)(7193020); SRVR:DM5PR2101MB0727; x-ms-traffictypediagnostic: DM5PR2101MB0727: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(28532068793085)(89211679590171)(12401385986421)(228905959029699); x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(3231355)(2280164)(944501410)(52105095)(2018427008)(93006095)(93001095)(3002001)(10201501046)(6055026)(149027)(150027)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123562045)(20161123560045)(20161123564045)(20161123558120)(201708071742011)(7699051)(76991041); SRVR:DM5PR2101MB0727; BCL:0; PCL:0; RULEID:; SRVR:DM5PR2101MB0727; x-forefront-prvs: 0802ADD973 x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(1496009)(39860400002)(396003)(136003)(376002)(366004)(346002)(199004)(189003)(8676002)(81156014)(25786009)(446003)(2900100001)(102836004)(46003)(52116002)(6346003)(81166006)(11346002)(105586002)(2351001)(8936002)(386003)(4326008)(76176011)(6506007)(10090500001)(5250100002)(7736002)(2616005)(486006)(305945005)(53376002)(6116002)(186003)(16799955002)(1076002)(2501003)(476003)(6916009)(99286004)(22452003)(97736004)(45954006)(71200400001)(71190400001)(72206003)(478600001)(966005)(6306002)(551934003)(10290500003)(5640700003)(14454004)(36756003)(86362001)(19627235002)(575784001)(6436002)(16200700003)(15188155005)(2906002)(53946003)(86612001)(106356001)(54906003)(316002)(6486002)(256004)(6512007)(14444005)(114624004)(68736007)(5660300001)(53936002)(60540400001)(579004)(569006); DIR:OUT; SFP:1102; SCL:1; SRVR:DM5PR2101MB0727; H:DM5PR2101MB1128.namprd21.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; received-spf: None (protection.outlook.com: microsoft.com does not designate permitted sender hosts) authentication-results: spf=none (sender IP is ) smtp.mailfrom=Christopher.Co@microsoft.com; x-microsoft-antispam-message-info: GyU5yWL1PRpftEC8yoPXVl4NvPB072ZdkY94QSC7DF5vLim1r1tlzMuc18omb4g81ye9qtujwPH0xue83BR6x0Lu+nxje2Y+68FQXAVy9SGyzvIQU4XxOmAiSyJObo0PxP+7bn07BnyM4ZXCPrwOKVkLOwkIk3cdOI9x9xGMWZEnVfBxyQS4y8DrA5ISqsjYkNDu1o90Wn7a1BP2l+jDcVS/G8AqoyeuTdiJT1XEbqkW2gDlPlxjhSGzOb0+G18D3N2N1YWsJbb8J4hOq6cRmxbKcu5K9TxfNrqsXhUmTKJpvyDLsMERBrggvb+gyCQNpvVEd6GTRee4p7+Y7xFgN5eDgXZfjJ5MrZtkGwXyi3jpEpsgmMIAv94aDzIXL2CIwBrKANNI73K/YhmcTs6RCkL6jeazqTF4j12nw6GHvFuO49H4BG+XLnMg1/MZI2L1EJ6EFciLYZO4DjzRYLqG5g7wJ3qrZe52wyyLybvBRgHR+rmvy70a/V3zhmsc+oYB+qnF6Ysda+sk1BVc3TtGs/EwZO2lv3zpeEEOJ3NOO+R1XhfJr7cSLYFgNl7ay4vx spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-Network-Message-Id: d307ef0c-a5cb-4429-11b1-08d61f9be509 X-MS-Exchange-CrossTenant-originalarrivaltime: 21 Sep 2018 08:26:15.0597 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR2101MB0727 Subject: [PATCH edk2-platforms 22/27] Silicon/NXP: Add i.MX6 GOP driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 21 Sep 2018 08:26:22 -0000 Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable 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 Cc: Ard Biesheuvel Cc: Leif Lindholm Cc: Michael D Kinney --- 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/iMX6P= kg/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 B= SD 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 IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Display.h" +#include "CPMem.h" +#include "GopDxe.h" +#include "Ipu.h" + +CPMEM_PARAM *CpMemParamBasePtr =3D (CPMEM_PARAM *)(IPU1_BASE + CSP_IPUV3_C= PMEM_REGS_OFFSET); + +STATIC CONST UINT8 ChannelMap[] =3D { + 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", __FUNCT= ION__, + ParamPtr->Word0Pack.ScrollHorizontalDirection)); + DEBUG ((DEBUG_VERBOSE, "%a: ScrollVerticalDirection 0x%08x\n", __FUNCTIO= N__, + 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", __FUNCT= ION__, + ParamPtr->Word0Pack.ConditionalAccessPolarity)); + DEBUG ((DEBUG_VERBOSE, "%a: ConditionalAccessEnable 0x%08x\n", __FUNCTIO= N__, + 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 =3D -1; + + for (i =3D 0; i < ARRAYSIZE (ChannelMap); i +=3D 2) { + if (ChannelMap[i] =3D=3D Channel) { + Shift =3D ChannelMap[i + 1]; + break; + } + } + + if (Shift =3D=3D -1) { + DEBUG ((DEBUG_WARN, "%a: Channel %d does not have lock bits\n", + __FUNCTION__, Channel)); + return; + } + + if (Channel < 29) { + LockReg =3D (UINTN)DisplayInterfaceContextPtr->IpuMmioBasePtr + IPU_ID= MAC_LOCK_EN_1; + } else { + LockReg =3D (UINTN)DisplayInterfaceContextPtr->IpuMmioBasePtr + IPU_ID= MAC_LOCK_EN_2; + } + + Value =3D MmioRead32 ((UINT32)LockReg); + Value &=3D ~(0x3 << Shift); + Value |=3D (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 =3D DisplayInterfaceContextPtr->CpMemParamBasePtr; + Status =3D EFI_SUCCESS; + PixelBurst =3D 1; + DecodeAddressSelect =3D 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 =3D 15; // 16 Pixel. Valid range is 1 - 64 pixel + PixelFormatSelector =3D CPMEM_PFS_RGB; + Offset0 =3D 8; + Offset1 =3D 16; + Offset2 =3D 24; + Offset3 =3D 0; + BytesPerPixel =3D 4; + break; + default: + ASSERT (FALSE); + Status =3D EFI_UNSUPPORTED; + break; + } + if (EFI_ERROR (Status)) { + goto Exit; + } + + switch (FrameBufferPtr->Bpp) { + case 8: + Width0 =3D 0; + Width1 =3D 0; + Width2 =3D 0; + Width3 =3D 0; + break; + case 32: + if (PixelFormatSelector =3D=3D CPMEM_PFS_RGB) { + Width0 =3D 7; + Width1 =3D 7; + Width2 =3D 7; + Width3 =3D 7; + } else { + Width0 =3D 0; + Width1 =3D 0; + Width2 =3D 0; + Width3 =3D 0; + } + break; + default: + ASSERT (FALSE); + Status =3D EFI_UNSUPPORTED; + break; + } + if (EFI_ERROR (Status)) { + goto Exit; + } + // Setting up CPMEM word 0 + CpmemWord0PackedReg.XVVirtualCoordinate =3D 0; + CpmemWord0PackedReg.YVVirtualCoordinate =3D 0; + + // Subblock is unused although expect to have some Value after write + CpmemWord0PackedReg.XBinnerBlockCoordinate =3D 0; + CpmemWord0PackedReg.YBinnerBlockCoordinate =3D 0; + CpmemWord0PackedReg.NewSubBlock =3D 0; + + // Verify "current field" definition + CpmemWord0PackedReg.CurrentField =3D 0; + + // Disable scrolling + CpmemWord0PackedReg.ScrollXCounter =3D 0; + CpmemWord0PackedReg.ScrollYCounter =3D 0; + CpmemWord0PackedReg.NumberOfScroll =3D 0; + CpmemWord0PackedReg.ScrollDeltaX =3D 0; + CpmemWord0PackedReg.ScrollMax =3D 0; + CpmemWord0PackedReg.ScrollingConfiguration =3D 0; + CpmemWord0PackedReg.ScrollingEnable =3D 0; + CpmemWord0PackedReg.ScrollDeltaY =3D 0; + CpmemWord0PackedReg.ScrollHorizontalDirection =3D 0; + CpmemWord0PackedReg.ScrollVerticalDirection =3D 0; + + // Bits per pixel + CpmemWord0PackedReg.BitsPerPixel =3D FrameBufferPtr->Bpp; + + // Decode Address Select + CpmemWord0PackedReg.DecodeAddressSelect =3D DecodeAddressSelect; + + // Scan order is progressive no support for interlace mode + CpmemWord0PackedReg.ScanOrder =3D CPMEM_SO_PROGRESSIVE; + + // Band mode is sub frame double buffering + CpmemWord0PackedReg.BandMode =3D CPMEM_BNDM_DISABLE; + + // Block mode used for post filtering and rotation + CpmemWord0PackedReg.BlockMode =3D CPMEM_BM_DISABLE; + + // No support for rotation and flipping for now + CpmemWord0PackedReg.Rotation =3D CPMEM_ROT_NO_ROTATION; + CpmemWord0PackedReg.HorizontalFlip =3D CPMEM_HF_NO_HFLIP; + CpmemWord0PackedReg.VerticalFlip =3D CPMEM_HF_NO_VFLIP; + CpmemWord0PackedReg.ThresholdEnable =3D CPMEM_THE_DISABLE; + + // Disable conditional access + CpmemWord0PackedReg.ConditionalAccessEnable =3D CPMEM_CAP_SKIP_LOW; + CpmemWord0PackedReg.ConditionalAccessPolarity =3D CPMEM_CAE_DISABLE; + + // Frame width and height, minus one as 0 =3D=3D 1 pixel + CpmemWord0PackedReg.FrameWidth =3D FrameBufferPtr->Width - 1; + CpmemWord0PackedReg.FrameHeight =3D FrameBufferPtr->Height - 1; + + // No interrupt required at the end of line + CpmemWord0PackedReg.EndOfLineInterrupt =3D CPMEM_EOLI_DISABLE; + + // Setting up CPMEM word 1 + // Buffer 0, use the [31:3] bit address + CpmemWord1PackedReg.ExtMemBuffer0Address =3D FrameBufferPtr->PhyAddr >> = 3; + + // Buffer 1, use the same buffer for now + CpmemWord1PackedReg.ExtMemBuffer1Address =3D FrameBufferPtr->PhyAddr >> = 3; + + // Currently do not support interlace mode + CpmemWord1PackedReg.InterlaceOffset =3D 0; + + // Pixel format and burst + CpmemWord1PackedReg.NumberOfPixelsInWholeBurstAccess =3D PixelBurst; + CpmemWord1PackedReg.PixelFormatSelect =3D PixelFormatSelector; + + // Alpha config + CpmemWord1PackedReg.AlphaUsed =3D CPMEM_ALU_SAME_BUFFER; + + // AXI ID 0 should be okay, we don't have anything else contending for i= t + CpmemWord1PackedReg.AxiId =3D CPMEM_ID_ID_0; + + CpmemWord1PackedReg.Threshold =3D CPMEM_THE_DISABLE; + + // Stride, width and offset + CpmemWord1PackedReg.StrideLine =3D (FrameBufferPtr->Pitch * BytesPerPixe= l) - 1; + CpmemWord1PackedReg.Width0 =3D Width0; + CpmemWord1PackedReg.Width1 =3D Width1; + CpmemWord1PackedReg.Width2 =3D Width2; + CpmemWord1PackedReg.Width3 =3D Width3; + CpmemWord1PackedReg.Offset0 =3D Offset0; + CpmemWord1PackedReg.Offset1 =3D Offset1; + CpmemWord1PackedReg.Offset2 =3D Offset2; + CpmemWord1PackedReg.Offset3 =3D Offset3; + + // SX SY is ignored since scrolling is disabled + CpmemWord1PackedReg.SelectSXSYSet =3D 0; + + // Conditional read is always enabled so fully transperant pixel are + // not read. + CpmemWord1PackedReg.ConditionalReadEnable =3D CPMEM_CRE_ENABLE; + + // Finally write into cpmem IDMAC channel + pCpmemChannel =3D (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/iMX6P= kg/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 B= SD 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 IM= PLIED. +* +**/ + +#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 =3D 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 B= SD 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 IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 =3D HdmiDdcRead ( + &DisplayContextPtr->DiContext[HdmiDisplay], + SlaveAddress, + RegisterAddress, + ReadSize, + HDMI_DDC_STANDARD_MODE, + DataReadPtr + ); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "%a: HdmiDdcRead failed\n", __FUNCTION__)); + } + break; + case MipiDisplay: + case Lvds0Display: + case Lvds1Display: + default: + Status =3D 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 B= SD 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 IM= PLIED. +* +**/ + +#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/iMX= 6Pkg/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 B= SD 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 IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +// 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 =3D { + 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 =3D { + 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 =3D Hannstar_XGA; + Status =3D EFI_SUCCESS; + } else { + Status =3D GetEdidPreferredTiming (EdidDataPtr, EdidDataSize, Preferre= dTimingPtr); + if (Status !=3D EFI_SUCCESS) { + // If EDID is unavailable use the default timing + Status =3D EFI_SUCCESS; + *PreferredTimingPtr =3D 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 =3D 1; + PreferredTimingPtr->PixelFormat =3D PIXEL_FORMAT_BGRA32; + PreferredTimingPtr->Bpp =3D 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 =3D AllocateRuntimePool (sizeof (*pTempDisplayContex= t)); + if (pTempDisplayContext =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: Fail to allocate display context\n", __FUNCT= ION__)); + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + ZeroMem (pTempDisplayContext, sizeof (*pTempDisplayContext)); + + pTempDisplayContext->IoMuxMmioBasePtr =3D (VOID *)IOMUXC_GPR_BASE_ADDRES= S; + if (pTempDisplayContext->IoMuxMmioBasePtr =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: Fail to map IO Mux register\n", __FUNCTION__= )); + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + pTempDisplayContext->IpuMmioBasePtr[IPU1] =3D (VOID *)IPU1_BASE; + if (pTempDisplayContext->IoMuxMmioBasePtr =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: Fail to map IPU1 IO Mux register\n", __FUNCT= ION__)); + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } +#if !defined(CPU_IMX6SDL) + pTempDisplayContext->IpuMmioBasePtr[IPU2] =3D (VOID *)IPU2_BASE; + if (pTempDisplayContext->IoMuxMmioBasePtr =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: Fail to map IPU2 IO Mux register\n", __FUNCT= ION__)); + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } +#endif + for (DisplayCounter =3D HdmiDisplay; DisplayCounter < DisplayTypeMax; ++= DisplayCounter) { + pTempDisplayContext->DiContext[DisplayCounter].displayInterface =3D + DisplayCounter; + } + + if (FeaturePcdGet (PcdLvdsEnable)) { + Status =3D InitLvds (pTempDisplayContext); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "%a: Fail to intialize LVDS\n", __FUNCTION__)); + goto Exit; + } + } else { + Status =3D InitHdmi (pTempDisplayContext); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "%a: Fail to intialize HDMI\n", __FUNCTION__)); + goto Exit; + } + } + + *DisplayConfigPPtr =3D 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 =3D Lvds0Display; + } else { + DisplayDevice =3D HdmiDisplay; + } + + // Currently only support single display mode on HDMI/LVDS + if (DisplayMode !=3D SINGLE_MODE && DiOrder[0] !=3D DisplayDevice) { + Status =3D EFI_UNSUPPORTED; + goto Exit; + } + + // Currently going to a very simplistic approach of enabling HDMI/LVDS s= ingle + // display on HDMI/LVDS port. This configuration is applied regardless i= f + // there is a monitor connected. No hot plug, monitor detection support. + Status =3D 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] =3D IPU_DISPLAY_INTERFACE_0_OFFSET; + DisplayInterfaceOffset[1] =3D IPU_DISPLAY_INTERFACE_1_OFFSET; + Status =3D ValidateDisplayConfig (DisplayContextPtr, DisplayMode, DiOrde= r); + if (Status !=3D EFI_SUCCESS) { + DisplayContextPtr->DisplayConfig.DisplayMode =3D UNKNOWN_MODE; + ZeroMem ( + DisplayContextPtr->DisplayConfig.DiOrder, + sizeof (DisplayContextPtr->DisplayConfig.DiOrder) + ); + DEBUG ((DEBUG_ERROR, "%a: Unsupported display configuration\n", __FUNC= TION__)); + Status =3D EFI_UNSUPPORTED; + goto Exit; + } + + DisplayContextPtr->DisplayConfig.DisplayMode =3D 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 =3D 0; + for (IpuIndex =3D IPU1; IpuIndex < IPU_TOTAL; IpuIndex++) { + for (DisplayInterfaceIndex =3D DisplayInterface0; + DisplayInterfaceIndex < DisplayInterfaceMax; + DisplayInterfaceIndex++) + { + if (DisplayModeIndex >=3D (UINT32)DisplayMode) { + break; + } + DisplayModeIndex++; + + DisplayContextPtr->DisplayConfig.DiOrder[DisplayInterfaceIndex] =3D + DiOrder[DisplayInterfaceIndex]; + pDisplayInterfaceContext =3D + &DisplayContextPtr->DiContext[DiOrder[DisplayInterfaceIndex]]; + pDisplayInterfaceContext->IpuMmioBasePtr =3D + DisplayContextPtr->IpuMmioBasePtr[IpuIndex]; + pDisplayInterfaceContext->IpuDiRegsPtr =3D + (IPU_DIx_REGS *)(((UINTN)DisplayContextPtr->IpuMmioBasePtr[IpuInde= x]) + + DisplayInterfaceOffset[DisplayInterfaceIn= dex]); + pDisplayInterfaceContext->CpMemParamBasePtr =3D + (VOID *)(((UINTN)pDisplayInterfaceContext->IpuMmioBasePtr) + + CSP_IPUV3_CPMEM_REGS_OFFSET); + } + } + + Status =3D 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 =3D EFI_SUCCESS; + pDisplayConfig =3D &DisplayContextPtr->DisplayConfig; + Status =3D SetDisplayConfig (DisplayContextPtr, DisplayMode, DiOrder); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, + "%a: Fail to set display configuration %d\n", + __FUNCTION__, DisplayMode)); + Status =3D EFI_UNSUPPORTED; + goto Exit; + } + + // Setup muxing first before configuring DI and DC + Status =3D SetupDisplayMux (DisplayContextPtr); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "%a: SetDisplayMux failed \n", __FUNCTION__)); + goto Exit; + } + + for (DisplayModeIndex =3D 0; + DisplayModeIndex < (UINT32)pDisplayConfig->DisplayMode; + ++DisplayModeIndex) + { + CurrentDisplayInterface =3D pDisplayConfig->DiOrder[DisplayModeIndex]; + pDisplayInterfaceContext =3D &DisplayContextPtr->DiContext[CurrentDisp= layInterface]; + pCurrentDisplayTiming =3D &pDisplayConfig->DisplayTiming[DisplayModeIn= dex]; + + Status =3D ConfigureDisplayControllerChannel ( + pDisplayInterfaceContext, + CurrentDisplayInterface, + DisplayModeIndex, + pCurrentDisplayTiming + ); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, + "%a:ConfigureDisplayControllerChannel fail display %d index %d\n", + __FUNCTION__, CurrentDisplayInterface, DisplayModeIndex)); + goto Exit; + } + + Status =3D ConfigureDisplayInterface ( + pDisplayInterfaceContext, + DisplayModeIndex, + pCurrentDisplayTiming + ); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "%a: Fail to configure DI\n", __FUNCTION__)); + goto Exit; + } + + switch (CurrentDisplayInterface) { + case HdmiDisplay: + Status =3D SetHdmiDisplay (pDisplayInterfaceContext, pCurrentDisplay= Timing); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "%a: Fail to set HDMI timing\n", __FUNCTION__= )); + goto Exit; + } + break; + case Lvds0Display: + case Lvds1Display: + break; + default: + Status =3D EFI_UNSUPPORTED; + break; + } + if (EFI_ERROR (Status)) { + goto Exit; + } + + Status =3D ConfigureFrameBuffer ( + pDisplayInterfaceContext, + &pDisplayConfig->DisplaySurface[DisplayModeIndex] + ); + if (Status !=3D 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 =3D=3D 0) || (SurfaceInfoPtr->Height =3D=3D 0= )) { + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + DEBUG ((DEBUG_INFO, "%a: Frame Buffer AddrP=3D%Xh\n", + __FUNCTION__, FixedPcdGet32 (PcdFrameBufferBase))); + DEBUG ((DEBUG_INFO, "%a: Frame Buffer Size=3D%Xh\n", + __FUNCTION__, FixedPcdGet32 (PcdFrameBufferSize))); + + SurfaceInfoPtr->VirtAddrPtr =3D (VOID *)(UINTN)FixedPcdGet32 (PcdFrameBu= fferBase); + SurfaceInfoPtr->PhyAddr =3D (UINT32)(SurfaceInfoPtr->VirtAddrPtr); + SurfaceInfoPtr->Pitch =3D SurfaceInfoPtr->Width; + + DEBUG ((DEBUG_INFO, + "%a: Allocate FB PhyAddr %x VirtAddr %x\n", + __FUNCTION__, SurfaceInfoPtr->PhyAddr, SurfaceInfoPtr->VirtAddrPtr)); + + Status =3D EFI_SUCCESS; + +Exit: + DEBUG ((DEBUG_INFO, "%a: Exit =3D %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 =3D ConfigureCpmemFrameBuffer ( + DisplayInterfaceContextPtr, + IDMAC_CHANNEL_DP_PRIMARY_FLOW_MAIN_PLANE, + FrameBufferPtr + ); + if (Status !=3D 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 =3D 8; + break; + default: + BitDepth =3D 0; + break; + } + + return BitDepth; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/Display.h b/Silicon/NXP/iMX= 6Pkg/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 B= SD 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 IM= PLIED. +* +**/ + +#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 =3D 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/Silic= on/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 B= SD 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 IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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", __FUNCT= ION__)); + + DEBUG ((DEBUG_VERBOSE, "%a: ## Configuration\n\n", __FUNCTION__)); + RegVal =3D 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 =3D 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 =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_DISP_CONF1_0_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_DISP_CONF1_0_OFFSET %x\n", + __FUNCTION__, RegVal)); + RegVal =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_DISP_CONF1_1_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_DISP_CONF1_1_OFFSET %x\n", + __FUNCTION__, RegVal)); + RegVal =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_DISP_CONF1_2_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_DISP_CONF1_2_OFFSET %x\n", + __FUNCTION__, RegVal)); + RegVal =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_DISP_CONF1_3_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_DISP_CONF1_3_OFFSET %x\n", + __FUNCTION__, RegVal)); + RegVal =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_DISP_CONF2_0_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_DISP_CONF2_0_OFFSET %x\n", + __FUNCTION__, RegVal)); + RegVal =3D 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 =3D 0, Index =3D 0; Index < 26; Counter +=3D 4, ++Index) = { + RegVal =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_MAP_CONF_0_OFFSET + Cou= nter); + 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 =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_RL0_CH_5_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_RL0_CH_5_OFFSET %x\n", + __FUNCTION__, RegVal)); + RegVal =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_RL1_CH_5_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_RL1_CH_5_OFFSET %x\n", + __FUNCTION__, RegVal)); + RegVal =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_RL2_CH_5_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_RL2_CH_5_OFFSET %x\n", + __FUNCTION__, RegVal)); + RegVal =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_RL3_CH_5_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DC_RL3_CH_5_OFFSET %x\n", + __FUNCTION__, RegVal)); + RegVal =3D 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 =3D 0, Index =3D 0; Index < 10; Counter +=3D 8, ++Index) { + DEBUG ((DEBUG_VERBOSE, "%a: (%d)\n", __FUNCTION__, Index)); + RegVal =3D IpuRead32 ( + IpuMmioBasePtr, + IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + Counter); + DEBUG ((DEBUG_VERBOSE, "%a: - %8x\n", __FUNCTION__, RegVal)); + RegVal =3D 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 =3D IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + (MicroCodeAdd= r * 8); + ZeroMem ((VOID *)&WrodCommand, sizeof (WrodCommand)); + WrodCommand.STOP =3D 1; + WrodCommand.OPCODE =3D 0x18; + WrodCommand.DATA =3D Data; + WrodCommand.MAPPING =3D Mapping; + WrodCommand.WAVEFORM =3D WaveForm + 1; + WrodCommand.GLUELOGIC =3D GlueLogic; + WrodCommand.SYNC =3D Sync; + IpuWrite32 (IpuMmioBasePtr, MicroCodeAddrOffset, WrodCommand.LowWord); + IpuWrite32 (IpuMmioBasePtr, MicroCodeAddrOffset + 4, WrodCommand.HighWor= d); + return EFI_SUCCESS; +} + +EFI_STATUS +SetDisplayControllerChannelState ( + IN VOID *IpuMmioBasePtr, + IN PROG_CHAN_TYP ChannelType + ) +{ + IPU_DC_WR_CH_CONF_5_REG WrChConfigReg; + + WrChConfigReg.Reg =3D IpuRead32 (IpuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OFF= SET); + WrChConfigReg.PROG_CHAN_TYP =3D ChannelType; + IpuWrite32 (IpuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OFFSET, WrChConfigReg.Re= g); + 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 =3D DisplayInterfaceContextPtr->IpuMmioBasePtr; + Status =3D EFI_SUCCESS; + + ZeroMem ((VOID *)&WrChConfigReg, sizeof (WrChConfigReg)); + WrChConfigReg.PROG_START_TIME =3D 0; + WrChConfigReg.FILED_MODE =3D 0; + WrChConfigReg.CHAN_MASK_DEFAULT =3D 0; // only used highest priority + WrChConfigReg.PROG_CHAN_TYP =3D 0; // Begin as disable + WrChConfigReg.PROG_DISP_ID =3D DisplayInterface; + WrChConfigReg.PROG_DI_ID =3D DisplayIndex % 2; + WrChConfigReg.W_SIZE =3D 0x02; // 24 Bits + WrChConfigReg.Reserved1 =3D 0; + WrChConfigReg.Reserved2 =3D 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 =3D 0; + WrChConfigReg.CHAN_MASK_DEFAULT =3D 0; // only used highest priority + WrChConfigReg.PROG_CHAN_TYP =3D 4; // Enable + WrChConfigReg.PROG_DISP_ID =3D DisplayInterface; + WrChConfigReg.PROG_DI_ID =3D DisplayIndex % 2; + WrChConfigReg.W_SIZE =3D 0x02; // 1 Bits + WrChConfigReg.Reserved1 =3D 0; + WrChConfigReg.Reserved2 =3D 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 =3D 0x02; // What is byte_enabled + DisplayConfig1Reg.ADDR_INCREMENT =3D 0; // Increase by 1 byte + DisplayConfig1Reg.ADDR_BE_L_INC =3D 0; + DisplayConfig1Reg.MCU_ACC_LB_MASK_3 =3D 0; + DisplayConfig1Reg.DISP_RD_VALUE_PTR =3D 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 =3D 2; // Sync flow + DisplayControllerGenReg.MASK_EN =3D 0; // Disable masking + DisplayControllerGenReg.MASK4CHAN_5 =3D 0; // Ignore as mask is disabled + DisplayControllerGenReg.SYNC_PRIORITY_5 =3D 1; // Higher sync priority f= or channel 5 + DisplayControllerGenReg.SYNC_PRIORITY_1 =3D 0; // Lower sync priority + DisplayControllerGenReg.DC_CH5_TYPE =3D 0; // Normal mode, sync flow thr= ough channel 5 + DisplayControllerGenReg.DC_BK_EN =3D 0; // No cursor support + DisplayControllerGenReg.DC_BKDIV =3D 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 =3D 0; + DcMapConf0Reg.MAPPING_PNTR_BYTE1_X =3D 1; + DcMapConf0Reg.MAPPING_PNTR_BYTE2_X =3D 2; + DcMapConf0Reg.MAPPING_PNTR_BYTE0_Y =3D 3; // Unused + DcMapConf0Reg.MAPPING_PNTR_BYTE1_Y =3D 4; // Unused + DcMapConf0Reg.MAPPING_PNTR_BYTE2_Y =3D 5; // Unused + IpuWrite32 (pIpuMmioBase, IPU_DC_MAP_CONF_0_OFFSET, DcMapConf0Reg.Reg); + + switch (DisplayInterface) { + // PixelFormat RGB24 + case HdmiDisplay: + Mask0 =3D 0xFF; + Mask1 =3D 0xFF; + Mask2 =3D 0xFF; + Offset0 =3D 7; + Offset1 =3D 15; + Offset2 =3D 23; + break; + // PixelFormat RGB666 + case Lvds0Display: + case Lvds1Display: + Mask0 =3D 0xFC; + Mask1 =3D 0xFC; + Mask2 =3D 0xFC; + Offset0 =3D 5; + Offset1 =3D 11; + Offset2 =3D 17; + break; + default: + ASSERT (FALSE); + Status =3D EFI_UNSUPPORTED; + break; + } + if (EFI_ERROR (Status)) { + goto Exit; + } + + DcConfOffsetMaskReg.MD_MASK_X =3D Mask0; + DcConfOffsetMaskReg.MD_OFFSET_X =3D Offset0; // Blue + DcConfOffsetMaskReg.MD_MASK_Y =3D Mask1; + DcConfOffsetMaskReg.MD_OFFSET_Y =3D Offset1; // Green + IpuWrite32 (pIpuMmioBase, IPU_DC_MAP_CONF_15_OFFSET, DcConfOffsetMaskReg= .Reg); + + DcConfOffsetMaskReg.MD_MASK_X =3D Mask2; + DcConfOffsetMaskReg.MD_OFFSET_X =3D Offset2; // Red + DcConfOffsetMaskReg.MD_MASK_Y =3D 0x00; + DcConfOffsetMaskReg.MD_OFFSET_Y =3D 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 =3D 0; + DcRl0Ch5Reg.COD_NL_PRIORITY_CHAN_5 =3D 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 =3D 1; + DcRl2Ch5Reg.COD_EOL_PRIORITY_CHAN_5 =3D 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 =3D 2; + DcRl4Ch5Reg.COD_NEW_DATA_PRIORITY_CHAN_5 =3D 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 =3D EFI_SUCCESS; + +Exit: + return Status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayController.h b/Silic= on/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 B= SD 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 IM= PLIED. +* +**/ + +#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 =3D 0, + DC_CHANNEL_DC_SYNC_ASYNC =3D 1, + DC_CHANNEL_DC_ASYNC =3D 2, + DC_CHANNEL_DP_MAIN =3D 5, + DC_CHANNEL_DP_SECONDARY =3D 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 =3D 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/Silico= n/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 B= SD 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 IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 =3D 8; // Limit printing (max 12) + + DEBUG ((DEBUG_VERBOSE, "%a: ------- DI Register Dump -------\n", __FUNCT= ION__)); + // Print out generator value for D0 + DEBUG ((DEBUG_VERBOSE, "%a: ## Wave Gen\n", __FUNCTION__)); + for (index =3D 0; index < printTotalGen; ++index) { + regVal =3D 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 =3D 0; index < printTotalGen; ++index) { + for (setNumber =3D 0; setNumber < 4; ++setNumber) { + regVal =3D READ_WAVE_SET (IpuDiRegsPtr, index, setNumber); + DEBUG ((DEBUG_VERBOSE, "%a: DI0_DW_SET%d_%d 0x%08x\n", + __FUNCTION__, setNumber, index, regVal)); + } + } + + regVal =3D IpuRead32 (IpuMmioBasePtr, IPU_IPU_PM_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_IPU_PM_OFFSET %x\n", + __FUNCTION__, regVal)); + + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_BS_CLKGEN0_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_BS_CLKGEN0_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_BS_CLKGEN1_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_BS_CLKGEN1_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SCR_CONF_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SCR_CONF_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN0_1_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN0_1_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN1_1_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN1_1_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN0_2_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN0_2_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN1_2_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN1_2_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN0_3_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN0_3_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN1_3_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN1_3_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN0_4_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN0_4_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN1_4_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN1_4_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN0_5_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN0_5_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SW_GEN1_5_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SW_GEN1_5_OFFSET %x\n", + __FUNCTION__, regVal)); + + for (index =3D 0; index < 5; ++index) { + regVal =3D 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 =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_SYNC_AS_GEN_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_SYNC_AS_GEN_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_GENERAL_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_GENERAL_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D DiRead32 (IpuDiRegsPtr, IPU_DIx_POL_OFFSET); + DEBUG ((DEBUG_VERBOSE, "%a: IPU_DIx_POL_OFFSET %x\n", + __FUNCTION__, regVal)); + regVal =3D 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", __FUNCT= ION__)); +} +#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 =3D OffsetResolution; + DiSwGen0Reg.dix_offset_value =3D OffsetValue; + DiSwGen0Reg.dix_run_resolution =3D RunResolution; + DiSwGen0Reg.dix_run_value_m1 =3D RunValue; + DiWrite32 ( + IpuDiRegsPtr, + IPU_DIx_SW_GEN0_1_OFFSET + ((CounterIndex - 1) * 0x04), + DiSwGen0Reg.Reg + ); + + ZeroMem ((VOID *)&DiSwGen1Reg, sizeof (DiSwGen1Reg)); + DiSwGen1Reg.dix_cnt_up =3D CounterUp; + DiSwGen1Reg.dix_cnt_polarity_clr_sel =3D CounterPolarityClearSelect; + DiSwGen1Reg.dix_cnt_polarity_trigger_sel =3D CounterPolarityTriggerSelec= t; + DiSwGen1Reg.dix_cnt_down =3D CounterDown; + DiSwGen1Reg.dix_cnt_clr_sel =3D CounterClearSelect; + DiSwGen1Reg.dix_cnt_auto_reload =3D CounterAutoReload; + DiSwGen1Reg.dix_cnt_polarity_gen_en =3D CounterPolarityGenEn; + DiWrite32 ( + IpuDiRegsPtr, + IPU_DIx_SW_GEN1_1_OFFSET + ((CounterIndex - 1) * 0x04), + DiSwGen1Reg.Reg + ); + + StepIndex =3D (CounterIndex - 1) / 2; + StepRepeatReg.Reg =3D IpuRead32 ( + IpuMmioBasePtr, + IPU_DI0_STP_REP_OFFSET + (StepIndex * 0x4) + ); + + if (CounterIndex % 2) { + StepRepeatReg.dix_step_repeat_2i_minus_1 =3D StepRepeat; + } else { + StepRepeatReg.dix_step_repeat_2i =3D 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 =3D DisplayTimingPtr->PixelClock; + HorizontalLength =3D DisplayTimingPtr->HActive + DisplayTimingPtr->HBlan= k; + VerticalLength =3D DisplayTimingPtr->VActive + DisplayTimingPtr->VBlank; + pIpuMmioBase =3D DisplayInterfaceContextPtr->IpuMmioBasePtr; + pIpuDiRegs =3D DisplayInterfaceContextPtr->IpuDiRegsPtr; + Status =3D EFI_SUCCESS; + + Status =3D ImxSetPll5ReferenceRate (DisplayTimingPtr->PixelClock); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "%a: Fail to setup PLL5=3D%r\n", __FUNCTION__, St= atus)); + 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 =3D (UINT32) ((DisplayInterfaceFrequency << 4) / DisplayTimingPt= r->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 >>=3D 4; + + DiWrite32 (pIpuDiRegs, IPU_DIx_BS_CLKGEN1_OFFSET, BaseDiv << 16); + // Calculate divisor, again this would usually be 1. + BaseDiv =3D (UINT32) (DisplayInterfaceFrequency / DisplayTimingPtr->Pixe= lClock); + + // 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 =3D 0; + DixDwSetReg.dix_data_cnt_downx_i =3D 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 =3D 0; + DixDwSetReg.dix_data_cnt_downx_i =3D 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 =3D DwSet0; + DixDwGenReg.dix_pt_1_i =3D DwSet0; + DixDwGenReg.dix_pt_2_i =3D DwSet0; + DixDwGenReg.dix_pt_3_i =3D DwSet0; + DixDwGenReg.dix_pt_4_i =3D DwSet3; + DixDwGenReg.dix_pt_5_i =3D DwSet0; + DixDwGenReg.dix_pt_6_i =3D DwSet0; + DixDwGenReg.dix_cst_i =3D DwSet0; + // Reuse the base divisor to determine extra IPU cycles. + DixDwGenReg.dix_componnent_size_i =3D BaseDiv - 1; + DixDwGenReg.dix_access_size_i =3D 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 =3D 3 - 1; + // Number of row DI prepares next frame data. + DixSyncAsGenReg.dix_sync_start =3D 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 =3D DI_COUNTER_1_INTERNAL_HSYNC - 1; + // Stop at the next edge of the display clock + DixGeneralReg.DIx_CLOCK_STOP_MODE =3D 0; + // The display's clock is stopped after the next VSYNC + DixGeneralReg.DIx_DISP_CLOCK_INIT =3D 0; + // IPP_PIN_2 is coming from counter #2 + DixGeneralReg.dix_mask_sel =3D 0; + // External clock - for not the video PLL + DixGeneralReg.dix_vsync_ext =3D 1; + // External clock - for not the video PLL + DixGeneralReg.dix_clk_ext =3D 1; + // 4 cycle watch dog based on BSP + DixGeneralReg.DIx_WATCHDOG_MODE =3D 0; + // default sync to counter 0 + DixGeneralReg.dix_sync_count_sel =3D DI_COUNTER_1_INTERNAL_HSYNC - 1; + // In the event of error drive the last component + DixGeneralReg.dix_err_treatment =3D 0; + // An internal VSYNC signal asserted 2 lines before the DI's VSYNC + DixGeneralReg.dix_erm_vsync_sel =3D 0; + + switch (DisplayInterfaceContextPtr->displayInterface) { + case HdmiDisplay: + // Zero for HDMI display + DixGeneralReg.dix_polarity_disp_clk =3D 0; + DixGeneralReg.dix_polarity_cs1 =3D 0; + DixGeneralReg.dix_polarity_cs0 =3D 0; + DixGeneralReg.dix_polarity_i_1 =3D 0; + break; + default: + Status =3D 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 =3D 1; + DixPolReg.dix_cs0_polarity =3D 0x7F; + // CS1 + DixPolReg.DIx_CS1_DATA_POLARITY =3D 1; + DixPolReg.dix_cs1_polarity =3D 0x7F; + // DRDY + DixPolReg.DIx_DRDY_DATA_POLARITY =3D 0; + DixPolReg.dix_drdy_polarity =3D 0x7F; + // Wait + DixPolReg.DIx_WAIT_POLARITY =3D 0; + // CS0 byte enable polarity + DixPolReg.DIx_CS0_BYTE_EN_POLARITY =3D 0; + // CS1 byte enable polarity + DixPolReg.DIx_CS1_BYTE_EN_POLARITY =3D 0; + DiWrite32 (pIpuDiRegs, IPU_DIx_POL_OFFSET, DixPolReg.Reg); + + DispGenReg =3D IpuRead32 (pIpuMmioBase, IPU_IPU_DISP_GEN_OFFSET); + DispGenReg &=3D ~(0x0F << 18); + DispGenReg |=3D (2 << 18); + IpuWrite32 (pIpuMmioBase, IPU_IPU_DISP_GEN_OFFSET, DispGenReg); + +#ifdef DEBUG + DumpBasicDisplayInterfaceReg (pIpuMmioBase, pIpuDiRegs); +#endif /* DEBUG */ + + Status =3D EFI_SUCCESS; + +Exit: + return Status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/DisplayInterface.h b/Silico= n/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 B= SD 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 IM= PLIED. +* +**/ + +#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) + (GE= N_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/iMX6Pk= g/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 B= SD 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 IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 =3D Imx6DdcRead ( + DisplayContextPtr, + DisplayInterface, + EDID_I2C_ADDRESS, + 0, + EDID_MIN_SIZE, + EdidDataPtr + ); + if (Status !=3D EFI_SUCCESS) { + goto Exit; + } + + Status =3D ValidateEdidData ( + EdidDataPtr + ); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_WARN, "%a: Invalid EDID data\n", __FUNCTION__)); + goto Exit; + } + + DEBUG ((DEBUG_INFO, "%a: EDID initialized\n", __FUNCTION__)); + + *EdidDataSizePtr =3D 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 =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + pEdidPreferredTiming =3D (DETAILED_TIMING_DESCRIPTOR *)&EdidDataPtr[EDID= _DTD_1_OFFSET]; + Status =3D ConvertDTDToDisplayTiming (pEdidPreferredTiming, PreferredTim= ing); + if (Status !=3D 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/iMX6Pk= g/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 B= SD 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 IM= PLIED. +* +**/ + +#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/iMX6= Pkg/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 B= SD 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 IM= PLIED. +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 =3D { + 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 =3D { + { + { + 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 =3D { + VidGopQueryMode, // QueryMode + VidGopSetMode, // SetMode + VidGopBlt, // Blt + &VidGopMode // Mode +}; + +EFI_EDID_DISCOVERED_PROTOCOL EdidDiscovered =3D { + 0, + NULL +}; + +EFI_EDID_ACTIVE_PROTOCOL EdidActive =3D { + 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 =3D 0; i < DisplayTypeMax; i++) { + DisplayInterfaceOrder[i] =3D NoDisplayType; + } + ReservedDisplayMemorySize =3D FixedPcdGet32 (PcdFrameBufferSize); + if (FeaturePcdGet (PcdLvdsEnable)) { + DisplayDevice =3D Lvds0Display; + } else { + DisplayDevice =3D HdmiDisplay; + } + + Status =3D InitDisplay (&DisplayContextPtr); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Fail to init display, Status=3D%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. Current= ly only + // support single display, so allocate single(1) frame buffer + // Allocate frame buffer + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width =3D + DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming.HActive; + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height =3D + DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming.VActive; + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp =3D + DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming.Bpp; + DisplayContextPtr->DisplayConfig.DisplaySurface[0].PixelFormat =3D + DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming.PixelForma= t; + + // iMX6 UEFI reserves display memory for fullHD buffer size. + // PcdFrameBufferSize=3D800000h 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 =3D + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width * + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height * + (DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp / 8); + + DEBUG ((DEBUG_INFO, "%a: Display Memory: Needed=3D%d, Available=3D%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 =3D FullHDTim= ing.HActive; + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height =3D + FullHDTiming.VActive; + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp =3D FullHDTimin= g.Bpp; + CopyMem ( + &DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming, + &FullHDTiming, + sizeof (DISPLAY_TIMING) + ); + } + + DEBUG ((DEBUG_INFO, "%a: - allocating frame buffer... \n", + __FUNCTION__)); + Status =3D AllocateFrameBuffer (&DisplayContextPtr->DisplayConfig.Displa= ySurface[0]); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to allocate fb, Status=3D%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] =3D DisplayDevice; + DisplayContextPtr->DisplayConfig.DisplayTiming[0] =3D + DisplayContextPtr->DiContext[DisplayDevice].PreferredTiming; + + Status =3D ApplyDisplayConfig ( + DisplayContextPtr, + SINGLE_MODE, + DisplayInterfaceOrder + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to set display. Exit Status=3D%r\n", + __FUNCTION__, Status)); + goto Exit; + } + + VidGopModeInfo.Version =3D 0; + VidGopModeInfo.HorizontalResolution =3D + DisplayContextPtr->DisplayConfig.DisplayTiming[0].HActive; + VidGopModeInfo.VerticalResolution =3D + DisplayContextPtr->DisplayConfig.DisplayTiming[0].VActive; + VidGopModeInfo.PixelFormat =3D PixelBlueGreenRedReserved8BitPerColor; + ZeroMem ( + &VidGopModeInfo.PixelInformation, + sizeof (VidGopModeInfo.PixelInformation) + ); + + VidGopModeInfo.PixelsPerScanLine =3D VidGopModeInfo.HorizontalResolution= ; + VidGopMode.MaxMode =3D 1; + VidGopMode.Mode =3D 0; + VidGopMode.Info =3D &VidGopModeInfo; + VidGopMode.SizeOfInfo =3D sizeof (VidGopModeInfo); + VidGopMode.FrameBufferBase =3D + (EFI_PHYSICAL_ADDRESS) DisplayContextPtr->DisplayConfig.DisplaySurface= [0].PhyAddr; + VidGopMode.FrameBufferSize =3D + VidGopModeInfo.HorizontalResolution * + VidGopModeInfo.VerticalResolution * + (DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp / 8); + DisplayContextPtr->DisplayConfig.OsHandle[0] =3D (UINT32)&ImageHandle; + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiGraphicsOutputProtocolGuid, + &VidGop, + &gEfiDevicePathProtocolGuid, + &VidDevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to install protocol, Status=3D%x\n", + __FUNCTION__, Status)); + goto Exit; + } + +Exit: + DEBUG ((DEBUG_INFO, "%a: Exit =3D %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 =3D Lvds0Display; + } else { + DisplayDevice =3D HdmiDisplay; + } + + EdidDiscovered.SizeOfEdid =3D DisplayContextPtr->DiContext[DisplayDevice= ].EdidDataSize; + EdidDiscovered.Edid =3D DisplayContextPtr->DiContext[DisplayDevice].Edid= Data; + EdidActive.SizeOfEdid =3D DisplayContextPtr->DiContext[DisplayDevice].Ed= idDataSize; + EdidActive.Edid =3D DisplayContextPtr->DiContext[DisplayDevice].EdidData= ; + Status =3D 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=3D%r\n= ", + __FUNCTION__, Status)); + } + + if (ModeNumber !=3D 0) { + DEBUG ((DEBUG_ERROR, "%a: Saw request to query mode %d\n", + __FUNCTION__, ModeNumber)); + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + OutputMode =3D (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) + AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); + if (OutputMode =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + OutputMode->Version =3D 0; + OutputMode->HorizontalResolution =3D VidGopModeInfo.HorizontalResolution= ; + OutputMode->VerticalResolution =3D VidGopModeInfo.VerticalResolution; + OutputMode->PixelFormat =3D PixelBlueGreenRedReserved8BitPerColor; + OutputMode->PixelsPerScanLine =3D VidGopModeInfo.HorizontalResolution; + *SizeOfInfo =3D sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + *Info =3D OutputMode; + + Status =3D EFI_SUCCESS; + +Exit: + return Status; +} + +EFI_STATUS +VidGopSetMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber + ) +{ + EFI_STATUS Status; + + if (ModeNumber !=3D 0) { + DEBUG ((DEBUG_ERROR, "%a: Saw request to set mode to %d\n", + __FUNCTION__, ModeNumber)); + Status =3D EFI_UNSUPPORTED; + goto Exit; + } + + Status =3D 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 =3D (UINT32 *)((UINTN)VidGopMode.FrameBufferBase); + FrameWidth =3D VidGopModeInfo.HorizontalResolution; + if (Delta =3D=3D 0) { + BufferWidth =3D Width; + } else { + BufferWidth =3D Delta / PIXEL_BYTES; + } + + if (BltOperation =3D=3D EfiBltVideoFill) { + FrameOffset =3D FrameWidth * DestinationY + DestinationX; + for (i =3D DestinationY; i < DestinationY + Height; i++) { + SetMem32 ( + FrameBuffer + FrameOffset, + Width * PIXEL_BYTES, + *(UINT32 *)BltBuffer + ); + FrameOffset +=3D FrameWidth; + } + } else if (BltOperation =3D=3D EfiBltVideoToBltBuffer) { + FrameOffset =3D FrameWidth * SourceY + SourceX; + BufferOffset =3D BufferWidth * DestinationY + DestinationX; + for (i =3D SourceY; i < SourceY + Height; i++) { + CopyMem ( + BltBuffer + BufferOffset, + FrameBuffer + FrameOffset, + Width * PIXEL_BYTES + ); + FrameOffset +=3D FrameWidth; + BufferOffset +=3D BufferWidth; + } + } else if (BltOperation =3D=3D EfiBltBufferToVideo) { + FrameOffset =3D FrameWidth * DestinationY + DestinationX; + BufferOffset =3D BufferWidth * SourceY + SourceX; + for (i =3D SourceY; i < SourceY + Height; i++) { + CopyMem ( + FrameBuffer + FrameOffset, + BltBuffer + BufferOffset, + Width * PIXEL_BYTES + ); + FrameOffset +=3D FrameWidth; + BufferOffset +=3D BufferWidth; + } + } else if (BltOperation =3D=3D EfiBltVideoToVideo) { + FrameOffset =3D FrameWidth * DestinationY + DestinationX; + BufferOffset =3D FrameWidth * SourceY + SourceX; + for (i =3D SourceY; i < SourceY + Height; i++) { + CopyMem ( + FrameBuffer + FrameOffset, + FrameBuffer + BufferOffset, + Width * PIXEL_BYTES + ); + FrameOffset +=3D FrameWidth; + BufferOffset +=3D 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/iMX6= Pkg/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 B= SD 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 IM= PLIED. +* +**/ + +#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/iM= X6Pkg/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.
+# 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 B= SD 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 IM= PLIED. +# +#**/ + +[Defines] + INF_VERSION =3D 0x0001001A + BASE_NAME =3D GopDxe + FILE_GUID =3D E68088EF-D1A4-4336-C1DB-4D3A204730A6 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D 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/iMX6Pk= g/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 B= SD 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 IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Display.h" +#include "GopDxe.h" +#include "Hdmi.h" +#include "Edid.h" + +PLL_MPLL_CONFIG PllMpllGenericConfigSetting[] =3D { + { 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 =3D FALSE; + for (; Timeout > 0; Timeout--) { + I2cmphyStat0Reg.Reg =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_IH_I2CMPHY_STAT0 + ); + if (I2cmphyStat0Reg.i2cmphydone) { + WaitResult =3D TRUE; + break; + } + gBS->Stall (1); + } + +#if DEBUG + if ((Timeout =3D=3D 0) || (I2cmphyStat0Reg.i2cmphyerror =3D=3D 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 =3D 1; + I2cmphyStat0Reg.i2cmphydone =3D 1; + I2cmphyStat0Reg.reserved =3D 0; + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_IH_I2CMPHY_STAT0, + I2cmphyStat0Reg.Reg + ); + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_ADDRESS_ADD= R, + Addr + ); + + I2cmOperationReg.Reg =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_PHY_I2CM_OPERATION_ADDR + ); + I2cmOperationReg.read =3D 1; + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_OPERATION_A= DDR, + I2cmOperationReg.Reg + ); + + ReadStatus =3D HdmiPhyPollI2cDone (HdmiDisplayContextPtr, 1000); + if (!ReadStatus) { + DEBUG ((DEBUG_ERROR, "%a: Fail to read I2c HDMI Phy\n", __FUNCTION__))= ; + goto Exit; + } + + Data0 =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_PHY_I2CM_DATAI_0_ADDR + ); + Data1 =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_PHY_I2CM_DATAI_1_ADDR + ); + *DataPtr =3D 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 =3D (Data & 0x00FF); + Data1 =3D (Data >> 8); + I2cmphyStat0Reg.i2cmphyerror =3D 1; + I2cmphyStat0Reg.i2cmphydone =3D 1; + I2cmphyStat0Reg.reserved =3D 1; + I2cmOperationReg.read =3D 0; + I2cmOperationReg.reserved0 =3D 0; + I2cmOperationReg.write =3D 0; + I2cmOperationReg.reserved1 =3D 0; + + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_IH_I2CMPHY_STAT0, + I2cmphyStat0Reg.Reg + ); + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_ADDRESS_ADD= R, + Addr + ); + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_DATAO_0_ADD= R, + Data0 + ); + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_DATAO_1_ADD= R, + Data1 + ); + + I2cmOperationReg.read =3D 0; + I2cmOperationReg.write =3D 1; + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_I2CM_OPERATION_A= DDR, + I2cmOperationReg.Reg + ); + return HdmiPhyPollI2cDone (HdmiDisplayContextPtr, 1000); +} + +BOOLEAN +GetGenericConfigSetting ( + IN DISPLAY_TIMING *DisplayTimingPtr, + OUT PLL_MPLL_CONFIG **ConfigGenericSettingPPtr + ) +{ + UINT32 ColorDepth; + BOOLEAN FoundConfig; + UINT32 SettingIndex; + + FoundConfig =3D FALSE; + ColorDepth =3D GetColorDepth (DisplayTimingPtr->PixelFormat); + + for (SettingIndex =3D 0; + SettingIndex < ARRAYSIZE (PllMpllGenericConfigSetting); + ++SettingIndex) + { + if ((DisplayTimingPtr->PixelClock =3D=3D + PllMpllGenericConfigSetting[SettingIndex].PixelClock) && + (DisplayTimingPtr->PixelRepetition =3D=3D + PllMpllGenericConfigSetting[SettingIndex].PixelRepetition) && + (ColorDepth =3D=3D PllMpllGenericConfigSetting[SettingIndex].Color= Depth)) + { + FoundConfig =3D TRUE; + *ConfigGenericSettingPPtr =3D &PllMpllGenericConfigSetting[SettingIn= dex]; + break; + } + } + + // Use the fallback value the last index if no configuration is found + if (FoundConfig =3D=3D FALSE) { + *ConfigGenericSettingPPtr =3D + &PllMpllGenericConfigSetting[ARRAYSIZE (PllMpllGenericConfigSetting)= ]; + FoundConfig =3D TRUE; + } + + return FoundConfig; +} + +EFI_STATUS +InitHdmi ( + IN DISPLAY_CONTEXT *DisplayContextPtr + ) +{ + DISPLAY_INTERFACE_CONTEXT *pHdmiDisplayContext; + EFI_STATUS Status; + + pHdmiDisplayContext =3D &DisplayContextPtr->DiContext[HdmiDisplay]; + Status =3D EFI_SUCCESS; + ZeroMem (pHdmiDisplayContext, sizeof (*pHdmiDisplayContext)); + + pHdmiDisplayContext->MmioBasePtr =3D (VOID *)HDMI_BASE; + if (pHdmiDisplayContext->MmioBasePtr =3D=3D 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 =3D ReadEdid ( + DisplayContextPtr, + HdmiDisplay, + pHdmiDisplayContext->EdidData, + &pHdmiDisplayContext->EdidDataSize + ); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_WARN, "%a: Fail to read HDMI EDID data\n", __FUNCTION__)= ); + Status =3D EFI_SUCCESS; + } + + Status =3D GetPreferredTiming ( + pHdmiDisplayContext->EdidData, + pHdmiDisplayContext->EdidDataSize, + &pHdmiDisplayContext->PreferredTiming + ); + if (Status !=3D EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "%a: Fail to retrieve HDMI preferred timing\n", + __FUNCTION__)); + goto Exit; + } + + if ((pHdmiDisplayContext->PreferredTiming.HActive =3D=3D 1920) && + (pHdmiDisplayContext->PreferredTiming.VActive =3D=3D 1080)) + { + pHdmiDisplayContext->PreferredTiming.HBlank -=3D 6; + } + +Exit: + return Status; +} + +EFI_STATUS +SetHdmiPower ( + IN DISPLAY_INTERFACE_CONTEXT *HdmiDisplayContextPtr, + IN BOOLEAN PowerState + ) +{ + HDMI_PHY_CONF0_REG CurrentHdmiPhyConf0Reg; + + CurrentHdmiPhyConf0Reg.Reg =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePt= r + + HDMI_PHY_CONF0 + ); + if (PowerState) { + // Setup PHY + CurrentHdmiPhyConf0Reg.PDZ =3D 1; + CurrentHdmiPhyConf0Reg.ENTMDS =3D 1; + CurrentHdmiPhyConf0Reg.gen2_pddq =3D 1; + CurrentHdmiPhyConf0Reg.gen2_txpwron =3D 1; + CurrentHdmiPhyConf0Reg.seldataenpol =3D 1; + CurrentHdmiPhyConf0Reg.seldipif =3D 0; + } else { + // Just power down PHY for shutdown + CurrentHdmiPhyConf0Reg.PDZ =3D 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 =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_FC_AUDSCONF + ); + FcAudsconfReg.aud_packet_layout =3D 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 =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + if (GetGenericConfigSetting (Timings, &pPllMpllConfig) =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: No compatible generic config found\n", + __FUNCTION__)); + Status =3D EFI_UNSUPPORTED; + goto Exit; + } + + // Color Space Converter : Not used in UEFI + McClkdisReg.Reg =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_MC_CLKDIS + ); + // Disable CEC, color converter, audio & pixel repitition + McClkdisReg.cecclk_disable =3D 1; + McClkdisReg.cscclk_disable =3D 1; + McClkdisReg.audclk_disable =3D 1; + McClkdisReg.prepclk_disable =3D 1; + McClkdisReg.hdcpclk_disable =3D 1; + McClkdisReg.tmdsclk_disable =3D 0; + McClkdisReg.pixelclk_disable =3D 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 configurat= ion + // programmed on the HDMI_PHY must be done in Power-down mode. + CurrentHdmiPhyConf0Reg.Reg =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePt= r + + HDMI_PHY_CONF0 + ); + CurrentHdmiPhyConf0Reg.gen2_txpwron =3D 0; + CurrentHdmiPhyConf0Reg.gen2_pddq =3D 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 i= n + // a well - defined state + PhyRstzReg.Reg =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_MC_PHYRSTZ + ); + PhyRstzReg.phyrstz =3D 1; + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_MC_PHYRSTZ, + PhyRstzReg.Reg + ); + PhyRstzReg.phyrstz =3D 0; + gBS->Stall (10); + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_MC_PHYRSTZ, + PhyRstzReg.Reg + ); + + HeacphyRstReg.Reg =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_MC_HEACPHY_RST + ); + HeacphyRstReg.heacphyrst =3D 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 i= s + // coherent with the MPLL's high-speed output clock, because both clock= s are + // shaped by the MPLL response. + // In NonCoherent mode, the TMDS clock is the MPLL reference clock, whi= ch is + // not coherent with the MPLL's high-speed output clock. + PhyStatus =3D HdmiPhyI2cWrite ( + HdmiDisplayContextPtr, + HDMI_PHY_CPCE_CTRL, + pPllMpllConfig->HdmiPhyCpceCtrl.Reg + ); + if (PhyStatus =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_CPCE_CTRL %x\n", + __FUNCTION__, pPllMpllConfig->HdmiPhyCpceCtrl.Reg)); + Status =3D EFI_DEVICE_ERROR; + goto Exit; + } + + PhyStatus =3D HdmiPhyI2cWrite ( + HdmiDisplayContextPtr, + HDMI_PHY_CURRCTRL, + pPllMpllConfig->HdmiPhyCurrctrl.Reg + ); + if (PhyStatus =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_CURRCTRL\n", + __FUNCTION__)); + Status =3D EFI_DEVICE_ERROR; + goto Exit; + }; + + PhyStatus =3D HdmiPhyI2cWrite ( + HdmiDisplayContextPtr, + HDMI_PHY_GMPCTRL, + pPllMpllConfig->HdmiPhyGmpctrl.Reg + ); + if (PhyStatus =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_GMPCTRL\n", + __FUNCTION__)); + Status =3D EFI_DEVICE_ERROR; + goto Exit; + } + + // Maintaining the order of phy register writes + PhyStatus =3D HdmiPhyI2cWrite ( + HdmiDisplayContextPtr, + HDMI_PHY_PLLPHBYCTRL, + 0x0000 + ); + if (PhyStatus =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_PLLPHBYCTRL\n", + __FUNCTION__)); + Status =3D EFI_DEVICE_ERROR; + goto Exit; + } + + // Coherent mode + PhyStatus =3D HdmiPhyI2cWrite ( + HdmiDisplayContextPtr, + HDMI_PHY_MSM_CTRL, + 0x0006 + ); + if (PhyStatus =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_MSM_CTRL\n", + __FUNCTION__)); + Status =3D EFI_DEVICE_ERROR; + goto Exit; + } + + // Resistance value 133.33 ohm + PhyStatus =3D HdmiPhyI2cWrite ( + HdmiDisplayContextPtr, + HDMI_PHY_TXTERM, + 0x0005 + ); + if (PhyStatus =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_TXTERM\n", + __FUNCTION__)); + Status =3D EFI_DEVICE_ERROR; + goto Exit; + } + + // Enable clock symbol + PhyStatus =3D HdmiPhyI2cWrite ( + HdmiDisplayContextPtr, + HDMI_PHY_CKSYMTXCTRL, + 0x8009 + ); + if (PhyStatus =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_CKSYMTXCTRL\n", + __FUNCTION__)); + Status =3D EFI_DEVICE_ERROR; + goto Exit; + } + + PhyStatus =3D HdmiPhyI2cWrite ( + HdmiDisplayContextPtr, + HDMI_PHY_VLEVCTRL, + 0x0210 + ); + if (PhyStatus =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_VLEVCTRL\n", + __FUNCTION__)); + Status =3D EFI_DEVICE_ERROR; + goto Exit; + } + + // Enable override + PhyStatus =3D HdmiPhyI2cWrite ( + HdmiDisplayContextPtr, + HDMI_PHY_CKCALCTRL, + 0x8000 + ); + if (PhyStatus =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: Fail to write to HDMI_PHY_CKCALCTRL\n", + __FUNCTION__)); + Status =3D EFI_DEVICE_ERROR; + goto Exit; + } + + CurrentHdmiPhyConf0Reg.gen2_txpwron =3D 1; + CurrentHdmiPhyConf0Reg.gen2_pddq =3D 0; + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_PHY_CONF0, + CurrentHdmiPhyConf0Reg.Reg + ); + + Status =3D EFI_DEVICE_ERROR; + for (RetryCount =3D 5; RetryCount > 0; RetryCount--) { + PhyStat0Reg.Reg =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_PHY_STAT0 + ); + if (!PhyStat0Reg.TX_PHY_LOCK) { + Status =3D EFI_SUCCESS; + break; + } + gBS->Stall (1000); + } + + if (RetryCount =3D=3D 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 =3D SetHdmiPhy (HdmiDisplayContextPtr, Timings); + if (Status !=3D 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 =3D DataReadPtr; + Status =3D 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 =3D 0; AddrCount < ReadSize; ++AddrCount) { + I2cRetryCount =3D 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 =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_IH_I2CM_STAT0 + ); + for (I2cRetryCount =3D 1000; I2cRetryCount > 0; I2cRetryCount--) { + I2cmIntStatus =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_IH_I2CM_STAT0 + ); + if (I2cmIntStatus !=3D 0) { + break; + } + } + + if (I2cRetryCount =3D=3D 0) { + Status =3D 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 =3D MmioRead8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + + HDMI_I2CM_DATAI + ); + pCurrentDataRead++; + MmioWrite8 ( + (UINT32)HdmiDisplayContextPtr->MmioBasePtr + HDMI_IH_I2CM_STAT0, + I2C_MASTER_ERROR | I2C_MASTER_DONE + ); + } else { + Status =3D 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/iMX6Pk= g/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 B= SD 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 IM= PLIED. +* +**/ + +#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 =3D 0x01, + DDC_READ_EXT_OPERATION =3D 0x02, + DDC_WRITE_OPERATION =3D 0x10, +} DDC_OPERATION; + +typedef enum { + HDMI_DDC_STANDARD_MODE =3D 0x00, + HDMI_DDC_FAST_MODE =3D 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/iMX6P= kg/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 B= SD 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 IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 =3D DisplayContextPtr->IoMuxMmioBasePtr; + DisplayMode =3D DisplayContextPtr->DisplayConfig.DisplayMode; + pDisplayInterfaceType =3D DisplayContextPtr->DisplayConfig.DiOrder; + Status =3D EFI_SUCCESS; + + Gpr3Reg =3D MmioRead32 ((UINT32)&pIomuxcGprReg->GPR3); + Gpr3Reg &=3D ~(HDMI_MUX_CTL_MASK | MIPI_MUX_CTL_MASK | + LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK); + MmioWrite32 ((UINT32)&pIomuxcGprReg->GPR3, Gpr3Reg); + + for (DisplayInterfaceIndex =3D 0; DisplayInterfaceIndex < (UINT32)Displa= yMode; ++DisplayInterfaceIndex) { + Gpr3Reg =3D MmioRead32 ((UINT32)&pIomuxcGprReg->GPR3); + switch (pDisplayInterfaceType[DisplayInterfaceIndex]) { + case HdmiDisplay: + SourceMask =3D HDMI_MUX_CTL_MASK; + SourceValue =3D DisplayInterfaceIndex << HDMI_MUX_CTL_OFFSET; + break; + case MipiDisplay: + SourceMask =3D MIPI_MUX_CTL_MASK; + SourceValue =3D DisplayInterfaceIndex << MIPI_MUX_CTL_OFFSET; + break; + case Lvds0Display: + SourceMask =3D LVDS0_MUX_CTL_MASK; + SourceValue =3D DisplayInterfaceIndex << LVDS0_MUX_CTL_OFFSET; + break; + case Lvds1Display: + SourceMask =3D LVDS1_MUX_CTL_MASK; + SourceValue =3D DisplayInterfaceIndex << LVDS1_MUX_CTL_OFFSET; + break; + default: + Status =3D EFI_UNSUPPORTED; + break; + } + if (EFI_ERROR (Status)) { + break; + } + + Gpr3Reg &=3D ~SourceMask; + Gpr3Reg |=3D SourceValue; + MmioWrite32 ((UINT32)&pIomuxcGprReg->GPR3, Gpr3Reg); + } + + return Status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GopDxe/IoMux.h b/Silicon/NXP/iMX6P= kg/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 B= SD 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 IM= PLIED. +* +**/ + +#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 B= SD 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 IM= PLIED. +* +**/ + +#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/iMX6Pk= g/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 B= SD 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 IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 =3D EFI_SUCCESS; + pLvdsDisplayContext =3D &DisplayContextPtr->DiContext[Lvds0Display]; + ZeroMem (pLvdsDisplayContext, sizeof (*pLvdsDisplayContext)); + + pLvdsDisplayContext->MmioBasePtr =3D (VOID *)LDB_BASE; + if (pLvdsDisplayContext->MmioBasePtr =3D=3D 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 =3D MmioRead32 ((UINT32)pLvdsDisplayContext->MmioBasePtr = + LDB_CTRL); + LdbCtrlReg.ch0_mode =3D 1; + LdbCtrlReg.ch1_mode =3D 1; + LdbCtrlReg.di0_vs_polarity =3D 1; + LdbCtrlReg.di1_vs_polarity =3D 1; + MmioWrite32 ((UINT32)pLvdsDisplayContext->MmioBasePtr + LDB_CTRL, LdbCtr= lReg.Reg); + + // No EDID available + pLvdsDisplayContext->EdidDataSize =3D 0; + + Status =3D GetPreferredTiming ( + pLvdsDisplayContext->EdidData, + pLvdsDisplayContext->EdidDataSize, + &pLvdsDisplayContext->PreferredTiming + ); + if (Status !=3D 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/iMX6Pk= g/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 B= SD 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 IM= PLIED. +* +**/ + +#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_ */ --=20 2.16.2.gvfs.1.33.gf5370f1