Implement the glue library that exposes the PCIe root complexes to
the generic PCI host bridge driver. Since that driver is the first
one to access the PCI config space, put the low level init code for
the RCs into this library's constructor.
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.c | 223 ++++++++++++
Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.inf | 50 +++
Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLibConstructor.c | 383 ++++++++++++++++++++
3 files changed, 656 insertions(+)
diff --git a/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.c b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.c
new file mode 100644
index 000000000000..10ddaac3b924
--- /dev/null
+++ b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.c
@@ -0,0 +1,223 @@
+/** @file
+ PCI Host Bridge Library instance for Socionext Synquacer ARM SOC
+
+ Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
+
+ 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 <PiDxe.h>
+#include <IndustryStandard/Pci22.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Platform/Pcie.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+
+#pragma pack(1)
+typedef 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[] = {
+ {
+ {
+ {
+ 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[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+
+STATIC PCI_ROOT_BRIDGE mPciRootBridges[] = {
+ {
+ 0, // Segment
+ 0, // Supports
+ 0, // Attributes
+ TRUE, // DmaAbove4G
+ FALSE, // NoExtendedConfigSpace
+ FALSE, // ResourceAssigned
+ EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |
+ EFI_PCI_HOST_BRIDGE_MEM64_DECODE, // AllocationAttributes
+ { SYNQUACER_PCI_SEG0_BUSNUM_MIN,
+ SYNQUACER_PCI_SEG0_BUSNUM_MAX }, // Bus
+ { SYNQUACER_PCI_SEG0_PORTIO_MIN,
+ SYNQUACER_PCI_SEG0_PORTIO_MAX }, // Io
+ { SYNQUACER_PCI_SEG0_MMIO32_MIN,
+ SYNQUACER_PCI_SEG0_MMIO32_MAX }, // Mem
+ { SYNQUACER_PCI_SEG0_MMIO64_MIN,
+ SYNQUACER_PCI_SEG0_MMIO64_MAX }, // MemAbove4G
+ { MAX_UINT64, 0x0 }, // PMem
+ { MAX_UINT64, 0x0 }, // PMemAbove4G
+ (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[0]
+ }, {
+ 1, // Segment
+ 0, // Supports
+ 0, // Attributes
+ TRUE, // DmaAbove4G
+ FALSE, // NoExtendedConfigSpace
+ FALSE, // ResourceAssigned
+ EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |
+ EFI_PCI_HOST_BRIDGE_MEM64_DECODE, // AllocationAttributes
+ { SYNQUACER_PCI_SEG1_BUSNUM_MIN,
+ SYNQUACER_PCI_SEG1_BUSNUM_MAX }, // Bus
+ { SYNQUACER_PCI_SEG1_PORTIO_MIN,
+ SYNQUACER_PCI_SEG1_PORTIO_MAX }, // Io
+ { SYNQUACER_PCI_SEG1_MMIO32_MIN,
+ SYNQUACER_PCI_SEG1_MMIO32_MAX }, // Mem
+ { SYNQUACER_PCI_SEG1_MMIO64_MIN,
+ SYNQUACER_PCI_SEG1_MMIO64_MAX }, // MemAbove4G
+ { MAX_UINT64, 0x0 }, // PMem
+ { MAX_UINT64, 0x0 }, // PMemAbove4G
+ (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 = ARRAY_SIZE (mPciRootBridges);
+
+ return mPciRootBridges;
+}
+
+/**
+ 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
+ )
+{
+}
+
+/**
+ 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/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.inf b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.inf
new file mode 100644
index 000000000000..cfa9b2fc1c07
--- /dev/null
+++ b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.inf
@@ -0,0 +1,50 @@
+## @file
+# PCI Host Bridge Library instance for Socionext Synquacer ARM SOC
+#
+# Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
+#
+# 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 = 0x00010019
+ BASE_NAME = SynquacerPciHostBridgeLib
+ FILE_GUID = fdc92446-65bc-4f86-b4a0-014a2119a732
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciHostBridgeLib|DXE_DRIVER
+ CONSTRUCTOR = SynquacerPciHostBridgeLibConstructor
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = AARCH64
+#
+
+[Sources]
+ SynquacerPciHostBridgeLib.c
+ SynquacerPciHostBridgeLibConstructor.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Silicon/Socionext/Synquacer/Synquacer.dec
+
+[LibraryClasses]
+ ArmLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+
+[FixedPcd]
+ gArmTokenSpaceGuid.PcdPciIoTranslation
diff --git a/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLibConstructor.c b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLibConstructor.c
new file mode 100644
index 000000000000..b3acca32070f
--- /dev/null
+++ b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLibConstructor.c
@@ -0,0 +1,383 @@
+/** @file
+ PCI Host Bridge Library instance for Socionext Synquacer ARM SOC
+
+ Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
+
+ 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 <PiDxe.h>
+#include <IndustryStandard/Pci22.h>
+#include <Library/ArmLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Platform/Pcie.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 CORE_CONTROL 0x000
+#define APP_LTSSM_ENABLE BIT4
+#define DEVICE_TYPE (BIT3 | BIT2 | BIT1 | BIT0)
+
+#define AXI_CLK_STOP 0x004
+#define DBI_ACLK_STOP BIT8
+#define SLV_ACLK_STOP BIT4
+#define MSTR_ACLK_STOP BIT0
+#define DBI_CSYSREQ_REG BIT9
+#define SLV_CSYSREQ_REG BIT5
+#define MSTR_CSYSREQ_REG BIT1
+
+#define RESET_CONTROL_1 0x00C
+#define PERST_N_O_REG BIT5
+#define PERST_N_I_REG BIT4
+#define BUTTON_RST_N_REG BIT1
+#define PWUP_RST_N_REG BIT0
+
+#define RESET_CONTROL_2 0x010
+
+#define RESET_SELECT_1 0x014
+#define SQU_RST_SEL BIT29
+#define PHY_RST_SEL BIT28
+#define PWR_RST_SEL BIT24
+#define STI_RST_SEL BIT20
+#define N_STI_RST_SEL BIT16
+#define CORE_RST_SEL BIT12
+#define PERST_SEL BIT4
+#define BUTTON_RST_SEL BIT1
+#define PWUP_RST_SEL BIT0
+
+#define RESET_SELECT_2 0x018
+#define DBI_ARST_SEL BIT8
+#define SLV_ARST_SEL BIT4
+#define MSTR_ARST_SEL BIT0
+
+#define EM_CONTROL 0x030
+#define PRE_DET_STT_REG BIT4
+
+#define EM_SELECT 0x034
+#define PRE_DET_STT_SEL BIT4
+
+#define PM_CONTROL_2 0x050
+#define SYS_AUX_PWR_DET BIT8
+
+#define PHY_CONFIG_COM_6 0x114
+#define PIPE_PORT_SEL (BIT1 | BIT0)
+
+#define LINK_MONITOR 0x210
+#define SMLH_LINK_UP BIT0
+
+#define LINK_CAPABILITIES_REG 0x07C
+#define PCIE_CAP_MAX_LINK_WIDTH (BIT7 | BIT6 | BIT5 | BIT4)
+#define PCIE_CAP_MAX_LINK_SPEED (BIT3 | BIT2 | BIT1 | BIT0)
+
+#define LINK_CONTROL_LINK_STATUS_REG 0x080
+#define PCIE_CAP_NEGO_LINK_WIDTH (BIT23 | BIT22 | BIT21 | BIT20)
+#define PCIE_CAP_LINK_SPEED (BIT19 | BIT18 | BIT17 | BIT16)
+
+#define TYPE1_CLASS_CODE_REV_ID_REG 0x008
+#define BASE_CLASS_CODE 0xFF000000
+#define BASE_CLASS_CODE_VALUE 0x06
+#define SUBCLASS_CODE 0x00FF0000
+#define SUBCLASS_CODE_VALUE 0x04
+#define PROGRAM_INTERFACE 0x0000FF00
+#define PROGRAM_INTERFACE_VALUE 0x00
+
+#define MISC_CONTROL_1_OFF 0x8BC
+#define DBI_RO_WR_EN BIT0
+
+STATIC
+VOID
+ConfigureWindow (
+ IN EFI_PHYSICAL_ADDRESS DbiBase,
+ IN UINTN Index,
+ IN UINT64 CpuBase,
+ IN UINT64 PciBase,
+ IN UINT64 Size,
+ IN UINTN Type,
+ IN UINTN EnableFlags
+ )
+{
+ ArmDataMemoryBarrier ();
+
+ MmioWrite32 (DbiBase + IATU_VIEWPORT_OFF,
+ IATU_VIEWPORT_OUTBOUND | IATU_VIEWPORT_REGION_INDEX (Index));
+
+ ArmDataMemoryBarrier ();
+
+ MmioWrite32 (DbiBase + IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0,
+ (UINT32)(CpuBase & 0xFFFFFFFF));
+ MmioWrite32 (DbiBase + IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0,
+ (UINT32)(CpuBase >> 32));
+ MmioWrite32 (DbiBase + IATU_LIMIT_ADDR_OFF_OUTBOUND_0,
+ (UINT32)(CpuBase + Size - 1));
+ MmioWrite32 (DbiBase + IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0,
+ (UINT32)(PciBase & 0xFFFFFFFF));
+ MmioWrite32 (DbiBase + IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0,
+ (UINT32)(PciBase >> 32));
+ MmioWrite32 (DbiBase + IATU_REGION_CTRL_1_OFF_OUTBOUND_0,
+ Type);
+ MmioWrite32 (DbiBase + IATU_REGION_CTRL_2_OFF_OUTBOUND_0,
+ IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN | EnableFlags);
+}
+
+STATIC
+VOID
+SnPcieSetData (
+ EFI_PHYSICAL_ADDRESS Base,
+ UINT32 Offset,
+ UINT32 Mask,
+ UINT32 In
+ )
+{
+ UINT32 Data;
+ UINT32 Shift;
+
+ Shift = 1;
+ if (In) {
+ while (!(Mask & Shift))
+ Shift <<= 1;
+ Data = (MmioRead32 (Base + Offset) & ~Mask) | (In * Shift);
+ } else {
+ Data = MmioRead32 (Base + Offset) & ~Mask;
+ }
+
+ MmioWrite32 (Base + Offset, Data);
+}
+
+STATIC
+UINT32
+SnPcieReadData (
+ EFI_PHYSICAL_ADDRESS Base,
+ UINT32 Offset,
+ UINT32 Mask
+ )
+{
+ UINT32 Shift;
+
+ Shift = 0;
+ while (!(Mask & 1)) {
+ Mask >>= 1;
+ Shift++;
+ }
+
+ return (MmioRead32 (Base + Offset) >> Shift) & Mask;
+}
+
+STATIC
+VOID
+SnDbiRoWrEn (
+ IN EFI_PHYSICAL_ADDRESS DbiBase,
+ IN INTN MaxLinkWidth,
+ IN INTN MaxLinkSpeed
+ )
+{
+ SnPcieSetData (DbiBase, MISC_CONTROL_1_OFF, DBI_RO_WR_EN, 1);
+
+ SnPcieSetData (DbiBase, LINK_CAPABILITIES_REG, PCIE_CAP_MAX_LINK_WIDTH, MaxLinkWidth);
+ SnPcieSetData (DbiBase, LINK_CAPABILITIES_REG, PCIE_CAP_MAX_LINK_SPEED, MaxLinkSpeed);
+
+ SnPcieSetData (DbiBase, TYPE1_CLASS_CODE_REV_ID_REG, BASE_CLASS_CODE, BASE_CLASS_CODE_VALUE);
+ SnPcieSetData (DbiBase, TYPE1_CLASS_CODE_REV_ID_REG, SUBCLASS_CODE, SUBCLASS_CODE_VALUE);
+ SnPcieSetData (DbiBase, TYPE1_CLASS_CODE_REV_ID_REG, PROGRAM_INTERFACE, PROGRAM_INTERFACE_VALUE);
+
+ SnPcieSetData (DbiBase, MISC_CONTROL_1_OFF, DBI_RO_WR_EN, 0);
+}
+
+STATIC
+VOID
+PciInitController (
+ IN EFI_PHYSICAL_ADDRESS ExsBase,
+ IN EFI_PHYSICAL_ADDRESS DbiBase,
+ IN EFI_PHYSICAL_ADDRESS ConfigBase,
+ IN CONST PCI_ROOT_BRIDGE *RootBridge
+ )
+{
+ SnPcieSetData (ExsBase, EM_SELECT, PRE_DET_STT_SEL, 0);
+ SnPcieSetData (ExsBase, EM_CONTROL, PRE_DET_STT_REG, 0);
+ SnPcieSetData (ExsBase, EM_CONTROL, PRE_DET_STT_REG, 1);
+
+ // 1: Assert all PHY / LINK resets
+ SnPcieSetData (ExsBase, RESET_SELECT_1 , PERST_SEL , 0);
+ SnPcieSetData (ExsBase, RESET_CONTROL_1, PERST_N_I_REG , 0);
+ SnPcieSetData (ExsBase, RESET_CONTROL_1, PERST_N_O_REG , 0);
+
+ // Device Reset(PERST#) is effective afrer Set device_type (RC)
+ SnPcieSetData (ExsBase, RESET_SELECT_1 , PWUP_RST_SEL , 0);
+ SnPcieSetData (ExsBase, RESET_CONTROL_1, PWUP_RST_N_REG, 0);
+ SnPcieSetData (ExsBase, RESET_SELECT_1 , BUTTON_RST_SEL , 0);
+ SnPcieSetData (ExsBase, RESET_CONTROL_1, BUTTON_RST_N_REG, 0);
+ SnPcieSetData (ExsBase, RESET_SELECT_1 , PWR_RST_SEL , 1);
+ SnPcieSetData (ExsBase, RESET_SELECT_2 , MSTR_ARST_SEL , 1);
+ SnPcieSetData (ExsBase, RESET_SELECT_2 , SLV_ARST_SEL , 1);
+ SnPcieSetData (ExsBase, RESET_SELECT_2 , DBI_ARST_SEL , 1);
+ SnPcieSetData (ExsBase, RESET_SELECT_1 , CORE_RST_SEL , 1);
+ SnPcieSetData (ExsBase, RESET_SELECT_1 , STI_RST_SEL , 1);
+ SnPcieSetData (ExsBase, RESET_SELECT_1 , N_STI_RST_SEL , 1);
+ SnPcieSetData (ExsBase, RESET_SELECT_1 , SQU_RST_SEL , 1);
+ SnPcieSetData (ExsBase, RESET_SELECT_1 , PHY_RST_SEL , 1);
+
+ // 2: Set P<n>_app_ltssm_enable='0' for reprogramming before linkup.
+ SnPcieSetData (ExsBase, CORE_CONTROL, APP_LTSSM_ENABLE, 0);
+
+ // 3: Set device_type (RC)
+ SnPcieSetData (ExsBase, CORE_CONTROL, DEVICE_TYPE, 4);
+
+ // 4: Set Bifurcation 1=disable 4=able
+ // 5: Supply Reference (It has executed)
+ // 6: Wait for 10usec (Reference Clocks is stable)
+ // 7 De assert PERST# */
+ SnPcieSetData (ExsBase, RESET_CONTROL_1, PERST_N_I_REG, 1);
+ SnPcieSetData (ExsBase, RESET_CONTROL_1, PERST_N_O_REG, 1);
+
+ // 8 Assert SYS_AUX_PWR_DET
+ SnPcieSetData(ExsBase, PM_CONTROL_2, SYS_AUX_PWR_DET, 1);
+
+ // 9 Supply following clocks
+ SnPcieSetData (ExsBase, AXI_CLK_STOP, MSTR_CSYSREQ_REG, 1);
+ SnPcieSetData (ExsBase, AXI_CLK_STOP, MSTR_ACLK_STOP, 0);
+ SnPcieSetData (ExsBase, AXI_CLK_STOP, SLV_CSYSREQ_REG, 1);
+ SnPcieSetData (ExsBase, AXI_CLK_STOP, SLV_ACLK_STOP, 0);
+ SnPcieSetData (ExsBase, AXI_CLK_STOP, DBI_CSYSREQ_REG, 1);
+ SnPcieSetData (ExsBase, AXI_CLK_STOP, DBI_ACLK_STOP, 0);
+
+ // 10 De assert PHY reset
+ // 11 De assert LINK's PMC reset
+ SnPcieSetData (ExsBase, RESET_CONTROL_1, PWUP_RST_N_REG, 1);
+ SnPcieSetData (ExsBase, RESET_CONTROL_1, BUTTON_RST_N_REG, 1);
+ // 12 PHY auto
+ // 13 Wrapper auto
+ // 14-17 PHY auto
+ // 18 Wrapper auto
+ // 19 Update registers through DBI AXI Slave interface
+ SnDbiRoWrEn (DbiBase, 4 /* lanes */, /* Gen */ 2);
+
+ //
+ // ECAM shift mode uses bits [27:12] of the untranslated address as
+ // B/D/F identifiers. This only works as expected if the base of the
+ // region is aligned to 256 MB, or the effective bus numbers will be
+ // out of sync with the bus base and limit values we chose.
+ //
+ ASSERT ((ConfigBase % SIZE_256MB) == RootBridge->Bus.Base * SIZE_1MB);
+
+ MmioOr32 (DbiBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_IO_SPACE |
+ EFI_PCI_COMMAND_MEMORY_SPACE |
+ EFI_PCI_COMMAND_BUS_MASTER);
+
+ // Region 0: MMIO32 range
+ ConfigureWindow (DbiBase, 0,
+ RootBridge->Mem.Base,
+ RootBridge->Mem.Base,
+ RootBridge->Mem.Limit - RootBridge->Mem.Base + 1,
+ IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM,
+ 0);
+
+ // Region 1: Type 0 config space
+ ConfigureWindow (DbiBase, 1,
+ ConfigBase + RootBridge->Bus.Base * SIZE_1MB,
+ 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 (DbiBase, 2,
+ ConfigBase + RootBridge->Bus.Base * SIZE_1MB + SIZE_64KB,
+ 0x0,
+ (RootBridge->Bus.Limit - RootBridge->Bus.Base + 1) * SIZE_1MB - SIZE_64KB,
+ 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 (DbiBase, 3,
+ FixedPcdGet32 (PcdPciIoTranslation) + RootBridge->Io.Base,
+ RootBridge->Io.Base,
+ RootBridge->Io.Limit - RootBridge->Io.Base + 1,
+ IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_IO,
+ 0);
+
+ // Region 4: MMIO64 range
+ ConfigureWindow (DbiBase, 4,
+ RootBridge->MemAbove4G.Base,
+ RootBridge->MemAbove4G.Base,
+ RootBridge->MemAbove4G.Limit - RootBridge->MemAbove4G.Base + 1,
+ IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM,
+ 0);
+
+ // enable link
+ if (SnPcieReadData (ExsBase, CORE_CONTROL, APP_LTSSM_ENABLE) == 0) {
+ SnPcieSetData (ExsBase, CORE_CONTROL, APP_LTSSM_ENABLE, 1);
+ }
+}
+
+STATIC CONST struct {
+ EFI_PHYSICAL_ADDRESS DbiBase;
+ EFI_PHYSICAL_ADDRESS ExsBase;
+ EFI_PHYSICAL_ADDRESS ConfigBase;
+} mBaseAddresses [] = {
+ {
+ SYNQUACER_PCI_SEG0_DBI_BASE,
+ SYNQUACER_PCI_SEG0_EXS_BASE,
+ SYNQUACER_PCI_SEG0_CONFIG_BASE
+ },
+ {
+ SYNQUACER_PCI_SEG1_DBI_BASE,
+ SYNQUACER_PCI_SEG1_EXS_BASE,
+ SYNQUACER_PCI_SEG1_CONFIG_BASE
+ },
+};
+
+
+EFI_STATUS
+EFIAPI
+SynquacerPciHostBridgeLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ PCI_ROOT_BRIDGE *RootBridges;
+ UINTN Count;
+ UINTN Idx;
+
+ RootBridges = PciHostBridgeGetRootBridges (&Count);
+ ASSERT (Count == ARRAY_SIZE(mBaseAddresses));
+ if (Count != ARRAY_SIZE(mBaseAddresses)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Idx = 0; Idx < Count; Idx++) {
+ PciInitController (mBaseAddresses[Idx].ExsBase,
+ mBaseAddresses[Idx].DbiBase,
+ mBaseAddresses[Idx].ConfigBase,
+ &RootBridges[Idx]);
+ }
+
+ return EFI_SUCCESS;
+}
+
--
2.11.0
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
On Fri, Sep 08, 2017 at 07:23:06PM +0100, Ard Biesheuvel wrote: > Implement the glue library that exposes the PCIe root complexes to > the generic PCI host bridge driver. Since that driver is the first > one to access the PCI config space, put the low level init code for > the RCs into this library's constructor. > > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> > --- > Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.c | 223 ++++++++++++ > Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.inf | 50 +++ > Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLibConstructor.c | 383 ++++++++++++++++++++ > 3 files changed, 656 insertions(+) > > diff --git a/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.c b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.c > new file mode 100644 > index 000000000000..10ddaac3b924 > --- /dev/null > +++ b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.c > @@ -0,0 +1,223 @@ > +/** @file > + PCI Host Bridge Library instance for Socionext Synquacer ARM SOC > + > + Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR> > + > + 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 <PiDxe.h> > +#include <IndustryStandard/Pci22.h> > +#include <Library/DebugLib.h> > +#include <Library/DevicePathLib.h> > +#include <Library/MemoryAllocationLib.h> > +#include <Library/PcdLib.h> > +#include <Library/PciHostBridgeLib.h> > +#include <Platform/Pcie.h> > +#include <Protocol/PciRootBridgeIo.h> > +#include <Protocol/PciHostBridgeResourceAllocation.h> The above is well enough sorted that I'd let it slip, but it isn't flawless. > + > +#pragma pack(1) > +typedef 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[] = { > + { > + { > + { > + ACPI_DEVICE_PATH, > + ACPI_DP, > + { > + (UINT8) (sizeof(ACPI_HID_DEVICE_PATH)), > + (UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8) Shift the spaces after (UINT8) to after sizeof? > + } > + }, > + EISA_PNP_ID(0x0A08), // PCI Express Space before (? Why don't we have that 0x0a08 in a central header? > + 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) Shift the spaces after (UINT8) to after sizeof? > + } > + }, > + EISA_PNP_ID(0x0A08), // PCI Express Same as above. > + 1 > + }, > + > + { > + 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" > +}; > + > +STATIC PCI_ROOT_BRIDGE mPciRootBridges[] = { > + { > + 0, // Segment > + 0, // Supports > + 0, // Attributes > + TRUE, // DmaAbove4G > + FALSE, // NoExtendedConfigSpace > + FALSE, // ResourceAssigned > + EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | > + EFI_PCI_HOST_BRIDGE_MEM64_DECODE, // AllocationAttributes > + { SYNQUACER_PCI_SEG0_BUSNUM_MIN, > + SYNQUACER_PCI_SEG0_BUSNUM_MAX }, // Bus > + { SYNQUACER_PCI_SEG0_PORTIO_MIN, > + SYNQUACER_PCI_SEG0_PORTIO_MAX }, // Io > + { SYNQUACER_PCI_SEG0_MMIO32_MIN, > + SYNQUACER_PCI_SEG0_MMIO32_MAX }, // Mem > + { SYNQUACER_PCI_SEG0_MMIO64_MIN, > + SYNQUACER_PCI_SEG0_MMIO64_MAX }, // MemAbove4G > + { MAX_UINT64, 0x0 }, // PMem > + { MAX_UINT64, 0x0 }, // PMemAbove4G > + (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[0] > + }, { > + 1, // Segment > + 0, // Supports > + 0, // Attributes > + TRUE, // DmaAbove4G > + FALSE, // NoExtendedConfigSpace > + FALSE, // ResourceAssigned > + EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | > + EFI_PCI_HOST_BRIDGE_MEM64_DECODE, // AllocationAttributes > + { SYNQUACER_PCI_SEG1_BUSNUM_MIN, > + SYNQUACER_PCI_SEG1_BUSNUM_MAX }, // Bus > + { SYNQUACER_PCI_SEG1_PORTIO_MIN, > + SYNQUACER_PCI_SEG1_PORTIO_MAX }, // Io > + { SYNQUACER_PCI_SEG1_MMIO32_MIN, > + SYNQUACER_PCI_SEG1_MMIO32_MAX }, // Mem > + { SYNQUACER_PCI_SEG1_MMIO64_MIN, > + SYNQUACER_PCI_SEG1_MMIO64_MAX }, // MemAbove4G > + { MAX_UINT64, 0x0 }, // PMem > + { MAX_UINT64, 0x0 }, // PMemAbove4G > + (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 = ARRAY_SIZE (mPciRootBridges); > + > + return mPciRootBridges; > +} > + > +/** > + 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 > + ) > +{ > +} > + > +/** > + 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]) > + ) > + ); Replace with ARRAY_SIZE? > + 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/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.inf b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.inf > new file mode 100644 > index 000000000000..cfa9b2fc1c07 > --- /dev/null > +++ b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLib.inf > @@ -0,0 +1,50 @@ > +## @file > +# PCI Host Bridge Library instance for Socionext Synquacer ARM SOC > +# > +# Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR> > +# > +# 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 = 0x00010019 > + BASE_NAME = SynquacerPciHostBridgeLib > + FILE_GUID = fdc92446-65bc-4f86-b4a0-014a2119a732 > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = PciHostBridgeLib|DXE_DRIVER > + CONSTRUCTOR = SynquacerPciHostBridgeLibConstructor > + > +# > +# The following information is for reference only and not required by the build > +# tools. > +# > +# VALID_ARCHITECTURES = AARCH64 Do we only have AArch64 support for this specific component? > +# > + > +[Sources] > + SynquacerPciHostBridgeLib.c > + SynquacerPciHostBridgeLibConstructor.c > + > +[Packages] > + ArmPkg/ArmPkg.dec > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + Silicon/Socionext/Synquacer/Synquacer.dec > + > +[LibraryClasses] > + ArmLib > + DebugLib > + DevicePathLib > + MemoryAllocationLib > + > +[FixedPcd] > + gArmTokenSpaceGuid.PcdPciIoTranslation > diff --git a/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLibConstructor.c b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLibConstructor.c > new file mode 100644 > index 000000000000..b3acca32070f > --- /dev/null > +++ b/Silicon/Socionext/Synquacer/Library/SynquacerPciHostBridgeLib/SynquacerPciHostBridgeLibConstructor.c > @@ -0,0 +1,383 @@ > +/** @file > + PCI Host Bridge Library instance for Socionext Synquacer ARM SOC > + > + Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR> > + > + 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 <PiDxe.h> > +#include <IndustryStandard/Pci22.h> > +#include <Library/ArmLib.h> > +#include <Library/DebugLib.h> > +#include <Library/IoLib.h> > +#include <Library/PciHostBridgeLib.h> > +#include <Platform/Pcie.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 CORE_CONTROL 0x000 > +#define APP_LTSSM_ENABLE BIT4 > +#define DEVICE_TYPE (BIT3 | BIT2 | BIT1 | BIT0) > + > +#define AXI_CLK_STOP 0x004 > +#define DBI_ACLK_STOP BIT8 > +#define SLV_ACLK_STOP BIT4 > +#define MSTR_ACLK_STOP BIT0 > +#define DBI_CSYSREQ_REG BIT9 > +#define SLV_CSYSREQ_REG BIT5 > +#define MSTR_CSYSREQ_REG BIT1 > + > +#define RESET_CONTROL_1 0x00C > +#define PERST_N_O_REG BIT5 > +#define PERST_N_I_REG BIT4 > +#define BUTTON_RST_N_REG BIT1 > +#define PWUP_RST_N_REG BIT0 > + > +#define RESET_CONTROL_2 0x010 > + > +#define RESET_SELECT_1 0x014 > +#define SQU_RST_SEL BIT29 > +#define PHY_RST_SEL BIT28 > +#define PWR_RST_SEL BIT24 > +#define STI_RST_SEL BIT20 > +#define N_STI_RST_SEL BIT16 > +#define CORE_RST_SEL BIT12 > +#define PERST_SEL BIT4 > +#define BUTTON_RST_SEL BIT1 > +#define PWUP_RST_SEL BIT0 > + > +#define RESET_SELECT_2 0x018 > +#define DBI_ARST_SEL BIT8 > +#define SLV_ARST_SEL BIT4 > +#define MSTR_ARST_SEL BIT0 > + > +#define EM_CONTROL 0x030 > +#define PRE_DET_STT_REG BIT4 > + > +#define EM_SELECT 0x034 > +#define PRE_DET_STT_SEL BIT4 > + > +#define PM_CONTROL_2 0x050 > +#define SYS_AUX_PWR_DET BIT8 > + > +#define PHY_CONFIG_COM_6 0x114 > +#define PIPE_PORT_SEL (BIT1 | BIT0) > + > +#define LINK_MONITOR 0x210 > +#define SMLH_LINK_UP BIT0 > + > +#define LINK_CAPABILITIES_REG 0x07C > +#define PCIE_CAP_MAX_LINK_WIDTH (BIT7 | BIT6 | BIT5 | BIT4) > +#define PCIE_CAP_MAX_LINK_SPEED (BIT3 | BIT2 | BIT1 | BIT0) > + > +#define LINK_CONTROL_LINK_STATUS_REG 0x080 > +#define PCIE_CAP_NEGO_LINK_WIDTH (BIT23 | BIT22 | BIT21 | BIT20) > +#define PCIE_CAP_LINK_SPEED (BIT19 | BIT18 | BIT17 | BIT16) > + > +#define TYPE1_CLASS_CODE_REV_ID_REG 0x008 > +#define BASE_CLASS_CODE 0xFF000000 > +#define BASE_CLASS_CODE_VALUE 0x06 > +#define SUBCLASS_CODE 0x00FF0000 > +#define SUBCLASS_CODE_VALUE 0x04 > +#define PROGRAM_INTERFACE 0x0000FF00 > +#define PROGRAM_INTERFACE_VALUE 0x00 > + > +#define MISC_CONTROL_1_OFF 0x8BC > +#define DBI_RO_WR_EN BIT0 > + > +STATIC > +VOID > +ConfigureWindow ( > + IN EFI_PHYSICAL_ADDRESS DbiBase, > + IN UINTN Index, > + IN UINT64 CpuBase, > + IN UINT64 PciBase, > + IN UINT64 Size, > + IN UINTN Type, > + IN UINTN EnableFlags > + ) > +{ > + ArmDataMemoryBarrier (); > + > + MmioWrite32 (DbiBase + IATU_VIEWPORT_OFF, > + IATU_VIEWPORT_OUTBOUND | IATU_VIEWPORT_REGION_INDEX (Index)); > + > + ArmDataMemoryBarrier (); > + > + MmioWrite32 (DbiBase + IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0, > + (UINT32)(CpuBase & 0xFFFFFFFF)); > + MmioWrite32 (DbiBase + IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0, > + (UINT32)(CpuBase >> 32)); > + MmioWrite32 (DbiBase + IATU_LIMIT_ADDR_OFF_OUTBOUND_0, > + (UINT32)(CpuBase + Size - 1)); > + MmioWrite32 (DbiBase + IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0, > + (UINT32)(PciBase & 0xFFFFFFFF)); > + MmioWrite32 (DbiBase + IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0, > + (UINT32)(PciBase >> 32)); > + MmioWrite32 (DbiBase + IATU_REGION_CTRL_1_OFF_OUTBOUND_0, > + Type); > + MmioWrite32 (DbiBase + IATU_REGION_CTRL_2_OFF_OUTBOUND_0, > + IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN | EnableFlags); No barrier needed here? > +} > + > +STATIC > +VOID > +SnPcieSetData ( > + EFI_PHYSICAL_ADDRESS Base, > + UINT32 Offset, > + UINT32 Mask, > + UINT32 In > + ) > +{ > + UINT32 Data; > + UINT32 Shift; > + > + Shift = 1; > + if (In) { > + while (!(Mask & Shift)) { > + Shift <<= 1; } / Leif > + Data = (MmioRead32 (Base + Offset) & ~Mask) | (In * Shift); > + } else { > + Data = MmioRead32 (Base + Offset) & ~Mask; > + } > + > + MmioWrite32 (Base + Offset, Data); > +} > + > +STATIC > +UINT32 > +SnPcieReadData ( > + EFI_PHYSICAL_ADDRESS Base, > + UINT32 Offset, > + UINT32 Mask > + ) > +{ > + UINT32 Shift; > + > + Shift = 0; > + while (!(Mask & 1)) { > + Mask >>= 1; > + Shift++; > + } > + > + return (MmioRead32 (Base + Offset) >> Shift) & Mask; > +} > + > +STATIC > +VOID > +SnDbiRoWrEn ( > + IN EFI_PHYSICAL_ADDRESS DbiBase, > + IN INTN MaxLinkWidth, > + IN INTN MaxLinkSpeed > + ) > +{ > + SnPcieSetData (DbiBase, MISC_CONTROL_1_OFF, DBI_RO_WR_EN, 1); > + > + SnPcieSetData (DbiBase, LINK_CAPABILITIES_REG, PCIE_CAP_MAX_LINK_WIDTH, MaxLinkWidth); > + SnPcieSetData (DbiBase, LINK_CAPABILITIES_REG, PCIE_CAP_MAX_LINK_SPEED, MaxLinkSpeed); > + > + SnPcieSetData (DbiBase, TYPE1_CLASS_CODE_REV_ID_REG, BASE_CLASS_CODE, BASE_CLASS_CODE_VALUE); > + SnPcieSetData (DbiBase, TYPE1_CLASS_CODE_REV_ID_REG, SUBCLASS_CODE, SUBCLASS_CODE_VALUE); > + SnPcieSetData (DbiBase, TYPE1_CLASS_CODE_REV_ID_REG, PROGRAM_INTERFACE, PROGRAM_INTERFACE_VALUE); > + > + SnPcieSetData (DbiBase, MISC_CONTROL_1_OFF, DBI_RO_WR_EN, 0); > +} > + > +STATIC > +VOID > +PciInitController ( > + IN EFI_PHYSICAL_ADDRESS ExsBase, > + IN EFI_PHYSICAL_ADDRESS DbiBase, > + IN EFI_PHYSICAL_ADDRESS ConfigBase, > + IN CONST PCI_ROOT_BRIDGE *RootBridge > + ) > +{ > + SnPcieSetData (ExsBase, EM_SELECT, PRE_DET_STT_SEL, 0); > + SnPcieSetData (ExsBase, EM_CONTROL, PRE_DET_STT_REG, 0); > + SnPcieSetData (ExsBase, EM_CONTROL, PRE_DET_STT_REG, 1); > + > + // 1: Assert all PHY / LINK resets > + SnPcieSetData (ExsBase, RESET_SELECT_1 , PERST_SEL , 0); > + SnPcieSetData (ExsBase, RESET_CONTROL_1, PERST_N_I_REG , 0); > + SnPcieSetData (ExsBase, RESET_CONTROL_1, PERST_N_O_REG , 0); > + > + // Device Reset(PERST#) is effective afrer Set device_type (RC) > + SnPcieSetData (ExsBase, RESET_SELECT_1 , PWUP_RST_SEL , 0); > + SnPcieSetData (ExsBase, RESET_CONTROL_1, PWUP_RST_N_REG, 0); > + SnPcieSetData (ExsBase, RESET_SELECT_1 , BUTTON_RST_SEL , 0); > + SnPcieSetData (ExsBase, RESET_CONTROL_1, BUTTON_RST_N_REG, 0); > + SnPcieSetData (ExsBase, RESET_SELECT_1 , PWR_RST_SEL , 1); > + SnPcieSetData (ExsBase, RESET_SELECT_2 , MSTR_ARST_SEL , 1); > + SnPcieSetData (ExsBase, RESET_SELECT_2 , SLV_ARST_SEL , 1); > + SnPcieSetData (ExsBase, RESET_SELECT_2 , DBI_ARST_SEL , 1); > + SnPcieSetData (ExsBase, RESET_SELECT_1 , CORE_RST_SEL , 1); > + SnPcieSetData (ExsBase, RESET_SELECT_1 , STI_RST_SEL , 1); > + SnPcieSetData (ExsBase, RESET_SELECT_1 , N_STI_RST_SEL , 1); > + SnPcieSetData (ExsBase, RESET_SELECT_1 , SQU_RST_SEL , 1); > + SnPcieSetData (ExsBase, RESET_SELECT_1 , PHY_RST_SEL , 1); > + > + // 2: Set P<n>_app_ltssm_enable='0' for reprogramming before linkup. > + SnPcieSetData (ExsBase, CORE_CONTROL, APP_LTSSM_ENABLE, 0); > + > + // 3: Set device_type (RC) > + SnPcieSetData (ExsBase, CORE_CONTROL, DEVICE_TYPE, 4); > + > + // 4: Set Bifurcation 1=disable 4=able > + // 5: Supply Reference (It has executed) > + // 6: Wait for 10usec (Reference Clocks is stable) > + // 7 De assert PERST# */ > + SnPcieSetData (ExsBase, RESET_CONTROL_1, PERST_N_I_REG, 1); > + SnPcieSetData (ExsBase, RESET_CONTROL_1, PERST_N_O_REG, 1); > + > + // 8 Assert SYS_AUX_PWR_DET > + SnPcieSetData(ExsBase, PM_CONTROL_2, SYS_AUX_PWR_DET, 1); > + > + // 9 Supply following clocks > + SnPcieSetData (ExsBase, AXI_CLK_STOP, MSTR_CSYSREQ_REG, 1); > + SnPcieSetData (ExsBase, AXI_CLK_STOP, MSTR_ACLK_STOP, 0); > + SnPcieSetData (ExsBase, AXI_CLK_STOP, SLV_CSYSREQ_REG, 1); > + SnPcieSetData (ExsBase, AXI_CLK_STOP, SLV_ACLK_STOP, 0); > + SnPcieSetData (ExsBase, AXI_CLK_STOP, DBI_CSYSREQ_REG, 1); > + SnPcieSetData (ExsBase, AXI_CLK_STOP, DBI_ACLK_STOP, 0); > + > + // 10 De assert PHY reset > + // 11 De assert LINK's PMC reset > + SnPcieSetData (ExsBase, RESET_CONTROL_1, PWUP_RST_N_REG, 1); > + SnPcieSetData (ExsBase, RESET_CONTROL_1, BUTTON_RST_N_REG, 1); > + // 12 PHY auto > + // 13 Wrapper auto > + // 14-17 PHY auto > + // 18 Wrapper auto > + // 19 Update registers through DBI AXI Slave interface > + SnDbiRoWrEn (DbiBase, 4 /* lanes */, /* Gen */ 2); > + > + // > + // ECAM shift mode uses bits [27:12] of the untranslated address as > + // B/D/F identifiers. This only works as expected if the base of the > + // region is aligned to 256 MB, or the effective bus numbers will be > + // out of sync with the bus base and limit values we chose. > + // > + ASSERT ((ConfigBase % SIZE_256MB) == RootBridge->Bus.Base * SIZE_1MB); > + > + MmioOr32 (DbiBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_IO_SPACE | > + EFI_PCI_COMMAND_MEMORY_SPACE | > + EFI_PCI_COMMAND_BUS_MASTER); > + > + // Region 0: MMIO32 range > + ConfigureWindow (DbiBase, 0, > + RootBridge->Mem.Base, > + RootBridge->Mem.Base, > + RootBridge->Mem.Limit - RootBridge->Mem.Base + 1, > + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM, > + 0); > + > + // Region 1: Type 0 config space > + ConfigureWindow (DbiBase, 1, > + ConfigBase + RootBridge->Bus.Base * SIZE_1MB, > + 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 (DbiBase, 2, > + ConfigBase + RootBridge->Bus.Base * SIZE_1MB + SIZE_64KB, > + 0x0, > + (RootBridge->Bus.Limit - RootBridge->Bus.Base + 1) * SIZE_1MB - SIZE_64KB, > + 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 (DbiBase, 3, > + FixedPcdGet32 (PcdPciIoTranslation) + RootBridge->Io.Base, > + RootBridge->Io.Base, > + RootBridge->Io.Limit - RootBridge->Io.Base + 1, > + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_IO, > + 0); > + > + // Region 4: MMIO64 range > + ConfigureWindow (DbiBase, 4, > + RootBridge->MemAbove4G.Base, > + RootBridge->MemAbove4G.Base, > + RootBridge->MemAbove4G.Limit - RootBridge->MemAbove4G.Base + 1, > + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM, > + 0); > + > + // enable link > + if (SnPcieReadData (ExsBase, CORE_CONTROL, APP_LTSSM_ENABLE) == 0) { > + SnPcieSetData (ExsBase, CORE_CONTROL, APP_LTSSM_ENABLE, 1); > + } > +} > + > +STATIC CONST struct { > + EFI_PHYSICAL_ADDRESS DbiBase; > + EFI_PHYSICAL_ADDRESS ExsBase; > + EFI_PHYSICAL_ADDRESS ConfigBase; > +} mBaseAddresses [] = { > + { > + SYNQUACER_PCI_SEG0_DBI_BASE, > + SYNQUACER_PCI_SEG0_EXS_BASE, > + SYNQUACER_PCI_SEG0_CONFIG_BASE > + }, > + { > + SYNQUACER_PCI_SEG1_DBI_BASE, > + SYNQUACER_PCI_SEG1_EXS_BASE, > + SYNQUACER_PCI_SEG1_CONFIG_BASE > + }, > +}; > + > + > +EFI_STATUS > +EFIAPI > +SynquacerPciHostBridgeLibConstructor ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + PCI_ROOT_BRIDGE *RootBridges; > + UINTN Count; > + UINTN Idx; > + > + RootBridges = PciHostBridgeGetRootBridges (&Count); > + ASSERT (Count == ARRAY_SIZE(mBaseAddresses)); > + if (Count != ARRAY_SIZE(mBaseAddresses)) { > + return EFI_INVALID_PARAMETER; > + } > + > + for (Idx = 0; Idx < Count; Idx++) { > + PciInitController (mBaseAddresses[Idx].ExsBase, > + mBaseAddresses[Idx].DbiBase, > + mBaseAddresses[Idx].ConfigBase, > + &RootBridges[Idx]); > + } > + > + return EFI_SUCCESS; > +} > + > -- > 2.11.0 > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2024 Red Hat, Inc.