From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id B377DAC09F7 for ; Thu, 19 Oct 2023 02:59:33 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=HBSLTQYI1MKTaVw9O7XWONtvagJYOwlWTTri8uIL2lQ=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Date:Message-ID:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type:Content-Transfer-Encoding; s=20140610; t=1697684372; v=1; b=fEpUIeogZ5guHAtLNI9zlEmECxbr8tZE1sKwBGGzx9M7bK1/BilQmedi7IwPjlLDTl6xIIwv ta0FdlJvc0Am0BUwD93ZPRcNIQf7/FRoOaJpGdfKiCQYias+IAc6FWqDj82/6pMGi8/GwSWTyPn 5xp53vNvwhJIy5jsUGRT/pzE= X-Received: by 127.0.0.2 with SMTP id NOOQYY7687511x4rZSKew9Oy; Wed, 18 Oct 2023 19:59:32 -0700 X-Received: from fd01.gateway.ufhost.com (fd01.gateway.ufhost.com [61.152.239.71]) by mx.groups.io with SMTP id smtpd.web10.19409.1697684369986346324 for ; Wed, 18 Oct 2023 19:59:31 -0700 X-Received: from EXMBX166.cuchost.com (unknown [175.102.18.54]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "EXMBX166", Issuer "EXMBX166" (not verified)) by fd01.gateway.ufhost.com (Postfix) with ESMTP id D9C0C80A4; Thu, 19 Oct 2023 10:59:27 +0800 (CST) X-Received: from EXMBX073.cuchost.com (172.16.6.83) by EXMBX166.cuchost.com (172.16.6.76) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Thu, 19 Oct 2023 10:59:27 +0800 X-Received: from localhost.localdomain (202.188.176.82) by EXMBX073.cuchost.com (172.16.6.83) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Thu, 19 Oct 2023 10:59:25 +0800 From: "John Chew" To: CC: mindachen1987 , Sunil V L , John Chew Subject: [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver Date: Thu, 19 Oct 2023 10:59:16 +0800 Message-ID: <20231019025921.1593-1-yuinyee.chew@starfivetech.com> MIME-Version: 1.0 X-Originating-IP: [202.188.176.82] X-ClientProxiedBy: EXCAS061.cuchost.com (172.16.6.21) To EXMBX073.cuchost.com (172.16.6.83) X-YovoleRuleAgent: yovoleflag Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,yuinyee.chew@starfivetech.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: zgFzctA6rXY1crbVUOfd90G5x7686176AA= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=fEpUIeog; dmarc=none; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io From: mindachen1987 Cc: Sunil V L Co-authored-by: John Chew Signed-off-by: mindachen1987 --- Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c = | 249 ++++ Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf = | 48 + Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstr= uctor.c | 405 ++++++ Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c = | 1460 ++++++++++++++++++++ Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf = | 33 + 5 files changed, 2195 insertions(+) diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBri= dgeLib.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridg= eLib.c new file mode 100644 index 000000000000..7d73cb5b4b5c --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.= c @@ -0,0 +1,249 @@ +/** @file + * + * PCI Host Bridge Library instance for StarFive JH7110 SOC + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma pack(1) + +typedef PACKED struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; + +#pragma pack () + +STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[= ] =3D { + { + { + { + 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 + } + } + }, + + { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)), + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8) + } + }, + EISA_PNP_ID (0x0A08), // PCI Express + 1 + }, + + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } + }, +}; + +GLOBAL_REMOVE_IF_UNREFERENCED +CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] =3D { + L"Mem", L"I/O", L"Bus" +}; + +// These should come from the PCD... +#define JH7110_PCI_BUSNUM_MIN 0x00 +#define JH7110_PCI_BUSNUM_MAX 0xFF +#define JH7110_PCI_PORTIO_MIN 0x01 +#define JH7110_PCI_PORTIO_MAX 0x00 // MIN>MAX disables PIO +#define JH7110_PCI_PORTIO_OFFSET 0x00 +// The bridge thinks its MMIO is here (which means it can't access this ar= ea in phy ram) + +#define JH7110_PCI_SEG0_MMIO32_MIN (0x30000000) +#define JH7110_PCI_SEG0_MMIO32_MAX (JH7110_PCI_SEG0_MMIO32_MIN + 0x7FFFFF= F) +// The CPU views it via a window here.. +// We might be able to size another region? +#define JH7110_PCI_SEG0_MMIO64_MIN (0x900000000) +#define JH7110_PCI_SEG0_MMIO64_MAX (0x940000000) + +#define JH7110_PCI_SEG1_MMIO32_MIN (0x38000000) +#define JH7110_PCI_SEG1_MMIO32_MAX (JH7110_PCI_SEG1_MMIO32_MIN + 0x7FFFFF= F) +// The CPU views it via a window here.. +// We might be able to size another region? +#define JH7110_PCI_SEG1_MMIO64_MIN (0x980000000) +#define JH7110_PCI_SEG1_MMIO64_MAX (0x9c0000000) + +// +// See description in MdeModulePkg/Include/Library/PciHostBridgeLib.h +// +PCI_ROOT_BRIDGE mPciRootBridges[] =3D { + { + 0, // Segment + 0, // Supports + 0, // Attributes + FALSE, // DmaAbove4G + FALSE, // NoExtendedConfigSpace (true= =3D256 byte config, false=3D4k) + FALSE, // ResourceAssigned + EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | + EFI_PCI_HOST_BRIDGE_MEM64_DECODE, // AllocationAttributes + { JH7110_PCI_BUSNUM_MIN, + JH7110_PCI_BUSNUM_MAX }, // Bus + { JH7110_PCI_PORTIO_MIN, + JH7110_PCI_PORTIO_MAX, + MAX_UINT64 - JH7110_PCI_PORTIO_OFFSET + 1 }, // Io + { JH7110_PCI_SEG0_MMIO32_MIN, JH7110_PCI_SEG0_MMIO32_MAX, 0 }, // Mem + { JH7110_PCI_SEG0_MMIO64_MIN,JH7110_PCI_SEG0_MMIO64_MAX, 0 }, // Mem= Above4G + { MAX_UINT32, 0x0 }, // Pef= etchable Mem + { MAX_UINT64, 0x0 }, // Pef= etchable MemAbove4G + (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[0] + }, + { + 1, // Segment + 0, // Supports + 0, // Attributes + FALSE, // DmaAbove4G + FALSE, // NoExtendedConfigSpace (true=3D2= 56 byte config, false=3D4k) + FALSE, // ResourceAssigned + EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | + EFI_PCI_HOST_BRIDGE_MEM64_DECODE, // AllocationAttributes + { JH7110_PCI_BUSNUM_MIN, + JH7110_PCI_BUSNUM_MAX }, // Bus + { JH7110_PCI_PORTIO_MIN, + JH7110_PCI_PORTIO_MAX, + MAX_UINT64 - JH7110_PCI_PORTIO_OFFSET + 1 }, // Io + { JH7110_PCI_SEG1_MMIO32_MIN, JH7110_PCI_SEG1_MMIO32_MAX, 0 }, // Mem + { JH7110_PCI_SEG1_MMIO64_MIN, JH7110_PCI_SEG1_MMIO64_MAX, 0}, // Mem= Above4G + { MAX_UINT32, 0x0 }, // Pef= etchable Mem + { MAX_UINT64, 0x0 }, // Pef= etchable MemAbove4G + (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[1] + } +}; + +/** + 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 ( + OUT UINTN *Count + ) +{ + *Count =3D ARRAY_SIZE (mPciRootBridges); + return mPciRootBridges; +} + +/** + Free the root bridge instances array returned from PciHostBridgeGetRootB= ridges(). + + @param Bridges The root bridge instances array. + @param Count The count of the array. +**/ +VOID +EFIAPI +PciHostBridgeFreeRootBridges ( + PCI_ROOT_BRIDGE *Bridges, + UINTN Count + ) +{ +} + +/** + 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 reso= urces + 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 =3D 0; + Descriptor =3D (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration; + while (Descriptor->Desc =3D=3D ACPI_ADDRESS_SPACE_DESCRIPTOR) { + DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++)); + for ( ; Descriptor->Desc =3D=3D ACPI_ADDRESS_SPACE_DESCRIPTOR; Descrip= tor++) { + ASSERT ( + Descriptor->ResType < + ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr) + ); + DEBUG ( + (DEBUG_ERROR, " %s: Length/Alignment =3D 0x%lx / 0x%lx\n", + mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType= ], + Descriptor->AddrLen, Descriptor->AddrRangeMax + ) + ); + if (Descriptor->ResType =3D=3D ACPI_ADDRESS_SPACE_TYPE_MEM) { + DEBUG ( + (DEBUG_ERROR, " Granularity/SpecificFlag =3D %ld / %02x= %s\n", + Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag= , + ((Descriptor->SpecificFlag & + EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETC= HABLE + ) !=3D 0) ? L" (Prefetchable)" : L"" + ) + ); + } + } + + // + // Skip the END descriptor for root bridge + // + ASSERT (Descriptor->Desc =3D=3D ACPI_END_TAG_DESCRIPTOR); + Descriptor =3D (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)( + (EFI_ACPI_END_TAG_D= ESCRIPTOR *)Descriptor + 1 + ); + } +} diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBri= dgeLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBri= dgeLib.inf new file mode 100644 index 000000000000..c6d498df2d62 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.= inf @@ -0,0 +1,48 @@ +## @file +# +# PCI Host Bridge Library instance for StarFive JH7110 SOC +# Liberally borrowed from the SynQuacer +# +# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010019 + BASE_NAME =3D PciHostBridgeLib + FILE_GUID =3D 606d906f-eba7-d5c6-fcf0-6aeedea00193 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D PciHostBridgeLib|DXE_DRIVER + CONSTRUCTOR =3D JH7110PciHostBridgeLibConstructor + +# +# The following information is for reference only and not required by the = build +# tools. +# +# VALID_ARCHITECTURES =3D ARM AARCH64 RISCV64 +# + +[Sources] + PciHostBridgeLib.c + PciHostBridgeLibConstructor.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec + +[LibraryClasses] + DebugLib + DevicePathLib + MemoryAllocationLib + PcdLib + UefiBootServicesTableLib + +[FixedPcd] + gJH7110TokenSpaceGuid.PcdJH7110PciRegBase + gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioAdr + gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioLen + gJH7110TokenSpaceGuid.PcdJH7110PciCpuMmioAdr diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBri= dgeLibConstructor.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/P= ciHostBridgeLibConstructor.c new file mode 100644 index 000000000000..05d10e08232c --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibC= onstructor.c @@ -0,0 +1,405 @@ +/** @file + * + * PCI Host Bridge Library instance for StarFive JH7110 SOC + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + * This module initializes the Pci as close to a standard + * PCI root complex as possible. The general information + * for this driver was sourced from. + * + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RegWrite(addr, data) MmioWrite32((addr), (data)) +#define RegRead(addr, data) ((data) =3D MmioRead32 (addr)) + +#define STG_SYSCON_BASE 0x10240000 + +#define STG_SYSCON_K_RP_NEP_MASK (1 << 8) +#define STG_SYSCON_CKREF_SRC_SHIFT 18 +#define STG_SYSCON_CKREF_SRC_MASK (0x3 << 18) +#define STG_SYSCON_CLKREQ_MASK (1 << 22) +#define STG_SYSCON_BASE 0x10240000 +#define SYS_CLK_BASE 0x13020000 +#define STG_CLK_BASE 0x10230000 +#define SYS_CLK_NOC_OFFSET 0x98 +#define STG_PCIE_CLK_OFFSET 0x20 +#define STG_PCIE_CLKS 0xc +#define STG_PCIE_RESET_OFFSET 0x74 +#define SYS_GPIO_BASE 0x13040000 + +#define PREF_MEM_WIN_64_SUPPORT (1 << 3) +#define PMSG_LTR_SUPPORT (1 << 2) +#define PDLA_LINK_SPEED_GEN2 (1 << 12) +#define PLDA_FUNCTION_DIS (1 << 15) +#define PLDA_FUNC_NUM 4 +#define PLDA_PHY_FUNC_SHIFT 9 +#define PLDA_RP_ENABLE 1 + +#define PCIE_BASIC_STATUS 0x018 +#define PCIE_CFGNUM 0x140 +#define IMASK_LOCAL 0x180 +#define ISTATUS_LOCAL 0x184 +#define IMSI_ADDR 0x190 +#define ISTATUS_MSI 0x194 +#define CFG_SPACE 0x1000 +#define GEN_SETTINGS 0x80 +#define PCIE_PCI_IDS 0x9C +#define PCIE_WINROM 0xFC +#define PMSG_SUPPORT_RX 0x3F0 +#define PCI_MISC 0xB4 + +#define STG_SYSCON_AXI4_SLVL_ARFUNC_MASK 0x7FFF00 +#define STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT 0x8 +#define STG_SYSCON_AXI4_SLVL_AWFUNC_MASK 0x7FFF +#define STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT 0x0 + +#define XR3PCI_ATR_AXI4_SLV0 0x800 +#define XR3PCI_ATR_SRC_ADDR_LOW 0x0 +#define XR3PCI_ATR_SRC_ADDR_HIGH 0x4 +#define XR3PCI_ATR_TRSL_ADDR_LOW 0x8 +#define XR3PCI_ATR_TRSL_ADDR_HIGH 0xc +#define XR3PCI_ATR_TRSL_PARAM 0x10 +#define XR3PCI_ATR_TABLE_OFFSET 0x20 +#define XR3PCI_ATR_MAX_TABLE_NUM 8 + +#define XR3PCI_ATR_SRC_ADDR_MASK 0xfffff000 +#define XR3PCI_ATR_TRSL_ADDR_MASK 0xfffff000 +#define XR3PCI_ATR_SRC_WIN_SIZE_SHIFT 1 +#define XR3_PCI_ECAM_SIZE 28 + +#define IDS_PCI_TO_PCI_BRIDGE 0x060400 +#define IDS_CLASS_CODE_SHIFT 8 +#define SYS_GPIO_OUTPUT_OFF 0x40 + +UINT32 AtrTableNum; +UINT64 PCIE_CFG_BASE[2] =3D { 0x940000000, 0x9c0000000 }; +UINT64 PCI_MEMREGION_32[2] =3D { 0x30000000, 0x38000000 }; +UINT64 PCI_MEMREGION_64[2] =3D { 0x900000000, 0x980000000 }; +UINT64 PCI_MEMREGION_SIZE[2] =3D { 27, 30 }; +UINT32 STG_ARFUNC_OFFSET[2] =3D { 0xc0, 0x270 }; +UINT32 STG_AWFUNC_OFFSET[2] =3D { 0xc4, 0x274 }; +UINT32 STG_RP_REP_OFFSET[2] =3D { 0x130, 0x2e0 }; +UINT32 PCIE_GPIO[2] =3D { 26, 28 }; + +STATIC inline UINT64 +GetPcieRegBase ( + IN UINT32 Port + ) +{ + return PCIE_REG_BASE + Port * 0x1000000; +} + +VOID +PcieRegWrite ( + IN UINT32 Port, + IN UINTN Offset, + IN UINT32 Value + ) +{ + UINT64 Base =3D GetPcieRegBase (Port); + + RegWrite ((UINT64)Base + Offset, Value); +} + +UINT32 +PcieRegRead ( + IN UINT32 Port, + IN UINTN Offset + ) +{ + UINT32 Value =3D 0; + UINT64 Base =3D GetPcieRegBase (Port); + + RegRead ((UINT64)Base + Offset, Value); + return Value; +} + +STATIC VOID +PcieUpdatebits ( + IN UINT64 Base, + IN UINTN Offset, + IN UINT32 Mask, + IN UINT32 val + ) +{ + UINT32 Value =3D 0; + + Value =3D MmioRead32 ((UINT64)Base + Offset); + Value &=3D ~Mask; + Value |=3D val; + MmioWrite32 ((UINT64)Base + Offset, Value); +} + +STATIC +VOID +PcieFuncSet ( + IN UINT32 Port + ) +{ + INTN i; + UINT32 Value; + UINT64 Base =3D GetPcieRegBase (Port); + + /* Disable physical functions except #0 */ + for (i =3D 1; i < PLDA_FUNC_NUM; i++) { + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_ARFUNC_OFFSET[Port], + STG_SYSCON_AXI4_SLVL_ARFUNC_MASK, + (i << PLDA_PHY_FUNC_SHIFT) << + STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT + ); + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_AWFUNC_OFFSET[Port], + STG_SYSCON_AXI4_SLVL_AWFUNC_MASK, + (i << PLDA_PHY_FUNC_SHIFT) << + STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT + ); + PcieUpdatebits ( + Base, + PCI_MISC, + PLDA_FUNCTION_DIS, + PLDA_FUNCTION_DIS + ); + } + + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_ARFUNC_OFFSET[Port], + STG_SYSCON_AXI4_SLVL_ARFUNC_MASK, + 0 + ); + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_AWFUNC_OFFSET[Port], + STG_SYSCON_AXI4_SLVL_AWFUNC_MASK, + 0 + ); + + /* Enable root port*/ + PcieUpdatebits ( + Base, + GEN_SETTINGS, + PLDA_RP_ENABLE, + PLDA_RP_ENABLE + ); + + Value =3D (IDS_PCI_TO_PCI_BRIDGE << IDS_CLASS_CODE_SHIFT); + PcieRegWrite (Port, PCIE_PCI_IDS, Value); + + PcieUpdatebits ( + Base, + PMSG_SUPPORT_RX, + PMSG_LTR_SUPPORT, + 0 + ); + + /* Prefetchable memory window 64-bit addressing support */ + PcieUpdatebits ( + Base, + PCIE_WINROM, + PREF_MEM_WIN_64_SUPPORT, + PREF_MEM_WIN_64_SUPPORT + ); +} + +STATIC +VOID +PcieSTGInit ( + IN UINT32 Port + ) +{ + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_RP_REP_OFFSET[Port], + STG_SYSCON_K_RP_NEP_MASK, + STG_SYSCON_K_RP_NEP_MASK + ); + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_AWFUNC_OFFSET[Port], + STG_SYSCON_CKREF_SRC_MASK, + 2 << STG_SYSCON_CKREF_SRC_SHIFT + ); + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_AWFUNC_OFFSET[Port], + STG_SYSCON_CLKREQ_MASK, + STG_SYSCON_CLKREQ_MASK + ); +} + +STATIC +VOID +PcieClockInit ( + IN UINT32 Port + ) +{ + RegWrite ( + STG_CLK_BASE + STG_PCIE_CLK_OFFSET + + Port * STG_PCIE_CLKS, + 1 << 31 + ); /*axi mst0*/ + RegWrite ( + STG_CLK_BASE + STG_PCIE_CLK_OFFSET + + Port * STG_PCIE_CLKS + 4, + 1 << 31 + ); /* apb */ + RegWrite ( + STG_CLK_BASE + STG_PCIE_CLK_OFFSET + + Port * STG_PCIE_CLKS + 8, + 1 << 31 + ); /* tl0 */ +} + +STATIC +VOID +PcieResetDeassert ( + IN UINT32 Port + ) +{ + UINT32 PortOffset =3D Port * 6 + 11; + + PcieUpdatebits ( + STG_CLK_BASE, + STG_PCIE_RESET_OFFSET, + 0x3f << (PortOffset), + 0 + ); /*reset all*/ +} + +VOID +PcieResetAssert ( + IN UINT32 Port + ) +{ + UINT32 PortOffset =3D Port * 6 + 11; + + PcieUpdatebits ( + STG_CLK_BASE, + STG_PCIE_RESET_OFFSET, + 0x3f << (PortOffset), + 0x3f << (PortOffset) + ); /*axi mst0*/ +} + +STATIC +VOID +PcieGpioResetSet ( + IN UINT32 Port, + IN UINT32 Value + ) +{ + UINT32 Remain, Mask; + + Remain =3D PCIE_GPIO[Port] & 0x3; + Mask =3D 0xff << (Remain * 8); + PcieUpdatebits ( + SYS_GPIO_BASE, + SYS_GPIO_OUTPUT_OFF + (PCIE_GPIO[Port] & 0xfffc), + Mask, + Value << (Remain * 8) + ); +} + +STATIC +VOID +PcieAtrInit ( + IN UINT32 Port, + IN UINT64 SrcAddr, + IN UINT64 TrslAddr, + IN UINT32 WinSize, + IN UINT32 Config + ) +{ + UINT64 Base =3D GetPcieRegBase (Port) + XR3PCI_ATR_AXI4_SLV0; + UINT32 Value; + + Base +=3D XR3PCI_ATR_TABLE_OFFSET * AtrTableNum; + AtrTableNum++; + + /* X3PCI_ATR_SRC_ADDR_LOW: + * - bit 0: enable entry, + * - bits 1-6: ATR window size: total size in bytes: 2^(ATR_WSIZE + 1) + * - bits 7-11: reserved + * - bits 12-31: start of source address + */ + Value =3D SrcAddr; + // DEBUG ((DEBUG_ERROR, "addr low %x\n", Value)); + RegWrite ( + Base + XR3PCI_ATR_SRC_ADDR_LOW, + (Value & XR3PCI_ATR_SRC_ADDR_MASK) | ((WinSize - 1) << 1) | 0x= 1 + ); + Value =3D SrcAddr >> 32; + // DEBUG ((DEBUG_ERROR, "addr high %x\n", Value)); + RegWrite (Base + XR3PCI_ATR_SRC_ADDR_HIGH, Value); + Value =3D TrslAddr; + RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_LOW, Value); + Value =3D TrslAddr >> 32; + RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_HIGH, Value); + RegWrite (Base + XR3PCI_ATR_TRSL_PARAM, Config); +} + +EFI_STATUS +EFIAPI +JH7110PciHostBridgeLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT32 PortIndex; + + DEBUG ((DEBUG_ERROR, "PCIe RootBridge constructor\n")); + for (PortIndex =3D 0; PortIndex < 2; PortIndex++) { + PcieSTGInit (PortIndex); + RegWrite (SYS_CLK_BASE + SYS_CLK_NOC_OFFSET, 1 << 31); + PcieClockInit (PortIndex); + PcieResetDeassert (PortIndex); + PcieGpioResetSet (PortIndex, 0); + PcieFuncSet (PortIndex); + + PcieAtrInit ( + PortIndex, + PCIE_CFG_BASE[PortIndex], + 0, + XR3_PCI_ECAM_SIZE, + 1 + ); + PcieAtrInit ( + PortIndex, + PCI_MEMREGION_32[PortIndex], + PCI_MEMREGION_32[PortIndex], + PCI_MEMREGION_SIZE[0], + 0 + ); + PcieAtrInit ( + PortIndex, + PCI_MEMREGION_64[PortIndex], + PCI_MEMREGION_64[PortIndex], + PCI_MEMREGION_SIZE[1], + 0 + ); + PcieGpioResetSet (PortIndex, 1); + MicroSecondDelay (300); + + DEBUG ((DEBUG_ERROR, "PCIe port %d init\n", PortIndex)); + } + + return EFI_SUCCESS; +} diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib= .c b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c new file mode 100644 index 000000000000..43dca2a6236a --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c @@ -0,0 +1,1460 @@ +/** @file + * + * PCI Segment Library for StarFive JH7110 SoC + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + PciCfgWidthUint8 =3D 0, + PciCfgWidthUint16, + PciCfgWidthUint32, + PciCfgWidthMax +} PCI_CFG_WIDTH; + +/* + * This PCIe config space is unusual... + * The root port is the first bytes of the register space (offset 0) + * The individual devices are then selected by computing their BDF index + * and writing that into the CFG_INDEX register (offset 0x9000) + * the "ECAM" data is then read/writeable at CFG_DATA (offset 0x8000) + */ + +#define EFI_PCI_ADDR_BUS(bus) ((bus >> 20) & 0xFF) /* Note PCI_SEGMENT_= LIB_ADDRESS */ +#define EFI_PCI_ADDR_DEV(dev) ((dev >> 15) & 0x1F) +#define EFI_PCI_ADDR_FUN(fun) ((fun >> 12) & 0x07) + +/** + Assert the validity of a PCI Segment address. + A valid PCI Segment address should not contain 1's in bits 28..31 and 48= ..63 + + @param A The address to validate. + @param M Additional bits to assert to be zero. + +**/ +#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A, M) \ + ASSERT (((A) & (0xffff0000f0000000ULL | (M))) =3D=3D 0) + +/** + Given the nature of how we access PCI devices, we ensure that + read/write accesses are serialized through the use of a lock. +**/ +STATIC +EFI_LOCK mPciSegmentReadWriteLock =3D EFI_INITIALIZE_LOCK_VARIABLE (TPL_H= IGH_LEVEL); + +// STATIC UINT64 mPciSegmentLastAccess; /* Avoid repeat CFG_INDEX upda= tes */ + +/** + Internal worker function to obtain config space base address. + + @param Address The address that encodes the PCI Bus, Device, Function a= nd + Register. + + @return The value read from the PCI configuration register. + +**/ +STATIC +UINT64 +PciSegmentLibGetConfigBase ( + IN UINT64 Address, + IN UINT16 Segment, + IN UINT32 Write + ) +{ + UINT64 Base; + UINT64 Offset; + UINT32 Dev; + UINT32 Bus; + + Base =3D PCIE_CONFIG_BASE; + Offset =3D Address & 0xFFF; /* Pick off the 4k register offset */ + Address &=3D 0xFFFF000; /* Clear the offset leave only the BD= F */ + + /* The root port is at the base of the PCIe register space */ + if (Address !=3D 0) { + Dev =3D EFI_PCI_ADDR_DEV (Address); + Bus =3D EFI_PCI_ADDR_BUS (Address); + + /* + * There can only be a single device on bus 1 (downstream of root). + * Subsequent busses (behind a PCIe switch) can have more. + */ + if (Dev > 0) { + return 0xFFFFFFFF; + } + + return Base + Segment * 0x80000000 + Address + Offset; + } else { + if (Write && ((Offset =3D=3D 0x10) || (Offset =3D=3D 0x14))) { + return 0xFFFFFFFF; + } + } + + return Base + Segment * 0x80000000 + Offset; +} + +/** + Internal worker function to read a PCI configuration register. + + @param Address The address that encodes the PCI Bus, Device, Function a= nd + Register. + @param Width The width of data to read + + @return The value read from the PCI configuration register. + +**/ +STATIC +UINT32 +PciSegmentLibReadWorker ( + IN UINT64 Address, + IN PCI_CFG_WIDTH Width + ) +{ + UINT64 Base; + UINT32 Ret; + UINT16 Segment =3D (Address >> 32); + + EfiAcquireLock (&mPciSegmentReadWriteLock); + Base =3D PciSegmentLibGetConfigBase (Address, Segment, 0); + + if (Base =3D=3D 0xFFFFFFFF) { + EfiReleaseLock (&mPciSegmentReadWriteLock); + return Base; + } + + switch (Width) { + case PciCfgWidthUint8: + Ret =3D MmioRead8 (Base); + break; + case PciCfgWidthUint16: + Ret =3D MmioRead16 (Base); + break; + case PciCfgWidthUint32: + Ret =3D MmioRead32 (Base); + break; + default: + ASSERT (FALSE); + Ret =3D 0; + } + + EfiReleaseLock (&mPciSegmentReadWriteLock); + // DEBUG ((DEBUG_ERROR, "PCIe seg read Address %lx %lx width %d val %x S= egment %d\n", Base, Address, Width, Ret, Segment)); + return Ret; +} + +/** + Internal worker function to writes a PCI configuration register. + + @param Address The address that encodes the PCI Bus, Device, Function a= nd + Register. + @param Width The width of data to write + @param Data The value to write. + + @return The value written to the PCI configuration register. + +**/ +STATIC +UINT32 +PciSegmentLibWriteWorker ( + IN UINT64 Address, + IN PCI_CFG_WIDTH Width, + IN UINT32 Data + ) +{ + UINT64 Base; + UINT16 Segment =3D (Address >> 32); + + EfiAcquireLock (&mPciSegmentReadWriteLock); + Base =3D PciSegmentLibGetConfigBase (Address, Segment, 1); + + if (Base =3D=3D 0xFFFFFFFF) { + EfiReleaseLock (&mPciSegmentReadWriteLock); + return Data; + } + + switch (Width) { + case PciCfgWidthUint8: + MmioWrite8 (Base, Data); + break; + case PciCfgWidthUint16: + MmioWrite16 (Base, Data); + break; + case PciCfgWidthUint32: + MmioWrite32 (Base, Data); + break; + default: + ASSERT (FALSE); + } + + EfiReleaseLock (&mPciSegmentReadWriteLock); + return Data; +} + +/** + Register a PCI device so PCI configuration registers may be accessed aft= er + SetVirtualAddressMap(). + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Bus, Device, Function a= nd + Register. + + @retval RETURN_SUCCESS The PCI device was registered for runti= me access. + @retval RETURN_UNSUPPORTED An attempt was made to call this functi= on + after ExitBootServices(). + @retval RETURN_UNSUPPORTED The resources required to access the PC= I device + at runtime could not be mapped. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources availabl= e to + complete the registration. + +**/ +RETURN_STATUS +EFIAPI +PciSegmentRegisterForRuntimeAccess ( + IN UINTN Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + return RETURN_UNSUPPORTED; +} + +/** + Reads an 8-bit PCI configuration register. + + Reads and returns the 8-bit PCI configuration register specified by Addr= ess. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, + and Register. + + @return The 8-bit PCI configuration register specified by Address. + +**/ +UINT8 +EFIAPI +PciSegmentRead8 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + return (UINT8)PciSegmentLibReadWorker (Address, PciCfgWidthUint8); +} + +/** + Writes an 8-bit PCI configuration register. + + Writes the 8-bit PCI configuration register specified by Address with th= e value specified by Value. + Value is returned. This function must guarantee that all PCI read and w= rite operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Devic= e, Function, and Register. + @param Value The value to write. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentWrite8 ( + IN UINT64 Address, + IN UINT8 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + return (UINT8)PciSegmentLibWriteWorker (Address, PciCfgWidthUint8, Value= ); +} + +/** + Performs a bitwise OR of an 8-bit PCI configuration register with an 8-b= it value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by= OrData, + and writes the result to the 8-bit PCI configuration register specified = by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentOr8 ( + IN UINT64 Address, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) | Or= Data)); +} + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-= bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + and writes the result to the 8-bit PCI configuration register specified = by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAnd8 ( + IN UINT64 Address, + IN UINT8 AndData + ) +{ + return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) & An= dData)); +} + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-= bit value, + followed a bitwise OR with another 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + performs a bitwise OR between the result of the AND operation and the va= lue specified by OrData, + and writes the result to the 8-bit PCI configuration register specified = by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAndThenOr8 ( + IN UINT64 Address, + IN UINT8 AndData, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 (Address, (UINT8)((PciSegmentRead8 (Address) & A= ndData) | OrData)); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in an 8-bit PCI configuration register. The bit fiel= d is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address The PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + + @return The value of the bit field read from the PCI configuration regis= ter. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldRead8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead8 (PciSegmentRead8 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of t= he + 8-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit an= d EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param Value The new value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldWrite8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 Value + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldWrite8 (PciSegmentRead8 (Address), Star= tBit, EndBit, Value) + ); +} + +/** + Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, = and + writes the result back to the bit field in the 8-bit port. + + Reads the 8-bit PCI configuration register specified by Address, perform= s a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 8-bit PCI configuration register + specified by Address. The value written to the PCI configuration registe= r is + returned. This function must guarantee that all PCI read and write opera= tions + are serialized. Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldOr8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldOr8 (PciSegmentRead8 (Address), StartBi= t, EndBit, OrData) + ); +} + +/** + Reads a bit field in an 8-bit PCI configuration register, performs a bit= wise + AND, and writes the result back to the bit field in the 8-bit register. + + Reads the 8-bit PCI configuration register specified by Address, perform= s a + bitwise AND between the read result and the value specified by AndData, = and + writes the result to the 8-bit PCI configuration register specified by + Address. The value written to the PCI configuration register is returned= . + This function must guarantee that all PCI read and write operations are + serialized. Extra left bits in AndData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param AndData The value to AND with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldAnd8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 AndData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldAnd8 (PciSegmentRead8 (Address), StartB= it, EndBit, AndData) + ); +} + +/** + Reads a bit field in an 8-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 8-bit port. + + Reads the 8-bit PCI configuration register specified by Address, perform= s a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 8-bit PCI + configuration register specified by Address. The value written to the PC= I + configuration register is returned. This function must guarantee that al= l PCI + read and write operations are serialized. Extra left bits in both AndDat= a and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldAndThenOr8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 AndData, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldAndThenOr8 (PciSegmentRead8 (Address), = StartBit, EndBit, AndData, OrData) + ); +} + +/** + Reads a 16-bit PCI configuration register. + + Reads and returns the 16-bit PCI configuration register specified by Add= ress. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + + @return The 16-bit PCI configuration register specified by Address. + +**/ +UINT16 +EFIAPI +PciSegmentRead16 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + return (UINT16)PciSegmentLibReadWorker (Address, PciCfgWidthUint16); +} + +/** + Writes a 16-bit PCI configuration register. + + Writes the 16-bit PCI configuration register specified by Address with t= he value specified by Value. + Value is returned. This function must guarantee that all PCI read and w= rite operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Devic= e, Function, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT16 +EFIAPI +PciSegmentWrite16 ( + IN UINT64 Address, + IN UINT16 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + return (UINT16)PciSegmentLibWriteWorker (Address, PciCfgWidthUint16, Val= ue); +} + +/** + Performs a bitwise OR of a 16-bit PCI configuration register with + a 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, perfor= ms a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 16-bit PCI configuration register + specified by Address. The value written to the PCI configuration registe= r is + returned. This function must guarantee that all PCI read and write opera= tions + are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, F= unction and + Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentOr16 ( + IN UINT64 Address, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) |= OrData)); +} + +/** + Performs a bitwise AND of a 16-bit PCI configuration register with a 16-= bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + and writes the result to the 16-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentAnd16 ( + IN UINT64 Address, + IN UINT16 AndData + ) +{ + return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) &= AndData)); +} + +/** + Performs a bitwise AND of a 16-bit PCI configuration register with a 16-= bit value, + followed a bitwise OR with another 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + performs a bitwise OR between the result of the AND operation and the va= lue specified by OrData, + and writes the result to the 16-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentAndThenOr16 ( + IN UINT64 Address, + IN UINT16 AndData, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16)((PciSegmentRead16 (Address) = & AndData) | OrData)); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in a 16-bit PCI configuration register. The bit fiel= d is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address The PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + + @return The value of the bit field read from the PCI configuration regis= ter. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldRead16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead16 (PciSegmentRead16 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of t= he + 16-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit an= d EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + @param Value The new value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldWrite16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 Value + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldWrite16 (PciSegmentRead16 (Address), S= tartBit, EndBit, Value) + ); +} + +/** + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by= OrData, + and writes the result to the 16-bit PCI configuration register specified= by Address. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldOr16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldOr16 (PciSegmentRead16 (Address), Star= tBit, EndBit, OrData) + ); +} + +/** + Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, + and writes the result back to the bit field in the 16-bit port. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by= OrData, + and writes the result to the 16-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + The ordinal of the least significant bit in a byte is = bit 0. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + The ordinal of the most significant bit in a byte is b= it 7. + @param AndData The value to AND with the read value from the PCI conf= iguration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldAnd16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 AndData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldAnd16 (PciSegmentRead16 (Address), Sta= rtBit, EndBit, AndData) + ); +} + +/** + Reads a bit field in a 16-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 16-bit port. + + Reads the 16-bit PCI configuration register specified by Address, perfor= ms a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 16-bit PCI + configuration register specified by Address. The value written to the PC= I + configuration register is returned. This function must guarantee that al= l PCI + read and write operations are serialized. Extra left bits in both AndDat= a and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldAndThenOr16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 AndData, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldAndThenOr16 (PciSegmentRead16 (Address= ), StartBit, EndBit, AndData, OrData) + ); +} + +/** + Reads a 32-bit PCI configuration register. + + Reads and returns the 32-bit PCI configuration register specified by Add= ress. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, + and Register. + + @return The 32-bit PCI configuration register specified by Address. + +**/ +UINT32 +EFIAPI +PciSegmentRead32 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + return PciSegmentLibReadWorker (Address, PciCfgWidthUint32); +} + +/** + Writes a 32-bit PCI configuration register. + + Writes the 32-bit PCI configuration register specified by Address with t= he value specified by Value. + Value is returned. This function must guarantee that all PCI read and w= rite operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Devic= e, + Function, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT32 +EFIAPI +PciSegmentWrite32 ( + IN UINT64 Address, + IN UINT32 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + return PciSegmentLibWriteWorker (Address, PciCfgWidthUint32, Value); +} + +/** + Performs a bitwise OR of a 32-bit PCI configuration register with a 32-b= it value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by= OrData, + and writes the result to the 32-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentOr32 ( + IN UINT64 Address, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData); +} + +/** + Performs a bitwise AND of a 32-bit PCI configuration register with a 32-= bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + and writes the result to the 32-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, + and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentAnd32 ( + IN UINT64 Address, + IN UINT32 AndData + ) +{ + return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) & AndData)= ; +} + +/** + Performs a bitwise AND of a 32-bit PCI configuration register with a 32-= bit value, + followed a bitwise OR with another 32-bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + performs a bitwise OR between the result of the AND operation and the va= lue specified by OrData, + and writes the result to the 32-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, + and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentAndThenOr32 ( + IN UINT64 Address, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData= ) | OrData); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in a 32-bit PCI configuration register. The bit fiel= d is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address The PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + + @return The value of the bit field read from the PCI configuration regis= ter. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldRead32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of t= he + 32-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit an= d EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param Value The new value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldWrite32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 Value + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldWrite32 (PciSegmentRead32 (Address), S= tartBit, EndBit, Value) + ); +} + +/** + Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, = and + writes the result back to the bit field in the 32-bit port. + + Reads the 32-bit PCI configuration register specified by Address, perfor= ms a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 32-bit PCI configuration register + specified by Address. The value written to the PCI configuration registe= r is + returned. This function must guarantee that all PCI read and write opera= tions + are serialized. Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldOr32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldOr32 (PciSegmentRead32 (Address), Star= tBit, EndBit, OrData) + ); +} + +/** + Reads a bit field in a 32-bit PCI configuration register, performs a bit= wise + AND, and writes the result back to the bit field in the 32-bit register. + + + Reads the 32-bit PCI configuration register specified by Address, perfor= ms a bitwise + AND between the read result and the value specified by AndData, and writ= es the result + to the 32-bit PCI configuration register specified by Address. The value= written to + the PCI configuration register is returned. This function must guarante= e that all PCI + read and write operations are serialized. Extra left bits in AndData ar= e stripped. + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param AndData The value to AND with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldAnd32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 AndData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldAnd32 (PciSegmentRead32 (Address), Sta= rtBit, EndBit, AndData) + ); +} + +/** + Reads a bit field in a 32-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 32-bit port. + + Reads the 32-bit PCI configuration register specified by Address, perfor= ms a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 32-bit PCI + configuration register specified by Address. The value written to the PC= I + configuration register is returned. This function must guarantee that al= l PCI + read and write operations are serialized. Extra left bits in both AndDat= a and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldAndThenOr32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldAndThenOr32 (PciSegmentRead32 (Address= ), StartBit, EndBit, AndData, OrData) + ); +} + +/** + Reads a range of PCI configuration registers into a caller supplied buff= er. + + Reads the range of PCI configuration registers specified by StartAddress= and + Size into the buffer specified by Buffer. This function only allows the = PCI + configuration registers from a single PCI function to be read. Size is + returned. When possible 32-bit PCI configuration read cycles are used to= read + from StartAdress to StartAddress + Size. Due to alignment restrictions, = 8-bit + and 16-bit PCI configuration read cycles may be used at the beginning an= d the + end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress The starting address that encodes the PCI Segment,= Bus, + Device, Function and Register. + @param Size The size in bytes of the transfer. + @param Buffer The pointer to a buffer receiving the data read. + + @return Size + +**/ +UINTN +EFIAPI +PciSegmentReadBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + OUT VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); + ASSERT (((StartAddress & 0xFFF) + Size) <=3D 0x1000); + + if (Size =3D=3D 0) { + return Size; + } + + ASSERT (Buffer !=3D NULL); + + // + // Save Size for return + // + ReturnValue =3D Size; + + if ((StartAddress & BIT0) !=3D 0) { + // + // Read a byte if StartAddress is byte aligned + // + *(volatile UINT8 *)Buffer =3D PciSegmentRead8 (StartAddress); + StartAddress +=3D sizeof (UINT8); + Size -=3D sizeof (UINT8); + Buffer =3D (UINT8 *)Buffer + 1; + } + + if ((Size >=3D sizeof (UINT16)) && ((StartAddress & BIT1) !=3D 0)) { + // + // Read a word if StartAddress is word aligned + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + while (Size >=3D sizeof (UINT32)) { + // + // Read as many double words as possible + // + WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress)); + StartAddress +=3D sizeof (UINT32); + Size -=3D sizeof (UINT32); + Buffer =3D (UINT32 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT16)) { + // + // Read the last remaining word if exist + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT8)) { + // + // Read the last remaining byte if exist + // + *(volatile UINT8 *)Buffer =3D PciSegmentRead8 (StartAddress); + } + + return ReturnValue; +} + +/** + Copies the data in a caller supplied buffer to a specified range of PCI + configuration space. + + Writes the range of PCI configuration registers specified by StartAddres= s and + Size from the buffer specified by Buffer. This function only allows the = PCI + configuration registers from a single PCI function to be written. Size i= s + returned. When possible 32-bit PCI configuration write cycles are used t= o + write from StartAdress to StartAddress + Size. Due to alignment restrict= ions, + 8-bit and 16-bit PCI configuration write cycles may be used at the begin= ning + and the end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress The starting address that encodes the PCI Segment,= Bus, + Device, Function and Register. + @param Size The size in bytes of the transfer. + @param Buffer The pointer to a buffer containing the data to wri= te. + + @return The parameter of Size. + +**/ +UINTN +EFIAPI +PciSegmentWriteBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + IN VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); + ASSERT (((StartAddress & 0xFFF) + Size) <=3D 0x1000); + + if (Size =3D=3D 0) { + return 0; + } + + ASSERT (Buffer !=3D NULL); + + // The Bcm/Rpi has a single cfg which can be mapped + // to any given device on the bus, which means we need to remap + // it basically everytime a new config access is done + + // + // Save Size for return + // + ReturnValue =3D Size; + + if ((StartAddress & BIT0) !=3D 0) { + // + // Write a byte if StartAddress is byte aligned + // + PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer); + StartAddress +=3D sizeof (UINT8); + Size -=3D sizeof (UINT8); + Buffer =3D (UINT8 *)Buffer + 1; + } + + if ((Size >=3D sizeof (UINT16)) && ((StartAddress & BIT1) !=3D 0)) { + // + // Write a word if StartAddress is word aligned + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + while (Size >=3D sizeof (UINT32)) { + // + // Write as many double words as possible + // + PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer)); + StartAddress +=3D sizeof (UINT32); + Size -=3D sizeof (UINT32); + Buffer =3D (UINT32 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT16)) { + // + // Write the last remaining word if exist + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT8)) { + // + // Write the last remaining byte if exist + // + PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer); + } + + return ReturnValue; +} diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib= .inf b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf new file mode 100644 index 000000000000..30d9d9599564 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf @@ -0,0 +1,33 @@ +## @file +# PCI Segment Library for StarFive JH7110 SoC +# +# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D PciSegmentLib + FILE_GUID =3D 832163a2-41f5-c529-3f02-77fb68abbc2c + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D PciSegmentLib + +[Sources] + PciSegmentLib.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + PcdLib + UefiLib + +[FixedPcd] + gJH7110TokenSpaceGuid.PcdJH7110PciConfigRegBase --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#109779): https://edk2.groups.io/g/devel/message/109779 Mute This Topic: https://groups.io/mt/102053680/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-