From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=40.107.71.98; helo=nam05-by2-obe.outbound.protection.outlook.com; envelope-from=christopher.co@microsoft.com; receiver=edk2-devel@lists.01.org Received: from NAM05-BY2-obe.outbound.protection.outlook.com (mail-eopbgr710098.outbound.protection.outlook.com [40.107.71.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id B2CD920D7ADC5 for ; Thu, 19 Jul 2018 23:34:07 -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=B7CSTAXh+QqFIslG4hhl8d0GFOcAVvpG+pLei3d3c34=; b=Gz31dcVhb2i3zEep9FyzDum8WRPdpIFhKvhDUXOTtJcaaduhdabcoDIUVshfjhHcdg/Z4Lt7Ifa6VPWhglHosQlb15is2EueLj2jIQ9NF8CJQkYoFUiRWINMVf1Ic4rrq2feDcGuLXHrPt3E+6t689hxG3eioZebXu7ImdyAVNo= Received: from SN6PR2101MB1136.namprd21.prod.outlook.com (52.132.114.25) by SN6PR2101MB1133.namprd21.prod.outlook.com (52.132.114.22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.995.0; Fri, 20 Jul 2018 06:34:03 +0000 Received: from SN6PR2101MB1136.namprd21.prod.outlook.com ([fe80::78f8:214:33a:3c4]) by SN6PR2101MB1136.namprd21.prod.outlook.com ([fe80::78f8:214:33a:3c4%5]) with mapi id 15.20.0995.008; Fri, 20 Jul 2018 06:34:03 +0000 From: Chris Co To: "edk2-devel@lists.01.org" CC: Ard Biesheuvel , Leif Lindholm , Michael D Kinney Thread-Topic: [PATCH edk2-platforms 12/13] Silicon/NXP: Add i.MX6 GOP driver Thread-Index: AQHUH/OlgabD1qEKq0mI3J9u8Z2COA== Date: Fri, 20 Jul 2018 06:34:02 +0000 Message-ID: <20180720063328.26856-13-christopher.co@microsoft.com> References: <20180720063328.26856-1-christopher.co@microsoft.com> In-Reply-To: <20180720063328.26856-1-christopher.co@microsoft.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: CY4PR18CA0029.namprd18.prod.outlook.com (2603:10b6:903:9a::15) To SN6PR2101MB1136.namprd21.prod.outlook.com (2603:10b6:805:4::25) x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [2001:4898:80e8:a:75ac:13c7:7dde:5215] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; SN6PR2101MB1133; 6:C70BfTNIozVApwU2Mu6zKp8nuj64YBolOVAz/pURpc8fyCQS44bw+Nq8D/UtiVV+L/f49qbFcnB07b3bRU/RE/nGy2WLp9Egpac6pCmvNN0O+gklJIPrpQIbjz4Y9Ku3GvY+1bO/iRPUU+LnbK9T3tDA/brV31emmtycFBbNVN0TVpkYYJnrgaZjGZN4Zb2VRzH3eBBPyfE3xothRmgFZWuEJrojhTDAssbXBHe39nuyglXaZpZB7fGmsx2WxXvESSrGrS/rjrq/dtQZDNjbmE5Xt7NHEpg/G7fullR3A071VAG+EQ8UQM+NLQONqWtq/1buTFS0ketRjkm3aeqOidCWfDMP1VCvGTmLVe6FaWSM+uZIMcVgtnyqt3034WObKpzc+n9rHryLVE9EE/A2Czay1QmRFOrPBUPHdY8A0PfQphDHqEs+mA8vtl30z4Mfw8/7jXZ0KWcsm+FUF8qCOw==; 5:IcuwA0+yDvq0gyzyD78Tupqx6zEVAJu0HE9tgPq6a47j6G8oSLcpG76j9vuG4fcEMqM2tiJym1BkEPpOg6daV2o/1D9VjWusJMJpzkk7kwphgfYVlOSsEqXPUwbTQmghqxJVSFLqBQp4jngaBsZMY8wIFlV8WrDQiepUWQ0uD4w=; 7:sMsrTfZjkySxZCzrfGUCnSyP6MIj0ggXh47bR/MVlkwsiWk+9EOaK3fUQ5gUMa/ANY1NDHjYLRiaDA6xSOicvT1nnIp1JvK0AaIt9PLeRu1F6gt8Sqkc8xtATEG3KmMxwj4ZPqlk6LGumlZQ9Pc07Pc0prc98HOeMVuhnQNv5BJS2n4GTKzsZ6RWut+2SChRvkOFC4eJZaJe/mLDDCy3lKUbwhN67K5PNhz4Fzxf3xhoHzgOXrjwW6asRAMArGkl x-ms-office365-filtering-correlation-id: 7518e147-7db1-4491-633d-08d5ee0ac7b3 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989117)(5600067)(711020)(4618075)(4534165)(4627221)(201703031133081)(201702281549075)(8990107)(2017052603328)(7193020); SRVR:SN6PR2101MB1133; x-ms-traffictypediagnostic: SN6PR2101MB1133: authentication-results: spf=none (sender IP is ) smtp.mailfrom=Christopher.Co@microsoft.com; x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(28532068793085)(89211679590171)(228905959029699); x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(10201501046)(3002001)(3231311)(944501410)(52105095)(2018427008)(93006095)(93001095)(6055026)(149027)(150027)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123558120)(20161123562045)(20161123560045)(20161123564045)(6072148)(201708071742011)(7699016); SRVR:SN6PR2101MB1133; BCL:0; PCL:0; RULEID:; SRVR:SN6PR2101MB1133; x-forefront-prvs: 073966E86B x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(1496009)(396003)(376002)(366004)(346002)(136003)(39860400002)(189003)(199004)(16200700003)(52116002)(16799955002)(53946003)(46003)(2906002)(2900100001)(15188155005)(36756003)(97736004)(386003)(256004)(99286004)(19627235002)(86612001)(575784001)(6506007)(14444005)(86362001)(186003)(76176011)(10090500001)(102836004)(1076002)(6306002)(6512007)(8936002)(6486002)(2616005)(476003)(5660300001)(486006)(478600001)(8676002)(6116002)(81156014)(81166006)(25786009)(4326008)(5640700003)(53376002)(53936002)(68736007)(6436002)(2501003)(10290500003)(22452003)(2351001)(7736002)(305945005)(5250100002)(6916009)(54906003)(14454004)(11346002)(72206003)(106356001)(966005)(551934003)(316002)(446003)(105586002)(569006); DIR:OUT; SFP:1102; SCL:1; SRVR:SN6PR2101MB1133; H:SN6PR2101MB1136.namprd21.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: microsoft.com does not designate permitted sender hosts) x-microsoft-antispam-message-info: h13ySi8LzCb/IwNRMx0ut7qiJYvEW4iT2MjVRPiAcDVj1CX7y2ZDrjwZDm+0ACP+3N+8ctCPflulC0BSZQtdU8V0xOuohn0iUQmxjx3Ni+wPjVkp/sAw5ExDE+863ao+CJtg642k6507ozYiIdAwkgIjv3CWyz7q1hNgwahJs3NUGM3CaCmxBuo75ODkAt3cKPyCzYow8wohXxc7naLjiU2csvdhGtjeAl3sXv9IYSO4KJ3cik61xEoYJvkH0YTUcVfvAypTSU0W34yHGbMSaxbydoy+zrwy6Uv5tZELxDrZrqe03MHAKTqfwe60cLAuoJcAvN7pTdHTu/DrT39CloGjaDopa3DVMih3sRruMns= spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-Network-Message-Id: 7518e147-7db1-4491-633d-08d5ee0ac7b3 X-MS-Exchange-CrossTenant-originalarrivaltime: 20 Jul 2018 06:34:02.8424 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR2101MB1133 Subject: [PATCH edk2-platforms 12/13] Silicon/NXP: Add i.MX6 GOP driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 20 Jul 2018 06:34:08 -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/GOP/CPMem.c | 327 +++++++++++ Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.h | 276 +++++++++ Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.c | 58 ++ Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.h | 27 + Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.c | 442 ++++++++++++++ Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.h | 171 ++++++ Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.c | 388 +++++++++++++ Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.h | 312 ++++++++++ Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.c | 444 ++++++++++++++ Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.h | 182 ++++++ Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.c | 82 +++ Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.h | 31 + Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.c | 608 ++++++++++++++++= ++++ Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.h | 537 ++++++++++++++++= + Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.c | 83 +++ Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.h | 31 + Silicon/NXP/iMX6Pkg/Drivers/GOP/Ipu.h | 236 ++++++++ Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.c | 81 +++ Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.h | 72 +++ Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.c | 38 ++ Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.h | 74 +++ Silicon/NXP/iMX6Pkg/Drivers/GOP/iMX6GOP.inf | 71 +++ Silicon/NXP/iMX6Pkg/Drivers/GOP/iMXVideoDxe.c | 488 ++++++++++++++++ 23 files changed, 5059 insertions(+) diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.c b/Silicon/NXP/iMX6Pkg/= Drivers/GOP/CPMem.c new file mode 100644 index 000000000000..cf05a13d95e5 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.c @@ -0,0 +1,327 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "Osal.h" + +#include "Display.h" +#include "CPMem.h" +#include "Ipu.h" + +CPMEM_PARAM* CpMemParamBasePtr =3D (CPMEM_PARAM*)(IPU1_BASE + CSP_IPUV3_CP= MEM_REGS_OFFSET); + +VOID DumpCPMEMParamPack (CPMEM_PARAM* ParamPtr) +{ + OS_INFO("--WORD0--\n"); + OS_INFO("XVVirtualCoordinate 0x%08x\n", ParamPtr->Word0Pack.XVVirtualC= oordinate); + OS_INFO("YVVirtualCoordinate 0x%08x\n", ParamPtr->Word0Pack.YVVirtualC= oordinate); + OS_INFO("XBinnerBlockCoordinate 0x%08x\n", ParamPtr->Word0Pack.XBinner= BlockCoordinate); + OS_INFO("YBinnerBlockCoordinate 0x%08x\n", ParamPtr->Word0Pack.YBinner= BlockCoordinate); + OS_INFO("NewSubBlock 0x%08x\n", ParamPtr->Word0Pack.NewSubBlock); + OS_INFO("CurrentField 0x%08x\n", ParamPtr->Word0Pack.CurrentField); + OS_INFO("ScrollXCounter 0x%08x\n", ParamPtr->Word0Pack.ScrollXCounter)= ; + OS_INFO("ScrollYCounter 0x%08x\n", ParamPtr->Word0Pack.ScrollYCounter)= ; + OS_INFO("NumberOfScroll 0x%08x\n", ParamPtr->Word0Pack.NumberOfScroll)= ; + OS_INFO("ScrollDeltaX 0x%08x\n", ParamPtr->Word0Pack.ScrollDeltaX); + OS_INFO("ScrollMax 0x%08x\n", ParamPtr->Word0Pack.ScrollMax); + OS_INFO("ScrollingConfiguration 0x%08x\n", ParamPtr->Word0Pack.Scrolli= ngConfiguration); + OS_INFO("ScrollingEnable 0x%08x\n", ParamPtr->Word0Pack.ScrollingEnabl= e); + OS_INFO("ScrollDeltaY 0x%08x\n", ParamPtr->Word0Pack.ScrollDeltaY); + OS_INFO("ScrollHorizontalDirection 0x%08x\n", ParamPtr->Word0Pack.Scro= llHorizontalDirection); + OS_INFO("ScrollVerticalDirection 0x%08x\n", ParamPtr->Word0Pack.Scroll= VerticalDirection); + OS_INFO("BitsPerPixel 0x%08x\n", ParamPtr->Word0Pack.BitsPerPixel); + OS_INFO("DecodeAddressSelect 0x%08x\n", ParamPtr->Word0Pack.DecodeAddr= essSelect); + OS_INFO("AccessDimension 0x%08x\n", ParamPtr->Word0Pack.AccessDimensio= n); + OS_INFO("ScanOrder 0x%08x\n", ParamPtr->Word0Pack.ScanOrder); + OS_INFO("BandMode 0x%08x\n", ParamPtr->Word0Pack.BandMode); + OS_INFO("BlockMode 0x%08x\n", ParamPtr->Word0Pack.BlockMode); + OS_INFO("Rotation 0x%08x\n", ParamPtr->Word0Pack.Rotation); + OS_INFO("HorizontalFlip 0x%08x\n", ParamPtr->Word0Pack.HorizontalFlip)= ; + OS_INFO("VerticalFlip 0x%08x\n", ParamPtr->Word0Pack.VerticalFlip); + OS_INFO("ThresholdEnable 0x%08x\n", ParamPtr->Word0Pack.ThresholdEnabl= e); + OS_INFO("ConditionalAccessPolarity 0x%08x\n", ParamPtr->Word0Pack.Cond= itionalAccessPolarity); + OS_INFO("ConditionalAccessEnable 0x%08x\n", ParamPtr->Word0Pack.Condit= ionalAccessEnable); + OS_INFO("FrameWidth 0x%08x\n", ParamPtr->Word0Pack.FrameWidth); + OS_INFO("FrameHeight 0x%08x\n", ParamPtr->Word0Pack.FrameHeight); + OS_INFO("EndOfLineInterrupt 0x%08x\n", ParamPtr->Word0Pack.EndOfLineIn= terrupt); + + OS_INFO("--WORD1--\n"); + OS_INFO("ExtMemBuffer0Address 0x%08x\n", ParamPtr->Word1Pack.ExtMemBuf= fer0Address); + OS_INFO("ExtMemBuffer1Address 0x%08x\n", ParamPtr->Word1Pack.ExtMemBuf= fer1Address); + OS_INFO("InterlaceOffset 0x%08x\n", ParamPtr->Word1Pack.InterlaceOffse= t); + OS_INFO("NumberOfPixelsInWholeBurstAccess 0x%08x\n", ParamPtr->Word1Pa= ck.NumberOfPixelsInWholeBurstAccess); + OS_INFO("PixelFormatSelect 0x%08x\n", ParamPtr->Word1Pack.PixelFormatS= elect); + OS_INFO("AlphaUsed 0x%08x\n", ParamPtr->Word1Pack.AlphaUsed); + OS_INFO("AlphaChannelMapping 0x%08x\n", ParamPtr->Word1Pack.AlphaChann= elMapping); + OS_INFO("AxiId 0x%08x\n", ParamPtr->Word1Pack.AxiId); + OS_INFO("Threshold 0x%08x\n", ParamPtr->Word1Pack.Threshold); + OS_INFO("StrideLine 0x%08x\n", ParamPtr->Word1Pack.StrideLine); + OS_INFO("Width0 0x%08x\n", ParamPtr->Word1Pack.Width0); + OS_INFO("Width1 0x%08x\n", ParamPtr->Word1Pack.Width1); + OS_INFO("Width2 0x%08x\n", ParamPtr->Word1Pack.Width2); + OS_INFO("Width3 0x%08x\n", ParamPtr->Word1Pack.Width3); + OS_INFO("Offset0 0x%08x\n", ParamPtr->Word1Pack.Offset0); + OS_INFO("Offset1 0x%08x\n", ParamPtr->Word1Pack.Offset1); + OS_INFO("Offset2 0x%08x\n", ParamPtr->Word1Pack.Offset2); + OS_INFO("Offset3 0x%08x\n", ParamPtr->Word1Pack.Offset3); + OS_INFO("SelectSXSYSet 0x%08x\n", ParamPtr->Word1Pack.SelectSXSYSet); + OS_INFO("ConditionalReadEnable 0x%08x\n", ParamPtr->Word1Pack.Conditio= nalReadEnable); +} + +VOID DumpBasicCPMEMReg ( + CPMEM_PARAM* CpmemChannel) +{ + OS_INFO("---------- CPMEM Register Dump ----------\n"); + OS_INFO("CPMEM\n"); + OS_INFO("IDMAC_CHANNEL_DP_PRIMARY_FLOW_MAIN_PLANE\n"); + DumpCPMEMParamPack(CpmemChannel); + OS_INFO("------------------------------------\n"); +} + +// +// Enable IDMAC lock setting, which optimises memory accesses and reduces +// power consumption +// +VOID SetIdmacLockEn( + DISPLAY_INTERFACE_CONTEXT* DIContextPtr, + UINT32 Channel, + UINT32 Setting + ) +{ + static const UINT8 channelMap[] =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, + }; + + UINTN lockReg; + UINT32 value; + int shift =3D -1; + int i; + + for (i =3D 0; i < (sizeof(channelMap) / sizeof(channelMap[0])); i +=3D= 2) { + if (channelMap[i] =3D=3D Channel) { + shift =3D channelMap[i + 1]; + break; + } + } + + if (shift =3D=3D -1) { + OS_WARNING("Channel %d does not have lock bits", Channel); + return; + } + + if (Channel < 29) { + lockReg =3D (UINTN)DIContextPtr->IpuMmioBasePtr + IPU_IDMAC_LOCK_E= N_1; + } else { + lockReg =3D (UINTN)DIContextPtr->IpuMmioBasePtr + IPU_IDMAC_LOCK_E= N_2; + } + + value =3D OS_READ32(lockReg); + value &=3D ~(0x3 << shift); + value |=3D (Setting & 0x3) << shift; + OS_WRITE32(lockReg, value); +} + +OS_STATUS ConfigureCPMEMFrameBuffer ( + DISPLAY_INTERFACE_CONTEXT* DIContextPtr, + UINT32 Channel, + SURFACE_INFO* FrameBufferPtr) +{ + OS_STATUS status; + CPMEM_WORD0_PACKED_REG cpmemWord0PackedReg; + CPMEM_WORD1_PACKED_REG cpmemWord1PackedReg; + CPMEM_DEC_SEL decodeAddressSelect =3D CPMEM_DEC_SEL_0_15; // Only appl= icable for 4 bpp + UINT32 pixelBurst =3D 1; + CPMEM_PFS_PACKED pixelFormatSelector; + UINT32 width0, width1, width2, width3; + UINT32 offset0, offset1, offset2, offset3; + UINT32 bytesPerPixel; + CPMEM_PARAM* cpmemChannel =3D DIContextPtr->CpMemParamBasePtr; + + OS_ZERO_MEM(&cpmemWord0PackedReg, sizeof(cpmemWord0PackedReg)); + OS_ZERO_MEM(&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 OS_STATUS_UNSUPPORTED; + goto Exit; + } + + switch (FrameBufferPtr->Bpp) + { + case 8: + width0 =3D width1 =3D width2 =3D width3 =3D 0; + break; + case 32: + if (pixelFormatSelector =3D=3D CPMEM_PFS_RGB) { + width0 =3D width1 =3D width2 =3D width3 =3D 7; + } else { + width0 =3D width1 =3D width2 =3D width3 =3D 0; + } + break; + default: + ASSERT(FALSE); + status =3D OS_STATUS_UNSUPPORTED; + 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= it + cpmemWord1PackedReg.AxiId =3D CPMEM_ID_ID_0; + + cpmemWord1PackedReg.Threshold =3D CPMEM_THE_DISABLE; + + // Stride, width and offset + cpmemWord1PackedReg.StrideLine =3D + (FrameBufferPtr->Pitch * bytesPerPixel) - 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; + + // Finallu write into cpmem IDMAC channel + cpmemChannel =3D (cpmemChannel + Channel); + + OS_MEM_COPY( + &cpmemChannel->Word0Pack, + &cpmemWord0PackedReg, + sizeof(cpmemChannel->Word0Pack)); + + OS_MEM_COPY( + &cpmemChannel->Word1Pack, + &cpmemWord1PackedReg, + sizeof(cpmemChannel->Word1Pack)); + + // IDMAC will generate 8 AXI bursts upon assertion of the DMA request + // This significantly reduces memory activity and power consumption + SetIdmacLockEn(DIContextPtr, Channel, 0x3); + + // Register dump, commented out by default +#ifdef REGISTER_DUMP + DumpBasicCPMEMReg(cpmemChannel); +#endif + + status =3D OS_STATUS_SUCCESS; + +Exit: + return status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.h b/Silicon/NXP/iMX6Pkg/= Drivers/GOP/CPMem.h new file mode 100644 index 000000000000..27bf75decbb2 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/CPMem.h @@ -0,0 +1,276 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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) + +OS_STATUS ConfigureCPMEMFrameBuffer ( + DISPLAY_INTERFACE_CONTEXT* DIContextPtr, + UINT32 Channel, + SURFACE_INFO* FrameBufferPtr + ); + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.c b/Silicon/NXP/iMX6Pkg/Dr= ivers/GOP/Ddc.c new file mode 100644 index 000000000000..fc128760df32 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.c @@ -0,0 +1,58 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright 2018 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "osal.h" + +#include "Display.h" +#include "Edid.h" +#include "Ddc.h" +#include "Hdmi.h" +#include "Lvds.h" + +OS_STATUS IMX6DDCRead ( + DISPLAY_CONTEXT* DisplayContextPtr, + DISPLAY_INTERFACE DisplayInterface, + UINT8 SlaveAddress, + UINT8 RegisterAddress, + UINT32 ReadSize, + UINT8* DataReadPtr) +{ + OS_STATUS status; + + switch (DisplayInterface) + { + case HDMI_DISPLAY: + status =3D HDMIDDCRead( + &DisplayContextPtr->DIContext[HDMI_DISPLAY], + SlaveAddress, + RegisterAddress, + ReadSize, + HDMI_DDC_STANDARD_MODE, + DataReadPtr); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("HDMIDDCRead failed\n"); + } + break; + case MIPI_DISPLAY: + case LVDS0_DISPLAY: + case LVDS1_DISPLAY: + default: + status =3D OS_STATUS_UNSUPPORTED; + break; + } + + return status; +} + diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.h b/Silicon/NXP/iMX6Pkg/Dr= ivers/GOP/Ddc.h new file mode 100644 index 000000000000..169af54aa6b4 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ddc.h @@ -0,0 +1,27 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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_ + +OS_STATUS IMX6DDCRead ( + DISPLAY_CONTEXT* DisplayContextPtr, + DISPLAY_INTERFACE DisplayInterface, + UINT8 SlaveAddress, + UINT8 RegisterAddress, + UINT32 ReadSize, + UINT8* DataReadPtr + ); + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.c b/Silicon/NXP/iMX6Pk= g/Drivers/GOP/Display.c new file mode 100644 index 000000000000..801b3cf4edd4 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.c @@ -0,0 +1,442 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright 2018 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "Osal.h" + +// Display muxing register +#include "iMX6.h" + +#include "Display.h" +#include "Edid.h" +#include "Hdmi.h" +#include "Lvds.h" +#include "DisplayInterface.h" +#include "DisplayController.h" +#include "CPMem.h" +#include "Ipu.h" +#include "IoMux.h" + +DISPLAY_TIMING DefaultTiming =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 +}; + +OS_STATUS GetPreferedTiming ( + UINT8* EdidDataPtr, + UINT32 EdidDataSize, + DISPLAY_TIMING* PreferredTimingPtr + ) +{ + OS_STATUS status; + + if (FeaturePcdGet(PcdLvdsEnable)) { + *PreferredTimingPtr =3D Hannstar_XGA; + status =3D OS_STATUS_SUCCESS; + } else { + status =3D GetEDIDPreferedTiming( + EdidDataPtr, + EdidDataSize, + PreferredTimingPtr); + if (status !=3D OS_STATUS_SUCCESS) { + // If EDID is unavailable use the default timing + status =3D OS_STATUS_SUCCESS; + *PreferredTimingPtr =3D DefaultTiming; + OS_WARNING("EDID data not available, falling back to default t= iming\n"); + } + } + + // Only support 8 bit per pixel and no pixel 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 + OS_WARNING("--GetPreferedTiming()\r\n"); + return status; +} + +OS_STATUS InitDisplay ( + DISPLAY_CONTEXT** DisplayConfigPPtr + ) +{ + OS_STATUS status; + DISPLAY_INTERFACE displayCounter; + DISPLAY_CONTEXT* tempDisplayContext; + + status =3D OS_ALLOC_CONTIGUOUS_MEMORY( + sizeof(*tempDisplayContext), + &tempDisplayContext); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to allocate display context\n"); + goto Exit; + } + + OS_ZERO_MEM(tempDisplayContext, sizeof(*tempDisplayContext)); + + tempDisplayContext->IoMuxMmioBasePtr =3D + (VOID*)OS_MMIO_MAP(IOMUXC_GPR_BASE_ADDRESS); + if (tempDisplayContext->IoMuxMmioBasePtr =3D=3D NULL) { + OS_ERROR("Fail to map IO Mux register"); + goto Exit; + } + + tempDisplayContext->IpuMmioBasePtr[IPU1] =3D + (VOID*)OS_MMIO_MAP(IPU1_BASE); + if (tempDisplayContext->IoMuxMmioBasePtr =3D=3D NULL) { + OS_ERROR("Fail to map IPU1 IO Mux register"); + goto Exit; + } +#if !defined(CPU_IMX6SDL) + tempDisplayContext->IpuMmioBasePtr[IPU2] =3D + (VOID*)OS_MMIO_MAP(IPU2_BASE); + if (tempDisplayContext->IoMuxMmioBasePtr =3D=3D NULL) { + OS_ERROR("Fail to map IPU2 IO Mux register"); + goto Exit; + } +#endif + for (displayCounter =3D HDMI_DISPLAY; + displayCounter < MAX_DISPLAY; + ++displayCounter) { + tempDisplayContext->DIContext[displayCounter].displayInterface =3D + displayCounter; + } + + if (FeaturePcdGet(PcdLvdsEnable)) { + status =3D InitLVDS(tempDisplayContext); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to intialize LVDS\n"); + goto Exit; + } + } else { + status =3D InitHDMI(tempDisplayContext); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to intialize HDMI\n"); + goto Exit; + } + } + + *DisplayConfigPPtr =3D tempDisplayContext; + +Exit: + return status; +} + + +OS_STATUS DeInitDisplay ( + DISPLAY_CONTEXT* DisplayContextPtr + ) +{ + + return OS_STATUS_SUCCESS; +} + +OS_STATUS ValidateDisplayConfig ( + DISPLAY_CONTEXT* DisplayContextPtr, + DISPLAY_MODE DisplayMode, + DISPLAY_INTERFACE* DIOrder + ) +{ + OS_STATUS status; + DISPLAY_INTERFACE DisplayDevice; + + if (FeaturePcdGet(PcdLvdsEnable)) { + DisplayDevice =3D LVDS0_DISPLAY; + } else { + DisplayDevice =3D HDMI_DISPLAY; + } + + // Currently only support single display mode on HDMI/LVDS + if (DisplayMode !=3D SINGLE_MODE && DIOrder[0] !=3D DisplayDevice) { + status =3D OS_STATUS_UNSUPPORTED; + goto Exit; + } + + // Currently going to a very simplistic approach of enabling HDMI/LVDS= single + // display on HDMI/LVDS port. This configuration is applied regardless= if + // there is a monitor connected. No hot plug, monitor detection suppor= t. + + status =3D OS_STATUS_SUCCESS; + +Exit: + return status; +} + +OS_STATUS SetDisplayConfig ( + DISPLAY_CONTEXT* DisplayContextPtr, + DISPLAY_MODE DisplayMode, + DISPLAY_INTERFACE* DIOrder + ) +{ + OS_STATUS status; + IPU_INDEX iPUIndex; + DI_INDEX diIndex; + UINT32 displayModeIndex; + UINT32 diOffset[DI_TOTAL] =3D + { IPU_DI0_GENERAL_OFFSET, IPU_DI1_GENERAL_OFFSET }; + + status =3D ValidateDisplayConfig( + DisplayContextPtr, + DisplayMode, + DIOrder); + if (status !=3D OS_STATUS_SUCCESS) { + DisplayContextPtr->DisplayConfig.DisplayMode =3D UNKNOWN_MODE; + OS_ZERO_MEM( + DisplayContextPtr->DisplayConfig.DIOrder, + sizeof(DisplayContextPtr->DisplayConfig.DIOrder)); + OS_ERROR("Unsupported display configuration\n"); + status =3D OS_STATUS_UNSUPPORTED; + goto Exit; + } + + DisplayContextPtr->DisplayConfig.DisplayMode =3D DisplayMode; + + OS_ZERO_MEM( + DisplayContextPtr->DisplayConfig.DIOrder, + sizeof(DisplayContextPtr->DisplayConfig.DIOrder)); + + // Assigning display interface in order. Require mode information on I= PU + // and DI valid combination + for (iPUIndex =3D IPU1, displayModeIndex =3D 0; + iPUIndex < IPU_TOTAL && displayModeIndex < (UINT32)DisplayMode; + ++iPUIndex) { + for (diIndex =3D DI0; + diIndex < DI_TOTAL && displayModeIndex < (UINT32)DisplayMode; + ++diIndex) { + DisplayContextPtr->DisplayConfig.DIOrder[diIndex] =3D + DIOrder[diIndex]; + DISPLAY_INTERFACE_CONTEXT* diContextPtr =3D + &DisplayContextPtr->DIContext[DIOrder[diIndex]]; + diContextPtr->IpuMmioBasePtr =3D + DisplayContextPtr->IpuMmioBasePtr[iPUIndex]; + diContextPtr->IpuDiRegsPtr =3D + (IPU_DIx_REGS*)(((UINTN)DisplayContextPtr->IpuMmioBasePtr[= iPUIndex]) + + diOffset[diIndex]); + diContextPtr->CpMemParamBasePtr =3D (VOID *) + (((UINTN)diContextPtr->IpuMmioBasePtr) + CSP_IPUV3_CPMEM_R= EGS_OFFSET); + ++displayModeIndex; + } + } + + status =3D OS_STATUS_SUCCESS; + +Exit: + return status; +} + +OS_STATUS ApplyDisplayConfig ( + DISPLAY_CONTEXT* DisplayContextPtr, + DISPLAY_MODE DisplayMode, + DISPLAY_INTERFACE* DIOrder + ) +{ + DISPLAY_CONFIG* displayConfigPtr =3D &DisplayContextPtr->DisplayConfig= ; + UINT32 displayModeIndex; + OS_STATUS status; + + status =3D SetDisplayConfig( + DisplayContextPtr, + DisplayMode, + DIOrder); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to set display configuration %d\n", DisplayMode); + status =3D OS_STATUS_UNSUPPORTED; + goto Exit; + } + + // Setup muxing first before configuring DI and DC + status =3D SetupDisplayMux( + DisplayContextPtr); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("SetDisplayMux failed \n"); + goto Exit; + } + + for (displayModeIndex =3D 0; + displayModeIndex < (UINT32)displayConfigPtr->DisplayMode; + ++displayModeIndex) { + UINT32 currentDI =3D displayConfigPtr->DIOrder[displayModeIndex]; + DISPLAY_INTERFACE_CONTEXT* displayInterfaceContextPtr =3D + &DisplayContextPtr->DIContext[currentDI]; + DISPLAY_TIMING* currentDisplayTimingPtr =3D + &displayConfigPtr->DisplayTiming[displayModeIndex]; + + status =3D ConfigureDCChannel( + displayInterfaceContextPtr, + currentDI, + displayModeIndex, + currentDisplayTimingPtr); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR( + "ConfigureDCChannel fail display %d index %d\n", + currentDI, + displayModeIndex); + goto Exit; + } + + status =3D ConfigureDI( + displayInterfaceContextPtr, + displayModeIndex, + currentDisplayTimingPtr); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to configure DI\n"); + goto Exit; + } + + switch (currentDI) + { + case HDMI_DISPLAY: + status =3D SetHDMIDisplay( + displayInterfaceContextPtr, + currentDisplayTimingPtr); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to set HDMI timing\n"); + goto Exit; + } + break; + case LVDS0_DISPLAY: + case LVDS1_DISPLAY: + break; + default: + status =3D OS_STATUS_UNSUPPORTED; + goto Exit; + } + + status =3D ConfigureFrameBuffer( + displayInterfaceContextPtr, + &displayConfigPtr->DisplaySurface[displayModeIndex]); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to configure frame buffer (%d)\n", displayModeI= ndex); + goto Exit; + } + } + +Exit: + return status; +} + +OS_STATUS AllocateFrameBuffer ( + SURFACE_INFO* SurfaceInfoPtr + ) +{ + OS_STATUS status; + OS_INFO("++AllocateFrameBuffer()\r\n"); + if((SurfaceInfoPtr->Width =3D=3D 0) || + (SurfaceInfoPtr->Height =3D=3D 0)) { + status =3D OS_STATUS_INVALID_PARAM; + goto Exit; + } + + OS_INFO("AllocateFrameBuffer() Frame Buffer AddrP=3D%Xh\r\n",FixedPcdG= et32(PcdFrameBufferBase)); + OS_INFO("AllocateFrameBuffer() Frame Buffer Size=3D%Xh\r\n",FixedPcdGe= t32(PcdFrameBufferSize)); + SurfaceInfoPtr->VirtAddrPtr =3D (VOID*)(UINTN)FixedPcdGet32(PcdFrameBu= fferBase); + + SurfaceInfoPtr->PhyAddr =3D + (UINT32)OS_VIRT_TO_PHY_ADDR(SurfaceInfoPtr->VirtAddrPtr); + SurfaceInfoPtr->Pitch =3D SurfaceInfoPtr->Width; + + OS_INFO( + "Allocate FB PhyAddr %x VirtAddr %x\n", + SurfaceInfoPtr->PhyAddr, + SurfaceInfoPtr->VirtAddrPtr); + + status =3D OS_STATUS_SUCCESS; + +Exit: + OS_INFO("--AllocateFrameBuffer()=3D%Xh\r\n",status); + return status; +} + +OS_STATUS ConfigureFrameBuffer ( + DISPLAY_INTERFACE_CONTEXT* DIContextPtr, + SURFACE_INFO* FrameBufferPtr + ) +{ + OS_STATUS status; + + // Only support single display for now + status =3D ConfigureCPMEMFrameBuffer( + DIContextPtr, + IDMAC_CHANNEL_DP_PRIMARY_FLOW_MAIN_PLANE, + FrameBufferPtr); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to configure CPMEM\n"); + goto Exit; + } + +Exit: + return status; +} + +UINT32 GetColorDepth ( + PIXEL_FORMAT PixelFormat + ) +{ + UINT32 bitDepth; + + switch(PixelFormat) + { + case PIXEL_FORMAT_ARGB32: + case PIXEL_FORMAT_BGRA32: + bitDepth =3D 8; + break; + default: + bitDepth =3D 0; + } + + return bitDepth; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.h b/Silicon/NXP/iMX6Pk= g/Drivers/GOP/Display.h new file mode 100644 index 000000000000..4a348bffed3a --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Display.h @@ -0,0 +1,171 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright 2018 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 { + DI0, + DI1, + DI_TOTAL, +} DI_INDEX; + +typedef enum { + HDMI_DISPLAY, + MIPI_DISPLAY, + LVDS0_DISPLAY, + LVDS1_DISPLAY, + MAX_DISPLAY, // Only 4 display supported by IPU + NO_DISPLAY =3D MAX_DISPLAY, +} DISPLAY_INTERFACE; + +typedef struct _SURFACE_INFO { + UINT32 PhyAddr; + UINT32* VirtAddrPtr; + UINT32 Width; + UINT32 Height; + UINT32 Pitch; + UINT32 Bpp; + PIXEL_FORMAT PixelFormat; +}SURFACE_INFO, *PSURFACE_INFO; + +typedef struct _IPU_DIx_REGS { + UINT32 DIxGENERAL; + UINT32 DIxBS_CLKGEN0; + UINT32 DIxBS_CLKGEN1; + UINT32 DIxSW_GEN0_1; + UINT32 DIxSW_GEN0_2; + UINT32 DIxSW_GEN0_3; + UINT32 DIxSW_GEN0_4; + UINT32 DIxSW_GEN0_5; + UINT32 DIxSW_GEN0_6; + UINT32 DIxSW_GEN0_7; + UINT32 DIxSW_GEN0_8; + UINT32 DIxSW_GEN0_9; + UINT32 DIxSW_GEN1_1; + UINT32 DIxSW_GEN1_2; + UINT32 DIxSW_GEN1_3; + UINT32 DIxSW_GEN1_4; + UINT32 DIxSW_GEN1_5; + UINT32 DIxSW_GEN1_6; + UINT32 DIxSW_GEN1_7; + UINT32 DIxSW_GEN1_8; + UINT32 DIxSW_GEN1_9; + UINT32 DIxSYNC_AS_GEN; + UINT32 DIxDW_GEN[12]; + UINT32 DIxDW_SET0[12]; + UINT32 DIxDW_SET1[12]; + UINT32 DIxDW_SET2[12]; + UINT32 DIxDW_SET3[12]; + UINT32 DIxSTP_REP[4]; + UINT32 DIxSTP_REP_9; + UINT32 DIxSER_CONF; + UINT32 DIxSSC; + UINT32 DIxPOL; + UINT32 DIxAW0; + UINT32 DIxAW1; + UINT32 DIxSCR_CONF; + UINT32 DIxSTAT; +} IPU_DIx_REGS, *PIPU_DIx_REGS; + +typedef struct _DISPLAY_INTERFACE_CONTEXT { + DISPLAY_INTERFACE displayInterface; + + VOID* MmioBasePtr; + VOID* IpuMmioBasePtr; + VOID* CpMemParamBasePtr; + IPU_DIx_REGS* IpuDiRegsPtr; + UINT32 EdidDataSize; + UINT8 EdidData[256]; + DISPLAY_TIMING PreferedTiming; +}DISPLAY_INTERFACE_CONTEXT, *PDISPLAY_INTERFACE_CONTEXT; + +typedef struct _DISPLAY_CONFIG { + DISPLAY_MODE DisplayMode; + DISPLAY_INTERFACE DIOrder[MAX_DISPLAY]; + SURFACE_INFO DisplaySurface[MAX_DISPLAY]; + DISPLAY_TIMING DisplayTiming[MAX_DISPLAY]; + UINT32 OsHandle[MAX_DISPLAY]; +}DISPLAY_CONFIG, *PDISPLAY_CONFIG; + +typedef struct _DISPLAY_CONTEXT { + DISPLAY_CONFIG DisplayConfig; + VOID* IoMuxMmioBasePtr; + VOID* IpuMmioBasePtr[IPU_TOTAL]; + DISPLAY_INTERFACE_CONTEXT DIContext[MAX_DISPLAY]; +}DISPLAY_CONTEXT, *PDISPLAY_CONTEXT; + +extern DISPLAY_TIMING DefaultTiming; + +OS_STATUS GetPreferedTiming ( + UINT8* EdidDataPtr, + UINT32 EdidDataSize, + DISPLAY_TIMING* PreferedTimingPtr + ); + +OS_STATUS InitDisplay ( + DISPLAY_CONTEXT** DisplayConfigPPtr + ); + +OS_STATUS DeInitDisplay ( + DISPLAY_CONTEXT* DisplayContextPtr + ); + +OS_STATUS ValidateDisplayConfig ( + DISPLAY_CONTEXT* DisplayContextPtr, + DISPLAY_MODE DisplayMode, + DISPLAY_INTERFACE* DIOrder + ); + +OS_STATUS SetDisplayConfig ( + DISPLAY_CONTEXT* DisplayContextPtr, + DISPLAY_MODE DisplayMode, + DISPLAY_INTERFACE* DIOrder + ); + +OS_STATUS ApplyDisplayConfig ( + DISPLAY_CONTEXT* DisplayContextPtr, + DISPLAY_MODE DisplayMode, + DISPLAY_INTERFACE* DIOrder + ); + +OS_STATUS AllocateFrameBuffer ( + SURFACE_INFO* SurfaceInfoPtr + ); + +OS_STATUS ConfigureFrameBuffer ( + DISPLAY_INTERFACE_CONTEXT* DIContextPtr, + SURFACE_INFO* FrameBufferPtr + ); + +UINT32 GetColorDepth ( + PIXEL_FORMAT PixelFormat + ); + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.c b/Silicon/= NXP/iMX6Pkg/Drivers/GOP/DisplayController.c new file mode 100644 index 000000000000..58830e98bd2b --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.c @@ -0,0 +1,388 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright 2018 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "osal.h" + +#include "Ipu.h" +#include "Display.h" +#include "DisplayController.h" +#include "DisplayInterface.h" + +VOID DumpBasicDCReg( + VOID* IpuMmioBasePtr) +{ + UINT32 regVal; + UINT32 counter, index; + + OS_INFO("---------- DC Register Dump ----------\n"); + OS_INFO("## Configuration\n\n"); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OFFSET); + OS_INFO("IPU_DC_WR_CH_CONF_5_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_WR_CH_CONF_1_OFFSET); + OS_INFO("IPU_DC_WR_CH_CONF_1_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_DISP_CONF1_0_OFFSET); + OS_INFO("IPU_DC_DISP_CONF1_0_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_DISP_CONF1_1_OFFSET); + OS_INFO("IPU_DC_DISP_CONF1_1_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_DISP_CONF1_2_OFFSET); + OS_INFO("IPU_DC_DISP_CONF1_2_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_DISP_CONF1_3_OFFSET); + OS_INFO("IPU_DC_DISP_CONF1_3_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_DISP_CONF2_0_OFFSET); + OS_INFO("IPU_DC_DISP_CONF2_0_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_GEN_OFFSET); + OS_INFO("IPU_DC_GEN_OFFSET %x\n", regVal); + OS_INFO("## Bus MAPPING\n\n"); + { + for (counter =3D 0, index =3D 0; index < 26; counter +=3D 4, ++ind= ex) { + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_MAP_CONF_0_OFFSET = + counter); + OS_INFO("IPU_DC_MAP_CONF_%d %x\n", index, regVal); + } + } + + OS_INFO("## Channel MicroCode setup\n\n"); + { + // Only print out channel 5 as we only support single mode for now + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_RL0_CH_5_OFFSET); + OS_INFO("IPU_DC_RL0_CH_5_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_RL1_CH_5_OFFSET); + OS_INFO("IPU_DC_RL1_CH_5_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_RL2_CH_5_OFFSET); + OS_INFO("IPU_DC_RL2_CH_5_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_RL3_CH_5_OFFSET); + OS_INFO("IPU_DC_RL3_CH_5_OFFSET %x\n", regVal); + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_DC_RL4_CH_5_OFFSET); + OS_INFO("IPU_DC_RL4_CH_5_OFFSET %x\n", regVal); + } + + OS_INFO("## MicroCode\n\n"); + { + // There are 256 template, only print out the first 10 + for (counter =3D 0, index =3D 0; index < 10; counter +=3D 8, ++ind= ex) { + OS_INFO("(%d)", index); + regVal =3D IpuRead32( + IpuMmioBasePtr, + IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + counter); + OS_INFO("- %8x", regVal); + regVal =3D IpuRead32( + IpuMmioBasePtr, + IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + counter + 4); + OS_INFO(" %8x -\n", regVal); + } + } + OS_INFO("------------------------------------\n\n"); +} + +#pragma pack(push, 1) +typedef union { + struct { + UINT32 SYNC : 4; + UINT32 GLUELOGIC : 7; + UINT32 WAVEFORM : 4; + UINT32 MAPPING : 5; + UINT32 DATA : 16; + UINT32 OPCODE : 5; + UINT32 STOP : 1; + UINT32 Unused : 22; + }; + struct { + UINT32 LowWord; + UINT32 HighWord; + }; +} DC_WROD_COMMAND_TEMPLATE; +#pragma pack(pop) + +OS_STATUS WriteWRODCommand ( + VOID* IpuMmioBasePtr, + UINT32 MicroCodeAddr, + UINT32 Data, + UINT32 Mapping, + UINT32 WaveForm, + UINT32 GlueLogic, + UINT32 Sync) +{ + DC_WROD_COMMAND_TEMPLATE wrodCommand; + UINT32 microCodeAddrOffset =3D + IPU_DC_TEMPLATE_REGS_ADDR_OFFSET + (MicroCodeAddr * 8); + + OS_ZERO_MEM((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.HighWo= rd); + + return OS_STATUS_SUCCESS; +} + +OS_STATUS SetDCChannelState ( + VOID* IpuMmioBasePtr, + PROG_CHAN_TYP ChannelType + ) +{ + IPU_DC_WR_CH_CONF_5_REG wrChConfigReg; + + wrChConfigReg.Reg =3D IpuRead32(IpuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OF= FSET); + + wrChConfigReg.PROG_CHAN_TYP =3D ChannelType; + + IpuWrite32(IpuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OFFSET, wrChConfigReg.R= eg); + + return OS_STATUS_SUCCESS; +} + +OS_STATUS ConfigureDCChannel ( + DISPLAY_INTERFACE_CONTEXT* DIContextPtr, + DISPLAY_INTERFACE DisplayInterface, + UINT32 DisplayIndex, + DISPLAY_TIMING* DisplayTimingPtr) +{ + OS_STATUS status; + IPU_DC_WR_CH_CONF_5_REG wrChConfigReg; + VOID* ipuMmioBasePtr =3D DIContextPtr->IpuMmioBasePtr; + + OS_ZERO_MEM((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(ipuMmioBasePtr, IPU_DC_WR_CH_CONF_5_OFFSET, wrChConfigReg.R= eg); + // Start address of memory always 0 + IpuWrite32(ipuMmioBasePtr, IPU_DC_WR_CH_ADDR_5_OFFSET, 0); + + OS_ZERO_MEM((void*)&wrChConfigReg, sizeof(wrChConfigReg)); + wrChConfigReg.FILED_MODE =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(ipuMmioBasePtr, IPU_DC_WR_CH_CONF_1_OFFSET, wrChConfigReg.R= eg); + IpuWrite32(ipuMmioBasePtr, IPU_DC_WR_CH_ADDR_1_OFFSET, 0); + + { + IPUx_DC_DISP_CONF1_REG dispConf1Reg; + + dispConf1Reg.DISP_TYP =3D 0x02; // What is byte_enabled + dispConf1Reg.ADDR_INCREMENT =3D 0; // Increase by 1 byte + dispConf1Reg.ADDR_BE_L_INC =3D 0; + dispConf1Reg.MCU_ACC_LB_MASK_3 =3D 0; + dispConf1Reg.DISP_RD_VALUE_PTR =3D 0; + IpuWrite32(ipuMmioBasePtr, IPU_DC_DISP_CONF1_0_OFFSET, dispConf1Re= g.Reg); + + // set stride + IpuWrite32(ipuMmioBasePtr, IPU_DC_DISP_CONF2_0_OFFSET, DisplayTimi= ngPtr->VActive); + } + + // Setup general register + { + IPUx_IPU_DC_GEN_REG dcGenReg; + + dcGenReg.Sync_1_6 =3D 2; // Sync flow + dcGenReg.MASK_EN =3D 0; // Disable masking + dcGenReg.MASK4CHAN_5 =3D 0; // Ignore as mask is disabled + dcGenReg.SYNC_PRIORITY_5 =3D 1; // Higher sync priority for channe= l 5 which is the main channel + dcGenReg.SYNC_PRIORITY_1 =3D 0; // Lower sync priority + dcGenReg.DC_CH5_TYPE =3D 0; // Normal mode, sync flow throuh chann= el 5 + dcGenReg.DC_BK_EN =3D 0; // No cursor support + dcGenReg.DC_BKDIV =3D 0; // No cursor support + + IpuWrite32(ipuMmioBasePtr, IPU_DC_GEN_OFFSET, dcGenReg.Reg); + } + + // Do not use any user event + IpuWrite32(ipuMmioBasePtr, IPU_DC_UGDE0_0_OFFSET, 0); + IpuWrite32(ipuMmioBasePtr, IPU_DC_UGDE1_0_OFFSET, 0); + IpuWrite32(ipuMmioBasePtr, IPU_DC_UGDE2_0_OFFSET, 0); + IpuWrite32(ipuMmioBasePtr, IPU_DC_UGDE3_0_OFFSET, 0); + + { + IPUx_DC_MAP_CONF_MAP_REG dcMapConf0Reg; + DC_MAP_CONF_OFFSET_MASK_REG dcConfOffsetMaskReg; + UINT32 mask0, mask1, mask2; + UINT32 offset0, offset1, offset2; + + dcMapConf0Reg.MAPPING_PNTR_BYTE0_X =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(ipuMmioBasePtr, IPU_DC_MAP_CONF_0_OFFSET, dcMapConf0Reg= .Reg); + + switch (DisplayInterface) + { + // PixelFormat RGB24 + case HDMI_DISPLAY: + mask0 =3D mask1 =3D mask2 =3D 0xFF; + offset0 =3D 7; + offset1 =3D 15; + offset2 =3D 23; + break; + // PixelFormat RGB666 + case LVDS0_DISPLAY: + case LVDS1_DISPLAY: + mask0 =3D mask1 =3D mask2 =3D 0xFC; + offset0 =3D 5; + offset1 =3D 11; + offset2 =3D 17; + break; + default: + ASSERT(FALSE); + status =3D OS_STATUS_UNSUPPORTED; + 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(ipuMmioBasePtr, IPU_DC_MAP_CONF_15_OFFSET, dcConfOffset= MaskReg.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(ipuMmioBasePtr, IPU_DC_MAP_CONF_16_OFFSET, dcConfOffset= MaskReg.Reg); + } + + // Setup microcode + { + IPU_DC_RL0_CH_5_REG dcRl0Ch5Reg; + IPU_DC_RL2_CH_5_REG dcRl2Ch5Reg; + IPU_DC_RL4_CH_5_REG dcRl4Ch5Reg; + + // New line event point to the first microcode (0) + OS_ZERO_MEM((void*)&dcRl0Ch5Reg, sizeof(dcRl0Ch5Reg)); + dcRl0Ch5Reg.COD_NL_START_CHAN_5 =3D 0; + dcRl0Ch5Reg.COD_NL_PRIORITY_CHAN_5 =3D 3; + IpuWrite32(ipuMmioBasePtr, IPU_DC_RL0_CH_5_OFFSET, dcRl0Ch5Reg.Reg= ); + + // End of line event point to the second microcode (1) + OS_ZERO_MEM((void*)&dcRl2Ch5Reg, sizeof(dcRl2Ch5Reg)); + dcRl2Ch5Reg.COD_EOL_START_CHAN_5 =3D 1; + dcRl2Ch5Reg.COD_EOL_PRIORITY_CHAN_5 =3D 2; + IpuWrite32(ipuMmioBasePtr, IPU_DC_RL2_CH_5_OFFSET, dcRl2Ch5Reg.Reg= ); + + // New data event point to the first microcode (2) + OS_ZERO_MEM((void*)&dcRl4Ch5Reg, sizeof(dcRl4Ch5Reg)); + dcRl4Ch5Reg.COD_NEW_DATA_START_CHAN_5 =3D 2; + dcRl4Ch5Reg.COD_NEW_DATA_PRIORITY_CHAN_5 =3D 1; + IpuWrite32(ipuMmioBasePtr, IPU_DC_RL4_CH_5_OFFSET, dcRl4Ch5Reg.Reg= ); + + // MicroCodeAddr + // - 0 set for new line event + // Data + // - Unsused + // Map to mapping parameter 0 + // - In order to point to MAPPING_PNTR_BYTE2_0, MAPPING_PNTR_BYTE1= _0, + // MAPPING_PNTR_BYTE0_0 the user should write 1 to the MAPPING f= ield + // WaveForm + // - Points to DI0_DW_GEN_0 or DI1_DW_GEN_0 (Define which waveform + // register is used, default to first IPUx_DI0_DW_SET0_1) + // GlueLogic + // - Once the signal is asserted then it remains asserted (high or= low + // according to the polarity) + // Sync + // - Sync with counter 5 + WriteWRODCommand( + ipuMmioBasePtr, + 0, + 0, + 1, + DW_GEN_0, + 8, + DI_COUNTER_5_ACTIVE_CLOCK); + + // MicroCodeAddr + // - 1 set for end of line event + // Data + // - Unsused + // Map to mapping parameter 0 + // - In order to point to MAPPING_PNTR_BYTE2_0, MAPPING_PNTR_BYTE1= _0, + // MAPPING_PNTR_BYTE0_0 the user should write 1 to the MAPPING f= ield + // 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 l= ow + // according to the polarity) + // Sync + // - Sync with counter 5 + WriteWRODCommand( + ipuMmioBasePtr, + 1, + 0, + 1, + DW_GEN_0, + 4, + DI_COUNTER_5_ACTIVE_CLOCK); + + // MicroCodeAddr + // - 2 set for new data event + // Data + // - Unsused + // Map to mapping parameter 0 + // - In order to point to MAPPING_PNTR_BYTE2_0, MAPPING_PNTR_BYTE1= _0, + // MAPPING_PNTR_BYTE0_0 the user should write 1 to the MAPPING f= ield + // WaveForm + // - Points to DI0_DW_GEN_0 or DI1_DW_GEN_0 (Define which waveform + // register is used, default to first IPUx_DI0_DW_SET0_1) + // GlueLogic + // - CS mode No impact on the waveform + // Sync + // - Sync with channel 5 + WriteWRODCommand( + ipuMmioBasePtr, + 2, + 0, + 1, + DW_GEN_0, + 8, + DI_COUNTER_5_ACTIVE_CLOCK); + } + + // Turn on channel without anti tearing + SetDCChannelState(DIContextPtr->IpuMmioBasePtr, PROG_CHAN_TYP_NORMAL); + + // Register dump, commented out by default +#ifdef REGISTER_DUMP + DumpBasicDCReg(ipuMmioBasePtr); +#endif + + status =3D OS_STATUS_SUCCESS; + +Exit: + return status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.h b/Silicon/= NXP/iMX6Pkg/Drivers/GOP/DisplayController.h new file mode 100644 index 000000000000..085632117367 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayController.h @@ -0,0 +1,312 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 _DC_H_ +#define _DC_H_ + +#define IPU_DC_OFFSET 0x00058000 + +// DC Registers +#define IPU_DC_READ_CH_CONF_OFFSET IPU_DC_OFFSET + 0x0000 +#define IPU_DC_READ_CH_ADDR_OFFSET IPU_DC_OFFSET + 0x0004 +#define IPU_DC_RL0_CH_0_OFFSET IPU_DC_OFFSET + 0x0008 +#define IPU_DC_RL1_CH_0_OFFSET IPU_DC_OFFSET + 0x000C +#define IPU_DC_RL2_CH_0_OFFSET IPU_DC_OFFSET + 0x0010 +#define IPU_DC_RL3_CH_0_OFFSET IPU_DC_OFFSET + 0x0014 +#define IPU_DC_RL4_CH_0_OFFSET IPU_DC_OFFSET + 0x0018 +#define IPU_DC_WR_CH_CONF_1_OFFSET IPU_DC_OFFSET + 0x001C +#define IPU_DC_WR_CH_ADDR_1_OFFSET IPU_DC_OFFSET + 0x0020 +#define IPU_DC_RL0_CH_1_OFFSET IPU_DC_OFFSET + 0x0024 +#define IPU_DC_RL1_CH_1_OFFSET IPU_DC_OFFSET + 0x0028 +#define IPU_DC_RL2_CH_1_OFFSET IPU_DC_OFFSET + 0x002C +#define IPU_DC_RL3_CH_1_OFFSET IPU_DC_OFFSET + 0x0030 +#define IPU_DC_RL4_CH_1_OFFSET IPU_DC_OFFSET + 0x0034 +#define IPU_DC_WR_CH_CONF_2_OFFSET IPU_DC_OFFSET + 0x0038 +#define IPU_DC_WR_CH_ADDR_2_OFFSET IPU_DC_OFFSET + 0x003C +#define IPU_DC_RL0_CH_2_OFFSET IPU_DC_OFFSET + 0x0040 +#define IPU_DC_RL1_CH_2_OFFSET IPU_DC_OFFSET + 0x0044 +#define IPU_DC_RL2_CH_2_OFFSET IPU_DC_OFFSET + 0x0048 +#define IPU_DC_RL3_CH_2_OFFSET IPU_DC_OFFSET + 0x004C +#define IPU_DC_RL4_CH_2_OFFSET IPU_DC_OFFSET + 0x0050 +#define IPU_DC_CMD_CH_CONF_3_OFFSET IPU_DC_OFFSET + 0x0054 +#define IPU_DC_CMD_CH_CONF_4_OFFSET IPU_DC_OFFSET + 0x0058 +#define IPU_DC_WR_CH_CONF_5_OFFSET IPU_DC_OFFSET + 0x005C +#define IPU_DC_WR_CH_ADDR_5_OFFSET IPU_DC_OFFSET + 0x0060 +#define IPU_DC_RL0_CH_5_OFFSET IPU_DC_OFFSET + 0x0064 +#define IPU_DC_RL1_CH_5_OFFSET IPU_DC_OFFSET + 0x0068 +#define IPU_DC_RL2_CH_5_OFFSET IPU_DC_OFFSET + 0x006C +#define IPU_DC_RL3_CH_5_OFFSET IPU_DC_OFFSET + 0x0070 +#define IPU_DC_RL4_CH_5_OFFSET IPU_DC_OFFSET + 0x0074 +#define IPU_DC_WR_CH_CONF_6_OFFSET IPU_DC_OFFSET + 0x0078 +#define IPU_DC_WR_CH_ADDR_6_OFFSET IPU_DC_OFFSET + 0x007C +#define IPU_DC_RL0_CH_6_OFFSET IPU_DC_OFFSET + 0x0080 +#define IPU_DC_RL1_CH_6_OFFSET IPU_DC_OFFSET + 0x0084 +#define IPU_DC_RL2_CH_6_OFFSET IPU_DC_OFFSET + 0x0088 +#define IPU_DC_RL3_CH_6_OFFSET IPU_DC_OFFSET + 0x008C +#define IPU_DC_RL4_CH_6_OFFSET IPU_DC_OFFSET + 0x0090 +#define IPU_DC_WR_CH_CONF1_8_OFFSET IPU_DC_OFFSET + 0x0094 +#define IPU_DC_WR_CH_CONF2_8_OFFSET IPU_DC_OFFSET + 0x0098 +#define IPU_DC_RL1_CH_8_OFFSET IPU_DC_OFFSET + 0x009C +#define IPU_DC_RL2_CH_8_OFFSET IPU_DC_OFFSET + 0x00A0 +#define IPU_DC_RL3_CH_8_OFFSET IPU_DC_OFFSET + 0x00A4 +#define IPU_DC_RL4_CH_8_OFFSET IPU_DC_OFFSET + 0x00A8 +#define IPU_DC_RL5_CH_8_OFFSET IPU_DC_OFFSET + 0x00AC +#define IPU_DC_RL6_CH_8_OFFSET IPU_DC_OFFSET + 0x00B0 +#define IPU_DC_WR_CH_CONF1_9_OFFSET IPU_DC_OFFSET + 0x00B4 +#define IPU_DC_WR_CH_CONF2_9_OFFSET IPU_DC_OFFSET + 0x00B8 +#define IPU_DC_RL1_CH_9_OFFSET IPU_DC_OFFSET + 0x00BC +#define IPU_DC_RL2_CH_9_OFFSET IPU_DC_OFFSET + 0x00C0 +#define IPU_DC_RL3_CH_9_OFFSET IPU_DC_OFFSET + 0x00C4 +#define IPU_DC_RL4_CH_9_OFFSET IPU_DC_OFFSET + 0x00C8 +#define IPU_DC_RL5_CH_9_OFFSET IPU_DC_OFFSET + 0x00CC +#define IPU_DC_RL6_CH_9_OFFSET IPU_DC_OFFSET + 0x00D0 +#define IPU_DC_GEN_OFFSET IPU_DC_OFFSET + 0x00D4 +#define IPU_DC_DISP_CONF1_0_OFFSET IPU_DC_OFFSET + 0x00D8 +#define IPU_DC_DISP_CONF1_1_OFFSET IPU_DC_OFFSET + 0x00DC +#define IPU_DC_DISP_CONF1_2_OFFSET IPU_DC_OFFSET + 0x00E0 +#define IPU_DC_DISP_CONF1_3_OFFSET IPU_DC_OFFSET + 0x00E4 +#define IPU_DC_DISP_CONF2_0_OFFSET IPU_DC_OFFSET + 0x00E8 +#define IPU_DC_DISP_CONF2_1_OFFSET IPU_DC_OFFSET + 0x00EC +#define IPU_DC_DISP_CONF2_2_OFFSET IPU_DC_OFFSET + 0x00F0 +#define IPU_DC_DISP_CONF2_3_OFFSET IPU_DC_OFFSET + 0x00F4 +#define IPU_DC_DI0_CONF1_OFFSET IPU_DC_OFFSET + 0x00F8 +#define IPU_DC_DI0_CONF2_OFFSET IPU_DC_OFFSET + 0x00FC +#define IPU_DC_DI1_CONF1_OFFSET IPU_DC_OFFSET + 0x0100 +#define IPU_DC_DI1_CONF2_OFFSET IPU_DC_OFFSET + 0x0104 +#define IPU_DC_MAP_CONF_0_OFFSET IPU_DC_OFFSET + 0x0108 +#define IPU_DC_MAP_CONF_1_OFFSET IPU_DC_OFFSET + 0x010C +#define IPU_DC_MAP_CONF_2_OFFSET IPU_DC_OFFSET + 0x0110 +#define IPU_DC_MAP_CONF_3_OFFSET IPU_DC_OFFSET + 0x0114 +#define IPU_DC_MAP_CONF_4_OFFSET IPU_DC_OFFSET + 0x0118 +#define IPU_DC_MAP_CONF_5_OFFSET IPU_DC_OFFSET + 0x011C +#define IPU_DC_MAP_CONF_6_OFFSET IPU_DC_OFFSET + 0x0120 +#define IPU_DC_MAP_CONF_7_OFFSET IPU_DC_OFFSET + 0x0124 +#define IPU_DC_MAP_CONF_8_OFFSET IPU_DC_OFFSET + 0x0128 +#define IPU_DC_MAP_CONF_9_OFFSET IPU_DC_OFFSET + 0x012C +#define IPU_DC_MAP_CONF_10_OFFSET IPU_DC_OFFSET + 0x0130 +#define IPU_DC_MAP_CONF_11_OFFSET IPU_DC_OFFSET + 0x0134 +#define IPU_DC_MAP_CONF_12_OFFSET IPU_DC_OFFSET + 0x0138 +#define IPU_DC_MAP_CONF_13_OFFSET IPU_DC_OFFSET + 0x013C +#define IPU_DC_MAP_CONF_14_OFFSET IPU_DC_OFFSET + 0x0140 +#define IPU_DC_MAP_CONF_15_OFFSET IPU_DC_OFFSET + 0x0144 +#define IPU_DC_MAP_CONF_16_OFFSET IPU_DC_OFFSET + 0x0148 +#define IPU_DC_MAP_CONF_17_OFFSET IPU_DC_OFFSET + 0x014C +#define IPU_DC_MAP_CONF_18_OFFSET IPU_DC_OFFSET + 0x0150 +#define IPU_DC_MAP_CONF_19_OFFSET IPU_DC_OFFSET + 0x0154 +#define IPU_DC_MAP_CONF_20_OFFSET IPU_DC_OFFSET + 0x0158 +#define IPU_DC_MAP_CONF_21_OFFSET IPU_DC_OFFSET + 0x015C +#define IPU_DC_MAP_CONF_22_OFFSET IPU_DC_OFFSET + 0x0160 +#define IPU_DC_MAP_CONF_23_OFFSET IPU_DC_OFFSET + 0x0164 +#define IPU_DC_MAP_CONF_24_OFFSET IPU_DC_OFFSET + 0x0168 +#define IPU_DC_MAP_CONF_25_OFFSET IPU_DC_OFFSET + 0x016C +#define IPU_DC_MAP_CONF_26_OFFSET IPU_DC_OFFSET + 0x0170 +#define IPU_DC_UGDE0_0_OFFSET IPU_DC_OFFSET + 0x0174 +#define IPU_DC_UGDE0_1_OFFSET IPU_DC_OFFSET + 0x0178 +#define IPU_DC_UGDE0_2_OFFSET IPU_DC_OFFSET + 0x017C +#define IPU_DC_UGDE0_3_OFFSET IPU_DC_OFFSET + 0x0180 +#define IPU_DC_UGDE1_0_OFFSET IPU_DC_OFFSET + 0x0184 +#define IPU_DC_UGDE1_1_OFFSET IPU_DC_OFFSET + 0x0188 +#define IPU_DC_UGDE1_2_OFFSET IPU_DC_OFFSET + 0x018C +#define IPU_DC_UGDE1_3_OFFSET IPU_DC_OFFSET + 0x0190 +#define IPU_DC_UGDE2_0_OFFSET IPU_DC_OFFSET + 0x0194 +#define IPU_DC_UGDE2_1_OFFSET IPU_DC_OFFSET + 0x0198 +#define IPU_DC_UGDE2_2_OFFSET IPU_DC_OFFSET + 0x019C +#define IPU_DC_UGDE2_3_OFFSET IPU_DC_OFFSET + 0x01A0 +#define IPU_DC_UGDE3_0_OFFSET IPU_DC_OFFSET + 0x01A4 +#define IPU_DC_UGDE3_1_OFFSET IPU_DC_OFFSET + 0x01A8 +#define IPU_DC_UGDE3_2_OFFSET IPU_DC_OFFSET + 0x01AC +#define IPU_DC_UGDE3_3_OFFSET IPU_DC_OFFSET + 0x01B0 +#define IPU_DC_LLA0_OFFSET IPU_DC_OFFSET + 0x01B4 +#define IPU_DC_LLA1_OFFSET IPU_DC_OFFSET + 0x01B8 +#define IPU_DC_R_LLA0_OFFSET IPU_DC_OFFSET + 0x01BC +#define IPU_DC_R_LLA1_OFFSET IPU_DC_OFFSET + 0x01C0 +#define IPU_DC_WR_CH_ADDR_5_ALT_OFFSET IPU_DC_OFFSET + 0x01C4 +#define IPU_DC_STAT_OFFSET IPU_DC_OFFSET + 0x01C8 + +// Microcode template +#define IPU_DC_TEMPLATE_REGS_ADDR_OFFSET 0x00180000 + +typedef enum { + DC_CHANNEL_READ =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; + +#pragma pack(pop) + +OS_STATUS SetDCChannelState ( + VOID* IpuMmioBasePtr, + PROG_CHAN_TYP State + ); + +OS_STATUS ConfigureDCChannel ( + DISPLAY_INTERFACE_CONTEXT* DIContextPtr, + DISPLAY_INTERFACE DisplayInterface, + UINT32 DisplayIndex, + DISPLAY_TIMING* DisplayTimingPtr + ); + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.c b/Silicon/N= XP/iMX6Pkg/Drivers/GOP/DisplayInterface.c new file mode 100644 index 000000000000..468cb4c90609 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.c @@ -0,0 +1,444 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "Osal.h" + +#include "Ipu.h" +#include "Display.h" +#include "DisplayInterface.h" + +#define READ_WAVE_GEN(IPU_BASE, GEN_INDEX) \ + DiRead32(IPU_BASE, IPU_DIx_DW_GEN_OFFSET + (GEN_INDEX * 0x4)) + +#define WRITE_WAVE_GEN(IPU_BASE, GEN_INDEX, VALUE) \ + DiWrite32(IPU_BASE, IPU_DIx_DW_GEN_OFFSET + (GEN_INDEX * 0x4), VALUE) + +#define READ_WAVE_SET(IPU_BASE, GEN_INDEX, SET_NUMBER) \ + DiRead32(IPU_BASE, IPU_DIx_DW_SET0_OFFSET + (SET_NUMBER * 0x30) + (GEN= _INDEX * 0x4)) + +#define WRITE_WAVE_SET(IPU_BASE, GEN_INDEX, SET_NUMBER, VALUE) \ + DiWrite32(IPU_BASE, IPU_DIx_DW_SET0_OFFSET + (SET_NUMBER * 0x30) + (GE= N_INDEX * 0x4), VALUE) + +VOID DumpBasicDIReg ( + VOID* IpuMmioBasePtr, + IPU_DIx_REGS* IpuDiRegsPtr + ) +{ + UINT32 index, setNumber, regVal; + UINT32 printTotalGen =3D 8; // Limit printing (max 12) + + OS_INFO("---------- DI Register Dump ----------\n"); + // Print out generator value for D0 + OS_INFO("## Wave Gen\n"); + for (index =3D 0; index < printTotalGen; ++index) { + regVal =3D READ_WAVE_GEN(IpuDiRegsPtr, index); + OS_INFO("DI0_DW_GEN_%d 0x%08x\n", index, regVal); + } + // Print out generator value for D0 + OS_INFO("## Wave Set\n"); + for (index =3D 0; index < printTotalGen; ++index) { + for (setNumber =3D 0; setNumber < 4; ++setNumber) { + regVal =3D READ_WAVE_SET(IpuDiRegsPtr, index, setNumber); + OS_INFO("DI0_DW_SET%d_%d 0x%08x\n", setNumber, index, regVal); + } + } + + regVal =3D IpuRead32(IpuMmioBasePtr, IPU_IPU_PM_OFFSET); + OS_INFO("IPU_IPU_PM_OFFSET %x\n", regVal); + + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_BS_CLKGEN0_OFFSET); + OS_INFO("IPU_DIx_BS_CLKGEN0_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_BS_CLKGEN1_OFFSET); + OS_INFO("IPU_DIx_BS_CLKGEN1_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SCR_CONF_OFFSET); + OS_INFO("IPU_DIx_SCR_CONF_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN0_1_OFFSET); + OS_INFO("IPU_DIx_SW_GEN0_1_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN1_1_OFFSET); + OS_INFO("IPU_DIx_SW_GEN1_1_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN0_2_OFFSET); + OS_INFO("IPU_DIx_SW_GEN0_2_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN1_2_OFFSET); + OS_INFO("IPU_DIx_SW_GEN1_2_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN0_3_OFFSET); + OS_INFO("IPU_DIx_SW_GEN0_3_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN1_3_OFFSET); + OS_INFO("IPU_DIx_SW_GEN1_3_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN0_4_OFFSET); + OS_INFO("IPU_DIx_SW_GEN0_4_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN1_4_OFFSET); + OS_INFO("IPU_DIx_SW_GEN1_4_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN0_5_OFFSET); + OS_INFO("IPU_DIx_SW_GEN0_5_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SW_GEN1_5_OFFSET); + OS_INFO("IPU_DIx_SW_GEN1_5_OFFSET %x\n", regVal); + + for (index =3D 0; index < 5; ++index) { + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_STP_REP_OFFSET + (index= * 0x4)); + OS_INFO("IPU_DIx_STP_%d_REP_OFFSET %x\n", index + 1, regVal); + } + + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_SYNC_AS_GEN_OFFSET); + OS_INFO("IPU_DIx_SYNC_AS_GEN_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_GENERAL_OFFSET); + OS_INFO("IPU_DIx_GENERAL_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_DIx_POL_OFFSET); + OS_INFO("IPU_DIx_POL_OFFSET %x\n", regVal); + regVal =3D DiRead32(IpuDiRegsPtr, IPU_IPU_DISP_GEN_OFFSET); + OS_INFO("IPU_IPU_DISP_GEN_OFFSET %x\n", regVal); + OS_INFO("------------------------------------\n\n"); +} + +VOID ConfigureSyncWave ( + VOID* IpuMmioBasePtr, + IPU_DIx_REGS* IpuDiRegsPtr, + UINT32 CounterIndex, + UINT32 RunValue, + UINT32 RunResolution, + UINT32 OffsetValue, + UINT32 OffsetResolution, + UINT32 CounterPolarityGenEn, + UINT32 CounterAutoReload, + UINT32 CounterClearSelect, + UINT32 CounterDown, + UINT32 CounterPolarityTriggerSelect, + UINT32 CounterPolarityClearSelect, + UINT32 CounterUp, + UINT32 StepRepeat + ) +{ + IPUx_DIx_SW_GEN0_x_REG diSwGen0Reg; + IPUx_DIx_SW_GEN1_x_REG diSwGen1Reg; + IPUx_DIx_STP_REP_REG stepRepeatReg; + + OS_ZERO_MEM((void*)&diSwGen0Reg, sizeof(diSwGen0Reg)); + diSwGen0Reg.dix_offset_resolution =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); + + OS_ZERO_MEM((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 CounterPolarityTriggerSel= ect; + 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); + + { + UINT32 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); + } +} + +OS_STATUS ConfigureDI ( + DISPLAY_INTERFACE_CONTEXT* DIContextPtr, + UINT32 DisplayIndex, + DISPLAY_TIMING* DisplayTimingPtr + ) +{ + OS_STATUS status; + UINT32 baseDiv; + UINT64 diFreq =3D DisplayTimingPtr->PixelClock; + UINT32 hTotal =3D DisplayTimingPtr->HActive + DisplayTimingPtr->HBlank= ; + UINT32 vTotal =3D DisplayTimingPtr->VActive + DisplayTimingPtr->VBlank= ; + VOID* ipuMmioBasePtr =3D DIContextPtr->IpuMmioBasePtr; + IPU_DIx_REGS* ipuDiRegsPtr =3D DIContextPtr->IpuDiRegsPtr; + + status =3D ImxSetPll5ReferenceRate(DisplayTimingPtr->PixelClock); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to setup PLL5=3D%r\n", status); + goto Exit; + } + + // Setup base timer (fundamental timer). The base timer should already + // setup to match the pixel clock frequency. + // Shift 4 as the bottom 4 bits are fractional + baseDiv =3D (UINT32)((diFreq << 4) / DisplayTimingPtr->PixelClock); + + DiWrite32(ipuDiRegsPtr, IPU_DIx_BS_CLKGEN0_OFFSET, baseDiv); + + // Up is always set to 0. Down is half of the pixel clock period where + // the first bit is fraction + baseDiv >>=3D 4; + + DiWrite32(ipuDiRegsPtr, IPU_DIx_BS_CLKGEN1_OFFSET, baseDiv << 16); + // Calculate divisor, again this would usually be 1. + baseDiv =3D (UINT32)(diFreq / DisplayTimingPtr->PixelClock); + + // Set up wave, there 12 wave quartet, for now default to the first. + // Each wave quartet has 4 set register + { + IPUx_DIx_DW_SET_REG dixDwSetReg; + IPUx_DIx_DW_GEN_REG dixDwGenReg; + + // Set 0 is just a blank signal where up and down is set to 0 + OS_ZERO_MEM((void*)&dixDwSetReg, sizeof(dixDwSetReg)); + dixDwSetReg.dix_data_cnt_upx_i =3D 0; + dixDwSetReg.dix_data_cnt_downx_i =3D 0; + WRITE_WAVE_SET( + ipuDiRegsPtr, + DW_GEN_0, + DW_SET_0, + dixDwSetReg.Reg); + + // Set 3 is setup to match pixel clock + OS_ZERO_MEM((void*)&dixDwSetReg, sizeof(dixDwSetReg)); + dixDwSetReg.dix_data_cnt_upx_i =3D 0; + dixDwSetReg.dix_data_cnt_downx_i =3D baseDiv * 2; + WRITE_WAVE_SET( + ipuDiRegsPtr, + DW_GEN_0, + DW_SET_3, + dixDwSetReg.Reg); + + // All pins blank signal except pin 15 + // Need to get pin mapping documentation + OS_ZERO_MEM((void*)&dixDwGenReg, sizeof(dixDwGenReg)); + dixDwGenReg.dix_pt_0_i =3D DW_SET_0; + dixDwGenReg.dix_pt_1_i =3D DW_SET_0; + dixDwGenReg.dix_pt_2_i =3D DW_SET_0; + dixDwGenReg.dix_pt_3_i =3D DW_SET_0; + dixDwGenReg.dix_pt_4_i =3D DW_SET_3; + dixDwGenReg.dix_pt_5_i =3D DW_SET_0; + dixDwGenReg.dix_pt_6_i =3D DW_SET_0; + dixDwGenReg.dix_cst_i =3D DW_SET_0; + + // Reuse the base divisor to determine extra IPU cycles. + dixDwGenReg.dix_componnent_size_i =3D dixDwGenReg.dix_access_size_= i =3D + baseDiv - 1; + WRITE_WAVE_GEN(ipuDiRegsPtr, DW_GEN_0, dixDwGenReg.Reg); + } + + // Spec mention this as number of display rows but display only works + // proper if this is setup as vertical total + DiWrite32(ipuDiRegsPtr, IPU_DIx_SCR_CONF_OFFSET, vTotal - 1); + + { + // Internal HSYNC + ConfigureSyncWave( + ipuMmioBasePtr, + ipuDiRegsPtr, + DI_COUNTER_1_INTERNAL_HSYNC, // CounterIndex + hTotal - 1, // Runvalue + DI_COUNTER_0_DISPLAY_CLOCK + 1, // RunResolution + 0, // OffsetValue + 0, // OffsetResolution + 0, // CounterPolarityGenEn + 1, // CounterAutoReload + DI_COUNTER_DISABLED, // CounterClearSelect + 0, // CountDown + 0, // CounterPolarityTriggerSelect + 0, // CounterPolarityClearSelect + 0, // CounterUp + 0); // StepRepeat + + // Output HSYNC + ConfigureSyncWave( + ipuMmioBasePtr, + ipuDiRegsPtr, + DI_COUNTER_2_OUTPUT_HSYNC, // CounterIndex + hTotal - 1, // Runvalue + DI_COUNTER_0_DISPLAY_CLOCK + 1, // RunResolution + 0, // OffsetValue + DI_COUNTER_0_DISPLAY_CLOCK + 1, // OffsetResolution - Display = clock + 1, // CounterPolarityGenEn + 1, // CounterAutoReload + DI_COUNTER_DISABLED, // CounterClearSelect + DisplayTimingPtr->HSync * 2, // CountDown + 1, // CounterPolarityTriggerSelect + 0, // CounterPolarityClearSelect + 0, // CounterUp + 0); // StepRepeat + + // Output VSYNC + ConfigureSyncWave( + ipuMmioBasePtr, + ipuDiRegsPtr, + DI_COUNTER_3_OUTPUT_VSYNC, // CounterIndex + vTotal - 1, // Runvalue + DI_COUNTER_1_INTERNAL_HSYNC + 1, // RunResolution - Counter 1 + 0, // OffsetValue + 0, // OffsetResolution + 1, // CounterPolarityGenEn + 1, // CounterAutoReload + DI_COUNTER_DISABLED, // CounterClearSelect + DisplayTimingPtr->VSync * 2, // CountDown + 2, // CounterPolarityTriggerSelect + 0, // CounterPolarityClearSelect + 0, // CounterUp + 0); // StepRepeat + + // Active lines + ConfigureSyncWave( + ipuMmioBasePtr, + ipuDiRegsPtr, + DI_COUNTER_4_ACTIVE_LINE , // CounterIndex + 0, // Runvalue + DI_COUNTER_2_OUTPUT_HSYNC + 1, // RunResolution - Counter 2 + DisplayTimingPtr->VSync + DisplayTimingPtr->VSyncOffset, // Of= fset + 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 VAc= tive + + // Active clock + ConfigureSyncWave( + ipuMmioBasePtr, + ipuDiRegsPtr, + DI_COUNTER_5_ACTIVE_CLOCK, // CounterIndex + 0, // Runvalue + DI_COUNTER_0_DISPLAY_CLOCK + 1, // RunResolution - Display clo= ck + DisplayTimingPtr->HSync + DisplayTimingPtr->HSyncOffset, // Of= fset + DI_COUNTER_0_DISPLAY_CLOCK + 1, // OffsetResolution - Display = clock + 0, // CounterPolarityGenEn + 0, // CounterAutoReload + DI_COUNTER_4_ACTIVE_LINE + 1, // CounterClearSelect - Counter = 4 + 0, // CountDown + 0, // CounterPolarityTriggerSelect + 0, // CounterPolarityClearSelect + 0, // CounterUp + DisplayTimingPtr->HActive); // StepRepeat + } + + { + IPUx_DIx_SYNC_AS_GEN_REG dixSyncAsGenReg; + + OS_ZERO_MEM((void*)&dixSyncAsGenReg, sizeof(dixSyncAsGenReg)); + // VSYNC is setup as counter 3 above, 0 index based + dixSyncAsGenReg.dix_vsync_sel =3D 3 - 1; + // Number of row DI prepares next frame data. + // This seem to be the default value. + dixSyncAsGenReg.dix_sync_start =3D 2; + DiWrite32(ipuDiRegsPtr, IPU_DIx_SYNC_AS_GEN_OFFSET, dixSyncAsGenRe= g.Reg); + } + + // Setup general register + { + IPUx_DIx_GENERAL_REG dixGeneralReg; + + OS_ZERO_MEM((void*)&dixGeneralReg, sizeof(dixGeneralReg)); + // Counter 1 as display line + dixGeneralReg.dix_disp_y_sel =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(DIContextPtr->displayInterface) + { + case HDMI_DISPLAY: + // 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 OS_STATUS_UNSUPPORTED; + OS_ERROR( + "Unsupported display interface %d", + DIContextPtr->displayInterface); + goto Exit; + } + + DiWrite32(ipuDiRegsPtr, IPU_DIx_GENERAL_OFFSET, dixGeneralReg.Reg)= ; + } + + { + IPUx_DIx_POL_REG dixPolReg; + + OS_ZERO_MEM((void*)&dixPolReg, sizeof(dixPolReg)); + // CS0 + dixPolReg.DIx_CS0_DATA_POLARITY =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(ipuDiRegsPtr, IPU_DIx_POL_OFFSET, dixPolReg.Reg); + } + + { + UINT32 dispGenReg; + + dispGenReg =3D IpuRead32(ipuMmioBasePtr, IPU_IPU_DISP_GEN_OFFSET); + dispGenReg &=3D ~(0x0F << 18); + dispGenReg |=3D (2 << 18); + IpuWrite32(ipuMmioBasePtr, IPU_IPU_DISP_GEN_OFFSET, dispGenReg); + } + + // Register dump, commented out by default +#ifdef REGISTER_DUMP + DumpBasicDIReg(ipuMmioBasePtr, ipuDiRegsPtr); +#endif + + status =3D OS_STATUS_SUCCESS; + +Exit: + return status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.h b/Silicon/N= XP/iMX6Pkg/Drivers/GOP/DisplayInterface.h new file mode 100644 index 000000000000..0c8ede1e8fde --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/DisplayInterface.h @@ -0,0 +1,182 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 _DI_H_ +#define _DI_H_ + +OS_STATUS ConfigureDI ( + DISPLAY_INTERFACE_CONTEXT* DIContextPtr, + UINT32 DisplayIndex, + DISPLAY_TIMING* DisplayTimingPtr + ); + +enum { + DW_GEN_0 =3D 0, + DW_GEN_1 =3D 1, + DW_GEN_2 =3D 2, + DW_GEN_3 =3D 3, + DW_GEN_4 =3D 4, + DW_GEN_5 =3D 5, + DW_GEN_6 =3D 6, + DW_GEN_7 =3D 7, + DW_GEN_8 =3D 8, + DW_GEN_9 =3D 9, + DW_GEN_10 =3D 10, + DW_GEN_11 =3D 11, +}; + +enum { + DW_SET_0 =3D 0, + DW_SET_1 =3D 1, + DW_SET_2 =3D 2, + DW_SET_3 =3D 3, +}; + +enum { + DI_COUNTER_DISABLED =3D 0, + DI_COUNTER_0_DISPLAY_CLOCK =3D 0, + DI_COUNTER_1_INTERNAL_HSYNC =3D 1, + DI_COUNTER_2_OUTPUT_HSYNC =3D 2, + DI_COUNTER_3_OUTPUT_VSYNC =3D 3, + DI_COUNTER_4_ACTIVE_LINE =3D 4, + DI_COUNTER_5_ACTIVE_CLOCK =3D 5, +}; + +#pragma pack(push, 1) + +// IPUx_DIx_GENERAL +typedef union { + struct { + UINT32 dix_polarity_i_1 : 8; + UINT32 dix_polarity_cs0 : 1; + UINT32 dix_polarity_cs1 : 1; + UINT32 dix_erm_vsync_sel : 1; + UINT32 dix_err_treatment : 1; + UINT32 dix_sync_count_sel : 4; + UINT32 Reserved : 1; + UINT32 dix_polarity_disp_clk : 1; + UINT32 DIx_WATCHDOG_MODE : 2; + UINT32 dix_clk_ext : 1; + UINT32 dix_vsync_ext : 1; + UINT32 dix_mask_sel : 1; + UINT32 DIx_DISP_CLOCK_INIT : 1; + UINT32 DIx_CLOCK_STOP_MODE : 4; + UINT32 dix_disp_y_sel : 3; + UINT32 dix_pin8_pin15_sel : 1; + }; + UINT32 Reg; +} IPUx_DIx_GENERAL_REG; + +// IPUx_DIx_SYNC_AS_GEN +typedef union { + struct { + UINT32 dix_sync_start : 12; + UINT32 Reserved1 : 1; + UINT32 dix_vsync_sel : 3; + UINT32 Reserved2 : 12; + UINT32 di0_sync_start_en : 1; + UINT32 Reserved3 : 3; + }; + UINT32 Reg; +} IPUx_DIx_SYNC_AS_GEN_REG; + +// IPUx_DIx_DW_SET +typedef union { + struct { + UINT32 dix_data_cnt_upx_i : 9; + UINT32 Reserved1 : 7; + UINT32 dix_data_cnt_downx_i : 9; + UINT32 Reserved2 : 7; + }; + UINT32 Reg; +} IPUx_DIx_DW_SET_REG; + +// IPUx_DIx_DW_GEN +typedef union { + struct { + UINT32 dix_pt_0_i : 2; // Pin 11 + UINT32 dix_pt_1_i : 2; // Pin 12 + UINT32 dix_pt_2_i : 2; // Pin 13 + UINT32 dix_pt_3_i : 2; // Pin 14 + UINT32 dix_pt_4_i : 2; // Pin 15 + UINT32 dix_pt_5_i : 2; // Pin 16 + UINT32 dix_pt_6_i : 2; // Pin 17 + UINT32 dix_cst_i : 2; // Chip Select + UINT32 dix_componnent_size_i : 8; + UINT32 dix_access_size_i : 8; + }; + UINT32 Reg; +} IPUx_DIx_DW_GEN_REG; + + +// IPUx_DIx_SW_GEN0_x_REG +typedef union { + struct { + UINT32 dix_offset_resolution : 3; + UINT32 dix_offset_value : 12; + UINT32 Reserved1: 1; + UINT32 dix_run_resolution : 3; + UINT32 dix_run_value_m1 : 12; + UINT32 Reserved2 : 1; + }; + UINT32 Reg; +} IPUx_DIx_SW_GEN0_x_REG; + +// IPUx_DIx_SW_GEN1_x_REG +typedef union { + struct { + UINT32 dix_cnt_up : 9; + UINT32 dix_cnt_polarity_clr_sel : 3; + UINT32 dix_cnt_polarity_trigger_sel : 3; + UINT32 Reserved1 : 1; + UINT32 dix_cnt_down: 9; + UINT32 dix_cnt_clr_sel : 3; + UINT32 dix_cnt_auto_reload : 1; + UINT32 dix_cnt_polarity_gen_en : 2; + UINT32 Reserved2 : 1; + }; + UINT32 Reg; +} IPUx_DIx_SW_GEN1_x_REG; + +// IPUx_DIx_STP_REP +typedef union { + struct { + UINT32 dix_step_repeat_2i_minus_1 : 12; + UINT32 Reserved1 : 4; + UINT32 dix_step_repeat_2i : 12; + UINT32 Reserved2 : 4; + }; + UINT32 Reg; +} IPUx_DIx_STP_REP_REG; + +// IPUx_DIx_POL +typedef union { + struct { + UINT32 dix_drdy_polarity : 7; + UINT32 DIx_DRDY_DATA_POLARITY : 1; + UINT32 dix_cs0_polarity : 7; + UINT32 DIx_CS0_DATA_POLARITY : 1; + UINT32 dix_cs1_polarity : 7; + UINT32 DIx_CS1_DATA_POLARITY : 1; + UINT32 DIx_CS0_BYTE_EN_POLARITY : 1; + UINT32 DIx_CS1_BYTE_EN_POLARITY : 1; + UINT32 DIx_WAIT_POLARITY : 1; + UINT32 Reserved : 5; + }; + UINT32 Reg; +} IPUx_DIx_POL_REG; + +#pragma pack(pop) + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.c b/Silicon/NXP/iMX6Pkg/D= rivers/GOP/Edid.c new file mode 100644 index 000000000000..85f8bd137963 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.c @@ -0,0 +1,82 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "Osal.h" +#include +#include "Display.h" +#include "Edid.h" +#include "Ddc.h" + +OS_STATUS ReadEDID ( + DISPLAY_CONTEXT* DisplayContextPtr, + DISPLAY_INTERFACE DisplayInterface, + UINT8* EdidDataPtr, + UINT32* EdidDataSizePtr) +{ + OS_STATUS status; + + status =3D IMX6DDCRead( + DisplayContextPtr, + DisplayInterface, + EDID_I2C_ADDRESS, + 0, + EDID_MIN_SIZE, + EdidDataPtr); + if (status !=3D OS_STATUS_SUCCESS) { + goto Exit; + } + + status =3D ValidateEdidData( + EdidDataPtr); + if (status !=3D OS_STATUS_SUCCESS) { + OS_WARNING("Invalid EDID data\n"); + goto Exit; + } + + OS_INFO("EDID initialized\n"); + + *EdidDataSizePtr =3D EDID_MIN_SIZE; + +Exit: + return status; +} + +OS_STATUS GetEDIDPreferedTiming ( + UINT8* EdidDataPtr, + UINT32 EdidDataSizePtr, + DISPLAY_TIMING* PreferedTiming +) +{ + OS_STATUS status; + DETAILED_TIMING_DESCRIPTOR* edidPreferedtiming; + + if (EdidDataSizePtr < EDID_MIN_SIZE) { + OS_WARNING("Insufficient EDID data\n"); + status =3D OS_STATUS_INVALID_PARAM; + goto Exit; + } + + edidPreferedtiming =3D + (DETAILED_TIMING_DESCRIPTOR*)&EdidDataPtr[EDID_DTD_1_OFFSET]; + + status =3D ConvertDTDToDisplayTiming(edidPreferedtiming, PreferedTimin= g); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Conversion to display timing failed\n"); + goto Exit; + } + +Exit: + + return status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.h b/Silicon/NXP/iMX6Pkg/D= rivers/GOP/Edid.h new file mode 100644 index 000000000000..578f938a304d --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Edid.h @@ -0,0 +1,31 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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_ + +OS_STATUS ReadEDID ( + DISPLAY_CONTEXT* DisplayContextPtr, + DISPLAY_INTERFACE DisplayInterface, + UINT8* EdidDataPtr, + UINT32* EdidDataSizePtr + ); + +OS_STATUS GetEDIDPreferedTiming ( + UINT8* EdidDataPtr, + UINT32 EdidDataSizePtr, + DISPLAY_TIMING* PreferedTiming + ); + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.c b/Silicon/NXP/iMX6Pkg/D= rivers/GOP/Hdmi.c new file mode 100644 index 000000000000..91901ea42b02 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.c @@ -0,0 +1,608 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "Osal.h" + +#include "Display.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 ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + UINT32 TimeOut + ) +{ + BOOLEAN waitResult =3D FALSE; + HDMI_IH_I2CMPHY_STAT0_REG I2cMPhyStat0Reg; + + do { + I2cMPhyStat0Reg.Reg =3D HDMIRead8(HDMI_IH_I2CMPHY_STAT0); + if (I2cMPhyStat0Reg.i2cmphydone) + { + waitResult =3D TRUE; + break; + } + + if (--TimeOut =3D=3D 0) + { + break; + } + + OS_SLEEP(1); + } while (I2cMPhyStat0Reg.i2cmphydone =3D=3D 0); + +#if DBG + if ((TimeOut =3D=3D 0) || (I2cMPhyStat0Reg.i2cmphyerror =3D=3D 1)) { + OS_ERROR( + "HDMI I2C failed value %x time out %d\n", + I2cMPhyStat0Reg.Reg, + TimeOut)); + } +#endif + + return waitResult; +} + +BOOLEAN HDMIPhyI2cRead ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + UINT8 Addr, + UINT16* DataPtr + ) +{ + BOOLEAN readStatus; + UINT16 data0, data1; + HDMI_IH_I2CMPHY_STAT0_REG I2cmPhyStat0Reg =3D { { 1, 1, 0 } }; + + HDMIWrite8(HDMI_IH_I2CMPHY_STAT0, I2cmPhyStat0Reg.Reg); + HDMIWrite8(HDMI_PHY_I2CM_ADDRESS_ADDR, Addr); + + { + HDMI_PHY_I2CM_OPERATION_ADDR_REG I2cmOperationReg; + + I2cmOperationReg.Reg =3D HDMIRead8(HDMI_PHY_I2CM_OPERATION_ADDR); + I2cmOperationReg.read =3D 1; + HDMIWrite8(HDMI_PHY_I2CM_OPERATION_ADDR, I2cmOperationReg.Reg); + } + + readStatus =3D HDMIPhyPollI2CDone(HdmiDisplayContextPtr, 1000); + if (!readStatus) { + OS_ERROR("Fail to read I2c HDMI Phy\n"); + goto Exit; + } + + data0 =3D HDMIRead8(HDMI_PHY_I2CM_DATAI_0_ADDR); + data1 =3D HDMIRead8(HDMI_PHY_I2CM_DATAI_1_ADDR); + + *DataPtr =3D data0 | (data1 << 8); + +Exit: + return readStatus; +} + +BOOLEAN HDMIPhyI2cWrite ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + UINT8 Addr, + UINT16 Data + ) +{ + UINT8 data1 =3D (Data >> 8); + UINT8 data0 =3D (Data & 0x00FF); + HDMI_IH_I2CMPHY_STAT0_REG I2cmPhyStat0Reg =3D { { 1, 1, 0 } }; + + HDMIWrite8(HDMI_IH_I2CMPHY_STAT0, I2cmPhyStat0Reg.Reg); + HDMIWrite8(HDMI_PHY_I2CM_ADDRESS_ADDR, Addr); + HDMIWrite8(HDMI_PHY_I2CM_DATAO_0_ADDR, data0); + HDMIWrite8(HDMI_PHY_I2CM_DATAO_1_ADDR, data1); + + { + HDMI_PHY_I2CM_OPERATION_ADDR_REG I2cmOperationReg =3D { { 0, 0, 0,= 0 } }; + + I2cmOperationReg.write =3D 1; + HDMIWrite8(HDMI_PHY_I2CM_OPERATION_ADDR, I2cmOperationReg.Reg); + } + + return HDMIPhyPollI2CDone(HdmiDisplayContextPtr, 1000); +} + +BOOLEAN GetGenericConfigSetting ( + DISPLAY_TIMING* DisplayTimingPtr, + PLL_MPLL_CONFIG** ConfigGenericSettingPPtr + ) +{ + BOOLEAN foundConfig =3D FALSE; + UINT32 settingIndex; + + for (settingIndex =3D 0; + settingIndex < ARRAYSIZE(PllMpllGenericConfigSetting); + ++settingIndex) { + + if ((DisplayTimingPtr->PixelClock =3D=3D + PllMpllGenericConfigSetting[settingIndex].PixelClock) && + (DisplayTimingPtr->PixelRepetition =3D=3D + PllMpllGenericConfigSetting[settingIndex].PixelRepetition)= && + (GetColorDepth(DisplayTimingPtr->PixelFormat) =3D=3D + PllMpllGenericConfigSetting[settingIndex].ColorDepth)) { + + foundConfig =3D TRUE; + *ConfigGenericSettingPPtr =3D &PllMpllGenericConfigSetting[set= tingIndex]; + break; + } + } + + // Use the fallback value the last index if no configuration is found + if (foundConfig =3D=3D FALSE) { + *ConfigGenericSettingPPtr =3D + &PllMpllGenericConfigSetting[ARRAYSIZE(PllMpllGenericConfigSet= ting)]; + foundConfig =3D TRUE; + } + + return foundConfig; +} + +OS_STATUS InitHDMI ( + DISPLAY_CONTEXT* DisplayContextPtr + ) +{ + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr =3D + &DisplayContextPtr->DIContext[HDMI_DISPLAY]; + OS_STATUS status =3D 0; + + OS_ZERO_MEM(HdmiDisplayContextPtr, sizeof(*HdmiDisplayContextPtr)); + + HdmiDisplayContextPtr->MmioBasePtr =3D (VOID*)OS_MMIO_MAP(HDMI_BASE); + if (HdmiDisplayContextPtr->MmioBasePtr =3D=3D NULL) { + OS_ERROR("Fail to map HDMI register\n"); + goto Exit; + } + + // Setup HDMI DDC muxing + OS_WRITE32(IOMUXC_SW_MUX_CTL_PAD_KEY_COL3, 0x00000012); + OS_WRITE32(IOMUXC_SW_MUX_CTL_PAD_KEY_ROW3, 0x00000012); + OS_WRITE32(IOMUXC_HDMI_II2C_CLKIN_SELECT_INPUT, 0x00000001); + OS_WRITE32(IOMUXC_HDMI_II2C_DATAIN_SELECT_INPUT, 0x00000001); + + SetHDMIPower(HdmiDisplayContextPtr, TRUE); + + // Mask all HDMI PHY interrupt + HDMIWrite8(HDMI_PHY_MASK0, 0xFF); + + status =3D ReadEDID( + DisplayContextPtr, + HDMI_DISPLAY, + HdmiDisplayContextPtr->EdidData, + &HdmiDisplayContextPtr->EdidDataSize); + if (status !=3D OS_STATUS_SUCCESS) { + OS_WARNING("Fail to read HDMI EDID data\n"); + status =3D OS_STATUS_SUCCESS; + } + + status =3D GetPreferedTiming( + HdmiDisplayContextPtr->EdidData, + HdmiDisplayContextPtr->EdidDataSize, + &HdmiDisplayContextPtr->PreferedTiming); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to retrieve HDMI prefered timing\n"); + goto Exit; + } + + if ((HdmiDisplayContextPtr->PreferedTiming.HActive =3D=3D 1920) && + (HdmiDisplayContextPtr->PreferedTiming.VActive =3D=3D 1080)) { + HdmiDisplayContextPtr->PreferedTiming.HBlank -=3D 6; + } + +Exit: + return status; +} + +OS_STATUS SetHDMIPower ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + BOOLEAN PowerState + ) +{ + HDMI_PHY_CONF0_REG CurrentHDMIPhyConf0; + + CurrentHDMIPhyConf0.Reg =3D HDMIRead8(HDMI_PHY_CONF0); + if (PowerState) { + // Setup PHY + CurrentHDMIPhyConf0.PDZ =3D 1; + CurrentHDMIPhyConf0.ENTMDS =3D 1; + CurrentHDMIPhyConf0.gen2_pddq =3D 1; + CurrentHDMIPhyConf0.gen2_txpwron =3D 1; + CurrentHDMIPhyConf0.seldataenpol =3D 1; + CurrentHDMIPhyConf0.seldipif =3D 0; + } else { + // Just power down PHY for shutdown + CurrentHDMIPhyConf0.PDZ =3D 0; + } + + HDMIWrite8(HDMI_PHY_CONF0, CurrentHDMIPhyConf0.Reg); + + OS_SLEEP(3); + + return OS_STATUS_SUCCESS; +} + +OS_STATUS SetHDMIPhy ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + DISPLAY_TIMING* Timings + ) +{ + OS_STATUS status; + HDMI_PHY_CONF0_REG CurrentHDMIPhyConf0; + PLL_MPLL_CONFIG* pllMpllConfig; + + // Disable Audio + { + HDMI_FC_AUDSCONF_REG fcAudsConf; + + fcAudsConf.Reg =3D HDMIRead8(HDMI_FC_AUDSCONF); + fcAudsConf.aud_packet_layout =3D 0; + HDMIWrite8(HDMI_FC_AUDSCONF, fcAudsConf.Reg); + } + + // Minimum PCLK period / frequency (pixel repetition) : 74 ns / 13.5 M= Hz + // Minimum PCLK period / frequency (no pixel repetition) : 39.7 ns / 2= 4.175 MHz + if(Timings->PixelClock < 13500000) { + OS_ERROR("Unsupported pixel clock %d\n", Timings->PixelClock); + status =3D OS_STATUS_INVALID_PARAM; + goto Exit; + } + + if (GetGenericConfigSetting(Timings, &pllMpllConfig) =3D=3D FALSE) { + OS_ERROR("No compatible generic config found\n"); + status =3D OS_STATUS_UNSUPPORTED; + goto Exit; + } + + // Color Space Converter : Not used in UEFI + { + HDMI_MC_CLKDIS_REG McClkdis; + + McClkdis.Reg =3D HDMIRead8(HDMI_MC_CLKDIS); + + // Disable CEC, color converter, audio & pixel repitition + McClkdis.cecclk_disable =3D 1; + McClkdis.cscclk_disable =3D 1; + McClkdis.audclk_disable =3D 1; + McClkdis.prepclk_disable =3D 1; + McClkdis.hdcpclk_disable =3D 1; + McClkdis.tmdsclk_disable =3D 0; + McClkdis.pixelclk_disable =3D 0; + + HDMIWrite8(HDMI_MC_CLKDIS, McClkdis.Reg); + } + + // Power down the PHY + // To set the HDMI_PHY in Power-down mode, set the TX_PWRON signal to = 1'b0 + // and the PDDQ signal to 1'b1. To power up the HDMI 3D Tx PHY and pla= ce it + // in Active mode, set TX_PWRON to 1'b1 and PDDQ to 1'b0. Any configur= ation + // programmed on the HDMI_PHY must be done in Power-down mode. + CurrentHDMIPhyConf0.Reg =3D HDMIRead8(HDMI_PHY_CONF0); + CurrentHDMIPhyConf0.gen2_txpwron =3D 0; + CurrentHDMIPhyConf0.gen2_pddq =3D 1; + HDMIWrite8(HDMI_PHY_CONF0, CurrentHDMIPhyConf0.Reg); + + // Let's reset the PHY to a well defined state based on spec. + // The PHY_RESET signal is used to place the digital section of the IP= in + // a well - defined state + { + HDMI_MC_PHYRSTZ_REG phyRstzReg; + HDMI_MC_HEACPHY_RST_REG heacphyRst; + + phyRstzReg.Reg =3D HDMIRead8(HDMI_MC_PHYRSTZ); + heacphyRst.Reg =3D HDMIRead8(HDMI_MC_HEACPHY_RST); + + phyRstzReg.phyrstz =3D 1; + HDMIWrite8(HDMI_MC_PHYRSTZ, phyRstzReg.Reg); + phyRstzReg.phyrstz =3D 0; + OS_SLEEP(10); + HDMIWrite8(HDMI_MC_PHYRSTZ, phyRstzReg.Reg); + + // Even though we dont currently support this, reset the ethernet = audio + // control too + heacphyRst.heacphyrst =3D 1; + HDMIWrite8(HDMI_MC_HEACPHY_RST, heacphyRst.Reg); + } + + // Program clock + // PLL / MPLL Operation + // The PLL / MPLL can be configured in Coherent mode or Non - Coherent= mode (default).In + // Coherent mode, the TMDS clock is the MPLL feedback clock, which is= coherent with the + // MPLL's high-speed output clock, because both clocks are shaped by = the MPLL response. + // In Non - Coherent mode, the TMDS clock is the MPLL reference clock= , which is not + // coherent with the MPLL's high-speed output clock. + if (HDMIPhyI2cWrite( + HdmiDisplayContextPtr, + HDMI_PHY_CPCE_CTRL, + pllMpllConfig->HdmiPhyCpceCtrl.Reg) =3D=3D 0) { + OS_ERROR("Fail to write to HDMI_PHY_CPCE_CTRL %x\n", + pllMpllConfig->HdmiPhyCpceCtrl.Reg); + status =3D OS_STATUS_DEVICE_ERROR; + goto Exit; + } + + if (HDMIPhyI2cWrite( + HdmiDisplayContextPtr, + HDMI_PHY_CURRCTRL, + pllMpllConfig->HdmiPhyCurrctrl.Reg) =3D=3D 0) { + OS_ERROR("Fail to write to HDMI_PHY_CURRCTRL\n"); + status =3D OS_STATUS_DEVICE_ERROR; + goto Exit; + }; + + if (HDMIPhyI2cWrite( + HdmiDisplayContextPtr, + HDMI_PHY_GMPCTRL, + pllMpllConfig->HdmiPhyGmpctrl.Reg) =3D=3D 0) { + OS_ERROR("Fail to write to HDMI_PHY_GMPCTRL\n"); + status =3D OS_STATUS_DEVICE_ERROR; + goto Exit; + } + + // Maintaining the order of phy register writes + if (HDMIPhyI2cWrite( + HdmiDisplayContextPtr, + HDMI_PHY_PLLPHBYCTRL, + 0x0000) =3D=3D 0) { + OS_ERROR("Fail to write to HDMI_PHY_PLLPHBYCTRL\n"); + status =3D OS_STATUS_DEVICE_ERROR; + goto Exit; + } + + // Coherent mode + if (HDMIPhyI2cWrite( + HdmiDisplayContextPtr, + HDMI_PHY_MSM_CTRL, + 0x0006) =3D=3D 0) { + OS_ERROR("Fail to write to HDMI_PHY_MSM_CTRL\n"); + status =3D OS_STATUS_DEVICE_ERROR; + goto Exit; + } + + // Resistance value 133.33 ohm + if (HDMIPhyI2cWrite( + HdmiDisplayContextPtr, + HDMI_PHY_TXTERM, + 0x0005) =3D=3D 0) { + OS_ERROR("Fail to write to HDMI_PHY_TXTERM\n"); + status =3D OS_STATUS_DEVICE_ERROR; + goto Exit; + } + + // Enable clock symbol + if (HDMIPhyI2cWrite( + HdmiDisplayContextPtr, + HDMI_PHY_CKSYMTXCTRL, + 0x8009) =3D=3D 0) { + OS_ERROR("Fail to write to HDMI_PHY_CKSYMTXCTRL\n"); + status =3D OS_STATUS_DEVICE_ERROR; + goto Exit; + } + + if (HDMIPhyI2cWrite( + HdmiDisplayContextPtr, + HDMI_PHY_VLEVCTRL, + 0x0210) =3D=3D 0) { + OS_ERROR("Fail to write to HDMI_PHY_VLEVCTRL\n"); + status =3D OS_STATUS_DEVICE_ERROR; + goto Exit; + } + + // Enable override + if (HDMIPhyI2cWrite( + HdmiDisplayContextPtr, + HDMI_PHY_CKCALCTRL, + 0x8000) =3D=3D 0) { + OS_ERROR("Fail to write to HDMI_PHY_CKCALCTRL\n"); + status =3D OS_STATUS_DEVICE_ERROR; + goto Exit; + } + + CurrentHDMIPhyConf0.gen2_txpwron =3D 1; + CurrentHDMIPhyConf0.gen2_pddq =3D 0; + HDMIWrite8(HDMI_PHY_CONF0, CurrentHDMIPhyConf0.Reg); + + { + HDMI_PHY_STAT0_REG phyStat0; + UINT32 poolTimeOut =3D 5; + + status =3D OS_STATUS_DEVICE_ERROR; + + do { + phyStat0.Reg =3D HDMIRead8(HDMI_PHY_STAT0); + + if (!phyStat0.TX_PHY_LOCK) { + status =3D OS_STATUS_SUCCESS; + break; + } + + OS_SLEEP(1000); + --poolTimeOut; + } while (poolTimeOut); + + if (poolTimeOut =3D=3D 0) { + OS_ERROR("TX PHY remain unlock\n"); + } + } + +Exit: + return status; +} + +OS_STATUS SetHDMIDisplay ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + DISPLAY_TIMING* Timings + ) +{ + OS_STATUS status; + + status =3D SetHDMIPhy(HdmiDisplayContextPtr, Timings); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("SetHDMIPhy failed\n"); + goto Exit; + } + +Exit: + return status; +} + +VOID SetDDCSpeed ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + DDC_MODE mode + ) +{ + HDMIWrite8(HDMI_I2CM_DIV, mode); +} + +OS_STATUS HDMIDDCRead ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + UINT8 SlaveAddress, + UINT8 RegisterAddress, + UINT32 ReadSize, + DDC_MODE DDCMode, + UINT8* DataReadPtr + ) +{ + OS_STATUS status; + UINT32 AddrCount; + UINT8* CurrentDataReadPtr =3D DataReadPtr; + + // Setup EDID transaction and loop through all byte request + SetDDCSpeed(HdmiDisplayContextPtr, DDCMode); + + HDMIWrite8(HDMI_IH_I2CM_STAT0, I2C_MASTER_ERROR | I2C_MASTER_DONE); + HDMIWrite8(HDMI_I2CM_SLAVE, SlaveAddress); + + for (AddrCount =3D 0; AddrCount < ReadSize; ++AddrCount) { + UINT32 i2CTimeOut =3D 1000; + + HDMIWrite8(HDMI_I2CM_ADDRESS, (UINT8)( RegisterAddress + AddrCount= )); + HDMIWrite8(HDMI_I2CM_SEGADDR, 0x00); + HDMIWrite8(HDMI_I2CM_OPERATION, DDC_READ_OPERATION); + + // Poll for completion + UINT8 i2CMIntStatus =3D HDMIRead8(HDMI_IH_I2CM_STAT0); + + while ((i2CMIntStatus =3D=3D 0) && (i2CTimeOut)) { + i2CMIntStatus =3D HDMIRead8(HDMI_IH_I2CM_STAT0); + --i2CTimeOut; + } + + if (i2CTimeOut =3D=3D 0) { + status =3D OS_STATUS_DEVICE_ERROR; + OS_ERROR("Timeout waiting for interrupt 0x%02x\n", i2CMIntStat= us); + goto Exit; + } + + if (i2CMIntStatus & I2C_MASTER_ERROR) { + status =3D OS_STATUS_DEVICE_ERROR; + OS_ERROR("Failed to read with DDC 0x%02x\n", i2CMIntStatus); + goto Exit; + } else if (i2CMIntStatus & I2C_MASTER_DONE) { + *CurrentDataReadPtr =3D HDMIRead8(HDMI_I2CM_DATAI); + CurrentDataReadPtr++; + } else { + status =3D OS_STATUS_DEVICE_ERROR; + OS_ERROR("Failed to read DDC unknown status 0x%02x\n", i2CMInt= Status); + goto Exit; + } + + HDMIWrite8(HDMI_IH_I2CM_STAT0, 0xFF); + } + + status =3D OS_STATUS_SUCCESS; + +Exit: + return status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.h b/Silicon/NXP/iMX6Pkg/D= rivers/GOP/Hdmi.h new file mode 100644 index 000000000000..f186f57105f7 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Hdmi.h @@ -0,0 +1,537 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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_ + +#define HDMIRead8(a) \ + OS_READ8((UINT32)HdmiDisplayContextPtr->MmioBasePtr + a) + +#define HDMIWrite8(a, b) \ + OS_WRITE8((UINT32)HdmiDisplayContextPtr->MmioBasePtr + a, b) + + +// HDMI Register Base Address +#define HDMI_BASE 0x00120000 + +// Interrupt Register Offset +#define HDMI_IH_FC_STAT0 0x0100 +#define HDMI_IH_FC_STAT1 0x0101 +#define HDMI_IH_FC_STAT2 0x0102 +#define HDMI_IH_AS_STAT0 0x0103 +#define HDMI_IH_PHY_STAT0 0x0104 +#define HDMI_IH_I2CM_STAT0 0x0105 +#define HDMI_IH_CEC_STAT0 0x0106 +#define HDMI_IH_VP_STAT0 0x0107 +#define HDMI_IH_I2CMPHY_STAT0 0x0108 +#define HDMI_IH_AHBDMAAUD_STAT0 0x0180 +#define HDMI_IH_MUTE_FC_STAT1 0x0181 +#define HDMI_IH_MUTE_FC_STAT2 0x0182 +#define HDMI_IH_MUTE_AS_STAT0 0x0183 +#define HDMI_IH_MUTE_PHY_STAT0 0x0184 +#define HDMI_IH_MUTE_I2CM_STAT0 0x0185 +#define HDMI_IH_MUTE_CEC_STAT0 0x0186 +#define HDMI_IH_MUTE_VP_STAT0 0x0187 +#define HDMI_IH_MUTE_I2CMPHY_STAT0 0x0188 +#define HDMI_IH_MUTE_AHBDMAAUD_STAT0 0x0189 +#define HDMI_IH_MUTE 0x01FF + +#define HDMI_FC_INVIDCONF 0x1000 +#define HDMI_FC_INHACTV0 0x1001 +#define HDMI_FC_INHACTV1 0x1002 +#define HDMI_FC_INHBLANK0 0x1003 +#define HDMI_FC_INHBLANK1 0x1004 +#define HDMI_FC_INVACTV0 0x1005 +#define HDMI_FC_INVACTV1 0x1006 +#define HDMI_FC_INVBLANK 0x1007 +#define HDMI_FC_HSYNCINDELAY0 0x1008 +#define HDMI_FC_HSYNCINDELAY1 0x1009 +#define HDMI_FC_HSYNCINWIDTH0 0x100A +#define HDMI_FC_HSYNCINWIDTH1 0x100B +#define HDMI_FC_VSYNCINDELAY 0x100C +#define HDMI_FC_VSYNCINWIDTH 0x100D +#define HDMI_FC_INFREQ0 0x100E +#define HDMI_FC_INFREQ1 0x100F +#define HDMI_FC_INFREQ2 0x1010 +#define HDMI_FC_CTRLDUR 0x1011 +#define HDMI_FC_EXCTRLDUR 0x1012 +#define HDMI_FC_EXCTRLSPAC 0x1013 +#define HDMI_FC_CH0PREAM 0x1014 +#define HDMI_FC_CH1PREAM 0x1015 +#define HDMI_FC_CH2PREAM 0x1016 +#define HDMI_FC_AVICONF3 0x1017 +#define HDMI_FC_GCP 0x1018 +#define HDMI_FC_AVICONF0 0x1019 +#define HDMI_FC_AVICONF1 0x101A +#define HDMI_FC_AVICONF2 0x101B +#define HDMI_FC_AVIVID 0x101C +#define HDMI_FC_AVIETB0 0x101D +#define HDMI_FC_AVIETB1 0x101E +#define HDMI_FC_AVISBB0 0x101F +#define HDMI_FC_AVISBB1 0x1020 +#define HDMI_FC_AVIELB0 0x1021 +#define HDMI_FC_AVIELB1 0x1022 +#define HDMI_FC_AVISRB0 0x1023 +#define HDMI_FC_AVISRB1 0x1024 +#define HDMI_FC_AUDICONF0 0x1025 +#define HDMI_FC_AUDICONF1 0x1026 +#define HDMI_FC_AUDICONF2 0x1027 +#define HDMI_FC_AUDICONF3 0x1028 +#define HDMI_FC_VSDIEEEID0 0x1029 +#define HDMI_FC_VSDSIZE 0x102A +#define HDMI_FC_VSDIEEEID1 0x1030 +#define HDMI_FC_VSDIEEEID2 0x1031 +#define HDMI_FC_VSDPAYLOAD0 0x1032 +#define HDMI_FC_VSDPAYLOAD1 0x1033 +#define HDMI_FC_VSDPAYLOAD2 0x1034 +#define HDMI_FC_VSDPAYLOAD3 0x1035 +#define HDMI_FC_VSDPAYLOAD4 0x1036 +#define HDMI_FC_VSDPAYLOAD5 0x1037 +#define HDMI_FC_VSDPAYLOAD6 0x1038 +#define HDMI_FC_VSDPAYLOAD7 0x1039 +#define HDMI_FC_VSDPAYLOAD8 0x103A +#define HDMI_FC_VSDPAYLOAD9 0x103B +#define HDMI_FC_VSDPAYLOAD10 0x103C +#define HDMI_FC_VSDPAYLOAD11 0x103D +#define HDMI_FC_VSDPAYLOAD12 0x103E +#define HDMI_FC_VSDPAYLOAD13 0x103F +#define HDMI_FC_VSDPAYLOAD14 0x1040 +#define HDMI_FC_VSDPAYLOAD15 0x1041 +#define HDMI_FC_VSDPAYLOAD16 0x1042 +#define HDMI_FC_VSDPAYLOAD17 0x1043 +#define HDMI_FC_VSDPAYLOAD18 0x1044 +#define HDMI_FC_VSDPAYLOAD19 0x1045 +#define HDMI_FC_VSDPAYLOAD20 0x1046 +#define HDMI_FC_VSDPAYLOAD21 0x1047 +#define HDMI_FC_VSDPAYLOAD22 0x1048 +#define HDMI_FC_VSDPAYLOAD23 0x1049 +#define HDMI_FC_SPDVENDORNAME0 0x104A +#define HDMI_FC_SPDVENDORNAME1 0x104B +#define HDMI_FC_SPDVENDORNAME2 0x104C +#define HDMI_FC_SPDVENDORNAME3 0x104D +#define HDMI_FC_SPDVENDORNAME4 0x104E +#define HDMI_FC_SPDVENDORNAME5 0x104F +#define HDMI_FC_SPDVENDORNAME6 0x1050 +#define HDMI_FC_SPDVENDORNAME7 0x1051 +#define HDMI_FC_SDPPRODUCTNAME0 0x1052 +#define HDMI_FC_SDPPRODUCTNAME1 0x1053 +#define HDMI_FC_SDPPRODUCTNAME2 0x1054 +#define HDMI_FC_SDPPRODUCTNAME3 0x1055 +#define HDMI_FC_SDPPRODUCTNAME4 0x1056 +#define HDMI_FC_SDPPRODUCTNAME5 0x1057 +#define HDMI_FC_SDPPRODUCTNAME6 0x1058 +#define HDMI_FC_SDPPRODUCTNAME7 0x1059 +#define HDMI_FC_SDPPRODUCTNAME8 0x105A +#define HDMI_FC_SDPPRODUCTNAME9 0x105B +#define HDMI_FC_SDPPRODUCTNAME10 0x105C +#define HDMI_FC_SDPPRODUCTNAME11 0x105D +#define HDMI_FC_SDPPRODUCTNAME12 0x105E +#define HDMI_FC_SDPPRODUCTNAME13 0x105F +#define HDMI_FC_SDPPRODUCTNAME14 0x1060 +#define HDMI_FC_SPDPRODUCTNAME15 0x1061 +#define HDMI_FC_SPDDEVICEINF 0x1062 +#define HDMI_FC_AUDSCONF 0x1063 +#define HDMI_FC_AUDSSTAT 0x1064 +#define HDMI_FC_AUDSV 0x1065 +#define HDMI_FC_AUDSU 0x1066 +#define HDMI_FC_AUDSCHNLS0 0x1067 +#define HDMI_FC_AUDSCHNLS1 0x1068 +#define HDMI_FC_AUDSCHNLS2 0x1069 +#define HDMI_FC_AUDSCHNLS3 0x106A +#define HDMI_FC_AUDSCHNLS4 0x106B +#define HDMI_FC_AUDSCHNLS5 0x106C +#define HDMI_FC_AUDSCHNLS6 0x106D +#define HDMI_FC_AUDSCHNLS7 0x106E +#define HDMI_FC_AUDSCHNLS8 0x106F +#define HDMI_FC_DATACH0FILL 0x1070 +#define HDMI_FC_DATACH1FILL 0x1071 +#define HDMI_FC_DATACH2FILL 0x1072 +#define HDMI_FC_CTRLQHIGH 0x1073 +#define HDMI_FC_CTRLQLOW 0x1074 +#define HDMI_FC_ACP0 0x1075 +#define HDMI_FC_ACP28 0x1076 +#define HDMI_FC_ACP27 0x1077 +#define HDMI_FC_ACP26 0x1078 +#define HDMI_FC_ACP25 0x1079 +#define HDMI_FC_ACP24 0x107A +#define HDMI_FC_ACP23 0x107B +#define HDMI_FC_ACP22 0x107C +#define HDMI_FC_ACP21 0x107D +#define HDMI_FC_ACP20 0x107E +#define HDMI_FC_ACP19 0x107F +#define HDMI_FC_ACP18 0x1080 +#define HDMI_FC_ACP17 0x1081 +#define HDMI_FC_ACP16 0x1082 +#define HDMI_FC_ACP15 0x1083 +#define HDMI_FC_ACP14 0x1084 +#define HDMI_FC_ACP13 0x1085 +#define HDMI_FC_ACP12 0x1086 +#define HDMI_FC_ACP11 0x1087 +#define HDMI_FC_ACP10 0x1088 +#define HDMI_FC_ACP9 0x1089 +#define HDMI_FC_ACP8 0x108A +#define HDMI_FC_ACP7 0x108B +#define HDMI_FC_ACP6 0x108C +#define HDMI_FC_ACP5 0x108D +#define HDMI_FC_ACP4 0x108E +#define HDMI_FC_ACP3 0x108F +#define HDMI_FC_ACP2 0x1090 +#define HDMI_FC_ACP1 0x1091 +#define HDMI_FC_ISCR1_0 0x1092 +#define HDMI_FC_ISCR1_16 0x1093 +#define HDMI_FC_ISCR1_15 0x1094 +#define HDMI_FC_ISCR1_14 0x1095 +#define HDMI_FC_ISCR1_13 0x1096 +#define HDMI_FC_ISCR1_12 0x1097 +#define HDMI_FC_ISCR1_11 0x1098 +#define HDMI_FC_ISCR1_10 0x1099 +#define HDMI_FC_ISCR1_9 0x109A +#define HDMI_FC_ISCR1_8 0x109B +#define HDMI_FC_ISCR1_7 0x109C +#define HDMI_FC_ISCR1_6 0x109D +#define HDMI_FC_ISCR1_5 0x109E +#define HDMI_FC_ISCR1_4 0x109F +#define HDMI_FC_ISCR1_3 0x10A0 +#define HDMI_FC_ISCR1_2 0x10A1 +#define HDMI_FC_ISCR1_1 0x10A2 +#define HDMI_FC_ISCR2_15 0x10A3 +#define HDMI_FC_ISCR2_14 0x10A4 +#define HDMI_FC_ISCR2_13 0x10A5 +#define HDMI_FC_ISCR2_12 0x10A6 +#define HDMI_FC_ISCR2_11 0x10A7 +#define HDMI_FC_ISCR2_10 0x10A8 +#define HDMI_FC_ISCR2_9 0x10A9 +#define HDMI_FC_ISCR2_8 0x10AA +#define HDMI_FC_ISCR2_7 0x10AB +#define HDMI_FC_ISCR2_6 0x10AC +#define HDMI_FC_ISCR2_5 0x10AD +#define HDMI_FC_ISCR2_4 0x10AE +#define HDMI_FC_ISCR2_3 0x10AF +#define HDMI_FC_ISCR2_2 0x10B0 +#define HDMI_FC_ISCR2_1 0x10B1 +#define HDMI_FC_ISCR2_0 0x10B2 +#define HDMI_FC_DATAUTO0 0x10B3 +#define HDMI_FC_DATAUTO1 0x10B4 +#define HDMI_FC_DATAUTO2 0x10B5 +#define HDMI_FC_DATMAN 0x10B6 +#define HDMI_FC_DATAUTO3 0x10B7 +#define HDMI_FC_RDRB0 0x10B8 +#define HDMI_FC_RDRB1 0x10B9 +#define HDMI_FC_RDRB2 0x10BA +#define HDMI_FC_RDRB3 0x10BB +#define HDMI_FC_RDRB4 0x10BC +#define HDMI_FC_RDRB5 0x10BD +#define HDMI_FC_RDRB6 0x10BE +#define HDMI_FC_RDRB7 0x10BF +#define HDMI_FC_STAT0 0x10D0 +#define HDMI_FC_INT0 0x10D1 +#define HDMI_FC_MASK0 0x10D2 +#define HDMI_FC_POL0 0x10D3 +#define HDMI_FC_STAT1 0x10D4 +#define HDMI_FC_INT1 0x10D5 +#define HDMI_FC_MASK1 0x10D6 +#define HDMI_FC_POL1 0x10D7 +#define HDMI_FC_STAT2 0x10D8 +#define HDMI_FC_INT2 0x10D9 +#define HDMI_FC_MASK2 0x10DA +#define HDMI_FC_POL2 0x10DB +#define HDMI_FC_PRCONF 0x10E0 + +// HDMI PHY Register Offset +#define HDMI_PHY_CONF0 0x3000 +#define HDMI_PHY_TST0 0x3001 +#define HDMI_PHY_TST1 0x3002 +#define HDMI_PHY_TST2 0x3003 +#define HDMI_PHY_STAT0 0x3004 +#define HDMI_PHY_INT0 0x3005 +#define HDMI_PHY_MASK0 0x3006 +#define HDMI_PHY_POL0 0x3007 +#define HDMI_PHY_I2CM_SLAVE_ADDR 0x3020 +#define HDMI_PHY_I2CM_ADDRESS_ADDR 0x3021 +#define HDMI_PHY_I2CM_DATAO_1_ADDR 0x3022 +#define HDMI_PHY_I2CM_DATAO_0_ADDR 0x3023 +#define HDMI_PHY_I2CM_DATAI_1_ADDR 0x3024 +#define HDMI_PHY_I2CM_DATAI_0_ADDR 0x3025 +#define HDMI_PHY_I2CM_OPERATION_ADDR 0x3026 +#define HDMI_PHY_I2CM_INT_ADDR 0x3027 +#define HDMI_PHY_I2CM_CTLINT_ADDR 0x3028 +#define HDMI_PHY_I2CM_DIV_ADDR 0x3029 +#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR 0x302a +#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR 0x302b +#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR 0x302c +#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR 0x302d +#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR 0x302e +#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR 0x302f +#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR 0x3030 +#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR 0x3031 +#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR 0x3032 + +// Main Controller Registers +#define HDMI_MC_CLKDIS 0x4001 +#define HDMI_MC_SWRSTZ 0x4002 +#define HDMI_MC_OPCTRL 0x4003 +#define HDMI_MC_FLOWCTRL 0x4004 +#define HDMI_MC_PHYRSTZ 0x4005 +#define HDMI_MC_LOCKONCLOCK 0x4006 +#define HDMI_MC_HEACPHY_RST 0x4007 + +// HDMI_PHY absolute address +#define HDMI_PHY_PWRCTRL 0x00 +#define HDMI_PHY_SERDIVCTRL 0x01 +#define HDMI_PHY_SERCKCTRL 0x02 +#define HDMI_PHY_SERCKKILLCTRL 0x03 +#define HDMI_PHY_TXRESCTRL 0x04 +#define HDMI_PHY_CKCALCTRL 0x05 +#define HDMI_PHY_CPCE_CTRL 0x06 +#define HDMI_PHY_TXCLKMEASCTRL 0x07 +#define HDMI_PHY_TXMEASCTRL 0x08 +#define HDMI_PHY_CKSYMTXCTRL 0x09 +#define HDMI_PHY_CMPSEQCTRL 0x0A +#define HDMI_PHY_CMPPWRCTRL 0x0B +#define HDMI_PHY_CMPMODECTRL 0x0C +#define HDMI_PHY_MEASCTRL 0x0D +#define HDMI_PHY_VLEVCTRL 0x0E +#define HDMI_PHY_D2ACTRL 0x0F +#define HDMI_PHY_CURRCTRL 0x10 +#define HDMI_PHY_DRVANACTRL 0x11 +#define HDMI_PHY_PLLMEASCTRL 0x12 +#define HDMI_PHY_PLLPHBYCTRL 0x13 +#define HDMI_PHY_GRP_CTRL 0x14 +#define HDMI_PHY_GMPCTRL 0x15 +#define HDMI_PHY_MPLLMEASCTRL 0x16 +#define HDMI_PHY_MSM_CTRL 0x17 +#define HDMI_PHY_SCRPB_STATUS 0x18 +#define HDMI_PHY_TXTERM 0x19 +#define HDMI_PHY_PTRPT_ENBL 0x1A +#define HDMI_PHY_PATTERNGEN 0x1B +#define HDMI_PHY_SDCAP_MODE 0x1C +#define HDMI_PHY_SCOPEMODE 0x1D +#define HDMI_PHY_DIGTXMODE 0x1E +#define HDMI_PHY_STR_STATUS 0x1F +#define HDMI_PHY_SCOPECNT0 0x20 +#define HDMI_PHY_SCOPECNT1 0x21 +#define HDMI_PHY_SCOPECNT2 0x22 +#define HDMI_PHY_SCOPECNTCLK 0x23 +#define HDMI_PHY_SCOPESAMPLE 0x24 +#define HDMI_PHY_SCOPECNTMSB01 0x25 +#define HDMI_PHY_SCOPECNTMSB2CK 0x26 + +// Register struct + +#pragma pack(push, 1) + +// HDMI_PHY_CONF0 0x0100 +typedef union { + struct { + UINT8 seldipif : 1; + UINT8 seldataenpol : 1; + UINT8 gen2_enhpdrxsense : 1; + UINT8 gen2_txpwron : 1; + UINT8 gen2_pddq : 1; + UINT8 sparectrl : 1; + UINT8 ENTMDS : 1; + UINT8 PDZ : 1; + }; + UINT8 Reg; +} HDMI_PHY_CONF0_REG; + +// HDMI_IH_I2CMPHY_STAT0 0x0108 +typedef union { + struct { + UINT8 i2cmphyerror : 1; + UINT8 i2cmphydone : 1; + UINT8 reserved : 6; + }; + UINT8 Reg; +} HDMI_IH_I2CMPHY_STAT0_REG; + +// HDMI_FC_AUDSCONF 0x01063 +typedef union { + struct { + UINT8 aud_packet_layout : 1; + UINT8 reserved : 4; + UINT8 aud_packet_sampfit : 4; + }; + UINT8 Reg; +} HDMI_FC_AUDSCONF_REG; + +// HDMI_PHY_STAT0 0x3004 +typedef union { + struct { + UINT8 TX_PHY_LOCK : 1; + UINT8 HPD : 1; + UINT8 reserved : 2; + UINT8 RX_SENSE0 : 1; + UINT8 RX_SENSE1 : 1; + UINT8 RX_SENSE2 : 1; + UINT8 RX_SENSE3 : 1; + }; + UINT8 Reg; + +} HDMI_PHY_STAT0_REG; + +// HDMI_PHY_I2CM_OPERATION_ADDR 0x3026 +typedef union { + struct { + UINT8 read : 1; + UINT8 reserved0 : 3; + UINT8 write : 1; + UINT8 reserved1 : 3; + }; + UINT8 Reg; +} HDMI_PHY_I2CM_OPERATION_ADDR_REG; + +// HDMI_MC_CLKDIS 0x4001 +typedef union { + struct { + UINT8 pixelclk_disable : 1; + UINT8 tmdsclk_disable : 1; + UINT8 prepclk_disable : 1; + UINT8 audclk_disable : 1; + UINT8 cscclk_disable : 1; + UINT8 cecclk_disable : 1; + UINT8 hdcpclk_disable : 1; + UINT8 reserved : 1; + }; + UINT8 Reg; +} HDMI_MC_CLKDIS_REG; + +// HDMI_MC_PHYRSTZ 0x4005 +typedef union { + struct { + UINT8 phyrstz : 1; + UINT8 reserved : 7; + }; + UINT8 Reg; +} HDMI_MC_PHYRSTZ_REG; + +// HDMI_MC_HEACPHY_RST 0x4007 +typedef union { + struct { + UINT8 heacphyrst : 1; + UINT8 reserved : 7; + }; + UINT8 Reg; +} HDMI_MC_HEACPHY_RST_REG; + +// HDMI PHY : HDMI_PHY_CPCE_CTRL 0x06 +typedef union { + struct { + UINT16 clr_dpth : 2; + UINT16 pixel_rep : 3; + UINT16 pll_n_cntrl : 2; + UINT16 mpll_n_cntrl : 2; + UINT16 ck_edgerate : 2; + UINT16 tx_edgerate : 2; + UINT16 prep_div : 2; + UINT16 reserved : 1; + }; + UINT16 Reg; +} HDMI_PHY_CPCE_CTRL_REG; + +// HDMI PHY : HDMI_PHY_CURRCTRL 0x10 +typedef union { + struct { + UINT16 pll_int_cntrl : 3; + UINT16 pll_prop_cntrl : 3; + UINT16 mpll_int_cntrl : 3; + UINT16 mpll_prop_cntrl : 3; + UINT16 reserved : 4; + }; + UINT16 Reg; +} HDMI_PHY_CURRCTRL_REG; + +// HDMI PHY : HDMI_PHY_GMPCTRL 0x15 +typedef union { + struct { + UINT16 mpll_gmp_cntrl : 2; + UINT16 pll_gmp_cntrl : 2; + UINT16 reserved : 12; + }; + UINT16 Reg; +} HDMI_PHY_GMPCTRL_REG; + +#pragma pack(pop) + +// HDMI DDC offset +#define HDMI_I2CM_SLAVE 0x7E00 +#define HDMI_I2CM_ADDRESS 0x7E01 +#define HDMI_I2CM_DATAO 0x7E02 +#define HDMI_I2CM_DATAI 0x7E03 +#define HDMI_I2CM_OPERATION 0x7E04 +#define HDMI_I2CM_INT 0x7E05 +#define HDMI_I2CM_CTLINT 0x7E06 +#define HDMI_I2CM_DIV 0x7E07 +#define HDMI_I2CM_SEGADDR 0x7E08 +#define HDMI_I2CM_SOFTRSTZ 0x7E09 +#define HDMI_I2CM_SEGPTR 0x7E0A +#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR 0x7E0B +#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR 0x7E0C +#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR 0x7E0D +#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR 0x7E0E +#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR 0x7E0F +#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR 0x7E10 +#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR 0x7E11 +#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12 + +// DDC Interrupt status +#define I2C_MASTER_ERROR 0x01 +#define I2C_MASTER_DONE 0x02 + +// HDMI bit configuration +typedef enum +{ + DDC_READ_OPERATION =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; + +typedef struct _PLL_MPLL_CONFIG { + UINT32 PixelClock; + UINT8 PixelRepetition; + UINT8 ColorDepth; + HDMI_PHY_CPCE_CTRL_REG HdmiPhyCpceCtrl; + HDMI_PHY_CURRCTRL_REG HdmiPhyCurrctrl; + HDMI_PHY_GMPCTRL_REG HdmiPhyGmpctrl; +}PLL_MPLL_CONFIG, *PPLL_MPLL_CONFIG; + +OS_STATUS InitHDMI ( + DISPLAY_CONTEXT* DisplayContextPtr + ); + +OS_STATUS SetHDMIPower ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + BOOLEAN PowerState + ); + +OS_STATUS SetHDMIDisplay ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + DISPLAY_TIMING* Timings + ); + +OS_STATUS HDMIDDCRead ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + UINT8 SlaveAddress, + UINT8 RegisterAddress, + UINT32 ReadSize, + DDC_MODE DDCMode, + UINT8* DataReadPtr); + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.c b/Silicon/NXP/iMX6Pkg/= Drivers/GOP/IoMux.c new file mode 100644 index 000000000000..7e5d575922a2 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.c @@ -0,0 +1,83 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright 2018 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "Osal.h" +#include "Display.h" +#include "IoMux.h" + +OS_STATUS SetupDisplayMux ( + DISPLAY_CONTEXT* DisplayContextPtr + ) +{ + OS_STATUS status; + DISPLAY_MODE displayMode =3D DisplayContextPtr->DisplayConfig.DisplayM= ode; + DISPLAY_INTERFACE* displayInterface =3D + DisplayContextPtr->DisplayConfig.DIOrder; + UINT32 regGPR3, sourceMask, sourceVal, dIIndex; + volatile IMX_IOMUXC_GPR_REGISTERS* ioMuxcGprRegisters =3D + DisplayContextPtr->IoMuxMmioBasePtr; + + regGPR3 =3D + OS_READ32(&ioMuxcGprRegisters->GPR3); + + regGPR3 &=3D ~(HDMI_MUX_CTL_MASK | + MIPI_MUX_CTL_MASK | + LVDS0_MUX_CTL_MASK | + LVDS1_MUX_CTL_MASK); + + OS_WRITE32( + &ioMuxcGprRegisters->GPR3, + regGPR3); + + for (dIIndex =3D 0; dIIndex < (UINT32)displayMode; ++dIIndex) { + regGPR3 =3D + OS_READ32(&ioMuxcGprRegisters->GPR3); + + switch (displayInterface[dIIndex]) + { + case HDMI_DISPLAY: + sourceMask =3D HDMI_MUX_CTL_MASK; + sourceVal =3D dIIndex << HDMI_MUX_CTL_OFFSET; + break; + case MIPI_DISPLAY: + sourceMask =3D MIPI_MUX_CTL_MASK; + sourceVal =3D dIIndex << MIPI_MUX_CTL_OFFSET; + break; + case LVDS0_DISPLAY: + sourceMask =3D LVDS0_MUX_CTL_MASK; + sourceVal =3D dIIndex << LVDS0_MUX_CTL_OFFSET; + break; + case LVDS1_DISPLAY: + sourceMask =3D LVDS1_MUX_CTL_MASK; + sourceVal =3D dIIndex << LVDS1_MUX_CTL_OFFSET; + break; + default: + status =3D OS_STATUS_UNSUPPORTED; + goto Exit; + } + + regGPR3 &=3D ~sourceMask; + regGPR3 |=3D sourceVal; + + OS_WRITE32( + &ioMuxcGprRegisters->GPR3, + regGPR3); + } + + status =3D OS_STATUS_SUCCESS; + +Exit: + return status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.h b/Silicon/NXP/iMX6Pkg/= Drivers/GOP/IoMux.h new file mode 100644 index 000000000000..5755b03ef8db --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/IoMux.h @@ -0,0 +1,31 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 + +OS_STATUS SetupDisplayMux ( + DISPLAY_CONTEXT* DisplayContextPtr + ); + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ipu.h b/Silicon/NXP/iMX6Pkg/Dr= ivers/GOP/Ipu.h new file mode 100644 index 000000000000..7fdb118c99be --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Ipu.h @@ -0,0 +1,236 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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) \ + OS_READ32(((unsigned char*)IPU_BASE + OFFSET)) + +#define IpuWrite32(IPU_BASE, OFFSET, VALUE) \ + OS_WRITE32(((unsigned char*)IPU_BASE + OFFSET), VALUE) + +#define DiRead32(DI_BASE, OFFSET) \ + OS_READ32(((unsigned char*)DI_BASE + OFFSET)) + +#define DiWrite32(DI_BASE, OFFSET, VALUE) \ + OS_WRITE32(((unsigned char*)DI_BASE + OFFSET), VALUE) + +// IPU Registers +#define IPU_IPU_CONF_OFFSET 0x00000000 +#define IPU_SISG_CTRL0_OFFSET 0x00000004 +#define IPU_SISG_CTRL1_OFFSET 0x00000008 +#define IPU_SISG_SET_OFFSET 0x0000000C +#define IPU_SISG_CLR_OFFSET 0x00000024 +#define IPU_IPU_INT_CTRL_1_OFFSET 0x0000003C +#define IPU_IPU_INT_CTRL_2_OFFSET 0x00000040 +#define IPU_IPU_INT_CTRL_3_OFFSET 0x00000044 +#define IPU_IPU_INT_CTRL_4_OFFSET 0x00000048 +#define IPU_IPU_INT_CTRL_5_OFFSET 0x0000004C +#define IPU_IPU_INT_CTRL_6_OFFSET 0x00000050 +#define IPU_IPU_INT_CTRL_7_OFFSET 0x00000054 +#define IPU_IPU_INT_CTRL_8_OFFSET 0x00000058 +#define IPU_IPU_INT_CTRL_9_OFFSET 0x0000005C +#define IPU_IPU_INT_CTRL_10_OFFSET 0x00000060 +#define IPU_IPU_INT_CTRL_11_OFFSET 0x00000064 +#define IPU_IPU_INT_CTRL_12_OFFSET 0x00000068 +#define IPU_IPU_INT_CTRL_13_OFFSET 0x0000006C +#define IPU_IPU_INT_CTRL_14_OFFSET 0x00000070 +#define IPU_IPU_INT_CTRL_15_OFFSET 0x00000074 +#define IPU_IPU_SDMA_EVENT_1_OFFSET 0x00000078 +#define IPU_IPU_SDMA_EVENT_2_OFFSET 0x0000007C +#define IPU_IPU_SDMA_EVENT_3_OFFSET 0x00000080 +#define IPU_IPU_SDMA_EVENT_4_OFFSET 0x00000084 +#define IPU_IPU_SDMA_EVENT_7_OFFSET 0x00000088 +#define IPU_IPU_SDMA_EVENT_8_OFFSET 0x0000008C +#define IPU_IPU_SDMA_EVENT_11_OFFSET 0x00000090 +#define IPU_IPU_SDMA_EVENT_12_OFFSET 0x00000094 +#define IPU_IPU_SDMA_EVENT_13_OFFSET 0x00000098 +#define IPU_IPU_SDMA_EVENT_14_OFFSET 0x0000009C +#define IPU_IPU_SRM_PRI1_OFFSET 0x000000A0 +#define IPU_IPU_SRM_PRI2_OFFSET 0x000000A4 +#define IPU_IPU_FS_PROC_FLOW1_OFFSET 0x000000A8 +#define IPU_IPU_FS_PROC_FLOW2_OFFSET 0x000000AC +#define IPU_IPU_FS_PROC_FLOW3_OFFSET 0x000000B0 +#define IPU_IPU_FS_DISP_FLOW1_OFFSET 0x000000B4 +#define IPU_IPU_FS_DISP_FLOW2_OFFSET 0x000000B8 +#define IPU_IPU_SKIP_OFFSET 0x000000BC +#define IPU_IPU_DISP_ALT_CONF_OFFSET 0x000000C0 +#define IPU_IPU_DISP_GEN_OFFSET 0x000000C4 +#define IPU_IPU_DISP_ALT1_OFFSET 0x000000C8 +#define IPU_IPU_DISP_ALT2_OFFSET 0x000000CC +#define IPU_IPU_DISP_ALT3_OFFSET 0x000000D0 +#define IPU_IPU_DISP_ALT4_OFFSET 0x000000D4 +#define IPU_IPU_SNOOP_OFFSET 0x000000D8 +#define IPU_IPU_MEM_RST_OFFSET 0x000000DC +#define IPU_IPU_PM_OFFSET 0x000000E0 +#define IPU_IPU_GPR_OFFSET 0x000000E4 +#define IPU_IPU_INT_STAT_1_OFFSET 0x000000E8 +#define IPU_IPU_INT_STAT_2_OFFSET 0x000000EC +#define IPU_IPU_INT_STAT_3_OFFSET 0x000000F0 +#define IPU_IPU_INT_STAT_4_OFFSET 0x000000F4 +#define IPU_IPU_INT_STAT_5_OFFSET 0x000000F8 +#define IPU_IPU_INT_STAT_6_OFFSET 0x000000FC +#define IPU_IPU_INT_STAT_7_OFFSET 0x00000100 +#define IPU_IPU_INT_STAT_8_OFFSET 0x00000104 +#define IPU_IPU_INT_STAT_9_OFFSET 0x00000108 +#define IPU_IPU_INT_STAT_10_OFFSET 0x0000010C +#define IPU_IPU_INT_STAT_11_OFFSET 0x00000110 +#define IPU_IPU_INT_STAT_12_OFFSET 0x00000114 +#define IPU_IPU_INT_STAT_13_OFFSET 0x00000118 +#define IPU_IPU_INT_STAT_14_OFFSET 0x0000011C +#define IPU_IPU_INT_STAT_15_OFFSET 0x00000120 +#define IPU_IPU_CUR_BUF_0_OFFSET 0x00000124 +#define IPU_IPU_CUR_BUF_1_OFFSET 0x00000128 +#define IPU_IPU_ALT_CUR_BUF_0_OFFSET 0x0000012C +#define IPU_IPU_ALT_CUR_BUF_1_OFFSET 0x00000130 +#define IPU_IPU_SRM_STAT_OFFSET 0x00000134 +#define IPU_IPU_PROC_TASKS_STAT_OFFSET 0x00000138 +#define IPU_IPU_DISP_TASKS_STAT_OFFSET 0x0000013C +#define IPU_IPU_CH_BUF0_RDY0_OFFSET 0x00000140 +#define IPU_IPU_CH_BUF0_RDY1_OFFSET 0x00000144 +#define IPU_IPU_CH_BUF1_RDY0_OFFSET 0x00000148 +#define IPU_IPU_CH_BUF1_RDY1_OFFSET 0x0000014C +#define IPU_IPU_CH_DB_MODE_SEL0_OFFSET 0x00000150 +#define IPU_IPU_CH_DB_MODE_SEL1_OFFSET 0x00000154 +#define IPU_IPU_ALT_CH_BUF0_RDY0_OFFSET 0x00000158 +#define IPU_IPU_ALT_CH_BUF0_RDY1_OFFSET 0x0000015C +#define IPU_IPU_ALT_CH_BUF1_RDY0_OFFSET 0x00000160 +#define IPU_IPU_ALT_CH_BUF1_RDY1_OFFSET 0x00000164 +#define IPU_IPU_ALT_CH_DB_MODE_SEL0_OFFSET 0x00000168 +#define IPU_IPU_ALT_CH_DB_MODE_SEL1_OFFSET 0x0000016C +#define CSP_IPUV3_CPMEM_REGS_OFFSET 0x00100000 + +// IPU DIx Registers +#define IPU_DIx_GENERAL_OFFSET 0x00000000 +#define IPU_DIx_BS_CLKGEN0_OFFSET 0x00000004 +#define IPU_DIx_BS_CLKGEN1_OFFSET 0x00000008 +#define IPU_DIx_SW_GEN0_1_OFFSET 0x0000000C +#define IPU_DIx_SW_GEN0_2_OFFSET 0x00000010 +#define IPU_DIx_SW_GEN0_3_OFFSET 0x00000014 +#define IPU_DIx_SW_GEN0_4_OFFSET 0x00000018 +#define IPU_DIx_SW_GEN0_5_OFFSET 0x0000001C +#define IPU_DIx_SW_GEN0_6_OFFSET 0x00000020 +#define IPU_DIx_SW_GEN0_7_OFFSET 0x00000024 +#define IPU_DIx_SW_GEN0_8_OFFSET 0x00000028 +#define IPU_DIx_SW_GEN0_9_OFFSET 0x0000002C +#define IPU_DIx_SW_GEN1_1_OFFSET 0x00000030 +#define IPU_DIx_SW_GEN1_2_OFFSET 0x00000034 +#define IPU_DIx_SW_GEN1_3_OFFSET 0x00000038 +#define IPU_DIx_SW_GEN1_4_OFFSET 0x0000003C +#define IPU_DIx_SW_GEN1_5_OFFSET 0x00000040 +#define IPU_DIx_SW_GEN1_6_OFFSET 0x00000044 +#define IPU_DIx_SW_GEN1_7_OFFSET 0x00000048 +#define IPU_DIx_SW_GEN1_8_OFFSET 0x0000004C +#define IPU_DIx_SW_GEN1_9_OFFSET 0x00000050 +#define IPU_DIx_SYNC_AS_GEN_OFFSET 0x00000054 +#define IPU_DIx_DW_GEN_OFFSET 0x00000058 +#define IPU_DIx_DW_SET0_OFFSET 0x00000088 +#define IPU_DIx_DW_SET1_OFFSET 0x000000B8 +#define IPU_DIx_DW_SET2_OFFSET 0x000000E8 +#define IPU_DIx_DW_SET3_OFFSET 0x00000118 +#define IPU_DIx_STP_REP_OFFSET 0x00000148 +#define IPU_DIx_STP_REP_9_OFFSET 0x00000158 +#define IPU_DIx_SER_CONF_OFFSET 0x0000015C +#define IPU_DIx_SSC_OFFSET 0x00000160 +#define IPU_DIx_POL_OFFSET 0x00000164 +#define IPU_DIx_AW0_OFFSET 0x00000168 +#define IPU_DIx_AW1_OFFSET 0x0000016C +#define IPU_DIx_SCR_CONF_OFFSET 0x00000170 +#define IPU_DIx_STAT_OFFSET 0x00000174 + +// IPU IDMAC Registers +#define IPU_IDMAC_LOCK_EN_1 0x00008024 +#define IPU_IDMAC_LOCK_EN_2 0x00008028 + +// IPU DI0 Registers +#define IPU_DI0_GENERAL_OFFSET 0x00040000 +#define IPU_DI0_BS_CLKGEN0_OFFSET 0x00040004 +#define IPU_DI0_BS_CLKGEN1_OFFSET 0x00040008 +#define IPU_DI0_SW_GEN0_1_OFFSET 0x0004000C +#define IPU_DI0_SW_GEN0_2_OFFSET 0x00040010 +#define IPU_DI0_SW_GEN0_3_OFFSET 0x00040014 +#define IPU_DI0_SW_GEN0_4_OFFSET 0x00040018 +#define IPU_DI0_SW_GEN0_5_OFFSET 0x0004001C +#define IPU_DI0_SW_GEN0_6_OFFSET 0x00040020 +#define IPU_DI0_SW_GEN0_7_OFFSET 0x00040024 +#define IPU_DI0_SW_GEN0_8_OFFSET 0x00040028 +#define IPU_DI0_SW_GEN0_9_OFFSET 0x0004002C +#define IPU_DI0_SW_GEN1_1_OFFSET 0x00040030 +#define IPU_DI0_SW_GEN1_2_OFFSET 0x00040034 +#define IPU_DI0_SW_GEN1_3_OFFSET 0x00040038 +#define IPU_DI0_SW_GEN1_4_OFFSET 0x0004003C +#define IPU_DI0_SW_GEN1_5_OFFSET 0x00040040 +#define IPU_DI0_SW_GEN1_6_OFFSET 0x00040044 +#define IPU_DI0_SW_GEN1_7_OFFSET 0x00040048 +#define IPU_DI0_SW_GEN1_8_OFFSET 0x0004004C +#define IPU_DI0_SW_GEN1_9_OFFSET 0x00040050 +#define IPU_DI0_SYNC_AS_GEN_OFFSET 0x00040054 +#define IPU_DI0_DW_GEN_OFFSET 0x00040058 +#define IPU_DI0_DW_SET0_OFFSET 0x00040088 +#define IPU_DI0_DW_SET1_OFFSET 0x000400B8 +#define IPU_DI0_DW_SET2_OFFSET 0x000400E8 +#define IPU_DI0_DW_SET3_OFFSET 0x00040118 +#define IPU_DI0_STP_REP_OFFSET 0x00040148 +#define IPU_DI0_STP_REP_9_OFFSET 0x00040158 +#define IPU_DI0_SER_CONF_OFFSET 0x0004015C +#define IPU_DI0_SSC_OFFSET 0x00040160 +#define IPU_DI0_POL_OFFSET 0x00040164 +#define IPU_DI0_AW0_OFFSET 0x00040168 +#define IPU_DI0_AW1_OFFSET 0x0004016C +#define IPU_DI0_SCR_CONF_OFFSET 0x00040170 +#define IPU_DI0_STAT_OFFSET 0x00040174 + +// IPU DI1 Registers +#define IPU_DI1_GENERAL_OFFSET 0x00048000 +#define IPU_DI1_BS_CLKGEN0_OFFSET 0x00048004 +#define IPU_DI1_BS_CLKGEN1_OFFSET 0x00048008 +#define IPU_DI1_SW_GEN0_1_OFFSET 0x0004800C +#define IPU_DI1_SW_GEN0_2_OFFSET 0x00048010 +#define IPU_DI1_SW_GEN0_3_OFFSET 0x00048014 +#define IPU_DI1_SW_GEN0_4_OFFSET 0x00048018 +#define IPU_DI1_SW_GEN0_5_OFFSET 0x0004801C +#define IPU_DI1_SW_GEN0_6_OFFSET 0x00048020 +#define IPU_DI1_SW_GEN0_7_OFFSET 0x00048024 +#define IPU_DI1_SW_GEN0_8_OFFSET 0x00048028 +#define IPU_DI1_SW_GEN0_9_OFFSET 0x0004802C +#define IPU_DI1_SW_GEN1_1_OFFSET 0x00048030 +#define IPU_DI1_SW_GEN1_2_OFFSET 0x00048034 +#define IPU_DI1_SW_GEN1_3_OFFSET 0x00048038 +#define IPU_DI1_SW_GEN1_4_OFFSET 0x0004803C +#define IPU_DI1_SW_GEN1_5_OFFSET 0x00048040 +#define IPU_DI1_SW_GEN1_6_OFFSET 0x00048044 +#define IPU_DI1_SW_GEN1_7_OFFSET 0x00048048 +#define IPU_DI1_SW_GEN1_8_OFFSET 0x0004804C +#define IPU_DI1_SW_GEN1_9_OFFSET 0x00048050 +#define IPU_DI1_SYNC_AS_GEN_OFFSET 0x00048054 +#define IPU_DI1_DW_GEN_OFFSET 0x00048058 +#define IPU_DI1_DW_SET0_OFFSET 0x00048088 +#define IPU_DI1_DW_SET1_OFFSET 0x000480B8 +#define IPU_DI1_DW_SET2_OFFSET 0x000480E8 +#define IPU_DI1_DW_SET3_OFFSET 0x00048118 +#define IPU_DI1_STP_REP_OFFSET 0x00048148 +#define IPU_DI1_STP_REP_9_OFFSET 0x00048158 +#define IPU_DI1_SER_CONF_OFFSET 0x0004815C +#define IPU_DI1_SSC_OFFSET 0x00048160 +#define IPU_DI1_POL_OFFSET 0x00048164 +#define IPU_DI1_AW0_OFFSET 0x00048168 +#define IPU_DI1_AW1_OFFSET 0x0004816C +#define IPU_DI1_SCR_CONF_OFFSET 0x00048170 +#define IPU_DI1_STAT_OFFSET 0x00048174 + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.c b/Silicon/NXP/iMX6Pkg/D= rivers/GOP/Lvds.c new file mode 100644 index 000000000000..325e81974888 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.c @@ -0,0 +1,81 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright 2018 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "Osal.h" +#include "Display.h" +#include "Lvds.h" +#include "Edid.h" + +OS_STATUS InitLVDS ( + DISPLAY_CONTEXT* DisplayContextPtr + ) +{ + DISPLAY_INTERFACE_CONTEXT* LvdsDisplayContextPtr =3D &DisplayContextPt= r->DIContext[LVDS0_DISPLAY]; + OS_STATUS status =3D 0; + + OS_ZERO_MEM(LvdsDisplayContextPtr, sizeof(*LvdsDisplayContextPtr)); + + LvdsDisplayContextPtr->MmioBasePtr =3D (VOID*)OS_MMIO_MAP(LDB_BASE); + if (LvdsDisplayContextPtr->MmioBasePtr =3D=3D NULL) { + OS_ERROR("Fail to map LDB register\n"); + goto Exit; + } + + + // LVDS CH1 enabled, routed to DI0; ipu_di01_vsync_active_low + { + + + LDB_CTRL_REG LdbCtrlReg; + LdbCtrlReg.Reg =3D LVDSRead32(LDB_CTRL); + LdbCtrlReg.ch0_mode =3D 1; + LdbCtrlReg.ch1_mode =3D 1; + LdbCtrlReg.di0_vs_polarity =3D 1; + LdbCtrlReg.di1_vs_polarity =3D 1; + LVDSWrite32(LDB_CTRL, LdbCtrlReg.Reg); + } + + // No EDID available + LvdsDisplayContextPtr->EdidDataSize =3D 0; + + status =3D GetPreferedTiming( + LvdsDisplayContextPtr->EdidData, + LvdsDisplayContextPtr->EdidDataSize, + &LvdsDisplayContextPtr->PreferedTiming); + if (status !=3D OS_STATUS_SUCCESS) { + OS_ERROR("Fail to retrieve LVDS prefered timing\n"); + goto Exit; + } + +Exit: + return status; +} + +OS_STATUS SetLVDSPower ( + DISPLAY_INTERFACE_CONTEXT* HdmiDisplayContextPtr, + BOOLEAN PowerState + ) +{ + return OS_STATUS_UNSUPPORTED; +} + +OS_STATUS SetLVDSDisplay ( + DISPLAY_INTERFACE_CONTEXT* LvdsDisplayContextPtr, + DISPLAY_TIMING* Timings + ) +{ + return OS_STATUS_UNSUPPORTED; +} + diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.h b/Silicon/NXP/iMX6Pkg/D= rivers/GOP/Lvds.h new file mode 100644 index 000000000000..f98b4aac0061 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Lvds.h @@ -0,0 +1,72 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright 2018 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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_ + +#define LVDSRead32(a) \ + OS_READ32((UINT32)LvdsDisplayContextPtr->MmioBasePtr + (a)) + +#define LVDSWrite32(a, b) \ + OS_WRITE32((UINT32)LvdsDisplayContextPtr->MmioBasePtr + (a), (= b)) + +// LDB Register Base Address +#define LDB_BASE 0x020E0008 + +// LDB Control Register offset +#define LDB_CTRL 0 + +// Register struct + +#pragma pack(push, 1) + +// LDB_CTRL_REG +typedef union { + struct { + UINT32 ch0_mode : 2; + UINT32 ch1_mode : 2; + UINT32 split_mode_en : 1; + UINT32 data_width_ch0 : 1; + UINT32 bit_mapping_ch0 : 1; + UINT32 data_width_ch1 : 1; + UINT32 bit_mapping_ch1 : 1; + UINT32 di0_vs_polarity : 1; + UINT32 di1_vs_polarity : 1; + UINT32 Reserved11_15 : 5; + UINT32 lvds_clk_shift : 3; + UINT32 Reserved19 : 1; + UINT32 counter_reset_val : 2; + UINT32 Reserved22_31 : 10; + }; + UINT32 Reg; +} LDB_CTRL_REG; + +#pragma pack(pop) + +OS_STATUS InitLVDS ( + DISPLAY_CONTEXT* DisplayContextPtr + ); + +OS_STATUS SetLVDSPower ( + DISPLAY_INTERFACE_CONTEXT* LvdsDisplayContextPtr, + BOOLEAN PowerState + ); + +OS_STATUS SetLVDSDisplay ( + DISPLAY_INTERFACE_CONTEXT* LvdsDisplayContextPtr, + DISPLAY_TIMING* Timings + ); + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.c b/Silicon/NXP/iMX6Pkg/D= rivers/GOP/Osal.c new file mode 100644 index 000000000000..664f9e008f1c --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.c @@ -0,0 +1,38 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "Osal.h" +#include "Display.h" +#include "Ipu.h" + +OS_STATUS UefiAllocContiguousMemory ( + UINT32 AllocSize, + VOID** MemoryPointer) +{ + OS_STATUS status; + + *MemoryPointer =3D NULL; + + *MemoryPointer =3D AllocateRuntimePool(AllocSize); + if (*MemoryPointer =3D=3D NULL) { + OS_ERROR("AllocateRuntimePool failed\n"); + status =3D OS_STATUS_INSUFFICIENT_RESOURCE; + goto Exit; + } + + status =3D OS_STATUS_SUCCESS; + +Exit: + return status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.h b/Silicon/NXP/iMX6Pkg/D= rivers/GOP/Osal.h new file mode 100644 index 000000000000..7719b0a1bddb --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/Osal.h @@ -0,0 +1,74 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 _OSAL_H_ +#define _OSAL_H_ + +// OS abstraction header + +#ifdef WIN32 // Windows + +#else // UEFI + +#include +#include +#include +#include +#include +#include + +// UEFI only headers +#include +#include +#include + +#define OS_READ8(ADDRESS) MmioRead8(ADDRESS) +#define OS_WRITE8(ADDRESS, VALUE) MmioWrite8(ADDRESS, VALUE) +#define OS_READ32(ADDRESS) MmioRead32((UINT32)ADDRESS) +#define OS_WRITE32(ADDRESS, VALUE) MmioWrite32((UINT32)ADDRESS, VALUE) + +#ifndef ARRAYSIZE +#define ARRAYSIZE(__array__) (sizeof((__array__))/sizeof((__array__[0]))) +#endif + +#define OS_STATUS EFI_STATUS +#define OS_STATUS_SUCCESS EFI_SUCCESS +#define OS_STATUS_INVALID_PARAM EFI_INVALID_PARAMETER +#define OS_STATUS_DEVICE_ERROR EFI_DEVICE_ERROR +#define OS_STATUS_UNSUPPORTED EFI_UNSUPPORTED +#define OS_STATUS_INSUFFICIENT_RESOURCE EFI_OUT_OF_RESOURCES + +OS_STATUS UefiAllocContiguousMemory ( + UINT32 AllocSize, + VOID** MemoryPointer + ); + +#define OS_MMIO_MAP(PHYSICAL_ADDRESS) PHYSICAL_ADDRESS +#define OS_SLEEP(MILISECOND) gBS->Stall(MILISECOND) +#define OS_ALLOC_CONTIGUOUS_MEMORY(ALLOC_SIZE, MEMORY_POINTER) \ + UefiAllocContiguousMemory(ALLOC_SIZE, (VOID**) MEMORY_POINTER) +#define OS_VIRT_TO_PHY_ADDR(VIRT_ADDR) (VIRT_ADDR) +#define OS_MEM_COPY(DEST, SRC, SIZE) CopyMem(DEST, SRC, SIZE) +#define OS_ZERO_MEM(VIRT_ADDR, SIZE) ZeroMem(VIRT_ADDR, SIZE) + +#define OS_LOG_FMT_HELPER(FMT, ...) \ + "iMX6Gop:" FMT "%a", __VA_ARGS__ + +#define OS_INFO(...) DEBUG((DEBUG_INFO, OS_LOG_FMT_HELPER(__VA_ARGS__, "")= )) +#define OS_WARNING(...) DEBUG((DEBUG_WARN, OS_LOG_FMT_HELPER(__VA_ARGS__, = ""))) +#define OS_ERROR(...) DEBUG((DEBUG_ERROR, OS_LOG_FMT_HELPER(__VA_ARGS__, "= "))) + +#endif + +#endif diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/iMX6GOP.inf b/Silicon/NXP/iMX6= Pkg/Drivers/GOP/iMX6GOP.inf new file mode 100644 index 000000000000..49e4788c0781 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/iMX6GOP.inf @@ -0,0 +1,71 @@ +#/** @file +# +# Copyright (c) 2011, ARM Ltd. All rights reserved.
+# Copyright (c) Microsoft Corporation. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the 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 0x00010005 + BASE_NAME =3D iMX6GOPDxe + FILE_GUID =3D E68088EF-D1A4-4336-C1DB-4D3A204730A6 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D VideoiMX6DxeInitialize + +[Sources.common] + iMXVideoDxe.c + Osal.c + Ddc.c + Display.c + Hdmi.c + Lvds.c + Edid.c + DisplayInterface.c + DisplayController.c + CPMem.c + IoMux.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Silicon/NXP/iMX6Pkg/iMX6Pkg.dec + +[LibraryClasses] + ArmLib + UefiLib + BaseLib + DebugLib + TimerLib + UefiDriverEntryPoint + UefiBootServicesTableLib + IoLib + BaseMemoryLib + iMX6ClkPwrLib + iMXDisplayLib + +[Protocols] + gEfiDevicePathProtocolGuid # Produced + gEfiGraphicsOutputProtocolGuid # Produced + gEfiEdidDiscoveredProtocolGuid # Produced + gEfiEdidActiveProtocolGuid # Produced + gEfiDevicePathToTextProtocolGuid + +[Pcd] + giMX6TokenSpaceGuid.PcdFrameBufferBase + giMX6TokenSpaceGuid.PcdFrameBufferSize + giMX6TokenSpaceGuid.PcdLvdsEnable + +[Depex] + gEfiCpuArchProtocolGuid AND gEfiTimerArchProtocolGuid diff --git a/Silicon/NXP/iMX6Pkg/Drivers/GOP/iMXVideoDxe.c b/Silicon/NXP/iM= X6Pkg/Drivers/GOP/iMXVideoDxe.c new file mode 100644 index 000000000000..f65c0df8f148 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/GOP/iMXVideoDxe.c @@ -0,0 +1,488 @@ +/** @file +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Copyright 2018 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the 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 "Osal.h" +#include "Display.h" +#include "Hdmi.h" +#include "Lvds.h" + +#define PIXEL_BYTES 4 + +typedef struct { + VENDOR_DEVICE_PATH Mmc; + EFI_DEVICE_PATH End; +} VID_DEVICE_PATH; + +DISPLAY_TIMING const FullHDTiming =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 + ); + +//--------------------------------------------------------------------- Gl= obals. + +static VID_DEVICE_PATH g_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 g_VidGopModeInfo; +static EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE g_VidGopMode; + +static EFI_GRAPHICS_OUTPUT_PROTOCOL g_VidGop =3D +{ + VidGopQueryMode, // QueryMode + VidGopSetMode, // SetMode + VidGopBlt, // Blt + &g_VidGopMode // Mode +}; + +EFI_EDID_DISCOVERED_PROTOCOL g_EdidDiscovered =3D { + 0, + NULL +}; + +EFI_EDID_ACTIVE_PROTOCOL g_EdidActive =3D { + 0, + NULL +}; + +DISPLAY_CONTEXT* DisplayContextPtr; + +DISPLAY_INTERFACE DisplayDevice; + +EFI_STATUS +VideoiMX6DxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS status; + UINT32 ReservedDisplayMemorySize; + UINT32 RequestedDisplayMemorySize; + DEBUG((DEBUG_INFO,"++VideoiMX6DxeInitialize()\r\n")); + + ReservedDisplayMemorySize =3D FixedPcdGet32(PcdFrameBufferSize); + + if (FeaturePcdGet(PcdLvdsEnable)) { + DisplayDevice =3D LVDS0_DISPLAY; + } else { + DisplayDevice =3D HDMI_DISPLAY; + } + + status =3D InitDisplay(&DisplayContextPtr); + if (EFI_ERROR(status)) { + DEBUG( + (DEBUG_ERROR, + "VideoiMX6DxeInitialize: Fail to init display, status=3D%r\n", + status)); + goto Exit; + } + + DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize - Allocate frame buffer\r\n"= )); + // To allocate frame buffer dynamically, there isn`t a built in graphi= c memory + // manager for UEFI, so we are allocating frame buffer manually. Curre= ntly only + // support single display, so allocate single(1) frame buffer + { + // Allocate frame buffer + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width =3D + DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming.HAc= tive; + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height =3D + DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming.VAc= tive; + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp =3D + DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming.Bpp= ; + DisplayContextPtr->DisplayConfig.DisplaySurface[0].PixelFormat =3D + DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming.Pix= elFormat; + + // iMX6 UEFI reserves display memory for fullHD buffer size. + // PcdFrameBufferSize=3D800000h or 8388608 bytes - 1920x1080x4 byt= es + // to prevent larger displays overrun our reserved memory size, ca= p display resolution to fullHD + // NOTE: for displays which do not have supported 1920x1080 mode m= ay cause poor or missing picture + + RequestedDisplayMemorySize=3DDisplayContextPtr->DisplayConfig.Disp= laySurface[0].Width * + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height * + (DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp/8); + + DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize: Display Memory: Needed= =3D%d, Available=3D%d\r\n",RequestedDisplayMemorySize, + ReservedDisplayMemorySize)); + + if (RequestedDisplayMemorySize > ReservedDisplayMemorySize) { + DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize WARNING. Display res= olution needs more video memory than reserved by %d bytes\r\n", + RequestedDisplayMemorySize - ReservedDisplayMemorySize)); + DEBUG((DEBUG_ERROR,"VideoiMX6DxeInitialize - display horizonta= l resolution too big. Cap to HD 1080p\r\n")); + + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width =3D F= ullHDTiming.HActive; + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height =3D = FullHDTiming.VActive; + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp =3D Ful= lHDTiming.Bpp; + + OS_MEM_COPY(&DisplayContextPtr->DIContext[DisplayDevice].Pref= eredTiming, + &FullHDTiming, sizeof(DISPLAY_TIMING)); + } + + DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize - allocating frame buffe= r... \r\n")); + status =3D AllocateFrameBuffer( + &DisplayContextPtr->DisplayConfig.DisplaySurface[0]); + if (EFI_ERROR(status)) { + DEBUG( + (DEBUG_ERROR, + "VideoiMX6DxeInitialize: Fail to allocate fb, status=3D%r\= n", + status)); + goto Exit; + }; + + DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize - Initialize the frame b= uffer to black\r\n")); + // Initialize the frame buffer to black + SetMem32( + (void*)DisplayContextPtr->DisplayConfig.DisplaySurface[0].PhyA= ddr, + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Width * + DisplayContextPtr->DisplayConfig.DisplaySurface[0].Height = * 4, + 0xFF000000); + + } + + DEBUG((DEBUG_INFO,"VideoiMX6DxeInitialize - set the display configurat= ion to single HDMI mode\r\n")); + // Set the display configuration to single HDMI/LVDS mode + { + DISPLAY_INTERFACE displayInterfaceOrder[MAX_DISPLAY] =3D { + DisplayDevice, + NO_DISPLAY, + NO_DISPLAY, + NO_DISPLAY, + }; + + DisplayContextPtr->DisplayConfig.DisplayTiming[0] =3D + DisplayContextPtr->DIContext[DisplayDevice].PreferedTiming; + + status =3D ApplyDisplayConfig( + DisplayContextPtr, + SINGLE_MODE, + displayInterfaceOrder); + if (EFI_ERROR(status)) { + DEBUG( + (DEBUG_ERROR, + "VideoiMX6DxeInitialize: Fail to set display. Exit status= =3D%r\n", + status)); + goto Exit; + } + } + + g_VidGopModeInfo.Version =3D 0; + g_VidGopModeInfo.HorizontalResolution =3D + DisplayContextPtr->DisplayConfig.DisplayTiming[0].HActive; + g_VidGopModeInfo.VerticalResolution =3D + DisplayContextPtr->DisplayConfig.DisplayTiming[0].VActive; + g_VidGopModeInfo.PixelFormat =3D PixelBlueGreenRedReserved8BitPerColor= ; + + OS_ZERO_MEM( + &g_VidGopModeInfo.PixelInformation, + sizeof(g_VidGopModeInfo.PixelInformation)); + + g_VidGopModeInfo.PixelsPerScanLine =3D g_VidGopModeInfo.HorizontalReso= lution; + g_VidGopMode.MaxMode =3D 1; + g_VidGopMode.Mode =3D 0; + g_VidGopMode.Info =3D &g_VidGopModeInfo; + g_VidGopMode.SizeOfInfo =3D sizeof(g_VidGopModeInfo); + g_VidGopMode.FrameBufferBase =3D + (EFI_PHYSICAL_ADDRESS) + DisplayContextPtr->DisplayConfig.DisplaySurface[0].PhyAddr; + g_VidGopMode.FrameBufferSize =3D + g_VidGopModeInfo.HorizontalResolution * + g_VidGopModeInfo.VerticalResolution * + (DisplayContextPtr->DisplayConfig.DisplaySurface[0].Bpp / 8); + + DisplayContextPtr->DisplayConfig.OsHandle[0] =3D (UINT32)&ImageHandle; + + status =3D gBS->InstallMultipleProtocolInterfaces( + &ImageHandle, + &gEfiGraphicsOutputProtocolGuid, + &g_VidGop, + &gEfiDevicePathProtocolGuid, + &g_VidDevicePath, + NULL); + if (EFI_ERROR(status)) { + DEBUG( + (DEBUG_ERROR, + "VideoiMX6DxeInitialize: Fail to install protocol, status=3D%r= \n", + status)); + goto Exit; + } + +Exit: + DEBUG((DEBUG_INFO,"--VideoiMX6DxeInitialize()=3D%Xh\r\n",status)); + return status; +} + +//---------------------------------------------------------------- GOP rou= tines. + +EFI_STATUS +EFIAPI +VidGopQueryMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ) +{ + EFI_STATUS status; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *outputMode; + + if (FeaturePcdGet(PcdLvdsEnable)) { + DisplayDevice =3D LVDS0_DISPLAY; + } else { + DisplayDevice =3D HDMI_DISPLAY; + } + + + g_EdidDiscovered.SizeOfEdid =3D + DisplayContextPtr->DIContext[DisplayDevice].EdidDataSize; + g_EdidDiscovered.Edid =3D + DisplayContextPtr->DIContext[DisplayDevice].EdidData; + g_EdidActive.SizeOfEdid =3D + DisplayContextPtr->DIContext[DisplayDevice].EdidDataSize; + g_EdidActive.Edid =3D + DisplayContextPtr->DIContext[DisplayDevice].EdidData; + + status =3D gBS->InstallMultipleProtocolInterfaces( + (EFI_HANDLE)DisplayContextPtr->DisplayConfig.OsHandle[0], + &gEfiEdidDiscoveredProtocolGuid, + &g_EdidDiscovered, + &gEfiEdidActiveProtocolGuid, + &g_EdidActive, + NULL); + if (EFI_ERROR(status)) { + DEBUG( + (DEBUG_ERROR, + "Fail to install EDID discover and active protocol status=3D%r= \n", + status)); + } + + if (ModeNumber !=3D 0) { + DEBUG((DEBUG_ERROR, "VidGopQueryMode: Saw request to query mode %d= \n", 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 g_VidGopModeInfo.HorizontalResolu= tion; + outputMode->VerticalResolution =3D g_VidGopModeInfo.VerticalResolution= ; + outputMode->PixelFormat =3D PixelBlueGreenRedReserved8BitPerColor; + + outputMode->PixelsPerScanLine =3D g_VidGopModeInfo.HorizontalResolutio= n; + *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 + ) +{ + OS_STATUS status; + + if (ModeNumber !=3D 0) { + DEBUG((DEBUG_ERROR, "VidGopSetMode: Saw request to set mode to %d\= n", ModeNumber)); + status =3D OS_STATUS_UNSUPPORTED; + goto Exit; + } + + status =3D OS_STATUS_SUCCESS; + +Exit: + return status; +} + +EFI_STATUS +VidGopBlt ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ) +{ + UINT32 *frameBuffer; + UINT32 frameWidth; + UINT32 frameOffset; + UINT32 bufferOffset; + UINT32 bufferWidth; + UINT32 i; + + frameBuffer =3D (UINT32 *) (UINTN) g_VidGopMode.FrameBufferBase; + frameWidth =3D g_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, "VideoDxe:VidGopBlt not impl %d\n", BltOperati= on)); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} --=20 2.16.2.gvfs.1.33.gf5370f1