From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=pass header.i=@semihalf-com.20150623.gappssmtp.com header.s=20150623 header.b=Elpm/xze; spf=none, err=SPF record not found (domain: semihalf.com, ip: 209.85.167.67, mailfrom: mw@semihalf.com) Received: from mail-lf1-f67.google.com (mail-lf1-f67.google.com [209.85.167.67]) by groups.io with SMTP; Thu, 09 May 2019 02:54:07 -0700 Received: by mail-lf1-f67.google.com with SMTP id h13so1094276lfc.7 for ; Thu, 09 May 2019 02:54:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=semihalf-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=udR2vLoF0mq+l+Zf2va0rq9k4/jMGlBjhcyyTLla3Xs=; b=Elpm/xzeUR8WbE0bQ1//UJhgWPo3ky+7HqW36d5edjUJSwC7WvMxWEv903SZwhEQ95 CPoYd6ege5sc2EOjmiQcVVSpLfbykNAJKwQ5BJYupqrOiplE1tDNso8MamhsEpC271AW D5dhe3aGQTlwYEoMOwWqm5DgH2Xgl06OGKBTRpZuZF+f5B26OlXmJh76VjkcZfj4I5Or vglpgmg+5jRGRrjAixEnFPCLraUqkah8naVQDDqEEs1DMLHNZSrV8BwL6ywmlDimY057 FDdi8kjfz6GddKPRhVOS0JwtEz/W89vP8Yc0CbrwPf9qLXObH4CMA/9Q6wj+x87Bzdvt 1IOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=udR2vLoF0mq+l+Zf2va0rq9k4/jMGlBjhcyyTLla3Xs=; b=lxyGidjrwMaSc95LINmFNFddZSuEqAgumlOVPIScbIoIUVhh4pUtoLXG/qLgVWLx6Y 47Qegg1BNqh50ndNSD4iDHSdX6c7GPAWGhUV7B5Rfx2/H7NLvDLKSHnY2UbOwiaTJjxW sA/QoISUYJsS+V0GeKe8urdTskIS7pLAYEqZPtKmbJ6opybdEbwfmu6Mzg8ul+B5Cox/ b2QM59gfj0azN21Mhn6ugZWpg+JP4ryJrvsm7qFfakNZroqVVMKkIg1rtoG4E1k6RSaz HJaOfmdgywdEDIM8QY/4o0hTqsi3HU7RNVhqEdKx5ft8oFkPeS5+o11rdJzn3Vi7rWDx 5dLg== X-Gm-Message-State: APjAAAVt3XEsue4bCF58KJw4Y1W9tO2tmr6VlmLn5zjrXHTTmeGhUyGO OYZklVzvRbEMRJ/2lupBXCYAMduforc= X-Google-Smtp-Source: APXvYqwpDPJQuS4jBsir9hR3ZVCRS6kbks9ErBeZNSRJ2cSfyoIDj2WKWG3LSixOdlZnJYjPMHr8vw== X-Received: by 2002:ac2:5143:: with SMTP id q3mr2020963lfd.169.1557395644487; Thu, 09 May 2019 02:54:04 -0700 (PDT) Return-Path: Received: from gilgamesh.semihalf.com (31-172-191-173.noc.fibertech.net.pl. [31.172.191.173]) by smtp.gmail.com with ESMTPSA id l25sm276668lfk.57.2019.05.09.02.54.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 09 May 2019 02:54:03 -0700 (PDT) From: "Marcin Wojtas" To: devel@edk2.groups.io Cc: leif.lindholm@linaro.org, ard.biesheuvel@linaro.org, mw@semihalf.com, jsd@semihalf.com, jaz@semihalf.com, kostap@marvell.com, Jici.Gao@arm.com, rebecca@bluestop.org, kettenis@jive.eu Subject: [edk2-platforms: PATCH 07/14] Marvell/Armada7k8k: Implement PciHostBridgeLib Date: Thu, 9 May 2019 11:53:35 +0200 Message-Id: <1557395622-32425-8-git-send-email-mw@semihalf.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1557395622-32425-1-git-send-email-mw@semihalf.com> References: <1557395622-32425-1-git-send-email-mw@semihalf.com> Add an implementation of the PciHostBridgeLib glue library that describes the PCIe RC on this SoC so that the generic PCI host bridge driver can attach to it. This includes a constructor which performs the SoC specific init and training sequences. This patch is based on work of Ard Biesheuvel and Jing Hua / Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Marcin Wojtas --- Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.inf | 52 +++ Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.h | 95 ++++++ Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.c | 244 +++++++++++++++ Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.c | 330 ++++++++++++++++++++ 4 files changed, 721 insertions(+) create mode 100644 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.inf create mode 100644 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.h create mode 100644 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.c create mode 100644 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.c diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.inf b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.inf new file mode 100644 index 0000000..e46f71d --- /dev/null +++ b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.inf @@ -0,0 +1,52 @@ +## @file +# PCI Host Bridge Library instance for Marvell Armada 7k/8k SOC +# +# Copyright (c) 2017, Linaro Ltd. All rights reserved.
+# Copyright (c) 2019 Marvell International Ltd. All rights reserved.
+# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR +# IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = Armada7k8kPciHostBridgeLib + FILE_GUID = 7f989c9d-02a0-4348-8aeb-ab2e1566fb18 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = PciHostBridgeLib|DXE_DRIVER + CONSTRUCTOR = Armada7k8kPciHostBridgeLibConstructor + +[Sources] + PciHostBridgeLib.c + PciHostBridgeLibConstructor.c + +[Packages] + ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Marvell/Marvell.dec + +[LibraryClasses] + ArmLib + ArmadaSoCDescLib + DebugLib + DevicePathLib + MemoryAllocationLib + MvGpioLib + UefiBootServicesTableLib + +[Protocols] + gEmbeddedGpioProtocolGuid + gMarvellBoardDescProtocolGuid + +[Depex] + gMarvellPlatformInitCompleteProtocolGuid diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.h b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.h new file mode 100644 index 0000000..ff9d919 --- /dev/null +++ b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.h @@ -0,0 +1,95 @@ +/** @file + PCI Host Bridge Library instance for Marvell 70x0/80x0 + + Copyright (c) 2017, Linaro Ltd. All rights reserved.
+ Copyright (c) 2019 Marvell International Ltd. All rights reserved.
+ + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#ifndef __PCI_HOST_BRIDGE_LIB_CONSTRUCTOR_H__ +#define __PCI_HOST_BRIDGE_LIB_CONSTRUCTOR_H__ + +#define IATU_VIEWPORT_OFF 0x900 +#define IATU_VIEWPORT_INBOUND BIT31 +#define IATU_VIEWPORT_OUTBOUND 0 +#define IATU_VIEWPORT_REGION_INDEX(Idx) ((Idx) & 7) + +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0 0x904 +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM 0x0 +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_IO 0x2 +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG0 0x4 +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG1 0x5 + +#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0 0x908 +#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN BIT31 +#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0_CFG_SHIFT_MODE BIT28 + +#define IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0 0x90C +#define IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0 0x910 +#define IATU_LIMIT_ADDR_OFF_OUTBOUND_0 0x914 +#define IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0 0x918 +#define IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0 0x91C + +#define PORT_LINK_CTRL_OFF 0x710 +#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_x1 (0x01 << 16) +#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_x2 (0x03 << 16) +#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_x4 (0x07 << 16) +#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_x8 (0x0f << 16) +#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_x16 (0x1f << 16) +#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_MASK (0x3f << 16) + +#define GEN2_CTRL_OFF 0x80c +#define GEN2_CTRL_OFF_NUM_OF_LANES(n) (((n) & 0x1f) << 8) +#define GEN2_CTRL_OFF_NUM_OF_LANES_MASK (0x1f << 8) +#define GEN2_CTRL_OFF_DIRECT_SPEED_CHANGE BIT17 + +#define PCIE_GLOBAL_CTRL_OFFSET 0x8000 +#define PCIE_GLOBAL_APP_LTSSM_EN BIT2 +#define PCIE_GLOBAL_CTRL_DEVICE_TYPE_RC (0x4 << 4) +#define PCIE_GLOBAL_CTRL_DEVICE_TYPE_MASK (0xF << 4) + +#define PCIE_GLOBAL_STATUS_REG 0x8008 +#define PCIE_GLOBAL_STATUS_RDLH_LINK_UP BIT1 +#define PCIE_GLOBAL_STATUS_PHY_LINK_UP BIT9 + +#define PCIE_PM_STATUS 0x8014 +#define PCIE_PM_LTSSM_STAT_MASK (0x3f << 3) + +#define PCIE_GLOBAL_INT_MASK1_REG 0x8020 +#define PCIE_INT_A_ASSERT_MASK BIT9 +#define PCIE_INT_B_ASSERT_MASK BIT10 +#define PCIE_INT_C_ASSERT_MASK BIT11 +#define PCIE_INT_D_ASSERT_MASK BIT12 + +#define PCIE_ARCACHE_TRC_REG 0x8050 +#define PCIE_AWCACHE_TRC_REG 0x8054 +#define PCIE_ARUSER_REG 0x805C +#define PCIE_AWUSER_REG 0x8060 + +#define ARCACHE_DEFAULT_VALUE 0x3511 +#define AWCACHE_DEFAULT_VALUE 0x5311 + +#define AX_USER_DOMAIN_INNER_SHAREABLE (0x1 << 4) +#define AX_USER_DOMAIN_OUTER_SHAREABLE (0x2 << 4) +#define AX_USER_DOMAIN_MASK (0x3 << 4) + +#define PCIE_LINK_CAPABILITY 0x7C +#define PCIE_LINK_CTL_2 0xA0 +#define TARGET_LINK_SPEED_MASK 0xF +#define LINK_SPEED_GEN_1 0x1 +#define LINK_SPEED_GEN_2 0x2 +#define LINK_SPEED_GEN_3 0x3 + +#define PCIE_GEN3_EQU_CTRL 0x8A8 +#define GEN3_EQU_EVAL_2MS_DISABLE BIT5 + +#define PCIE_LINK_UP_TIMEOUT_US 40000 + +#endif diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.c b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.c new file mode 100644 index 0000000..ff6288c --- /dev/null +++ b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.c @@ -0,0 +1,244 @@ +/** @file + PCI Host Bridge Library instance for Marvell Armada 70x0/80x0 + + Copyright (c) 2017, Linaro Ltd. All rights reserved.
+ Copyright (c) 2019 Marvell International Ltd. All rights reserved.
+ + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#pragma pack(1) +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; +#pragma pack () + +STATIC EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath = { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), + (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) + } + }, + EISA_PNP_ID(0x0A08), // PCI Express + 0 + }, + + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED +CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = { + L"Mem", L"I/O", L"Bus" +}; + +/** + Return all the root bridge instances in an array. + + @param Count Return the count of root bridge instances. + + @return All the root bridge instances in an array. + The array should be passed into PciHostBridgeFreeRootBridges() + when it's not used. + +**/ +PCI_ROOT_BRIDGE * +EFIAPI +PciHostBridgeGetRootBridges ( + UINTN *Count + ) +{ + MARVELL_BOARD_DESC_PROTOCOL *BoardDescriptionProtocol; + MV_BOARD_PCIE_DESCRIPTION *BoardPcieDescription; + MV_PCIE_CONTROLLER *PcieController; + PCI_ROOT_BRIDGE *PciRootBridges; + PCI_ROOT_BRIDGE *RootBridge; + EFI_STATUS Status; + UINTN Index; + + *Count = 0; + + /* Obtain list of available controllers */ + Status = gBS->LocateProtocol (&gMarvellBoardDescProtocolGuid, + NULL, + (VOID **)&BoardDescriptionProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Cannot locate BoardDesc protocol\n", + __FUNCTION__)); + return NULL; + } + + Status = BoardDescriptionProtocol->PcieDescriptionGet ( + BoardDescriptionProtocol, + &BoardPcieDescription); + if (Status == EFI_NOT_FOUND) { + /* No controllers used on the platform, exit silently */ + return NULL; + } else if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Cannot get Pcie board desc from BoardDesc protocol\n", + __FUNCTION__)); + return NULL; + } + + /* Assign return values */ + PciRootBridges = AllocateZeroPool (BoardPcieDescription->PcieControllerCount * + sizeof (PCI_ROOT_BRIDGE)); + if (PciRootBridges == NULL) { + DEBUG ((DEBUG_ERROR, "%a: Fail to allocate resources\n", __FUNCTION__)); + return NULL; + } + + *Count = BoardPcieDescription->PcieControllerCount; + RootBridge = PciRootBridges; + + /* Fill information of all root bridge instances */ + for (Index = 0; Index < *Count; Index++, RootBridge++) { + + PcieController = &(BoardPcieDescription->PcieControllers[Index]); + + RootBridge->Segment = 0; + RootBridge->Supports = 0; + RootBridge->Attributes = RootBridge->Supports; + + RootBridge->DmaAbove4G = FALSE; + + RootBridge->AllocationAttributes = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | + EFI_PCI_HOST_BRIDGE_MEM64_DECODE; + + RootBridge->Bus.Base = PcieController->PcieBusMin; + RootBridge->Bus.Limit = PcieController->PcieBusMax; + RootBridge->Io.Base = PcieController->PcieIoWinBase; + RootBridge->Io.Limit = PcieController->PcieIoWinBase + + PcieController->PcieIoWinSize - 1; + RootBridge->Mem.Base = PcieController->PcieMmio32WinBase; + RootBridge->Mem.Limit = PcieController->PcieMmio32WinBase + + PcieController->PcieMmio32WinSize - 1; + RootBridge->MemAbove4G.Base = PcieController->PcieMmio64WinBase; + RootBridge->MemAbove4G.Limit = PcieController->PcieMmio64WinBase + + PcieController->PcieMmio64WinSize - 1; + + /* No separate ranges for prefetchable and non-prefetchable BARs */ + RootBridge->PMem.Base = MAX_UINT64; + RootBridge->PMem.Limit = 0; + RootBridge->PMemAbove4G.Base = MAX_UINT64; + RootBridge->PMemAbove4G.Limit = 0; + + ASSERT (PcieController->PcieMmio64Translation == 0); + ASSERT (PcieController->PcieMmio32Translation == 0); + + RootBridge->NoExtendedConfigSpace = FALSE; + + RootBridge->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath; + } + + return PciRootBridges; +} + +/** + Free the root bridge instances array returned from PciHostBridgeGetRootBridges(). + + @param Bridges The root bridge instances array. + @param Count The count of the array. + +**/ +VOID +EFIAPI +PciHostBridgeFreeRootBridges ( + PCI_ROOT_BRIDGE *Bridges, + UINTN Count + ) +{ + FreePool (Bridges); +} + +/** + Inform the platform that the resource conflict happens. + + @param HostBridgeHandle Handle of the Host Bridge. + @param Configuration Pointer to PCI I/O and PCI memory resource + descriptors. The Configuration contains the resources + for all the root bridges. The resource for each root + bridge is terminated with END descriptor and an + additional END is appended indicating the end of the + entire resources. The resource descriptor field + values follow the description in + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + .SubmitResources(). + +**/ +VOID +EFIAPI +PciHostBridgeResourceConflict ( + EFI_HANDLE HostBridgeHandle, + VOID *Configuration + ) +{ + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; + UINTN RootBridgeIndex; + + DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n")); + + RootBridgeIndex = 0; + Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; + + while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) { + + DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++)); + + for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) { + ASSERT (Descriptor->ResType < + (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) / + sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0]))); + + DEBUG ((DEBUG_ERROR, + " %s: Length/Alignment = 0x%lx / 0x%lx\n", + mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType], + Descriptor->AddrLen, Descriptor->AddrRangeMax)); + + if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { + DEBUG ((DEBUG_ERROR, + " Granularity/SpecificFlag = %ld / %02x%s\n", + Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag, + ((Descriptor->SpecificFlag & + EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) ? + L" (Prefetchable)" : L"")); + } + } + /* Skip the END descriptor for root bridge */ + ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR); + Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)( + (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1); + } +} diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.c b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.c new file mode 100644 index 0000000..ced2c12 --- /dev/null +++ b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.c @@ -0,0 +1,330 @@ +/** @file + PCI Host Bridge Library instance for Marvell 70x0/80x0 + + Copyright (c) 2017, Linaro Ltd. All rights reserved.
+ Copyright (c) 2019 Marvell International Ltd. All rights reserved.
+ + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include "PciHostBridgeLibConstructor.h" + +/** + This function configures PCIE controllers IATU windows. + + @param [in] PcieBaseAddress PCIE controller base address. + @param [in] Index IATU window index. + @param [in] CpuBase Address from the CPU perspective. + @param [in] PciBase Target PCIE address. + @param [in] Size IATU window size. + @param [in] Type IATU window type. + @param [in] EnableFlags Extra configuration flags. + + @retval none + +**/ +STATIC +VOID +ConfigureWindow ( + IN EFI_PHYSICAL_ADDRESS PcieBaseAddress, + IN UINTN Index, + IN UINT64 CpuBase, + IN UINT64 PciBase, + IN UINT64 Size, + IN UINTN Type, + IN UINTN EnableFlags + ) +{ + ArmDataMemoryBarrier (); + + MmioWrite32 (PcieBaseAddress + IATU_VIEWPORT_OFF, + IATU_VIEWPORT_OUTBOUND | IATU_VIEWPORT_REGION_INDEX (Index)); + + ArmDataMemoryBarrier (); + + MmioWrite32 (PcieBaseAddress + IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0, + (UINT32)(CpuBase & 0xFFFFFFFF)); + MmioWrite32 (PcieBaseAddress + IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0, + (UINT32)(CpuBase >> 32)); + MmioWrite32 (PcieBaseAddress + IATU_LIMIT_ADDR_OFF_OUTBOUND_0, + (UINT32)(CpuBase + Size - 1)); + MmioWrite32 (PcieBaseAddress + IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0, + (UINT32)(PciBase & 0xFFFFFFFF)); + MmioWrite32 (PcieBaseAddress + IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0, + (UINT32)(PciBase >> 32)); + MmioWrite32 (PcieBaseAddress + IATU_REGION_CTRL_1_OFF_OUTBOUND_0, + Type); + MmioWrite32 (PcieBaseAddress + IATU_REGION_CTRL_2_OFF_OUTBOUND_0, + IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN | EnableFlags); +} + +/** + Perform PCIE slot reset using external GPIO pin. + + @param [in] PcieBaseAddress PCIE controller base address. + + @retval none + +**/ +STATIC +VOID +WaitForLink ( + IN EFI_PHYSICAL_ADDRESS PcieBaseAddress + ) +{ + UINT32 Mask; + UINT32 Status; + UINT32 Timeout; + + if (!(MmioRead32 (PcieBaseAddress + PCIE_PM_STATUS) & PCIE_PM_LTSSM_STAT_MASK)) { + DEBUG ((DEBUG_INIT, "%a: no PCIE device detected\n", __FUNCTION__)); + return; + } + + /* Wait for the link to establish itself */ + DEBUG ((DEBUG_INIT, "%a: waiting for PCIE link\n", __FUNCTION__)); + + Mask = PCIE_GLOBAL_STATUS_RDLH_LINK_UP | PCIE_GLOBAL_STATUS_PHY_LINK_UP; + Timeout = PCIE_LINK_UP_TIMEOUT_US / 10; + do { + Status = MmioRead32 (PcieBaseAddress + PCIE_GLOBAL_STATUS_REG); + if ((Status & Mask) == Mask) { + DEBUG ((DEBUG_ERROR, "pcie@0x%x link UP\n", PcieBaseAddress)); + break; + } + gBS->Stall (10); + } while (Timeout--); +} + +/** + Perform PCIE slot reset using external GPIO pin. + + @param [in] *PcieResetGpio GPIO pin description. + + @retval EFI_SUCEESS PCIE slot reset succeeded. + @retval Other Return error status. + +**/ +STATIC +EFI_STATUS +ResetPcieSlot ( + IN MV_GPIO_PIN *PcieResetGpio + ) +{ + EMBEDDED_GPIO_MODE Mode; + EMBEDDED_GPIO_PIN GpioPin; + EMBEDDED_GPIO *GpioProtocol; + EFI_STATUS Status; + + /* Get GPIO protocol */ + Status = MvGpioGetProtocol (PcieResetGpio->ControllerType, &GpioProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Unable to find GPIO protocol\n", __FUNCTION__)); + return Status; + } + + GpioPin = GPIO (PcieResetGpio->ControllerId, PcieResetGpio->PinNumber), + + /* Reset the slot by toggling the GPIO pin */ + Mode = PcieResetGpio->ActiveHigh ? GPIO_MODE_OUTPUT_1 : GPIO_MODE_OUTPUT_0; + Status = GpioProtocol->Set (GpioProtocol, GpioPin, Mode); + gBS->Stall (10 * 1000); + + Mode = PcieResetGpio->ActiveHigh ? GPIO_MODE_OUTPUT_0 : GPIO_MODE_OUTPUT_1; + Status = GpioProtocol->Set (GpioProtocol, GpioPin, Mode); + gBS->Stall (20 * 1000); + + return EFI_SUCCESS; +} + +/** + Obtain resources and perform a low-level PCIE controllers + configuration. + + @param [in] ImageHandle The image handle. + @param [in] *SystemTable The system table. + + @retval EFI_SUCEESS PCIE configuration successful. + @retval Other Return error status. + +**/ +EFI_STATUS +EFIAPI +Armada7k8kPciHostBridgeLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + MARVELL_BOARD_DESC_PROTOCOL *BoardDescriptionProtocol; + MV_BOARD_PCIE_DESCRIPTION *BoardPcieDescription; + MV_PCIE_CONTROLLER *PcieController; + EFI_PHYSICAL_ADDRESS PcieBaseAddress; + EFI_STATUS Status; + UINTN Index; + + /* Obtain list of available controllers */ + Status = gBS->LocateProtocol (&gMarvellBoardDescProtocolGuid, + NULL, + (VOID **)&BoardDescriptionProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Cannot locate BoardDesc protocol\n", + __FUNCTION__)); + return EFI_DEVICE_ERROR; + } + + Status = BoardDescriptionProtocol->PcieDescriptionGet ( + BoardDescriptionProtocol, + &BoardPcieDescription); + if (Status == EFI_NOT_FOUND) { + /* No controllers used on the platform, exit silently */ + return EFI_SUCCESS; + } else if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Cannot get Pcie board desc from BoardDesc protocol\n", + __FUNCTION__)); + return EFI_DEVICE_ERROR; + } + + for (Index = 0; Index < BoardPcieDescription->PcieControllerCount; Index++) { + + PcieController = &(BoardPcieDescription->PcieControllers[Index]); + + ASSERT (PcieController->PcieBusMin == 0); + ASSERT (PcieController->ConfigSpaceAddress % SIZE_256MB == 0); + + if (PcieController->HaveResetGpio == TRUE) { + /* Reset PCIE slot */ + Status = ResetPcieSlot (&PcieController->PcieResetGpio); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Cannot reset Pcie Slot\n", + __FUNCTION__)); + return EFI_DEVICE_ERROR; + } + } + + /* Low level PCIE controller configuration */ + PcieBaseAddress = PcieController->PcieBaseAddress; + + MmioAndThenOr32 (PcieBaseAddress + PORT_LINK_CTRL_OFF, + ~PORT_LINK_CTRL_OFF_LINK_CAPABLE_MASK, + PORT_LINK_CTRL_OFF_LINK_CAPABLE_x4); + + MmioAndThenOr32 (PcieBaseAddress + GEN2_CTRL_OFF, + ~GEN2_CTRL_OFF_NUM_OF_LANES_MASK, + GEN2_CTRL_OFF_NUM_OF_LANES(4) | GEN2_CTRL_OFF_DIRECT_SPEED_CHANGE); + + MmioAndThenOr32 (PcieBaseAddress + PCIE_GLOBAL_CTRL_OFFSET, + ~(PCIE_GLOBAL_CTRL_DEVICE_TYPE_MASK | PCIE_GLOBAL_APP_LTSSM_EN), + PCIE_GLOBAL_CTRL_DEVICE_TYPE_RC); + + MmioWrite32 (PcieBaseAddress + PCIE_ARCACHE_TRC_REG, + ARCACHE_DEFAULT_VALUE); + + MmioWrite32 (PcieBaseAddress + PCIE_AWCACHE_TRC_REG, + AWCACHE_DEFAULT_VALUE); + + MmioAndThenOr32 (PcieBaseAddress + PCIE_ARUSER_REG, + ~AX_USER_DOMAIN_MASK, + AX_USER_DOMAIN_OUTER_SHAREABLE); + + MmioAndThenOr32 (PcieBaseAddress + PCIE_AWUSER_REG, + ~AX_USER_DOMAIN_MASK, + AX_USER_DOMAIN_OUTER_SHAREABLE); + + MmioAndThenOr32 (PcieBaseAddress + PCIE_LINK_CTL_2, + ~TARGET_LINK_SPEED_MASK, + LINK_SPEED_GEN_3); + + MmioAndThenOr32 (PcieBaseAddress + PCIE_LINK_CAPABILITY, + ~TARGET_LINK_SPEED_MASK, + LINK_SPEED_GEN_3); + + MmioOr32 (PcieBaseAddress + PCIE_GEN3_EQU_CTRL, + GEN3_EQU_EVAL_2MS_DISABLE); + + MmioOr32 (PcieBaseAddress + PCIE_GLOBAL_CTRL_OFFSET, + PCIE_GLOBAL_APP_LTSSM_EN); + + /* Region 0: MMIO32 range */ + ConfigureWindow (PcieBaseAddress, + 0, + PcieController->PcieMmio32WinBase, + PcieController->PcieMmio32WinBase, + PcieController->PcieMmio32WinSize, + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM, + 0); + + /* Region 1: Type 0 config space */ + ConfigureWindow (PcieBaseAddress, + 1, + PcieController->ConfigSpaceAddress, + 0x0, + SIZE_64KB, + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG0, + IATU_REGION_CTRL_2_OFF_OUTBOUND_0_CFG_SHIFT_MODE); + + /* Region 2: Type 1 config space */ + ConfigureWindow (PcieBaseAddress, + 2, + PcieController->ConfigSpaceAddress + SIZE_64KB, + 0x0, + PcieController->PcieBusMax * SIZE_1MB, + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG1, + IATU_REGION_CTRL_2_OFF_OUTBOUND_0_CFG_SHIFT_MODE); + + /* Region 3: port I/O range */ + ConfigureWindow (PcieBaseAddress, + 3, + PcieController->PcieIoTranslation, + PcieController->PcieIoWinBase, + PcieController->PcieIoWinSize, + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_IO, + 0); + + /* Region 4: MMIO64 range */ + ConfigureWindow (PcieBaseAddress, + 4, + PcieController->PcieMmio64WinBase, + PcieController->PcieMmio64WinBase, + PcieController->PcieMmio64WinSize, + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM, + 0); + + MmioOr32 (PcieBaseAddress + PCIE_GLOBAL_INT_MASK1_REG, + PCIE_INT_A_ASSERT_MASK | + PCIE_INT_B_ASSERT_MASK | + PCIE_INT_C_ASSERT_MASK | + PCIE_INT_D_ASSERT_MASK); + + WaitForLink (PcieBaseAddress); + + /* Enable the RC */ + MmioOr32 (PcieBaseAddress + PCI_COMMAND_OFFSET, + EFI_PCI_COMMAND_IO_SPACE | + EFI_PCI_COMMAND_MEMORY_SPACE | + EFI_PCI_COMMAND_BUS_MASTER); + } + + return EFI_SUCCESS; +} -- 2.7.4