From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.38.127; helo=nam02-bl2-obe.outbound.protection.outlook.com; envelope-from=christopher.co@microsoft.com; receiver=edk2-devel@lists.01.org Received: from NAM02-BL2-obe.outbound.protection.outlook.com (mail-bl2nam02on0127.outbound.protection.outlook.com [104.47.38.127]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 4219B2115411D for ; Fri, 21 Sep 2018 01:26:15 -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=ECY2RXDMJtytdFjKxMDUqAq1BbB+cLqEHX332/d7254=; b=geWMN7i5bY3l3MCu1tO3nEV9G41va13pgVQPiDEJjITD9S9EyVjVrlhdCoj4AfCEQm+6pE+uf9Xlge0l5UK8H2EPA6lKEe5l2YEQmBmDIkd8QUJbq1G/U1F0XAzyKlpkyk0jsSfpvSD8fdfnJ7MF7mZ0TicrhdZEb79OxDfKzQ4= Received: from DM5PR2101MB1128.namprd21.prod.outlook.com (52.132.133.20) by DM5PR2101MB0727.namprd21.prod.outlook.com (10.167.110.39) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1185.6; Fri, 21 Sep 2018 08:26:14 +0000 Received: from DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::81f8:300e:d90:d49]) by DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::81f8:300e:d90:d49%3]) with mapi id 15.20.1164.008; Fri, 21 Sep 2018 08:26:13 +0000 From: Chris Co To: "edk2-devel@lists.01.org" CC: Ard Biesheuvel , Leif Lindholm , Michael D Kinney Thread-Topic: [PATCH edk2-platforms 21/27] Silicon/NXP: Add i.MX6 PCIe DXE driver Thread-Index: AQHUUYTCK1lOzlbbiUmucj0MhaicAg== Date: Fri, 21 Sep 2018 08:26:13 +0000 Message-ID: <20180921082542.35768-22-christopher.co@microsoft.com> References: <20180921082542.35768-1-christopher.co@microsoft.com> In-Reply-To: <20180921082542.35768-1-christopher.co@microsoft.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: MWHPR17CA0054.namprd17.prod.outlook.com (2603:10b6:300:93::16) To DM5PR2101MB1128.namprd21.prod.outlook.com (2603:10b6:4:a8::20) x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [2001:4898:80e8:8:388a:edc9:7085:c18] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DM5PR2101MB0727; 6:NAWqe4iNQDCX1hk/mRd0tdorb4y8+2YZXWxfxwFaRxUCNwqqIeaLQ98N3lvL6Y/eBtNaiMnazQDrhm5xWPtWvCulArpS2a0YFXTJeQhbnch0GThUWjyJUZujXQO/TDMezuSL4M0uxoF68vsEjy8Uu8JVxaSr5wEZwGPyttQj/30Lzu8mQTGry3NItCgwYBycqazBr/ioxnspH9ATlsTH6vM+SyRuXqqO+MSqIMEDqMwZk3wS0mLUL7IvzJfg7RZBsOwVoTe5gQq7QwDLBcvl06P2jt7vewegQeT8TLUVSmF2HhsyOoFkYenaMFIPqgeHzaMBtaWYjHBPqrj4fwuKoy3gU344sh7Mf3MumhIa3Jw2Axf+NL2HVA69GOCwAWRu1Q3CG9+G5gI90micq5PRWlmYPa50bAgy2Z2gCP8Tq+Y79qIW6aWAU9+7fttm8C1KWkk9BsE7esfaJpH3cgBCvQ==; 5:9UCt3y0msSrH87qf3hsyEJT31/Bv8Xi4KXF2py7wOoIxhkV3hafY828XLtG2fNFUChle/uZeQOwsp/ctQx9UO+vah/4vmgoJUM2eF/9OQjMUOLWXB71Ip5kT57WquNTS7yqVZTQBZaZSNOy20SDOcaazq9bVSpdfXXdpIyG3Nrg=; 7:fBc+o5ENBRzWr+B1mffnXDoE8kRM8Mx7S4UJ+ZX6Tq31w+QbdrorCwcnoJZhVdrjQOkNCco5LH4jldUeXmyNGHbCIDt613k0gN3cl9ugPUgbYRYBKOohb2QB8u3G00JmnVhjtLb0NGALafwlKiwMARxEtN0uLbWthWCzgP0SH9BVdMcJWGioSTzZixh9w/dEuFUDP+g8I23/5coRJuQAT/sft9TFO5AKUtUK1U7WYMZWs4JKMno+em8xkKDn236f x-ms-office365-filtering-correlation-id: 69b24a7b-05f0-4a8e-f016-08d61f9be485 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989299)(4534165)(4627221)(201703031133081)(201702281549075)(8990200)(5600074)(711020)(4618075)(2017052603328)(7193020); SRVR:DM5PR2101MB0727; x-ms-traffictypediagnostic: DM5PR2101MB0727: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(28532068793085)(89211679590171)(12401385986421)(228905959029699); x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(3231355)(2280164)(944501410)(52105095)(2018427008)(93006095)(93001095)(3002001)(10201501046)(6055026)(149027)(150027)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123562045)(20161123560045)(20161123564045)(20161123558120)(201708071742011)(7699051)(76991041); SRVR:DM5PR2101MB0727; BCL:0; PCL:0; RULEID:; SRVR:DM5PR2101MB0727; x-forefront-prvs: 0802ADD973 x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(1496009)(39860400002)(396003)(136003)(376002)(366004)(346002)(199004)(189003)(8676002)(81156014)(25786009)(446003)(2900100001)(102836004)(46003)(52116002)(6346003)(81166006)(11346002)(105586002)(2351001)(8936002)(386003)(4326008)(76176011)(6506007)(10090500001)(5250100002)(7736002)(2616005)(486006)(305945005)(53376002)(6116002)(186003)(16799955002)(1076002)(2501003)(476003)(6916009)(99286004)(22452003)(97736004)(45954006)(71200400001)(71190400001)(72206003)(478600001)(966005)(6306002)(10290500003)(5640700003)(14454004)(36756003)(86362001)(19627235002)(575784001)(6436002)(16200700003)(15188155005)(2906002)(53946003)(86612001)(106356001)(54906003)(316002)(6486002)(256004)(6512007)(14444005)(68736007)(5660300001)(53936002)(60540400001)(579004)(569006); DIR:OUT; SFP:1102; SCL:1; SRVR:DM5PR2101MB0727; H:DM5PR2101MB1128.namprd21.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; received-spf: None (protection.outlook.com: microsoft.com does not designate permitted sender hosts) authentication-results: spf=none (sender IP is ) smtp.mailfrom=Christopher.Co@microsoft.com; x-microsoft-antispam-message-info: WnZuCV8G15OXXYQfbbHOw7NcxxQ5txHGwbuYyFwW4ojXWpiHqMU/7fVuiKYVvYIezg+TBxzyCv/sdEH1dx+Z23kGjAvxGbe7mED6i1r3pmbITQGhzlHxwKPoDcD0o+qoT81IbJa5w3SalmSOzspMZRGpDAn4yaD+2BOsOem9n/ySXVgBXdCc+KPaJ5zuSnTqyWtmftn8XLQCDgeXuLRLZIlrpguc+JNAvIwSSVaEP2MaN61RSSm9UcX0A0IRfrq/7Paoif1mtcif+a21ICzVlQmRGUrTBtF6V5rwcw0cscb6BwbaWA5LtsLkfgTfmDwP4FikMWeif1ElusNg+gCgpDcHF2txDtpCkbxwdn6J/vp2P/Xvn4t/IGPfPTdgahRO7gPXSHf5mTd8qkBk5+Slpd7elI2WoIQVOgP3dtjoJwnbRTfaoBktuSxyYwSTnjKoU3sAfv530cWryWQpggd9cC8nUziK5H0RnhlxmzHOYU283XkCv4z76vJYtCfFnOg7R+zhadfesqPaTH9byTMlyA9pthLQQegU8ko4Aw6H/WUTZH6DQvcijikjTbhvWsEx spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-Network-Message-Id: 69b24a7b-05f0-4a8e-f016-08d61f9be485 X-MS-Exchange-CrossTenant-originalarrivaltime: 21 Sep 2018 08:26:13.8097 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR2101MB0727 Subject: [PATCH edk2-platforms 21/27] Silicon/NXP: Add i.MX6 PCIe DXE driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 21 Sep 2018 08:26:15 -0000 Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable This adds DXE driver support for PCIe on NXP i.MX6 SoCs. 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/PciExpress/iMX6PciExpress.c | 1139 +++++++++= +++++++++++ Silicon/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.h | 145 +++ Silicon/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.inf | 66 ++ 3 files changed, 1350 insertions(+) diff --git a/Silicon/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.c b/Sili= con/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.c new file mode 100644 index 000000000000..424ab2d77227 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.c @@ -0,0 +1,1139 @@ +/** @file +* +* Copyright (c) 2018 Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include "iMX6PciExpress.h" + +PCI_RESOURCE PcieResource[] =3D { + // Memory resource + { + PCIE_MEMORY_SPACE_BASE, + PCIE_MEMORY_SPACE_SIZE, + PCIE_MEMORY_SPACE_BASE + }, +}; + +// Pcie read and write function +EFI_STATUS +PciePciWrite ( + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Address, + IN UINTN Count, + IN VOID *Buffer + ); + +EFI_STATUS +PciePciRead ( + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Address, + IN UINTN Count, + IN VOID *Buffer + ); + +// Internal Address Translation Unit configuration table. Map the Pcie dev= ice +// configuration baesd on configuration. Pci IO space is not supported on +// Windows. Memory space segment is just mapped back to the same address. +// +// The following table is used to setup basic translation setting on vario= us +// ATU (Address Translation Unit). The ATU is responsible to retranslate +// address for inbound and outbound message. +// +// Address match mode address translation is based on the following formul= a : +// Address =3D Address - Base Address + Target Address +// +// There really isnt a need to retranslate the address for iMX6 however pr= oceed +// the program the ATU to for configuration and memory message. +IATU_SETTINGS iMX6iAtuSettings[] =3D { + // Configuration message + { + OUTBOUND, + 0, + CFG0_TYPE, + PCIE_DEVICE_CONFIG_BASE_REG, + 0, + PCIE_DEVICE_CONFIG_BASE_REG + PCIE_DEVICE_CONFIG_SIZE - 1, + PCIE_DEVICE_CONFIG_BASE_REG, + 0, + REGION_ENABLE, + }, + + // Memory message + { + OUTBOUND, + 2, + MEMORY_TYPE, + PCIE_MEMORY_SPACE_BASE, + 0, + PCIE_MEMORY_SPACE_BASE + PCIE_MEMORY_SPACE_SIZE - 1, + PCIE_MEMORY_SPACE_BASE, + 0, + REGION_ENABLE, + }, +}; + +VOID +PcieSetupiAtu ( + IN IATU_SETTINGS *SettingsPtr + ) +{ + volatile CSP_PCIE_PL_REGS *pPortLogicRegs; + + ASSERT (SettingsPtr->RegionIndex < MAX_iATU_REGION); + pPortLogicRegs =3D (CSP_PCIE_PL_REGS *)PCIE_CTRL_PORT_LOGIG_BASE_REG; + + // Program specific ATU region + MmioWrite32 ( + (UINTN)&pPortLogicRegs->PCIE_PL_iATUVR, + (SettingsPtr->RegionDirection << 31 | SettingsPtr->RegionIndex)); + + MmioWrite32 ( + (UINTN)&pPortLogicRegs->PCIE_PL_iATURC2, + REGION_DISABLE); + + MmioWrite32 ( + (UINTN)&pPortLogicRegs->PCIE_PL_iATURLBA, + SettingsPtr->LowerBaseAddr); + + MmioWrite32 ( + (UINTN)&pPortLogicRegs->PCIE_PL_iATURUBA, + SettingsPtr->UpperBaseAddr); + + MmioWrite32 ( + (UINTN)&pPortLogicRegs->PCIE_PL_iATURLA, + SettingsPtr->LimitAddr); + + MmioWrite32 ( + (UINTN)&pPortLogicRegs->PCIE_PL_iATURLTA, + SettingsPtr->LowerTargetAddr); + + MmioWrite32 ( + (UINTN)&pPortLogicRegs->PCIE_PL_iATURUTA, + SettingsPtr->UpperTargetAddr); + + MmioWrite32 ( + (UINTN)&pPortLogicRegs->PCIE_PL_iATURC1, + SettingsPtr->Type); + + MmioWrite32 ( + (UINTN)&pPortLogicRegs->PCIE_PL_iATURC2, + SettingsPtr->State); +} + +VOID +PcieSetupiAtuSettings ( + VOID + ) +{ + UINT32 i; + + // Initialize internal Address Translation Unit based on settings specif= y + // in iMX6iAtuSettings table. + for (i =3D 0; i < ARRAYSIZE (iMX6iAtuSettings); ++i) { + PcieSetupiAtu (&iMX6iAtuSettings[i]); + } + + return; +} + +EFI_STATUS +PcieSetPhyState ( + IN BOOLEAN State + ) +{ + volatile IMX_IOMUXC_GPR_REGISTERS *pIoMuxcGprRegisters; + IMX_IOMUXC_GPR1_REG Gpr1Reg; + + pIoMuxcGprRegisters =3D (IMX_IOMUXC_GPR_REGISTERS *)IOMUXC_GPR_BASE_ADDR= ESS; + Gpr1Reg.AsUint32 =3D MmioRead32 ((UINTN)&pIoMuxcGprRegisters->GPR1); + if (State =3D=3D TRUE) { +#if defined(CPU_IMX6DQP) + Gpr1Reg.PCIE_SW_RST =3D 0; +#endif + Gpr1Reg.REF_SSP_EN =3D 1; // Enable Pcie PHY + Gpr1Reg.TEST_POWERDOWN =3D 0; // Power down is not requested + } else { + Gpr1Reg.REF_SSP_EN =3D 0; // Disable Pcie PHY + Gpr1Reg.TEST_POWERDOWN =3D 1; // Power down is requested + } + MmioWrite32 ((UINTN)&pIoMuxcGprRegisters->GPR1, Gpr1Reg.AsUint32); + return EFI_SUCCESS; +} + +EFI_STATUS +PcieSetupInitSetting ( + VOID + ) +{ + volatile IMX_IOMUXC_GPR_REGISTERS *pIoMuxcGprRegisters; + EFI_STATUS Status; + IMX_IOMUXC_GPR1_REG Gpr1Reg; + IMX_IOMUXC_GPR12_REG Gpr12Reg; + IMX_IOMUXC_GPR8_REG Gpr8Reg; + + pIoMuxcGprRegisters =3D (IMX_IOMUXC_GPR_REGISTERS *)IOMUXC_GPR_BASE_ADDR= ESS; + + // If Pcie PHY is already enabled we are in an unexpected state, just ex= it + // and assume a bootloader has already setup Pcie and assigned resources= . + Gpr1Reg.AsUint32 =3D MmioRead32 ((UINTN)&pIoMuxcGprRegisters->GPR1); + if (Gpr1Reg.REF_SSP_EN =3D=3D 1) { + Status =3D EFI_DEVICE_ERROR; + goto Exit; + } + + // Disable the PHY first, without this Pci link randomly does not come u= p + Status =3D PcieSetPhyState (FALSE); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to disable Pcie PHY\n"); + goto Exit; + } + + // First configure Pcie and Pcie PHY default setting + Gpr12Reg.AsUint32 =3D MmioRead32 ((UINTN)&pIoMuxcGprRegisters->GPR12); + Gpr12Reg.APP_LTSSM_ENABLE =3D 0; // Set application not ready + Gpr12Reg.DIA_STATUS_BUS_SELECT =3D 0xB; // Debug functionality + Gpr12Reg.DEVICE_TYPE =3D 0x4; // Set to RC mode + Gpr12Reg.LOS_LEVEL =3D 0x9; // Set to 0x9 per reference ma= nual + MmioWrite32 ((UINTN)&pIoMuxcGprRegisters->GPR12, Gpr12Reg.AsUint32); + + // Gen1 | Gen2 3p5 | Gen2 6 | Swing full 127 | Swing low 127 + Gpr8Reg.PCS_TX_DEEMPH_GEN1 =3D 0; + Gpr8Reg.PCS_TX_DEEMPH_GEN2_3P5DB =3D 0; + Gpr8Reg.PCS_TX_DEEMPH_GEN2_6DB =3D 20; + Gpr8Reg.PCS_TX_SWING_FULL =3D 127; + Gpr8Reg.PCS_TX_SWING_LOW =3D 127; + MmioWrite32 ((UINTN)&pIoMuxcGprRegisters->GPR8, Gpr8Reg.AsUint32); + + Status =3D EFI_SUCCESS; + +Exit: + return Status; +} + +EFI_STATUS +PcieSetClockGate ( + IN IMX_CLOCK_GATE_STATE State + ) +{ + ImxClkPwrSetClockGate (IMX_PCIE_ROOT_ENABLE, State); + return EFI_SUCCESS; +} + +EFI_STATUS +PcieVerifyClocks ( + VOID + ) +{ + volatile IMX_CCM_ANALOG_REGISTERS *pCcmAnalogRegisters; + IMX_CCM_ANALOG_PLL_ENET_REG CcmAnalogPllReg; + + pCcmAnalogRegisters =3D (IMX_CCM_ANALOG_REGISTERS *)IMX_CCM_ANALOG_BASE; + CcmAnalogPllReg.AsUint32 =3D MmioRead32 ((UINTN)&pCcmAnalogRegisters->PL= L_ENET); + if ((CcmAnalogPllReg.POWERDOWN =3D=3D 0) && + (CcmAnalogPllReg.BYPASS =3D=3D 0) && + (CcmAnalogPllReg.ENABLE_125M =3D=3D 1) && + (CcmAnalogPllReg.LOCK =3D=3D 1)) { + return EFI_SUCCESS; + } + + return EFI_DEVICE_ERROR; +} + +VOID +PcieEnablePerstLine ( + VOID + ) +{ + // Enable board specific PERST line if one is defined + if (FixedPcdGet32 (PcdPcieResetGpio)) { + ImxGpioWrite ( + FixedPcdGet32 (PcdPcieResetGpioBankNumber), + FixedPcdGet32 (PcdPcieResetGpioIoNumber), + IMX_GPIO_HIGH); + gBS->Stall (20000); + } +} + +EFI_STATUS +PcieSetupPciBridge ( + VOID + ) +{ + UINT8 classCode[0]; + + // Setup the bridge class + classCode[0] =3D PCI_IF_BRIDGE_P2P; + classCode[1] =3D PCI_CLASS_BRIDGE_P2P; + classCode[2] =3D PCI_CLASS_BRIDGE; + + return PciePciWrite ( + EfiPciIoWidthUint8, + PCIE_HOST_CONFIG_BASE_REG + PCI_CLASSCODE_OFFSET, + 3, + classCode); +} + +EFI_STATUS +PcieSetLinkStatus ( + IN BOOLEAN State + ) +{ + volatile IMX_IOMUXC_GPR_REGISTERS *pIoMuxcGprRegisters; + IMX_IOMUXC_GPR12_REG Gpr12Reg; + + pIoMuxcGprRegisters =3D (IMX_IOMUXC_GPR_REGISTERS *)IOMUXC_GPR_BASE_ADDR= ESS; + Gpr12Reg.AsUint32 =3D MmioRead32 ((UINTN)&pIoMuxcGprRegisters->GPR12); + if (State =3D=3D TRUE) { + Gpr12Reg.APP_LTSSM_ENABLE =3D 1; // Enable link + } else { + Gpr12Reg.APP_LTSSM_ENABLE =3D 0; // Disable link + } + MmioWrite32 ((UINTN)&pIoMuxcGprRegisters->GPR12, Gpr12Reg.AsUint32); + + return EFI_SUCCESS; +} + +BOOLEAN +PcieIsLinkUp ( + VOID + ) +{ + volatile CSP_PCIE_PL_REGS *pPortLogicRegs; + UINT32 Debug1Reg; + + pPortLogicRegs =3D (CSP_PCIE_PL_REGS *)PCIE_CTRL_PORT_LOGIG_BASE_REG; + Debug1Reg =3D MmioRead32 ((UINTN)&pPortLogicRegs->PCIE_PL_DEBUG1); + return (Debug1Reg & PCIE_PL_DEBUG1_PHY_LINK_UP) ? TRUE : FALSE; +} + +EFI_STATUS +PcieWaitForLink ( + VOID + ) +{ + UINT32 Counter; + BOOLEAN LinkStatus; + + Counter =3D 200; + LinkStatus =3D PcieIsLinkUp (); + + // To optimize boot time, consider lowering timeout value + while (LinkStatus =3D=3D FALSE && Counter > 0) { + --Counter; + gBS->Stall (1000); + LinkStatus =3D PcieIsLinkUp (); + } + + return (LinkStatus) ? EFI_SUCCESS : EFI_DEVICE_ERROR; +} + +EFI_STATUS +PcieGetAlignAddress ( + IN UINTN Address, + IN UINTN AlignmentSize, + OUT UINTN *AlignAddress + ) +{ + EFI_STATUS Status; + + *AlignAddress =3D 0; + if ((AlignmentSize & (AlignmentSize - 1)) !=3D 0) { + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + // Even though we do not add a (AlignmentSize + 1) to the incoming addre= ss + // we would still align to the upper boundary as bit [19:00] is assumed = to + // be 0x000FFFFF per Pcie spec. + *AlignAddress =3D (Address) & ~(AlignmentSize - 1); + Status =3D EFI_SUCCESS; + +Exit: + return Status; +} + +EFI_STATUS +PcieGetPciConfigAddress ( + IN UINTN BusNumber, + IN UINTN DevNumber, + IN UINTN FuncNumber, + IN UINTN Register, + OUT UINTN *Address + ) +{ + UINT64 Offset; + EFI_STATUS Status; + + // For now only support bus 0 and bus 1 with one device in each bus + if (BusNumber =3D=3D 0 && DevNumber =3D=3D 0) { + Offset =3D EFI_PCI_ADDRESS (BusNumber, DevNumber, FuncNumber, Register= ); + *Address =3D PCIE_HOST_CONFIG_BASE_REG + Offset; + Status =3D EFI_SUCCESS; + } else if (BusNumber =3D=3D 1 && DevNumber =3D=3D 0) { + Offset =3D EFI_PCI_ADDRESS (BusNumber, DevNumber, FuncNumber, Register= ); + Offset -=3D EFI_PCI_ADDRESS (1, 0, FuncNumber, 0); + *Address =3D PCIE_DEVICE_CONFIG_BASE_REG + Offset; + Status =3D EFI_SUCCESS; + } else { + *Address =3D 0; + Status =3D EFI_INVALID_PARAMETER; + } + + return Status; +} + +EFI_STATUS +PciePciRead ( + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + UINT8 *pDest; + EFI_STATUS Status; + UINTN Stride; + + pDest =3D (UINT8 *)Buffer; + Width =3D (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03); + Stride =3D (UINTN)1 << Width; + + switch (Width) { + case EfiPciWidthUint8: + for (; Count > 0; --Count, pDest +=3D Stride, Address +=3D Stride) { + *pDest =3D MmioRead8 (Address); + } + Status =3D EFI_SUCCESS; + break; + case EfiPciWidthUint16: + for (; Count > 0; --Count, pDest +=3D Stride, Address +=3D Stride) { + *((UINT16 *)pDest) =3D MmioRead16 (Address); + } + Status =3D EFI_SUCCESS; + break; + case EfiPciWidthUint32: + for (; Count > 0; --Count, pDest +=3D Stride, Address +=3D Stride) { + *((UINT32 *)pDest) =3D MmioRead32 (Address); + } + Status =3D EFI_SUCCESS; + break; + default: + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + +Exit: + return Status; +} + +EFI_STATUS +PciePciWrite ( + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + UINT8 *pSrc; + EFI_STATUS Status; + UINTN Stride; + + pSrc =3D (UINT8 *)Buffer; + Width =3D (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03); + Stride =3D (UINTN)1 << Width; + + switch (Width) { + case EfiPciWidthUint8: + for (; Count > 0; --Count, pSrc +=3D Stride, Address +=3D Stride) { + MmioWrite8 (Address, *pSrc); + } + Status =3D EFI_SUCCESS; + break; + case EfiPciWidthUint16: + for (; Count > 0; --Count, pSrc +=3D Stride, Address +=3D Stride) { + MmioWrite16 (Address, *((UINT16 *)pSrc)); + } + Status =3D EFI_SUCCESS; + break; + case EfiPciWidthUint32: + for (; Count > 0; --Count, pSrc +=3D Stride, Address +=3D Stride) { + MmioWrite32 (Address, *((UINT32 *)pSrc)); + } + Status =3D EFI_SUCCESS; + break; + default: + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + +Exit: + return Status; +} + +EFI_STATUS +PcieDevicePresent ( + OUT PCI_TYPE00 *PciDevice, + IN UINTN Bus, + IN UINTN Device, + IN UINTN Func + ) +{ + UINTN Address; + EFI_STATUS Status; + + // Create Pci address map in terms of Bus, Device, and Func + Status =3D PcieGetPciConfigAddress (Bus, Device, Func, 0, &Address); + if (EFI_ERROR (Status)) { + Status =3D EFI_NOT_FOUND; + goto Exit; + } + + // Read the Vendor ID register + Status =3D PciePciRead ( + EfiPciWidthUint32, + Address, + 1, + PciDevice); + if (!EFI_ERROR (Status) && (PciDevice->Hdr).VendorId !=3D 0xffff) { + // Read the entire config header for the device + Status =3D PciePciRead ( + EfiPciWidthUint32, + Address, + sizeof (PCI_TYPE00) / sizeof (UINT32), + PciDevice); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to read Pci config space\n"); + } + } else { + PCIE_INFO ("No Pcie device found\n"); + Status =3D EFI_NOT_FOUND; + } + +Exit: + return Status; +} + +EFI_STATUS +PcieGetMemoryBarResource ( + IN UINTN BarSize, + IN UINTN *BarAddress, + IN BOOLEAN IsBridgeDevice + ) +{ + EFI_STATUS Status; + + if (BarSize > PcieResource->Size) { + PCIE_ERROR ("Insufficient Pcie memory for 0x%08x (Current size 0x%08x)= \n", + BarSize, + PcieResource->Size); + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + *BarAddress =3D PcieResource->Curr; + + if (IsBridgeDevice =3D=3D FALSE) { + PcieResource->Curr +=3D BarSize; + PcieResource->Size -=3D BarSize; + + PCIE_INFO ("Allocating memory resource 0x%08x size 0x%08x\n", + *BarAddress, + BarSize); + } + + PCIE_INFO ("Current memory resource 0x%08x Size 0x%08x\n", + PcieResource->Curr, + PcieResource->Size); + + Status =3D EFI_SUCCESS; + +Exit: + return Status; +} + +EFI_STATUS +PcieParseAssignBar ( + IN UINTN BaseAddress, + IN UINTN MaxBarIndex, + IN BOOLEAN IsBridgeDevice + ) +{ + UINT32 AllOne32; + UINT32 AllZero; + UINTN BarIndex; + UINTN BarOffset; + UINTN BarSize; + UINTN Originalvalue; + UINTN ResourceAddress; + UINTN ResponseValue; + EFI_STATUS Status; + + AllZero =3D 0; + AllOne32 =3D MAX_UINT32; + for (BarOffset =3D 0x10, BarIndex =3D 0; + BarOffset <=3D 0x24 && BarIndex < MaxBarIndex; + BarOffset +=3D sizeof (UINT32), ++BarIndex) { + + Status =3D PciePciRead ( + EfiPciWidthUint32, + BaseAddress + BarOffset, + 1, + &Originalvalue); + ASSERT_EFI_ERROR (Status); + + Status =3D PciePciWrite ( + EfiPciIoWidthUint32, + BaseAddress + BarOffset, + 1, + &AllOne32); + ASSERT_EFI_ERROR (Status); + + Status =3D PciePciRead ( + EfiPciWidthUint32, + BaseAddress + BarOffset, + 1, + &ResponseValue); + ASSERT_EFI_ERROR (Status); + + // No support for IO memory + // Refer : Pci Local Bus Specification (6.2.5.1) + if ((ResponseValue & 0x01) =3D=3D 0x01) { + Status =3D PciePciWrite ( + EfiPciIoWidthUint32, + BaseAddress + BarOffset, + 1, + &Originalvalue); + ASSERT_EFI_ERROR (Status); + continue; + } + + // No support for prefetch memory + if (((ResponseValue & 0x01) =3D=3D 0x00) && + ((ResponseValue & 0x08) =3D=3D 0x08)) { + Status =3D PciePciWrite ( + EfiPciIoWidthUint32, + BaseAddress + BarOffset, + 1, + &Originalvalue); + ASSERT_EFI_ERROR (Status); + continue; + } + + BarSize =3D (~(ResponseValue & 0xFFFFFFF0)) + 1; + + Status =3D PcieGetMemoryBarResource ( + BarSize, + &ResourceAddress, + IsBridgeDevice); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to acquire BAR resource\n"); + goto Exit; + } + + Status =3D PciePciWrite ( + EfiPciIoWidthUint32, + BaseAddress + BarOffset, + 1, + &ResourceAddress); + ASSERT_EFI_ERROR (Status); + + // The subsequent BAR is the upper 32 bit address + if (((ResponseValue & 0x04) =3D=3D 0x04) && + (BarIndex + 1) < MaxBarIndex) { + BarOffset +=3D sizeof (UINT32); + ++BarIndex; + + Status =3D PciePciWrite ( + EfiPciIoWidthUint32, + BaseAddress + BarOffset, + 1, + &AllZero); + ASSERT_EFI_ERROR (Status); + + continue; + } + } + + Status =3D EFI_SUCCESS; + +Exit: + return Status; +} + +EFI_STATUS +PcieConfigureDevice ( + IN PCI_TYPE00 PciDevice, + IN UINTN BusNumber, + IN UINTN DevNumber, + IN UINTN FuncNumber + ) +{ + UINT32 AllZero; + UINTN BaseAddress; + UINT8 FixedCacheLineSize; + UINT16 PciCommand; + EFI_STATUS Status; + + AllZero =3D 0; + + PCIE_INFO ( + "Configuring B:%02d D:%02d F:%02d\n", + BusNumber, + DevNumber, + FuncNumber); + + Status =3D PcieGetPciConfigAddress ( + BusNumber, + DevNumber, + FuncNumber, + 0, + &BaseAddress); + ASSERT_EFI_ERROR (Status); + + // Use a fixed cacheline size + FixedCacheLineSize =3D 0x10; + + Status =3D PciePciWrite ( + EfiPciIoWidthUint8, + BaseAddress + PCI_CACHELINE_SIZE_OFFSET, + 1, + &FixedCacheLineSize); + ASSERT_EFI_ERROR (Status); + + if (IS_PCI_BRIDGE (&PciDevice)) { + PCIE_INFO ("Pci Bridge\n"); + // Pcie initialization sequence, referenced from + // InitializePpb in MdeModulePkg/Bus/Pci/PciBusDxe + // No support for IO and prefetch memory + Status =3D PciePciWrite ( + EfiPciIoWidthUint8, + BaseAddress + 0x1C, + 1, + &AllZero); + ASSERT_EFI_ERROR (Status); + + Status =3D PciePciWrite ( + EfiPciIoWidthUint8, + BaseAddress + 0x1D, + 1, + &AllZero); + + Status =3D PciePciWrite ( + EfiPciIoWidthUint16, + BaseAddress + 0x24, + 1, + &AllZero); + ASSERT_EFI_ERROR (Status); + + Status =3D PciePciWrite ( + EfiPciIoWidthUint16, + BaseAddress + 0x26, + 1, + &AllZero); + ASSERT_EFI_ERROR (Status); + + Status =3D PciePciWrite ( + EfiPciIoWidthUint32, + BaseAddress + 0x28, + 1, + &AllZero); + ASSERT_EFI_ERROR (Status); + + Status =3D PciePciWrite ( + EfiPciIoWidthUint32, + BaseAddress + 0x2C, + 1, + &AllZero); + ASSERT_EFI_ERROR (Status); + + Status =3D PciePciWrite ( + EfiPciIoWidthUint16, + BaseAddress + 0x30, + 1, + &AllZero); + ASSERT_EFI_ERROR (Status); + + Status =3D PciePciWrite ( + EfiPciIoWidthUint16, + BaseAddress + 0x32, + 1, + &AllZero); + ASSERT_EFI_ERROR (Status); + + // Type 1 bridge only has 2 BAR register + Status =3D PcieParseAssignBar ( + BaseAddress, + 2, + TRUE); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to assign resource to Pci bridge\n"); + goto Exit; + } + } else { + // Device specific configuration should be implemented here + PCIE_INFO ("Pci device\n"); + + Status =3D PcieParseAssignBar ( + BaseAddress, + PCI_MAX_BAR, + FALSE); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to assign resource to Pci device\n"); + goto Exit; + } + } + + Status =3D PciePciRead ( + EfiPciIoWidthUint16, + BaseAddress + PCI_COMMAND_OFFSET, + 1, + &PciCommand); + ASSERT_EFI_ERROR (Status); + + PciCommand |=3D + (EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER); + + Status =3D PciePciWrite ( + EfiPciIoWidthUint16, + BaseAddress + PCI_COMMAND_OFFSET, + 1, + &PciCommand); + ASSERT_EFI_ERROR (Status); + + Status =3D EFI_SUCCESS; + +Exit: + return Status; +} + +EFI_STATUS +PcieSimpleScanBusAndAssignResource ( + IN UINTN BusNumber + ) +{ + UINTN BridgeMemory; + UINTN BridgeMemoryBase; + UINTN BridgeMemoryLimit; + UINTN BusBaseRegisterAddress; + UINT16 BusRegister; + UINTN DevNumber; + UINTN FunctionNumber; + PCI_TYPE00 PciDevice; + UINTN ResourceAddress; + EFI_STATUS Status; + UINT8 SubBus; + + for (DevNumber =3D 0; DevNumber <=3D PCI_MAX_DEVICE; ++DevNumber) { + for (FunctionNumber =3D 0; FunctionNumber <=3D PCI_MAX_FUNC; ++Functio= nNumber) { + PCIE_INFO ("Scanning device B: %02d D: %02d F: %02d\n", + BusNumber, + DevNumber, + FunctionNumber); + + Status =3D PcieDevicePresent ( + &PciDevice, + BusNumber, + DevNumber, + FunctionNumber); + if (Status =3D=3D EFI_NOT_FOUND) { + PCIE_INFO ("No Pci device found\n"); + Status =3D EFI_SUCCESS; + goto Exit; + } else if (EFI_ERROR (Status)) { + PCIE_ERROR ("Error detecting Pci device\n"); + goto Exit; + } + + Status =3D PcieConfigureDevice ( + PciDevice, + BusNumber, + DevNumber, + FunctionNumber); + if (EFI_ERROR (Status)) { + PCIE_ERROR ( + "Failed to configure device B:%02d D:%02d F:%02d\n", + BusNumber, + DevNumber, + FunctionNumber); + continue; + } + + if (IS_PCI_BRIDGE (&PciDevice)) { + BusRegister =3D (UINT16) (((BusNumber + 1) << 8) | (UINT16)BusNumb= er); + Status =3D PcieGetPciConfigAddress ( + BusNumber, + DevNumber, + FunctionNumber, + 0, + &BusBaseRegisterAddress); + + ASSERT_EFI_ERROR (Status); + + Status =3D PciePciWrite ( + EfiPciWidthUint16, + BusBaseRegisterAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTE= R_OFFSET, + 1, + &BusRegister); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to update bridge bus number %d\n", BusNumber= ); + continue; + } + + // Temporarily set maximum subordinate bus number, although for no= w + // only support 2 buses. + SubBus =3D 0XFF; + Status =3D PciePciWrite ( + EfiPciWidthUint8, + BusBaseRegisterAddress + PCI_BRIDGE_SUBORDINATE_BUS_REG= ISTER_OFFSET, + 1, + &SubBus); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to update bridge bus number %d\n", BusNumber= ); + continue; + } + + // Setup the memory base. + Status =3D PcieGetMemoryBarResource ( + 0, + &BridgeMemoryBase, + TRUE); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to acquire BAR resource\n"); + goto Exit; + } + + BridgeMemory =3D (BridgeMemoryBase >> 16) & 0xFFF0; + + Status =3D PciePciWrite ( + EfiPciIoWidthUint32, + BusBaseRegisterAddress + 0x20, + 1, + &BridgeMemory); + ASSERT_EFI_ERROR (Status); + + Status =3D PcieSimpleScanBusAndAssignResource ( + BusNumber + 1); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to scan new bus %d\n", BusNumber + 1); + continue; + } + + // Setup the memory limit. + Status =3D PcieGetMemoryBarResource ( + 0, + &ResourceAddress, + TRUE); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to acquire BAR resource\n"); + goto Exit; + } + + ASSERT (BridgeMemoryBase !=3D ResourceAddress); + + // Per spec align address has to be 1MB boundary + PcieGetAlignAddress ( + ResourceAddress, + 0x00100000, + &BridgeMemoryLimit); + ASSERT_EFI_ERROR (Status); + + BridgeMemory |=3D BridgeMemoryLimit; + + Status =3D PciePciWrite ( + EfiPciIoWidthUint32, + BusBaseRegisterAddress + 0x20, + 1, + &BridgeMemory); + ASSERT_EFI_ERROR (Status); + + SubBus =3D (BusNumber + 1); + Status =3D PciePciWrite ( + EfiPciWidthUint8, + BusBaseRegisterAddress + + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, + 1, + &SubBus); + if (EFI_ERROR (Status)) { + PCIE_ERROR ( + "Failed to update subordinate bus number %d\n", + BusNumber); + continue; + } + + // Claim any memory that is used for padding + Status =3D PcieGetMemoryBarResource ( + (BridgeMemoryLimit + 0x00100000) - ResourceAddress, + &ResourceAddress, + FALSE); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to realign resource\n"); + goto Exit; + } + } + + // Skip sub functions, this is not a multi function device + if (FunctionNumber =3D=3D 0 && !IS_PCI_MULTI_FUNC (&PciDevice)) { + FunctionNumber =3D PCI_MAX_FUNC; + } + } + } + +Exit: + return Status; +} + +EFI_STATUS +PcieInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTablePtr + ) +{ + EFI_STATUS Status; + + Status =3D PcieSetupInitSetting (); + if (EFI_ERROR (Status)) { + // EFI_DEVICE_ERROR indicates that a bootloader has already setup the + // Pcie controller. In this case just return success immediately + if (Status =3D=3D EFI_DEVICE_ERROR) { + Status =3D EFI_SUCCESS; + PCIE_WARNING ("Pcie already initialized\n"); + goto Exit; + } + + PCIE_ERROR ("Failed to enable Pcie gates\n"); + goto Exit; + } + + Status =3D PcieSetClockGate (IMX_CLOCK_GATE_STATE_ON); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to enable Pcie gates\n"); + goto Exit; + } + + Status =3D PcieVerifyClocks (); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to verify Pcie clocks, not configured!\n"); + goto Exit; + } + + Status =3D PcieSetPhyState (TRUE); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to enable Pcie PHY\n"); + goto Exit; + } + + // Very important to wait for Pcie PHY to settle here or the controller + // behaviour becomes unpredictable. + gBS->Stall (50000); + + PcieEnablePerstLine (); + + Status =3D PcieSetupPciBridge (); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to setup Pci bridge\n"); + goto Exit; + } + + Status =3D PcieSetLinkStatus (TRUE); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to enable Pcie link\n"); + goto Exit; + } + + Status =3D PcieWaitForLink (); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Pci link never came up\n"); + goto Exit; + } + + PcieSetupiAtuSettings (); + + // Start scanning from bus 0 onward + Status =3D PcieSimpleScanBusAndAssignResource (0); + if (EFI_ERROR (Status)) { + PCIE_ERROR ("PcieSimpleScanBusAndAssignResource failed %r\n", Status); + goto Exit; + } + +#ifdef DEBUG + volatile UINT32 *pPrintAddr; + UINT32 PrintIndex; + + pPrintAddr =3D (UINT32 *)PCIE_HOST_CONFIG_BASE_REG; + + PCIE_INFO ("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); + PCIE_INFO ("Host Device Configuration space\n"); + PCIE_INFO ("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); + for (PrintIndex =3D 0; PrintIndex < 16; ++PrintIndex) { + PCIE_INFO ("PCI [%02x] 0x%08x 0x%08x 0x%08x 0x%08x\n", \ + PrintIndex * 16, \ + pPrintAddr[0], \ + pPrintAddr[1], \ + pPrintAddr[2], \ + pPrintAddr[3]); + + pPrintAddr +=3D 4; + } + + PCIE_INFO ("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); + PCIE_INFO ("Device Configuration space 0x%08x\n", pPrintAddr); + PCIE_INFO ("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); + for (PrintIndex =3D 0; PrintIndex < 16; ++PrintIndex) { + PCIE_INFO ("PCI [%02x] 0x%08x 0x%08x 0x%08x 0x%08x\n", \ + PrintIndex * 16, \ + pPrintAddr[0], \ + pPrintAddr[1], \ + pPrintAddr[2], \ + pPrintAddr[3]); + + pPrintAddr +=3D 4; + } + PCIE_INFO ("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); +#endif + +Exit: + + if (EFI_ERROR (Status)) { + PCIE_ERROR ("Failed to initialize Pcie, disabling controller\n"); + PcieSetLinkStatus (FALSE); + PcieSetPhyState (FALSE); + PcieSetClockGate (IMX_CLOCK_GATE_STATE_OFF); + } + + // For debug printout the state of the PLL/PHY +#ifdef DEBUG + volatile IMX_CCM_ANALOG_REGISTERS *pCcmAnalogRegs; + volatile IMX_IOMUXC_GPR_REGISTERS *pIoMuxcRegs; + + pCcmAnalogRegs =3D (IMX_CCM_ANALOG_REGISTERS *)IMX_CCM_ANALOG_BASE; + pIoMuxcRegs =3D (IMX_IOMUXC_GPR_REGISTERS *)IMX_IOMUXC_BASE; + + PCIE_INFO ( "IMX_CCM_PLL_ENET 0x%08X\n", + MmioRead32 ((UINTN) &pCcmAnalogRegs->PLL_ENET)); + PCIE_INFO ( "IOMUXC_GPR1 0x%08X\n", MmioRead32 ((UINTN) &pIoMuxcRegs->GP= R1)); +#endif + return Status; +} diff --git a/Silicon/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.h b/Sili= con/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.h new file mode 100644 index 000000000000..029e93b277cf --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.h @@ -0,0 +1,145 @@ +/** @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. +* +**/ + +#pragma once + +#ifndef ARRAYSIZE +#define ARRAYSIZE(__array__) (sizeof((__array__))/sizeof((__array__[0]))) +#endif + +// Print macro +#define PCIE_INIT(PRINT_OUT, ...) \ + DEBUG((DEBUG_INIT, "iMX6PCIe:" PRINT_OUT, ##__VA_ARGS__)) +#define PCIE_INFO(PRINT_OUT, ...) \ + DEBUG((DEBUG_INFO, "iMX6PCIe:" PRINT_OUT, ##__VA_ARGS__)) +#define PCIE_WARNING(PRINT_OUT, ...) \ + DEBUG((DEBUG_WARN, "iMX6PCIe:" PRINT_OUT, ##__VA_ARGS__)) +#define PCIE_ERROR(PRINT_OUT, ...) \ + DEBUG((DEBUG_ERROR, "iMX6PCIe:" PRINT_OUT, ##__VA_ARGS__)) + +// PCIe related base address +#define PCIE_HOST_CONFIG_BASE_REG FixedPcdGet32(PcdPcieHostConfigBas= e) +#define PCIE_CTRL_PORT_LOGIG_BASE_REG 0x01FFC700 +#define PCIE_DEVICE_CONFIG_BASE_REG FixedPcdGet32(PcdPcieDeviceConfigB= ase) +#define PCIE_DEVICE_CONFIG_SIZE FixedPcdGet32(PcdPcieDeviceConfigS= ize) +#define PCIE_IO_SPACE_BASE FixedPcdGet32(PcdPcieIOBase) +#define PCIE_IO_SPACE_SIZE FixedPcdGet32(PcdPcieIOSize) +#define PCIE_MEMORY_SPACE_BASE FixedPcdGet32(PcdPciMemoryBase) +#define PCIE_MEMORY_SPACE_SIZE FixedPcdGet32(PcdPciMemorySize) +#define PCIE_PREFETCH_MEMORY_SPACE_BASE FixedPcdGet32(PcdPciPrefetchMemory= Base) +#define PCIE_PREFETCH_MEMORY_SPACE_SIZE FixedPcdGet32(PcdPciPrefetchMemory= Size) + +#pragma pack(push, 1) + +typedef struct { + UINT64 Base; + UINT64 Size; + UINT64 Curr; +} PCI_RESOURCE; + +// Debug register related bits +#define PCIE_PL_DEBUG1_PHY_LINK_UP (1 << 4) +#define PCIE_PL_DEBUG1_LINK_IN_TRAINING (1 << 29) + +// Address Translation Unit related definition +#define MAX_iATU_REGION 4 + +typedef enum _REGION_DIRECTION { + OUTBOUND, + INBOUND, +} REGION_DIRECTION; + +typedef enum _TLP_TYPE { + MEMORY_TYPE, + MEMORY_LOCK_TYPE, + IO_TYPE, + CFG0_TYPE =3D 4, + CFG1_TYPE =3D 5, +} TLP_TYPE; + +typedef enum _REGION_STATE { + REGION_DISABLE =3D 0, + REGION_ENABLE =3D 0x80000000, +} REGION_STATE; + +typedef struct { + UINT32 PCIE_PL_ALTRTR; // ACK latency timer and replay timer + UINT32 PCIE_PL_VSDR; // Vendor specific DLLP + UINT32 PCIE_PL_PFLR; // Port force link + UINT32 PCIE_PL_AFLACR; // ACK frequency and L0-L1 ASPM control + UINT32 PCIE_PL_PLCR; // Port link control + UINT32 PCIE_PL_LSR; // Lane skew + UINT32 PCIE_PL_SNR; // Symbol number + UINT32 PCIE_PL_STRFM1; // Symbol timer and filter mask 1 + UINT32 PCIE_PL_STRFM2; // Filter mask 2 + UINT32 PCIE_PL_AMODNPSR; // AMBA Multiple Outbound Decomposed NP = Sub-Requests + // Control + UINT32 PCIE_PL_DEBUG0; // Debug 0 + UINT32 PCIE_PL_DEBUG1; // Debug 1 + UINT32 PCIE_PL_TPFCSR; // Transmit Posted FC Credit Status + UINT32 PCIE_PL_TNFCSR; // Transmit Non-Posted FC Credit Status + UINT32 PCIE_PL_TCFCSR; // Transmit Completion FC Credit Status + UINT32 PCIE_PL_QSR; // Queue status + UINT32 PCIE_PL_VCTAR1; // Transmit Completion FC Status 1 + UINT32 PCIE_PL_VCTAR2; // Transmit Completion FC Status 1 + UINT32 PCIE_PL_VC0PRQC; // VC0 Posted Receive Queue Control + UINT32 PCIE_PL_VC0NRQC; // VC0 Non-Posted Receive Queue Control + UINT32 PCIE_PL_VC0CRQC; // VC0 Completion Receive Queue Control + UINT32 PCIE_PL_VCnPRQC; // VCn Posted Receive Queue Control + UINT32 PCIE_PL_VCnNRQC; // VCn Non-Posted Receive Queue Control + UINT32 PCIE_PL_VCnCRQC; // VCn Completion Receive Queue Control + UINT32 PCIE_PL_RESERVED_0[18]; + UINT32 PCIE_PL_VC0PBD; // VC0 Posted Buffer Depth + UINT32 PCIE_PL_VC0NPBD; // VC0 Non-Posted Buffer Depth + UINT32 PCIE_PL_VC0CBD; // VC0 Completion Buffer Depth + UINT32 PCIE_PL_VC1PBD; // VCn Posted Buffer Depth + UINT32 PCIE_PL_VC1NPBD; // VCn Non-Posted Buffer Depth + UINT32 PCIE_PL_VC1CBD; // VCn Completion Buffer Depth + UINT32 PCIE_PL_RESERVED_1[19]; + UINT32 PCIE_PL_G2CR; // Gen2 Control + UINT32 PCIE_PL_PHY_STATUS; // PHY status + UINT32 PCIE_PL_PHY_CTRL; // PHY control + UINT32 PCIE_PL_MRCCR0; // Master Response Composer Control 0 + UINT32 PCIE_PL_MRCCR1; // Master Response Composer Control 1 + UINT32 PCIE_PL_MSICA; // MSI Controller Address + UINT32 PCIE_PL_MSICUA; // MSI Controller Upper Address + UINT32 PCIE_PL_MSICIn_ENB; // MSI Controller Interrupt n Enable + UINT32 PCIE_PL_MSICIn_MASK; // MSI Controller Interrupt n Mask + UINT32 PCIE_PL_MSICIn_STATUS; // MSI Controller Interrupt n Status + UINT32 PCIE_PL_RESERVED_2[21]; + UINT32 PCIE_PL_MSICGPIO; // MSI Controller General Purpose IO + UINT32 PCIE_PL_RESERVED_3[29]; + UINT32 PCIE_PL_iATUVR; // iATU Viewport + UINT32 PCIE_PL_iATURC1; // iATU Control 1 + UINT32 PCIE_PL_iATURC2; // iATU Control 2 + UINT32 PCIE_PL_iATURLBA; // iATU Region Lower Base Address + UINT32 PCIE_PL_iATURUBA; // iATU Region Upper Base Address + UINT32 PCIE_PL_iATURLA; // iATU Region Limit Address + UINT32 PCIE_PL_iATURLTA; // iATU Region Lower Target Address + UINT32 PCIE_PL_iATURUTA; // iATU Region Upper Target Address +} CSP_PCIE_PL_REGS, *PCSP_PCIE_PL_REGS; + +typedef struct _IATU_SETTINGS { + UINT32 RegionDirection; + UINT32 RegionIndex; + TLP_TYPE Type; + UINT32 LowerBaseAddr; + UINT32 UpperBaseAddr; + UINT32 LimitAddr; + UINT32 LowerTargetAddr; + UINT32 UpperTargetAddr; + UINT32 State; +} IATU_SETTINGS, *PIATU_SETTINGS; + +#pragma pack(pop) diff --git a/Silicon/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.inf b/Si= licon/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.inf new file mode 100644 index 000000000000..99dbe9a4344e --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Drivers/PciExpress/iMX6PciExpress.inf @@ -0,0 +1,66 @@ +## @file +# +# Copyright (c) 2018 Microsoft Corporation. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the B= SD License +# which accompanies this distribution. The full text of the license may = be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +# +## + +[Defines] + INF_VERSION =3D 0x0001001A + BASE_NAME =3D iMX6PciExpress + FILE_GUID =3D 5A7FB871-8A19-48D5-A268-441E79AAFD9E + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D PcieInitialize + +[Sources.common] + iMX6PciExpress.c + +[Packages] + ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/NXP/iMX6Pkg/iMX6Pkg.dec + Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec + +[LibraryClasses] + BaseLib + DxeServicesTableLib + iMX6ClkPwrLib + IoLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + +[Pcd] + giMX6TokenSpaceGuid.PcdPcieDeviceConfigBase + giMX6TokenSpaceGuid.PcdPcieDeviceConfigSize + giMX6TokenSpaceGuid.PcdPcieHostConfigBase + giMX6TokenSpaceGuid.PcdPcieIOBase + giMX6TokenSpaceGuid.PcdPcieIOSize + giMX6TokenSpaceGuid.PcdPciMemoryBase + giMX6TokenSpaceGuid.PcdPciMemorySize + giMX6TokenSpaceGuid.PcdPciPrefetchMemoryBase + giMX6TokenSpaceGuid.PcdPciPrefetchMemorySize + giMX6TokenSpaceGuid.PcdPcieResetGpio + giMX6TokenSpaceGuid.PcdPcieResetGpioBankNumber + giMX6TokenSpaceGuid.PcdPcieResetGpioIoNumber + +[FixedPcd] + giMXPlatformTokenSpaceGuid.PcdGpioBankMemoryRange + +[Depex] + gEfiCpuArchProtocolGuid AND gEfiMetronomeArchProtocolGuid + --=20 2.16.2.gvfs.1.33.gf5370f1