aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/pci')
-rw-r--r--roms/u-boot/drivers/pci/Kconfig331
-rw-r--r--roms/u-boot/drivers/pci/Makefile57
-rw-r--r--roms/u-boot/drivers/pci/fsl_pci_init.c936
-rw-r--r--roms/u-boot/drivers/pci/pci-aardvark.c890
-rw-r--r--roms/u-boot/drivers/pci/pci-emul-uclass.c132
-rw-r--r--roms/u-boot/drivers/pci/pci-rcar-gen2.c264
-rw-r--r--roms/u-boot/drivers/pci/pci-rcar-gen3.c420
-rw-r--r--roms/u-boot/drivers/pci/pci-uclass.c1870
-rw-r--r--roms/u-boot/drivers/pci/pci.c588
-rw-r--r--roms/u-boot/drivers/pci/pci_auto.c376
-rw-r--r--roms/u-boot/drivers/pci/pci_auto_common.c119
-rw-r--r--roms/u-boot/drivers/pci/pci_auto_old.c387
-rw-r--r--roms/u-boot/drivers/pci/pci_common.c364
-rw-r--r--roms/u-boot/drivers/pci/pci_compat.c53
-rw-r--r--roms/u-boot/drivers/pci/pci_ftpci100.c319
-rw-r--r--roms/u-boot/drivers/pci/pci_gt64120.c177
-rw-r--r--roms/u-boot/drivers/pci/pci_indirect.c71
-rw-r--r--roms/u-boot/drivers/pci/pci_internal.h61
-rw-r--r--roms/u-boot/drivers/pci/pci_mpc85xx.c162
-rw-r--r--roms/u-boot/drivers/pci/pci_msc01.c125
-rw-r--r--roms/u-boot/drivers/pci/pci_mvebu.c541
-rw-r--r--roms/u-boot/drivers/pci/pci_octeontx.c365
-rw-r--r--roms/u-boot/drivers/pci/pci_rom.c402
-rw-r--r--roms/u-boot/drivers/pci/pci_sandbox.c136
-rw-r--r--roms/u-boot/drivers/pci/pci_sh4.c82
-rw-r--r--roms/u-boot/drivers/pci/pci_sh7751.c234
-rw-r--r--roms/u-boot/drivers/pci/pci_sh7780.c92
-rw-r--r--roms/u-boot/drivers/pci/pci_tegra.c1203
-rw-r--r--roms/u-boot/drivers/pci/pci_x86.c39
-rw-r--r--roms/u-boot/drivers/pci/pcie_brcmstb.c641
-rw-r--r--roms/u-boot/drivers/pci/pcie_dw_common.c369
-rw-r--r--roms/u-boot/drivers/pci/pcie_dw_common.h155
-rw-r--r--roms/u-boot/drivers/pci/pcie_dw_meson.c459
-rw-r--r--roms/u-boot/drivers/pci/pcie_dw_mvebu.c598
-rw-r--r--roms/u-boot/drivers/pci/pcie_dw_rockchip.c464
-rw-r--r--roms/u-boot/drivers/pci/pcie_dw_sifive.c507
-rw-r--r--roms/u-boot/drivers/pci/pcie_dw_ti.c361
-rw-r--r--roms/u-boot/drivers/pci/pcie_ecam_generic.c173
-rw-r--r--roms/u-boot/drivers/pci/pcie_fsl.c668
-rw-r--r--roms/u-boot/drivers/pci/pcie_fsl.h68
-rw-r--r--roms/u-boot/drivers/pci/pcie_fsl_fixup.c50
-rw-r--r--roms/u-boot/drivers/pci/pcie_imx.c836
-rw-r--r--roms/u-boot/drivers/pci/pcie_intel_fpga.c435
-rw-r--r--roms/u-boot/drivers/pci/pcie_iproc.c1287
-rw-r--r--roms/u-boot/drivers/pci/pcie_layerscape.c149
-rw-r--r--roms/u-boot/drivers/pci/pcie_layerscape.h192
-rw-r--r--roms/u-boot/drivers/pci/pcie_layerscape_ep.c341
-rw-r--r--roms/u-boot/drivers/pci/pcie_layerscape_fixup.c629
-rw-r--r--roms/u-boot/drivers/pci/pcie_layerscape_fixup_common.c157
-rw-r--r--roms/u-boot/drivers/pci/pcie_layerscape_fixup_common.h22
-rw-r--r--roms/u-boot/drivers/pci/pcie_layerscape_gen4.c585
-rw-r--r--roms/u-boot/drivers/pci/pcie_layerscape_gen4.h264
-rw-r--r--roms/u-boot/drivers/pci/pcie_layerscape_gen4_fixup.c245
-rw-r--r--roms/u-boot/drivers/pci/pcie_layerscape_rc.c388
-rw-r--r--roms/u-boot/drivers/pci/pcie_mediatek.c746
-rw-r--r--roms/u-boot/drivers/pci/pcie_octeon.c159
-rw-r--r--roms/u-boot/drivers/pci/pcie_phytium.c200
-rw-r--r--roms/u-boot/drivers/pci/pcie_rockchip.c570
-rw-r--r--roms/u-boot/drivers/pci/pcie_xilinx.c180
59 files changed, 22694 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/pci/Kconfig b/roms/u-boot/drivers/pci/Kconfig
new file mode 100644
index 000000000..b2b7b253f
--- /dev/null
+++ b/roms/u-boot/drivers/pci/Kconfig
@@ -0,0 +1,331 @@
+menuconfig PCI
+ bool "PCI support"
+ default y if PPC
+ help
+ Enable support for PCI (Peripheral Interconnect Bus), a type of bus
+ used on some devices to allow the CPU to communicate with its
+ peripherals.
+
+if PCI
+
+config DM_PCI
+ bool "Enable driver model for PCI"
+ depends on DM
+ help
+ Use driver model for PCI. Driver model is the new method for
+ orgnising devices in U-Boot. For PCI, driver model keeps track of
+ available PCI devices, allows scanning of PCI buses and provides
+ device configuration support.
+
+config DM_PCI_COMPAT
+ bool "Enable compatible functions for PCI"
+ depends on DM_PCI
+ help
+ Enable compatibility functions for PCI so that old code can be used
+ with CONFIG_DM_PCI enabled. This should be used as an interim
+ measure when porting a board to use driver model for PCI. Once the
+ board is fully supported, this option should be disabled.
+
+config PCI_AARDVARK
+ bool "Enable Aardvark PCIe driver"
+ default n
+ depends on DM_PCI
+ depends on DM_GPIO
+ depends on ARMADA_3700
+ help
+ Say Y here if you want to enable PCIe controller support on
+ Armada37x0 SoCs. The PCIe controller on Armada37x0 is based on
+ Aardvark hardware.
+
+config PCI_PNP
+ bool "Enable Plug & Play support for PCI"
+ depends on PCI || DM_PCI
+ default y
+ help
+ Enable PCI memory and I/O space resource allocation and assignment.
+
+config PCI_REGION_MULTI_ENTRY
+ bool "Enable Multiple entries of region type MEMORY in ranges for PCI"
+ depends on PCI || DM_PCI
+ default n
+ help
+ Enable PCI memory regions to be of multiple entry. Multiple entry
+ here refers to allow more than one count of address ranges for MEMORY
+ region type. This helps to add support for SoC's like OcteonTX/TX2
+ where every peripheral is on the PCI bus.
+
+config PCI_SRIOV
+ bool "Enable Single Root I/O Virtualization support for PCI"
+ depends on PCI || DM_PCI
+ default n
+ help
+ Say Y here if you want to enable PCI Single Root I/O Virtualization
+ capability support. This helps to enumerate Virtual Function devices
+ if available on a PCI Physical Function device and probe for
+ applicable drivers.
+
+config PCI_ARID
+ bool "Enable Alternate Routing-ID support for PCI"
+ depends on PCI || DM_PCI
+ default n
+ help
+ Say Y here if you want to enable Alternate Routing-ID capability
+ support on PCI devices. This helps to skip some devices in BDF
+ scan that are not present.
+
+config PCIE_ECAM_GENERIC
+ bool "Generic ECAM-based PCI host controller support"
+ default n
+ depends on DM_PCI
+ help
+ Say Y here if you want to enable support for generic ECAM-based
+ PCIe host controllers, such as the one emulated by QEMU.
+
+config PCI_PHYTIUM
+ bool "Phytium PCIe support"
+ depends on DM_PCI
+ help
+ Say Y here if you want to enable PCIe controller support on
+ Phytium SoCs.
+
+config PCIE_DW_MVEBU
+ bool "Enable Armada-8K PCIe driver (DesignWare core)"
+ depends on DM_PCI
+ depends on ARMADA_8K
+ help
+ Say Y here if you want to enable PCIe controller support on
+ Armada-8K SoCs. The PCIe controller on Armada-8K is based on
+ DesignWare hardware.
+
+config PCIE_DW_SIFIVE
+ bool "Enable SiFive FU740 PCIe"
+ depends on CLK_SIFIVE_PRCI
+ depends on RESET_SIFIVE
+ depends on SIFIVE_GPIO
+ select PCIE_DW_COMMON
+ help
+ Say Y here if you want to enable PCIe controller support on
+ FU740.
+
+config PCIE_FSL
+ bool "FSL PowerPC PCIe support"
+ depends on DM_PCI
+ help
+ Say Y here if you want to enable PCIe controller support on FSL
+ PowerPC MPC85xx, MPC86xx, B series, P series and T series SoCs.
+ This driver does not support SRIO_PCIE_BOOT feature.
+
+config PCI_MPC85XX
+ bool "MPC85XX PowerPC PCI support"
+ depends on DM_PCI
+ help
+ Say Y here if you want to enable PCI controller support on FSL
+ PowerPC MPC85xx SoC.
+
+config PCI_RCAR_GEN2
+ bool "Renesas RCar Gen2 PCIe driver"
+ depends on DM_PCI
+ depends on RCAR_32
+ help
+ Say Y here if you want to enable PCIe controller support on
+ Renesas RCar Gen2 SoCs. The PCIe controller on RCar Gen2 is
+ also used to access EHCI USB controller on the SoC.
+
+config PCI_RCAR_GEN3
+ bool "Renesas RCar Gen3 PCIe driver"
+ depends on DM_PCI
+ depends on RCAR_GEN3
+ help
+ Say Y here if you want to enable PCIe controller support on
+ Renesas RCar Gen3 SoCs.
+
+config PCI_SANDBOX
+ bool "Sandbox PCI support"
+ depends on SANDBOX && DM_PCI
+ help
+ Support PCI on sandbox, as an emulated bus. This permits testing of
+ PCI feature such as bus scanning, device configuration and device
+ access. The available (emulated) devices are defined statically in
+ the device tree but the normal PCI scan technique is used to find
+ then.
+
+config PCI_TEGRA
+ bool "Tegra PCI support"
+ depends on ARCH_TEGRA
+ depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186)
+ help
+ Enable support for the PCIe controller found on some generations of
+ Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has
+ 3 root ports with a total of 6 lanes and Tegra124 has 2 root ports
+ with a total of 5 lanes. Some boards require this for Ethernet
+ support to work (e.g. beaver, jetson-tk1).
+
+config PCI_OCTEONTX
+ bool "OcteonTX PCI support"
+ depends on (ARCH_OCTEONTX || ARCH_OCTEONTX2)
+ help
+ Enable support for the OcteonTX/TX2 SoC family ECAM/PEM controllers.
+ These controllers provide PCI configuration access to all on-board
+ peripherals so it should only be disabled for testing purposes
+
+config PCIE_OCTEON
+ bool "MIPS Octeon PCIe support"
+ depends on ARCH_OCTEON
+ help
+ Enable support for the MIPS Octeon SoC family PCIe controllers.
+
+config PCI_XILINX
+ bool "Xilinx AXI Bridge for PCI Express"
+ depends on DM_PCI
+ help
+ Enable support for the Xilinx AXI bridge for PCI express, an IP block
+ which can be used on some generations of Xilinx FPGAs.
+
+config PCIE_LAYERSCAPE
+ bool
+ default n
+
+config PCIE_LAYERSCAPE_RC
+ bool "Layerscape PCIe Root Complex mode support"
+ depends on DM_PCI
+ select PCIE_LAYERSCAPE
+ help
+ Enable Layerscape PCIe Root Complex mode driver support. The Layerscape
+ SoC may have one or several PCIe controllers. Each controller can be
+ configured to Root Complex mode by clearing the corresponding bit of
+ RCW[HOST_AGT_PEX].
+
+config PCI_IOMMU_EXTRA_MAPPINGS
+ bool "Support for specifying extra IOMMU mappings for PCI"
+ depends on PCIE_LAYERSCAPE_RC
+ help
+ Enable support for specifying extra IOMMU mappings for PCI
+ controllers through a special env var called "pci_iommu_extra" or
+ through a device tree property named "pci-iommu-extra" placed in
+ the node describing the PCI controller.
+ The intent is to cover SR-IOV scenarios which need mappings for VFs
+ and PCI hot-plug scenarios. More documentation can be found under:
+ arch/arm/cpu/armv8/fsl-layerscape/doc/README.pci_iommu_extra
+
+config PCIE_LAYERSCAPE_EP
+ bool "Layerscape PCIe Endpoint mode support"
+ depends on DM_PCI
+ select PCIE_LAYERSCAPE
+ select PCI_ENDPOINT
+ help
+ Enable Layerscape PCIe Endpoint mode driver support. The Layerscape
+ SoC may have one or several PCIe controllers. Each controller can be
+ configured to Endpoint mode by setting the corresponding bit of
+ RCW[HOST_AGT_PEX].
+
+config PCIE_LAYERSCAPE_GEN4
+ bool "Layerscape Gen4 PCIe support"
+ depends on DM_PCI
+ help
+ Support PCIe Gen4 on NXP Layerscape SoCs, which may have one or
+ several PCIe controllers. The PCIe controller can work in RC or
+ EP mode according to RCW[HOST_AGT_PEX] setting.
+
+config FSL_PCIE_COMPAT
+ string "PCIe compatible of Kernel DT"
+ depends on PCIE_LAYERSCAPE_RC || PCIE_LAYERSCAPE_GEN4
+ default "fsl,ls1012a-pcie" if ARCH_LS1012A
+ default "fsl,ls1028a-pcie" if ARCH_LS1028A
+ default "fsl,ls1043a-pcie" if ARCH_LS1043A
+ default "fsl,ls1046a-pcie" if ARCH_LS1046A
+ default "fsl,ls2080a-pcie" if ARCH_LS2080A
+ default "fsl,ls1088a-pcie" if ARCH_LS1088A
+ default "fsl,lx2160a-pcie" if ARCH_LX2160A
+ default "fsl,ls2088a-pcie" if ARCH_LX2162A
+ default "fsl,ls1021a-pcie" if ARCH_LS1021A
+ help
+ This compatible is used to find pci controller node in Kernel DT
+ to complete fixup.
+
+config FSL_PCIE_EP_COMPAT
+ string "PCIe EP compatible of Kernel DT"
+ depends on PCIE_LAYERSCAPE_RC || PCIE_LAYERSCAPE_GEN4
+ default "fsl,lx2160a-pcie-ep" if ARCH_LX2160A
+ default "fsl,ls-pcie-ep"
+ help
+ This compatible is used to find pci controller ep node in Kernel DT
+ to complete fixup.
+
+config PCIE_INTEL_FPGA
+ bool "Intel FPGA PCIe support"
+ depends on DM_PCI
+ help
+ Say Y here if you want to enable PCIe controller support on Intel
+ FPGA, example Stratix 10.
+
+config PCIE_IPROC
+ bool "Iproc PCIe support"
+ depends on DM_PCI
+ help
+ Broadcom iProc PCIe controller driver.
+ Say Y here if you want to enable Broadcom iProc PCIe controller,
+
+config PCI_MVEBU
+ bool "Enable Armada XP/38x PCIe driver"
+ depends on ARCH_MVEBU
+ select DM_PCI
+ select MISC
+ help
+ Say Y here if you want to enable PCIe controller support on
+ Armada XP/38x SoCs.
+
+config PCIE_DW_COMMON
+ bool
+ select DM_PCI
+
+config PCI_KEYSTONE
+ bool "TI Keystone PCIe controller"
+ select PCIE_DW_COMMON
+ help
+ Say Y here if you want to enable PCI controller support on AM654 SoC.
+
+config PCIE_MEDIATEK
+ bool "MediaTek PCIe Gen2 controller"
+ depends on DM_PCI
+ depends on ARCH_MEDIATEK
+ help
+ Say Y here if you want to enable Gen2 PCIe controller,
+ which could be found on MT7623 SoC family.
+
+config PCIE_DW_MESON
+ bool "Amlogic Meson DesignWare based PCIe controller"
+ depends on ARCH_MESON
+ select PCIE_DW_COMMON
+ help
+ Say Y here if you want to enable DW PCIe controller support on
+ Amlogic SoCs.
+
+config PCIE_ROCKCHIP
+ bool "Enable Rockchip PCIe driver"
+ depends on ARCH_ROCKCHIP
+ select DM_PCI
+ select PHY_ROCKCHIP_PCIE
+ default y if ROCKCHIP_RK3399
+ help
+ Say Y here if you want to enable PCIe controller support on
+ Rockchip SoCs.
+
+config PCIE_DW_ROCKCHIP
+ bool "Rockchip DesignWare based PCIe controller"
+ depends on ARCH_ROCKCHIP
+ select PCIE_DW_COMMON
+ select PHY_ROCKCHIP_SNPS_PCIE3
+ help
+ Say Y here if you want to enable DW PCIe controller support on
+ Rockchip SoCs.
+
+config PCI_BRCMSTB
+ bool "Broadcom STB PCIe controller"
+ depends on DM_PCI
+ depends on ARCH_BCM283X
+ help
+ Say Y here if you want to enable support for PCIe controller
+ on Broadcom set-top-box (STB) SoCs.
+ This driver currently supports only BCM2711 SoC and RC mode
+ of the controller.
+endif
diff --git a/roms/u-boot/drivers/pci/Makefile b/roms/u-boot/drivers/pci/Makefile
new file mode 100644
index 000000000..c742bb2c9
--- /dev/null
+++ b/roms/u-boot/drivers/pci/Makefile
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+ifneq ($(CONFIG_DM_PCI),)
+obj-$(CONFIG_DM_VIDEO) += pci_rom.o
+obj-$(CONFIG_PCI) += pci-uclass.o pci_auto.o
+obj-$(CONFIG_DM_PCI_COMPAT) += pci_compat.o
+obj-$(CONFIG_PCI_SANDBOX) += pci_sandbox.o
+obj-$(CONFIG_SANDBOX) += pci-emul-uclass.o
+obj-$(CONFIG_X86) += pci_x86.o pci_rom.o
+else
+obj-$(CONFIG_PCI) += pci.o pci_auto_old.o
+endif
+obj-$(CONFIG_PCI) += pci_auto_common.o pci_common.o
+
+obj-$(CONFIG_PCIE_ECAM_GENERIC) += pcie_ecam_generic.o
+obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o
+obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
+obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
+obj-$(CONFIG_PCI_MPC85XX) += pci_mpc85xx.o
+obj-$(CONFIG_PCI_MSC01) += pci_msc01.o
+obj-$(CONFIG_PCIE_IMX) += pcie_imx.o
+obj-$(CONFIG_FTPCI100) += pci_ftpci100.o
+obj-$(CONFIG_PCI_MVEBU) += pci_mvebu.o
+obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
+obj-$(CONFIG_PCI_RCAR_GEN3) += pci-rcar-gen3.o
+obj-$(CONFIG_SH4_PCI) += pci_sh4.o
+obj-$(CONFIG_SH7751_PCI) +=pci_sh7751.o
+obj-$(CONFIG_SH7780_PCI) +=pci_sh7780.o
+obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o
+obj-$(CONFIG_PCIE_IPROC) += pcie_iproc.o
+obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
+obj-$(CONFIG_PCIE_DW_MVEBU) += pcie_dw_mvebu.o
+obj-$(CONFIG_PCIE_FSL) += pcie_fsl.o pcie_fsl_fixup.o
+obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o
+obj-$(CONFIG_PCIE_LAYERSCAPE_RC) += pcie_layerscape_rc.o \
+ pcie_layerscape_fixup.o \
+ pcie_layerscape_fixup_common.o
+obj-$(CONFIG_PCIE_LAYERSCAPE_EP) += pcie_layerscape_ep.o
+obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \
+ pcie_layerscape_gen4_fixup.o \
+ pcie_layerscape_fixup_common.o
+obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
+obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o
+obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
+obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o
+obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
+obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
+obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
+obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie_dw_rockchip.o
+obj-$(CONFIG_PCIE_DW_MESON) += pcie_dw_meson.o
+obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o
+obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o
+obj-$(CONFIG_PCIE_OCTEON) += pcie_octeon.o
+obj-$(CONFIG_PCIE_DW_SIFIVE) += pcie_dw_sifive.o
diff --git a/roms/u-boot/drivers/pci/fsl_pci_init.c b/roms/u-boot/drivers/pci/fsl_pci_init.c
new file mode 100644
index 000000000..fc3327ec5
--- /dev/null
+++ b/roms/u-boot/drivers/pci/fsl_pci_init.c
@@ -0,0 +1,936 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2007-2012 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <env.h>
+#include <init.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/fsl_serdes.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's
+ *
+ * Initialize controller and call the common driver/pci pci_hose_scan to
+ * scan for bridges and devices.
+ *
+ * Hose fields which need to be pre-initialized by board specific code:
+ * regions[]
+ * first_busno
+ *
+ * Fields updated:
+ * last_busno
+ */
+
+#include <pci.h>
+#include <asm/io.h>
+#include <asm/fsl_pci.h>
+
+#define MAX_PCI_REGIONS 7
+
+#ifndef CONFIG_SYS_PCI_MEMORY_BUS
+#define CONFIG_SYS_PCI_MEMORY_BUS 0
+#endif
+
+#ifndef CONFIG_SYS_PCI_MEMORY_PHYS
+#define CONFIG_SYS_PCI_MEMORY_PHYS 0
+#endif
+
+#if defined(CONFIG_SYS_PCI_64BIT) && !defined(CONFIG_SYS_PCI64_MEMORY_BUS)
+#define CONFIG_SYS_PCI64_MEMORY_BUS (64ull*1024*1024*1024)
+#endif
+
+/* Setup one inbound ATMU window.
+ *
+ * We let the caller decide what the window size should be
+ */
+static void set_inbound_window(volatile pit_t *pi,
+ struct pci_region *r,
+ u64 size)
+{
+ u32 sz = (__ilog2_u64(size) - 1);
+#ifdef CONFIG_SYS_FSL_ERRATUM_A005434
+ u32 flag = 0;
+#else
+ u32 flag = PIWAR_LOCAL;
+#endif
+
+ flag |= PIWAR_EN | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
+
+ out_be32(&pi->pitar, r->phys_start >> 12);
+ out_be32(&pi->piwbar, r->bus_start >> 12);
+#ifdef CONFIG_SYS_PCI_64BIT
+ out_be32(&pi->piwbear, r->bus_start >> 44);
+#else
+ out_be32(&pi->piwbear, 0);
+#endif
+ if (r->flags & PCI_REGION_PREFETCH)
+ flag |= PIWAR_PF;
+ out_be32(&pi->piwar, flag | sz);
+}
+
+int fsl_setup_hose(struct pci_controller *hose, unsigned long addr)
+{
+ volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *) addr;
+
+ /* Reset hose to make sure its in a clean state */
+ memset(hose, 0, sizeof(struct pci_controller));
+
+ hose->regions = (struct pci_region *)
+ calloc(1, MAX_PCI_REGIONS * sizeof(struct pci_region));
+
+ pci_setup_indirect(hose, (u32)&pci->cfg_addr, (u32)&pci->cfg_data);
+
+ return fsl_is_pci_agent(hose);
+}
+
+static int fsl_pci_setup_inbound_windows(struct pci_controller *hose,
+ u64 out_lo, u8 pcie_cap,
+ volatile pit_t *pi)
+{
+ struct pci_region *r = hose->regions + hose->region_count;
+ u64 sz = min((u64)gd->ram_size, (1ull << 32));
+
+ phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS;
+ pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS;
+ pci_size_t pci_sz;
+
+ /* we have no space available for inbound memory mapping */
+ if (bus_start > out_lo) {
+ printf ("no space for inbound mapping of memory\n");
+ return 0;
+ }
+
+ /* limit size */
+ if ((bus_start + sz) > out_lo) {
+ sz = out_lo - bus_start;
+ debug ("limiting size to %llx\n", sz);
+ }
+
+ pci_sz = 1ull << __ilog2_u64(sz);
+ /*
+ * we can overlap inbound/outbound windows on PCI-E since RX & TX
+ * links a separate
+ */
+ if ((pcie_cap == PCI_CAP_ID_EXP) && (pci_sz < sz)) {
+ debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)sz);
+ pci_set_region(r, bus_start, phys_start, sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+
+ /* if we aren't an exact power of two match, pci_sz is smaller
+ * round it up to the next power of two. We report the actual
+ * size to pci region tracking.
+ */
+ if (pci_sz != sz)
+ sz = 2ull << __ilog2_u64(sz);
+
+ set_inbound_window(pi--, r++, sz);
+ sz = 0; /* make sure we dont set the R2 window */
+ } else {
+ debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ set_inbound_window(pi--, r++, pci_sz);
+
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+
+ pci_sz = 1ull << __ilog2_u64(sz);
+ if (sz) {
+ debug ("R1 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ set_inbound_window(pi--, r++, pci_sz);
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+ }
+ }
+
+#if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
+ /*
+ * On 64-bit capable systems, set up a mapping for all of DRAM
+ * in high pci address space.
+ */
+ pci_sz = 1ull << __ilog2_u64(gd->ram_size);
+ /* round up to the next largest power of two */
+ if (gd->ram_size > pci_sz)
+ pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1);
+ debug ("R64 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)CONFIG_SYS_PCI64_MEMORY_BUS,
+ (u64)CONFIG_SYS_PCI_MEMORY_PHYS,
+ (u64)pci_sz);
+ pci_set_region(r,
+ CONFIG_SYS_PCI64_MEMORY_BUS,
+ CONFIG_SYS_PCI_MEMORY_PHYS,
+ pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ set_inbound_window(pi--, r++, pci_sz);
+#else
+ pci_sz = 1ull << __ilog2_u64(sz);
+ if (sz) {
+ debug ("R2 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+ set_inbound_window(pi--, r++, pci_sz);
+ }
+#endif
+
+#ifdef CONFIG_PHYS_64BIT
+ if (sz && (((u64)gd->ram_size) < (1ull << 32)))
+ printf("Was not able to map all of memory via "
+ "inbound windows -- %lld remaining\n", sz);
+#endif
+
+ hose->region_count = r - hose->regions;
+
+ return 1;
+}
+
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
+static void fsl_pcie_boot_master(pit_t *pi)
+{
+ /* configure inbound window for slave's u-boot image */
+ debug("PCIEBOOT - MASTER: Inbound window for slave's image; "
+ "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+ struct pci_region r_inbound;
+ u32 sz_inbound = __ilog2_u64(CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE)
+ - 1;
+ pci_set_region(&r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ sz_inbound,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ set_inbound_window(pi--, &r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+
+ /* configure inbound window for slave's u-boot image */
+ debug("PCIEBOOT - MASTER: Inbound window for slave's image; "
+ "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+ pci_set_region(&r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ sz_inbound,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ set_inbound_window(pi--, &r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+
+ /* configure inbound window for slave's ucode and ENV */
+ debug("PCIEBOOT - MASTER: Inbound window for slave's "
+ "ucode and ENV; "
+ "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE);
+ sz_inbound = __ilog2_u64(CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE)
+ - 1;
+ pci_set_region(&r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS,
+ sz_inbound,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ set_inbound_window(pi--, &r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE);
+}
+
+static void fsl_pcie_boot_master_release_slave(int port)
+{
+ unsigned long release_addr;
+
+ /* now release slave's core 0 */
+ switch (port) {
+ case 1:
+ release_addr = CONFIG_SYS_PCIE1_MEM_VIRT
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
+ break;
+#ifdef CONFIG_SYS_PCIE2_MEM_VIRT
+ case 2:
+ release_addr = CONFIG_SYS_PCIE2_MEM_VIRT
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
+ break;
+#endif
+#ifdef CONFIG_SYS_PCIE3_MEM_VIRT
+ case 3:
+ release_addr = CONFIG_SYS_PCIE3_MEM_VIRT
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
+ break;
+#endif
+ default:
+ release_addr = 0;
+ break;
+ }
+ if (release_addr != 0) {
+ out_be32((void *)release_addr,
+ CONFIG_SRIO_PCIE_BOOT_RELEASE_MASK);
+ debug("PCIEBOOT - MASTER: "
+ "Release slave successfully! Now the slave should start up!\n");
+ } else {
+ debug("PCIEBOOT - MASTER: "
+ "Release slave failed!\n");
+ }
+}
+#endif
+
+void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
+{
+ u32 cfg_addr = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_addr;
+ u32 cfg_data = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_data;
+ u16 temp16;
+ u32 temp32;
+ u32 block_rev;
+ int enabled, r, inbound = 0;
+ u16 ltssm;
+ u8 temp8, pcie_cap;
+ int pcie_cap_pos;
+ int pci_dcr;
+ int pci_dsr;
+ int pci_lsr;
+
+#if defined(CONFIG_FSL_PCIE_DISABLE_ASPM)
+ int pci_lcr;
+#endif
+
+ volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr;
+ struct pci_region *reg = hose->regions + hose->region_count;
+ pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
+
+ /* Initialize ATMU registers based on hose regions and flags */
+ volatile pot_t *po = &pci->pot[1]; /* skip 0 */
+ volatile pit_t *pi;
+
+ u64 out_hi = 0, out_lo = -1ULL;
+ u32 pcicsrbar, pcicsrbar_sz;
+
+ pci_setup_indirect(hose, cfg_addr, cfg_data);
+
+#ifdef PEX_CCB_DIV
+ /* Configure the PCIE controller core clock ratio */
+ pci_hose_write_config_dword(hose, dev, 0x440,
+ ((gd->bus_clk / 1000000) *
+ (16 / PEX_CCB_DIV)) / 333);
+#endif
+ block_rev = in_be32(&pci->block_rev1);
+ if (PEX_IP_BLK_REV_2_2 <= block_rev) {
+ pi = &pci->pit[2]; /* 0xDC0 */
+ } else {
+ pi = &pci->pit[3]; /* 0xDE0 */
+ }
+
+ /* Handle setup of outbound windows first */
+ for (r = 0; r < hose->region_count; r++) {
+ unsigned long flags = hose->regions[r].flags;
+ u32 sz = (__ilog2_u64((u64)hose->regions[r].size) - 1);
+
+ flags &= PCI_REGION_SYS_MEMORY|PCI_REGION_TYPE;
+ if (flags != PCI_REGION_SYS_MEMORY) {
+ u64 start = hose->regions[r].bus_start;
+ u64 end = start + hose->regions[r].size;
+
+ out_be32(&po->powbar, hose->regions[r].phys_start >> 12);
+ out_be32(&po->potar, start >> 12);
+#ifdef CONFIG_SYS_PCI_64BIT
+ out_be32(&po->potear, start >> 44);
+#else
+ out_be32(&po->potear, 0);
+#endif
+ if (hose->regions[r].flags & PCI_REGION_IO) {
+ out_be32(&po->powar, POWAR_EN | sz |
+ POWAR_IO_READ | POWAR_IO_WRITE);
+ } else {
+ out_be32(&po->powar, POWAR_EN | sz |
+ POWAR_MEM_READ | POWAR_MEM_WRITE);
+ out_lo = min(start, out_lo);
+ out_hi = max(end, out_hi);
+ }
+ po++;
+ }
+ }
+ debug("Outbound memory range: %llx:%llx\n", out_lo, out_hi);
+
+ /* setup PCSRBAR/PEXCSRBAR */
+ pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0xffffffff);
+ pci_hose_read_config_dword (hose, dev, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
+ pcicsrbar_sz = ~pcicsrbar_sz + 1;
+
+ if (out_hi < (0x100000000ull - pcicsrbar_sz) ||
+ (out_lo > 0x100000000ull))
+ pcicsrbar = 0x100000000ull - pcicsrbar_sz;
+ else
+ pcicsrbar = (out_lo - pcicsrbar_sz) & -pcicsrbar_sz;
+ pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, pcicsrbar);
+
+ out_lo = min(out_lo, (u64)pcicsrbar);
+
+ debug("PCICSRBAR @ 0x%x\n", pcicsrbar);
+
+ pci_set_region(reg++, pcicsrbar, CONFIG_SYS_CCSRBAR_PHYS,
+ pcicsrbar_sz, PCI_REGION_SYS_MEMORY);
+ hose->region_count++;
+
+ /* see if we are a PCIe or PCI controller */
+ pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+ pci_dcr = pcie_cap_pos + 0x08;
+ pci_dsr = pcie_cap_pos + 0x0a;
+ pci_lsr = pcie_cap_pos + 0x12;
+
+ pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
+
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
+ /* boot from PCIE --master */
+ char *s = env_get("bootmaster");
+ char pcie[6];
+ sprintf(pcie, "PCIE%d", pci_info->pci_num);
+
+ if (s && (strcmp(s, pcie) == 0)) {
+ debug("PCIEBOOT - MASTER: Master port [ %d ] for pcie boot.\n",
+ pci_info->pci_num);
+ fsl_pcie_boot_master((pit_t *)pi);
+ } else {
+ /* inbound */
+ inbound = fsl_pci_setup_inbound_windows(hose,
+ out_lo, pcie_cap, pi);
+ }
+#else
+ /* inbound */
+ inbound = fsl_pci_setup_inbound_windows(hose, out_lo, pcie_cap, pi);
+#endif
+
+ for (r = 0; r < hose->region_count; r++)
+ debug("PCI reg:%d %016llx:%016llx %016llx %08lx\n", r,
+ (u64)hose->regions[r].phys_start,
+ (u64)hose->regions[r].bus_start,
+ (u64)hose->regions[r].size,
+ hose->regions[r].flags);
+
+ pci_register_hose(hose);
+ pciauto_config_init(hose); /* grab pci_{mem,prefetch,io} */
+ hose->current_busno = hose->first_busno;
+
+ out_be32(&pci->pedr, 0xffffffff); /* Clear any errors */
+ out_be32(&pci->peer, ~0x20140); /* Enable All Error Interrupts except
+ * - Master abort (pci)
+ * - Master PERR (pci)
+ * - ICCA (PCIe)
+ */
+ pci_hose_read_config_dword(hose, dev, pci_dcr, &temp32);
+ temp32 |= 0xf000e; /* set URR, FER, NFER (but not CER) */
+ pci_hose_write_config_dword(hose, dev, pci_dcr, temp32);
+
+#if defined(CONFIG_FSL_PCIE_DISABLE_ASPM)
+ pci_lcr = pcie_cap_pos + 0x10;
+ temp32 = 0;
+ pci_hose_read_config_dword(hose, dev, pci_lcr, &temp32);
+ temp32 &= ~0x03; /* Disable ASPM */
+ pci_hose_write_config_dword(hose, dev, pci_lcr, temp32);
+ udelay(1);
+#endif
+ if (pcie_cap == PCI_CAP_ID_EXP) {
+ if (block_rev >= PEX_IP_BLK_REV_3_0) {
+#define PEX_CSR0_LTSSM_MASK 0xFC
+#define PEX_CSR0_LTSSM_SHIFT 2
+ ltssm = (in_be32(&pci->pex_csr0)
+ & PEX_CSR0_LTSSM_MASK) >> PEX_CSR0_LTSSM_SHIFT;
+ enabled = (ltssm == 0x11) ? 1 : 0;
+#ifdef CONFIG_FSL_PCIE_RESET
+ int i;
+ /* assert PCIe reset */
+ setbits_be32(&pci->pdb_stat, 0x08000000);
+ (void) in_be32(&pci->pdb_stat);
+ udelay(1000);
+ /* clear PCIe reset */
+ clrbits_be32(&pci->pdb_stat, 0x08000000);
+ asm("sync;isync");
+ for (i = 0; i < 100 && ltssm < PCI_LTSSM_L0; i++) {
+ pci_hose_read_config_word(hose, dev, PCI_LTSSM,
+ &ltssm);
+ udelay(1000);
+ }
+#endif
+ } else {
+ /* pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm); */
+ /* enabled = ltssm >= PCI_LTSSM_L0; */
+ pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
+ enabled = ltssm >= PCI_LTSSM_L0;
+
+#ifdef CONFIG_FSL_PCIE_RESET
+ if (ltssm == 1) {
+ int i;
+ debug("....PCIe link error. " "LTSSM=0x%02x.", ltssm);
+ /* assert PCIe reset */
+ setbits_be32(&pci->pdb_stat, 0x08000000);
+ (void) in_be32(&pci->pdb_stat);
+ udelay(100);
+ debug(" Asserting PCIe reset @%p = %x\n",
+ &pci->pdb_stat, in_be32(&pci->pdb_stat));
+ /* clear PCIe reset */
+ clrbits_be32(&pci->pdb_stat, 0x08000000);
+ asm("sync;isync");
+ for (i=0; i<100 && ltssm < PCI_LTSSM_L0; i++) {
+ pci_hose_read_config_word(hose, dev, PCI_LTSSM,
+ &ltssm);
+ udelay(1000);
+ debug("....PCIe link error. "
+ "LTSSM=0x%02x.\n", ltssm);
+ }
+ enabled = ltssm >= PCI_LTSSM_L0;
+
+ /* we need to re-write the bar0 since a reset will
+ * clear it
+ */
+ pci_hose_write_config_dword(hose, dev,
+ PCI_BASE_ADDRESS_0, pcicsrbar);
+ }
+#endif
+ }
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_PCIE_A003
+ if (enabled == 0) {
+ serdes_corenet_t *srds_regs = (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
+ temp32 = in_be32(&srds_regs->srdspccr0);
+
+ if ((temp32 >> 28) == 3) {
+ int i;
+
+ out_be32(&srds_regs->srdspccr0, 2 << 28);
+ setbits_be32(&pci->pdb_stat, 0x08000000);
+ in_be32(&pci->pdb_stat);
+ udelay(100);
+ clrbits_be32(&pci->pdb_stat, 0x08000000);
+ asm("sync;isync");
+ for (i=0; i < 100 && ltssm < PCI_LTSSM_L0; i++) {
+ pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
+ udelay(1000);
+ }
+ enabled = ltssm >= PCI_LTSSM_L0;
+ }
+ }
+#endif
+ if (!enabled) {
+ /* Let the user know there's no PCIe link for root
+ * complex. for endpoint, the link may not setup, so
+ * print undetermined.
+ */
+ if (fsl_is_pci_agent(hose))
+ printf("undetermined, regs @ 0x%lx\n", pci_info->regs);
+ else
+ printf("no link, regs @ 0x%lx\n", pci_info->regs);
+ hose->last_busno = hose->first_busno;
+ return;
+ }
+
+ out_be32(&pci->pme_msg_det, 0xffffffff);
+ out_be32(&pci->pme_msg_int_en, 0xffffffff);
+
+ /* Print the negotiated PCIe link width */
+ pci_hose_read_config_word(hose, dev, pci_lsr, &temp16);
+ printf("x%d gen%d, regs @ 0x%lx\n", (temp16 & 0x3f0) >> 4,
+ (temp16 & 0xf), pci_info->regs);
+
+ hose->current_busno++; /* Start scan with secondary */
+ pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
+ }
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A007815
+ /* The Read-Only Write Enable bit defaults to 1 instead of 0.
+ * Set to 0 to protect the read-only registers.
+ */
+ clrbits_be32(&pci->dbi_ro_wr_en, 0x01);
+#endif
+
+ /* Use generic setup_device to initialize standard pci regs,
+ * but do not allocate any windows since any BAR found (such
+ * as PCSRBAR) is not in this cpu's memory space.
+ */
+ pciauto_setup_device(hose, dev, 0, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+
+ if (inbound) {
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &temp16);
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND,
+ temp16 | PCI_COMMAND_MEMORY);
+ }
+
+#ifndef CONFIG_PCI_NOSCAN
+ if (!fsl_is_pci_agent(hose)) {
+ debug(" Scanning PCI bus %02x\n",
+ hose->current_busno);
+ hose->last_busno = pci_hose_scan_bus(hose, hose->current_busno);
+ } else {
+ debug(" Not scanning PCI bus %02x. PI=%x\n",
+ hose->current_busno, temp8);
+ hose->last_busno = hose->current_busno;
+ }
+
+ /* if we are PCIe - update limit regs and subordinate busno
+ * for the virtual P2P bridge
+ */
+ if (pcie_cap == PCI_CAP_ID_EXP) {
+ pciauto_postscan_setup_bridge(hose, dev, hose->last_busno);
+ }
+#else
+ hose->last_busno = hose->current_busno;
+#endif
+
+ /* Clear all error indications */
+ if (pcie_cap == PCI_CAP_ID_EXP)
+ out_be32(&pci->pme_msg_det, 0xffffffff);
+ out_be32(&pci->pedr, 0xffffffff);
+
+ pci_hose_read_config_word(hose, dev, pci_dsr, &temp16);
+ if (temp16) {
+ pci_hose_write_config_word(hose, dev, pci_dsr, 0xffff);
+ }
+
+ pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16);
+ if (temp16) {
+ pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff);
+ }
+}
+
+int fsl_is_pci_agent(struct pci_controller *hose)
+{
+ int pcie_cap_pos;
+ u8 pcie_cap;
+ pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
+
+ pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+ pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
+ if (pcie_cap == PCI_CAP_ID_EXP) {
+ u8 header_type;
+
+ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE,
+ &header_type);
+ return (header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL;
+ } else {
+ u8 prog_if;
+
+ pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prog_if);
+ /* Programming Interface (PCI_CLASS_PROG)
+ * 0 == pci host or pcie root-complex,
+ * 1 == pci agent or pcie end-point
+ */
+ return (prog_if == FSL_PROG_IF_AGENT);
+ }
+}
+
+int fsl_pci_init_port(struct fsl_pci_info *pci_info,
+ struct pci_controller *hose, int busno)
+{
+ volatile ccsr_fsl_pci_t *pci;
+ struct pci_region *r;
+ pci_dev_t dev = PCI_BDF(busno,0,0);
+ int pcie_cap_pos;
+ u8 pcie_cap;
+
+ pci = (ccsr_fsl_pci_t *) pci_info->regs;
+
+ /* on non-PCIe controllers we don't have pme_msg_det so this code
+ * should do nothing since the read will return 0
+ */
+ if (in_be32(&pci->pme_msg_det)) {
+ out_be32(&pci->pme_msg_det, 0xffffffff);
+ debug (" with errors. Clearing. Now 0x%08x",
+ pci->pme_msg_det);
+ }
+
+ r = hose->regions + hose->region_count;
+
+ /* outbound memory */
+ pci_set_region(r++,
+ pci_info->mem_bus,
+ pci_info->mem_phys,
+ pci_info->mem_size,
+ PCI_REGION_MEM);
+
+ /* outbound io */
+ pci_set_region(r++,
+ pci_info->io_bus,
+ pci_info->io_phys,
+ pci_info->io_size,
+ PCI_REGION_IO);
+
+ hose->region_count = r - hose->regions;
+ hose->first_busno = busno;
+
+ fsl_pci_init(hose, pci_info);
+
+ if (fsl_is_pci_agent(hose)) {
+ fsl_pci_config_unlock(hose);
+ hose->last_busno = hose->first_busno;
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
+ } else {
+ /* boot from PCIE --master releases slave's core 0 */
+ char *s = env_get("bootmaster");
+ char pcie[6];
+ sprintf(pcie, "PCIE%d", pci_info->pci_num);
+
+ if (s && (strcmp(s, pcie) == 0))
+ fsl_pcie_boot_master_release_slave(pci_info->pci_num);
+#endif
+ }
+
+ pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+ pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
+ printf("PCI%s%x: Bus %02x - %02x\n", pcie_cap == PCI_CAP_ID_EXP ?
+ "e" : "", pci_info->pci_num,
+ hose->first_busno, hose->last_busno);
+ return(hose->last_busno + 1);
+}
+
+/* Enable inbound PCI config cycles for agent/endpoint interface */
+void fsl_pci_config_unlock(struct pci_controller *hose)
+{
+ pci_dev_t dev = PCI_BDF(hose->first_busno,0,0);
+ int pcie_cap_pos;
+ u8 pcie_cap;
+ u16 pbfr;
+
+ if (!fsl_is_pci_agent(hose))
+ return;
+
+ pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+ pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
+ if (pcie_cap != 0x0) {
+ ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)hose->cfg_addr;
+ u32 block_rev = in_be32(&pci->block_rev1);
+ /* PCIe - set CFG_READY bit of Configuration Ready Register */
+ if (block_rev >= PEX_IP_BLK_REV_3_0)
+ setbits_be32(&pci->config, FSL_PCIE_V3_CFG_RDY);
+ else
+ pci_hose_write_config_byte(hose, dev,
+ FSL_PCIE_CFG_RDY, 0x1);
+ } else {
+ /* PCI - clear ACL bit of PBFR */
+ pci_hose_read_config_word(hose, dev, FSL_PCI_PBFR, &pbfr);
+ pbfr &= ~0x20;
+ pci_hose_write_config_word(hose, dev, FSL_PCI_PBFR, pbfr);
+ }
+}
+
+#if defined(CONFIG_PCIE1) || defined(CONFIG_PCIE2) || \
+ defined(CONFIG_PCIE3) || defined(CONFIG_PCIE4)
+int fsl_configure_pcie(struct fsl_pci_info *info,
+ struct pci_controller *hose,
+ const char *connected, int busno)
+{
+ int is_endpoint;
+
+ set_next_law(info->mem_phys, law_size_bits(info->mem_size), info->law);
+ set_next_law(info->io_phys, law_size_bits(info->io_size), info->law);
+
+ is_endpoint = fsl_setup_hose(hose, info->regs);
+ printf("PCIe%u: %s", info->pci_num,
+ is_endpoint ? "Endpoint" : "Root Complex");
+ if (connected)
+ printf(" of %s", connected);
+ puts(", ");
+
+ return fsl_pci_init_port(info, hose, busno);
+}
+
+#if defined(CONFIG_FSL_CORENET)
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+ #define _DEVDISR_PCIE1 FSL_CORENET_DEVDISR3_PCIE1
+ #define _DEVDISR_PCIE2 FSL_CORENET_DEVDISR3_PCIE2
+ #define _DEVDISR_PCIE3 FSL_CORENET_DEVDISR3_PCIE3
+ #define _DEVDISR_PCIE4 FSL_CORENET_DEVDISR3_PCIE4
+#else
+ #define _DEVDISR_PCIE1 FSL_CORENET_DEVDISR_PCIE1
+ #define _DEVDISR_PCIE2 FSL_CORENET_DEVDISR_PCIE2
+ #define _DEVDISR_PCIE3 FSL_CORENET_DEVDISR_PCIE3
+ #define _DEVDISR_PCIE4 FSL_CORENET_DEVDISR_PCIE4
+#endif
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
+#elif defined(CONFIG_MPC85xx)
+ #define _DEVDISR_PCIE1 MPC85xx_DEVDISR_PCIE
+ #define _DEVDISR_PCIE2 MPC85xx_DEVDISR_PCIE2
+ #define _DEVDISR_PCIE3 MPC85xx_DEVDISR_PCIE3
+ #define _DEVDISR_PCIE4 0
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
+#elif defined(CONFIG_MPC86xx)
+ #define _DEVDISR_PCIE1 MPC86xx_DEVDISR_PCIE1
+ #define _DEVDISR_PCIE2 MPC86xx_DEVDISR_PCIE2
+ #define _DEVDISR_PCIE3 0
+ #define _DEVDISR_PCIE4 0
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR \
+ (&((immap_t *)CONFIG_SYS_IMMR)->im_gur)
+#else
+#error "No defines for DEVDISR_PCIE"
+#endif
+
+/* Implement a dummy function for those platforms w/o SERDES */
+static const char *__board_serdes_name(enum srds_prtcl device)
+{
+ switch (device) {
+#ifdef CONFIG_SYS_PCIE1_NAME
+ case PCIE1:
+ return CONFIG_SYS_PCIE1_NAME;
+#endif
+#ifdef CONFIG_SYS_PCIE2_NAME
+ case PCIE2:
+ return CONFIG_SYS_PCIE2_NAME;
+#endif
+#ifdef CONFIG_SYS_PCIE3_NAME
+ case PCIE3:
+ return CONFIG_SYS_PCIE3_NAME;
+#endif
+#ifdef CONFIG_SYS_PCIE4_NAME
+ case PCIE4:
+ return CONFIG_SYS_PCIE4_NAME;
+#endif
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+__attribute__((weak, alias("__board_serdes_name"))) const char *
+board_serdes_name(enum srds_prtcl device);
+
+static u32 devdisr_mask[] = {
+ _DEVDISR_PCIE1,
+ _DEVDISR_PCIE2,
+ _DEVDISR_PCIE3,
+ _DEVDISR_PCIE4,
+};
+
+int fsl_pcie_init_ctrl(int busno, u32 devdisr, enum srds_prtcl dev,
+ struct fsl_pci_info *pci_info)
+{
+ struct pci_controller *hose;
+ int num = dev - PCIE1;
+
+ hose = calloc(1, sizeof(struct pci_controller));
+ if (!hose)
+ return busno;
+
+ if (is_serdes_configured(dev) && !(devdisr & devdisr_mask[num])) {
+ busno = fsl_configure_pcie(pci_info, hose,
+ board_serdes_name(dev), busno);
+ } else {
+ printf("PCIe%d: disabled\n", num + 1);
+ }
+
+ return busno;
+}
+
+int fsl_pcie_init_board(int busno)
+{
+ struct fsl_pci_info pci_info;
+ ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC8xxx_GUTS_ADDR;
+ u32 devdisr;
+ u32 *addr;
+
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+ addr = &gur->devdisr3;
+#else
+ addr = &gur->devdisr;
+#endif
+ devdisr = in_be32(addr);
+
+#ifdef CONFIG_PCIE1
+ SET_STD_PCIE_INFO(pci_info, 1);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE1, &pci_info);
+#else
+ setbits_be32(addr, _DEVDISR_PCIE1); /* disable */
+#endif
+
+#ifdef CONFIG_PCIE2
+ SET_STD_PCIE_INFO(pci_info, 2);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE2, &pci_info);
+#else
+ setbits_be32(addr, _DEVDISR_PCIE2); /* disable */
+#endif
+
+#ifdef CONFIG_PCIE3
+ SET_STD_PCIE_INFO(pci_info, 3);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE3, &pci_info);
+#else
+ setbits_be32(addr, _DEVDISR_PCIE3); /* disable */
+#endif
+
+#ifdef CONFIG_PCIE4
+ SET_STD_PCIE_INFO(pci_info, 4);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE4, &pci_info);
+#else
+ setbits_be32(addr, _DEVDISR_PCIE4); /* disable */
+#endif
+
+ return busno;
+}
+#else
+int fsl_pcie_init_ctrl(int busno, u32 devdisr, enum srds_prtcl dev,
+ struct fsl_pci_info *pci_info)
+{
+ return busno;
+}
+
+int fsl_pcie_init_board(int busno)
+{
+ return busno;
+}
+#endif
+
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <linux/libfdt.h>
+#include <fdt_support.h>
+
+void ft_fsl_pci_setup(void *blob, const char *pci_compat,
+ unsigned long ctrl_addr)
+{
+ int off;
+ u32 bus_range[2];
+ phys_addr_t p_ctrl_addr = (phys_addr_t)ctrl_addr;
+ struct pci_controller *hose;
+
+ hose = find_hose_by_cfg_addr((void *)(ctrl_addr));
+
+ /* convert ctrl_addr to true physical address */
+ p_ctrl_addr = (phys_addr_t)ctrl_addr - CONFIG_SYS_CCSRBAR;
+ p_ctrl_addr += CONFIG_SYS_CCSRBAR_PHYS;
+
+ off = fdt_node_offset_by_compat_reg(blob, pci_compat, p_ctrl_addr);
+
+ if (off < 0)
+ return;
+
+ /* We assume a cfg_addr not being set means we didn't setup the controller */
+ if ((hose == NULL) || (hose->cfg_addr == NULL)) {
+ fdt_del_node(blob, off);
+ } else {
+ bus_range[0] = 0;
+ bus_range[1] = hose->last_busno - hose->first_busno;
+ fdt_setprop(blob, off, "bus-range", &bus_range[0], 2*4);
+ fdt_pci_dma_ranges(blob, off, hose);
+ }
+}
+#endif
diff --git a/roms/u-boot/drivers/pci/pci-aardvark.c b/roms/u-boot/drivers/pci/pci-aardvark.c
new file mode 100644
index 000000000..96aa039bd
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci-aardvark.c
@@ -0,0 +1,890 @@
+/*
+ * ***************************************************************************
+ * Copyright (C) 2015 Marvell International Ltd.
+ * ***************************************************************************
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 2 of the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * ***************************************************************************
+ */
+/* pcie_advk.c
+ *
+ * Ported from Linux driver - driver/pci/host/pci-aardvark.c
+ *
+ * Author: Victor Gu <xigu@marvell.com>
+ * Hezi Shahmoon <hezi.shahmoon@marvell.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+
+/* PCIe core registers */
+#define PCIE_CORE_CMD_STATUS_REG 0x4
+#define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0)
+#define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1)
+#define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2)
+#define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8
+#define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4)
+#define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11)
+#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE 0x2
+#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE_SHIFT 5
+#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE 0x2
+#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT 12
+#define PCIE_CORE_LINK_CTRL_STAT_REG 0xd0
+#define PCIE_CORE_LINK_TRAINING BIT(5)
+#define PCIE_CORE_ERR_CAPCTL_REG 0x118
+#define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX BIT(5)
+#define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN BIT(6)
+#define PCIE_CORE_ERR_CAPCTL_ECRC_CHECK BIT(7)
+#define PCIE_CORE_ERR_CAPCTL_ECRC_CHECK_RCV BIT(8)
+
+/* PIO registers base address and register offsets */
+#define PIO_BASE_ADDR 0x4000
+#define PIO_CTRL (PIO_BASE_ADDR + 0x0)
+#define PIO_CTRL_TYPE_MASK GENMASK(3, 0)
+#define PIO_CTRL_ADDR_WIN_DISABLE BIT(24)
+#define PIO_STAT (PIO_BASE_ADDR + 0x4)
+#define PIO_COMPLETION_STATUS_SHIFT 7
+#define PIO_COMPLETION_STATUS_MASK GENMASK(9, 7)
+#define PIO_COMPLETION_STATUS_OK 0
+#define PIO_COMPLETION_STATUS_UR 1
+#define PIO_COMPLETION_STATUS_CRS 2
+#define PIO_COMPLETION_STATUS_CA 4
+#define PIO_NON_POSTED_REQ BIT(10)
+#define PIO_ERR_STATUS BIT(11)
+#define PIO_ADDR_LS (PIO_BASE_ADDR + 0x8)
+#define PIO_ADDR_MS (PIO_BASE_ADDR + 0xc)
+#define PIO_WR_DATA (PIO_BASE_ADDR + 0x10)
+#define PIO_WR_DATA_STRB (PIO_BASE_ADDR + 0x14)
+#define PIO_RD_DATA (PIO_BASE_ADDR + 0x18)
+#define PIO_START (PIO_BASE_ADDR + 0x1c)
+#define PIO_ISR (PIO_BASE_ADDR + 0x20)
+
+/* Aardvark Control registers */
+#define CONTROL_BASE_ADDR 0x4800
+#define PCIE_CORE_CTRL0_REG (CONTROL_BASE_ADDR + 0x0)
+#define PCIE_GEN_SEL_MSK 0x3
+#define PCIE_GEN_SEL_SHIFT 0x0
+#define SPEED_GEN_1 0
+#define SPEED_GEN_2 1
+#define SPEED_GEN_3 2
+#define IS_RC_MSK 1
+#define IS_RC_SHIFT 2
+#define LANE_CNT_MSK 0x18
+#define LANE_CNT_SHIFT 0x3
+#define LANE_COUNT_1 (0 << LANE_CNT_SHIFT)
+#define LANE_COUNT_2 (1 << LANE_CNT_SHIFT)
+#define LANE_COUNT_4 (2 << LANE_CNT_SHIFT)
+#define LANE_COUNT_8 (3 << LANE_CNT_SHIFT)
+#define LINK_TRAINING_EN BIT(6)
+#define PCIE_CORE_CTRL2_REG (CONTROL_BASE_ADDR + 0x8)
+#define PCIE_CORE_CTRL2_RESERVED 0x7
+#define PCIE_CORE_CTRL2_TD_ENABLE BIT(4)
+#define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5)
+#define PCIE_CORE_CTRL2_ADDRWIN_MAP_ENABLE BIT(6)
+
+/* PCIe window configuration */
+#define OB_WIN_BASE_ADDR 0x4c00
+#define OB_WIN_BLOCK_SIZE 0x20
+#define OB_WIN_COUNT 8
+#define OB_WIN_REG_ADDR(win, offset) (OB_WIN_BASE_ADDR + \
+ OB_WIN_BLOCK_SIZE * (win) + \
+ (offset))
+#define OB_WIN_MATCH_LS(win) OB_WIN_REG_ADDR(win, 0x00)
+#define OB_WIN_ENABLE BIT(0)
+#define OB_WIN_MATCH_MS(win) OB_WIN_REG_ADDR(win, 0x04)
+#define OB_WIN_REMAP_LS(win) OB_WIN_REG_ADDR(win, 0x08)
+#define OB_WIN_REMAP_MS(win) OB_WIN_REG_ADDR(win, 0x0c)
+#define OB_WIN_MASK_LS(win) OB_WIN_REG_ADDR(win, 0x10)
+#define OB_WIN_MASK_MS(win) OB_WIN_REG_ADDR(win, 0x14)
+#define OB_WIN_ACTIONS(win) OB_WIN_REG_ADDR(win, 0x18)
+#define OB_WIN_DEFAULT_ACTIONS (OB_WIN_ACTIONS(OB_WIN_COUNT-1) + 0x4)
+#define OB_WIN_FUNC_NUM_MASK GENMASK(31, 24)
+#define OB_WIN_FUNC_NUM_SHIFT 24
+#define OB_WIN_FUNC_NUM_ENABLE BIT(23)
+#define OB_WIN_BUS_NUM_BITS_MASK GENMASK(22, 20)
+#define OB_WIN_BUS_NUM_BITS_SHIFT 20
+#define OB_WIN_MSG_CODE_ENABLE BIT(22)
+#define OB_WIN_MSG_CODE_MASK GENMASK(21, 14)
+#define OB_WIN_MSG_CODE_SHIFT 14
+#define OB_WIN_MSG_PAYLOAD_LEN BIT(12)
+#define OB_WIN_ATTR_ENABLE BIT(11)
+#define OB_WIN_ATTR_TC_MASK GENMASK(10, 8)
+#define OB_WIN_ATTR_TC_SHIFT 8
+#define OB_WIN_ATTR_RELAXED BIT(7)
+#define OB_WIN_ATTR_NOSNOOP BIT(6)
+#define OB_WIN_ATTR_POISON BIT(5)
+#define OB_WIN_ATTR_IDO BIT(4)
+#define OB_WIN_TYPE_MASK GENMASK(3, 0)
+#define OB_WIN_TYPE_SHIFT 0
+#define OB_WIN_TYPE_MEM 0x0
+#define OB_WIN_TYPE_IO 0x4
+#define OB_WIN_TYPE_CONFIG_TYPE0 0x8
+#define OB_WIN_TYPE_CONFIG_TYPE1 0x9
+#define OB_WIN_TYPE_MSG 0xc
+
+/* LMI registers base address and register offsets */
+#define LMI_BASE_ADDR 0x6000
+#define CFG_REG (LMI_BASE_ADDR + 0x0)
+#define LTSSM_SHIFT 24
+#define LTSSM_MASK 0x3f
+#define LTSSM_L0 0x10
+#define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44)
+
+/* PCIe core controller registers */
+#define CTRL_CORE_BASE_ADDR 0x18000
+#define CTRL_CONFIG_REG (CTRL_CORE_BASE_ADDR + 0x0)
+#define CTRL_MODE_SHIFT 0x0
+#define CTRL_MODE_MASK 0x1
+#define PCIE_CORE_MODE_DIRECT 0x0
+#define PCIE_CORE_MODE_COMMAND 0x1
+
+/* Transaction types */
+#define PCIE_CONFIG_RD_TYPE0 0x8
+#define PCIE_CONFIG_RD_TYPE1 0x9
+#define PCIE_CONFIG_WR_TYPE0 0xa
+#define PCIE_CONFIG_WR_TYPE1 0xb
+
+/* PCI_BDF shifts 8bit, so we need extra 4bit shift */
+#define PCIE_BDF(dev) (dev << 4)
+#define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20)
+#define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15)
+#define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12)
+#define PCIE_CONF_REG(reg) ((reg) & 0xffc)
+#define PCIE_CONF_ADDR(bus, devfn, where) \
+ (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \
+ PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
+
+/* PCIe Retries & Timeout definitions */
+#define PIO_MAX_RETRIES 1500
+#define PIO_WAIT_TIMEOUT 1000
+#define LINK_MAX_RETRIES 10
+#define LINK_WAIT_TIMEOUT 100000
+
+#define CFG_RD_UR_VAL 0xFFFFFFFF
+#define CFG_RD_CRS_VAL 0xFFFF0001
+
+/**
+ * struct pcie_advk - Advk PCIe controller state
+ *
+ * @reg_base: The base address of the register space.
+ * @first_busno: This driver supports multiple PCIe controllers.
+ * first_busno stores the bus number of the PCIe root-port
+ * number which may vary depending on the PCIe setup
+ * (PEX switches etc).
+ * @device: The pointer to PCI uclass device.
+ */
+struct pcie_advk {
+ void *base;
+ int first_busno;
+ struct udevice *dev;
+ struct gpio_desc reset_gpio;
+};
+
+static inline void advk_writel(struct pcie_advk *pcie, uint val, uint reg)
+{
+ writel(val, pcie->base + reg);
+}
+
+static inline uint advk_readl(struct pcie_advk *pcie, uint reg)
+{
+ return readl(pcie->base + reg);
+}
+
+/**
+ * pcie_advk_addr_valid() - Check for valid bus address
+ *
+ * @bdf: The PCI device to access
+ * @first_busno: Bus number of the PCIe controller root complex
+ *
+ * Return: 1 on valid, 0 on invalid
+ */
+static int pcie_advk_addr_valid(pci_dev_t bdf, int first_busno)
+{
+ /*
+ * In PCIE-E only a single device (0) can exist
+ * on the local bus. Beyound the local bus, there might be
+ * a Switch and everything is possible.
+ */
+ if ((PCI_BUS(bdf) == first_busno) && (PCI_DEV(bdf) > 0))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * pcie_advk_wait_pio() - Wait for PIO access to be accomplished
+ *
+ * @pcie: The PCI device to access
+ *
+ * Wait up to 1.5 seconds for PIO access to be accomplished.
+ *
+ * Return 1 (true) if PIO access is accomplished.
+ * Return 0 (false) if PIO access is timed out.
+ */
+static int pcie_advk_wait_pio(struct pcie_advk *pcie)
+{
+ uint start, isr;
+ uint count;
+
+ for (count = 0; count < PIO_MAX_RETRIES; count++) {
+ start = advk_readl(pcie, PIO_START);
+ isr = advk_readl(pcie, PIO_ISR);
+ if (!start && isr)
+ return 1;
+ /*
+ * Do not check the PIO state too frequently,
+ * 100us delay is appropriate.
+ */
+ udelay(PIO_WAIT_TIMEOUT);
+ }
+
+ dev_err(pcie->dev, "PIO read/write transfer time out\n");
+ return 0;
+}
+
+/**
+ * pcie_advk_check_pio_status() - Validate PIO status and get the read result
+ *
+ * @pcie: Pointer to the PCI bus
+ * @read: Read from or write to configuration space - true(read) false(write)
+ * @read_val: Pointer to the read result, only valid when read is true
+ *
+ */
+static int pcie_advk_check_pio_status(struct pcie_advk *pcie,
+ bool read,
+ uint *read_val)
+{
+ uint reg;
+ unsigned int status;
+ char *strcomp_status, *str_posted;
+
+ reg = advk_readl(pcie, PIO_STAT);
+ status = (reg & PIO_COMPLETION_STATUS_MASK) >>
+ PIO_COMPLETION_STATUS_SHIFT;
+
+ switch (status) {
+ case PIO_COMPLETION_STATUS_OK:
+ if (reg & PIO_ERR_STATUS) {
+ strcomp_status = "COMP_ERR";
+ break;
+ }
+ /* Get the read result */
+ if (read)
+ *read_val = advk_readl(pcie, PIO_RD_DATA);
+ /* No error */
+ strcomp_status = NULL;
+ break;
+ case PIO_COMPLETION_STATUS_UR:
+ if (read) {
+ /* For reading, UR is not an error status. */
+ *read_val = CFG_RD_UR_VAL;
+ strcomp_status = NULL;
+ } else {
+ strcomp_status = "UR";
+ }
+ break;
+ case PIO_COMPLETION_STATUS_CRS:
+ if (read) {
+ /* For reading, CRS is not an error status. */
+ *read_val = CFG_RD_CRS_VAL;
+ strcomp_status = NULL;
+ } else {
+ strcomp_status = "CRS";
+ }
+ break;
+ case PIO_COMPLETION_STATUS_CA:
+ strcomp_status = "CA";
+ break;
+ default:
+ strcomp_status = "Unknown";
+ break;
+ }
+
+ if (!strcomp_status)
+ return 0;
+
+ if (reg & PIO_NON_POSTED_REQ)
+ str_posted = "Non-posted";
+ else
+ str_posted = "Posted";
+
+ dev_err(pcie->dev, "%s PIO Response Status: %s, %#x @ %#x\n",
+ str_posted, strcomp_status, reg,
+ advk_readl(pcie, PIO_ADDR_LS));
+
+ return -EFAULT;
+}
+
+/**
+ * pcie_advk_read_config() - Read from configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct pcie_advk *pcie = dev_get_priv(bus);
+ uint reg;
+ int ret;
+
+ dev_dbg(pcie->dev, "PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) {
+ dev_dbg(pcie->dev, "- out of range\n");
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ if (advk_readl(pcie, PIO_START)) {
+ dev_err(pcie->dev,
+ "Previous PIO read/write transfer is still running\n");
+ if (offset != PCI_VENDOR_ID)
+ return -EINVAL;
+ *valuep = CFG_RD_CRS_VAL;
+ return 0;
+ }
+
+ /* Program the control register */
+ reg = advk_readl(pcie, PIO_CTRL);
+ reg &= ~PIO_CTRL_TYPE_MASK;
+ if (PCI_BUS(bdf) == pcie->first_busno)
+ reg |= PCIE_CONFIG_RD_TYPE0;
+ else
+ reg |= PCIE_CONFIG_RD_TYPE1;
+ advk_writel(pcie, reg, PIO_CTRL);
+
+ /* Program the address registers */
+ reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset);
+ advk_writel(pcie, reg, PIO_ADDR_LS);
+ advk_writel(pcie, 0, PIO_ADDR_MS);
+
+ /* Start the transfer */
+ advk_writel(pcie, 1, PIO_ISR);
+ advk_writel(pcie, 1, PIO_START);
+
+ if (!pcie_advk_wait_pio(pcie)) {
+ if (offset != PCI_VENDOR_ID)
+ return -EINVAL;
+ *valuep = CFG_RD_CRS_VAL;
+ return 0;
+ }
+
+ /* Check PIO status and get the read result */
+ ret = pcie_advk_check_pio_status(pcie, true, &reg);
+ if (ret)
+ return ret;
+
+ dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n",
+ offset, size, reg);
+ *valuep = pci_conv_32_to_size(reg, offset, size);
+
+ return 0;
+}
+
+/**
+ * pcie_calc_datastrobe() - Calculate data strobe
+ *
+ * @offset: The offset into the device's configuration space
+ * @size: Indicates the size of access to perform
+ *
+ * Calculate data strobe according to offset and size
+ *
+ */
+static uint pcie_calc_datastrobe(uint offset, enum pci_size_t size)
+{
+ uint bytes, data_strobe;
+
+ switch (size) {
+ case PCI_SIZE_8:
+ bytes = 1;
+ break;
+ case PCI_SIZE_16:
+ bytes = 2;
+ break;
+ default:
+ bytes = 4;
+ }
+
+ data_strobe = GENMASK(bytes - 1, 0) << (offset & 0x3);
+
+ return data_strobe;
+}
+
+/**
+ * pcie_advk_write_config() - Write to configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct pcie_advk *pcie = dev_get_priv(bus);
+ uint reg;
+
+ dev_dbg(pcie->dev, "PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n",
+ offset, size, value);
+
+ if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) {
+ dev_dbg(pcie->dev, "- out of range\n");
+ return 0;
+ }
+
+ if (advk_readl(pcie, PIO_START)) {
+ dev_err(pcie->dev,
+ "Previous PIO read/write transfer is still running\n");
+ return -EINVAL;
+ }
+
+ /* Program the control register */
+ reg = advk_readl(pcie, PIO_CTRL);
+ reg &= ~PIO_CTRL_TYPE_MASK;
+ if (PCI_BUS(bdf) == pcie->first_busno)
+ reg |= PCIE_CONFIG_WR_TYPE0;
+ else
+ reg |= PCIE_CONFIG_WR_TYPE1;
+ advk_writel(pcie, reg, PIO_CTRL);
+
+ /* Program the address registers */
+ reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset);
+ advk_writel(pcie, reg, PIO_ADDR_LS);
+ advk_writel(pcie, 0, PIO_ADDR_MS);
+ dev_dbg(pcie->dev, "\tPIO req. - addr = 0x%08x\n", reg);
+
+ /* Program the data register */
+ reg = pci_conv_size_to_32(0, value, offset, size);
+ advk_writel(pcie, reg, PIO_WR_DATA);
+ dev_dbg(pcie->dev, "\tPIO req. - val = 0x%08x\n", reg);
+
+ /* Program the data strobe */
+ reg = pcie_calc_datastrobe(offset, size);
+ advk_writel(pcie, reg, PIO_WR_DATA_STRB);
+ dev_dbg(pcie->dev, "\tPIO req. - strb = 0x%02x\n", reg);
+
+ /* Start the transfer */
+ advk_writel(pcie, 1, PIO_ISR);
+ advk_writel(pcie, 1, PIO_START);
+
+ if (!pcie_advk_wait_pio(pcie)) {
+ return -EINVAL;
+ }
+
+ /* Check PIO status */
+ pcie_advk_check_pio_status(pcie, false, &reg);
+
+ return 0;
+}
+
+/**
+ * pcie_advk_link_up() - Check if PCIe link is up or not
+ *
+ * @pcie: The PCI device to access
+ *
+ * Return 1 (true) on link up.
+ * Return 0 (false) on link down.
+ */
+static int pcie_advk_link_up(struct pcie_advk *pcie)
+{
+ u32 val, ltssm_state;
+
+ val = advk_readl(pcie, CFG_REG);
+ ltssm_state = (val >> LTSSM_SHIFT) & LTSSM_MASK;
+ return ltssm_state >= LTSSM_L0;
+}
+
+/**
+ * pcie_advk_wait_for_link() - Wait for link training to be accomplished
+ *
+ * @pcie: The PCI device to access
+ *
+ * Wait up to 1 second for link training to be accomplished.
+ *
+ * Return 1 (true) if link training ends up with link up success.
+ * Return 0 (false) if link training ends up with link up failure.
+ */
+static int pcie_advk_wait_for_link(struct pcie_advk *pcie)
+{
+ int retries;
+
+ /* check if the link is up or not */
+ for (retries = 0; retries < LINK_MAX_RETRIES; retries++) {
+ if (pcie_advk_link_up(pcie)) {
+ printf("PCIE-%d: Link up\n", pcie->first_busno);
+ return 0;
+ }
+
+ udelay(LINK_WAIT_TIMEOUT);
+ }
+
+ printf("PCIE-%d: Link down\n", pcie->first_busno);
+
+ return -ETIMEDOUT;
+}
+
+/*
+ * Set PCIe address window register which could be used for memory
+ * mapping.
+ */
+static void pcie_advk_set_ob_win(struct pcie_advk *pcie, u8 win_num,
+ phys_addr_t match, phys_addr_t remap,
+ phys_addr_t mask, u32 actions)
+{
+ advk_writel(pcie, OB_WIN_ENABLE |
+ lower_32_bits(match), OB_WIN_MATCH_LS(win_num));
+ advk_writel(pcie, upper_32_bits(match), OB_WIN_MATCH_MS(win_num));
+ advk_writel(pcie, lower_32_bits(remap), OB_WIN_REMAP_LS(win_num));
+ advk_writel(pcie, upper_32_bits(remap), OB_WIN_REMAP_MS(win_num));
+ advk_writel(pcie, lower_32_bits(mask), OB_WIN_MASK_LS(win_num));
+ advk_writel(pcie, upper_32_bits(mask), OB_WIN_MASK_MS(win_num));
+ advk_writel(pcie, actions, OB_WIN_ACTIONS(win_num));
+}
+
+static void pcie_advk_disable_ob_win(struct pcie_advk *pcie, u8 win_num)
+{
+ advk_writel(pcie, 0, OB_WIN_MATCH_LS(win_num));
+ advk_writel(pcie, 0, OB_WIN_MATCH_MS(win_num));
+ advk_writel(pcie, 0, OB_WIN_REMAP_LS(win_num));
+ advk_writel(pcie, 0, OB_WIN_REMAP_MS(win_num));
+ advk_writel(pcie, 0, OB_WIN_MASK_LS(win_num));
+ advk_writel(pcie, 0, OB_WIN_MASK_MS(win_num));
+ advk_writel(pcie, 0, OB_WIN_ACTIONS(win_num));
+}
+
+static void pcie_advk_set_ob_region(struct pcie_advk *pcie, int *wins,
+ struct pci_region *region, u32 actions)
+{
+ phys_addr_t phys_start = region->phys_start;
+ pci_addr_t bus_start = region->bus_start;
+ pci_size_t size = region->size;
+ phys_addr_t win_mask;
+ u64 win_size;
+
+ if (*wins == -1)
+ return;
+
+ /*
+ * The n-th PCIe window is configured by tuple (match, remap, mask)
+ * and an access to address A uses this window it if A matches the
+ * match with given mask.
+ * So every PCIe window size must be a power of two and every start
+ * address must be aligned to window size. Minimal size is 64 KiB
+ * because lower 16 bits of mask must be zero.
+ */
+ while (*wins < OB_WIN_COUNT && size > 0) {
+ /* Calculate the largest aligned window size */
+ win_size = (1ULL << (fls64(size) - 1)) |
+ (phys_start ? (1ULL << __ffs64(phys_start)) : 0);
+ win_size = 1ULL << __ffs64(win_size);
+ if (win_size < 0x10000)
+ break;
+
+ dev_dbg(pcie->dev,
+ "Configuring PCIe window %d: [0x%llx-0x%llx] as 0x%x\n",
+ *wins, (u64)phys_start, (u64)phys_start + win_size,
+ actions);
+ win_mask = ~(win_size - 1) & ~0xffff;
+ pcie_advk_set_ob_win(pcie, *wins, phys_start, bus_start,
+ win_mask, actions);
+
+ phys_start += win_size;
+ bus_start += win_size;
+ size -= win_size;
+ (*wins)++;
+ }
+
+ if (size > 0) {
+ *wins = -1;
+ dev_err(pcie->dev,
+ "Invalid PCIe region [0x%llx-0x%llx]\n",
+ (u64)region->phys_start,
+ (u64)region->phys_start + region->size);
+ }
+}
+
+/**
+ * pcie_advk_setup_hw() - PCIe initailzation
+ *
+ * @pcie: The PCI device to access
+ *
+ * Return: 0 on success
+ */
+static int pcie_advk_setup_hw(struct pcie_advk *pcie)
+{
+ struct pci_region *io, *mem, *pref;
+ int i, wins;
+ u32 reg;
+
+ /* Set to Direct mode */
+ reg = advk_readl(pcie, CTRL_CONFIG_REG);
+ reg &= ~(CTRL_MODE_MASK << CTRL_MODE_SHIFT);
+ reg |= ((PCIE_CORE_MODE_DIRECT & CTRL_MODE_MASK) << CTRL_MODE_SHIFT);
+ advk_writel(pcie, reg, CTRL_CONFIG_REG);
+
+ /* Set PCI global control register to RC mode */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg |= (IS_RC_MSK << IS_RC_SHIFT);
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+ /*
+ * Replace incorrect PCI vendor id value 0x1b4b by correct value 0x11ab.
+ * VENDOR_ID_REG contains vendor id in low 16 bits and subsystem vendor
+ * id in high 16 bits. Updating this register changes readback value of
+ * read-only vendor id bits in PCIE_CORE_DEV_ID_REG register. Workaround
+ * for erratum 4.1: "The value of device and vendor ID is incorrect".
+ */
+ advk_writel(pcie, 0x11ab11ab, VENDOR_ID_REG);
+
+ /* Set Advanced Error Capabilities and Control PF0 register */
+ reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX |
+ PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN |
+ PCIE_CORE_ERR_CAPCTL_ECRC_CHECK |
+ PCIE_CORE_ERR_CAPCTL_ECRC_CHECK_RCV;
+ advk_writel(pcie, reg, PCIE_CORE_ERR_CAPCTL_REG);
+
+ /* Set PCIe Device Control and Status 1 PF0 register */
+ reg = PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE |
+ (PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE <<
+ PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE_SHIFT) |
+ (PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE <<
+ PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT) |
+ PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE;
+ advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG);
+
+ /* Program PCIe Control 2 to disable strict ordering */
+ reg = PCIE_CORE_CTRL2_RESERVED |
+ PCIE_CORE_CTRL2_TD_ENABLE;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);
+
+ /* Set GEN2 */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg &= ~PCIE_GEN_SEL_MSK;
+ reg |= SPEED_GEN_2;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+ /* Set lane X1 */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg &= ~LANE_CNT_MSK;
+ reg |= LANE_COUNT_1;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+ /* Enable link training */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg |= LINK_TRAINING_EN;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+ /*
+ * Enable AXI address window location generation:
+ * When it is enabled, the default outbound window
+ * configurations (Default User Field: 0xD0074CFC)
+ * are used to transparent address translation for
+ * the outbound transactions. Thus, PCIe address
+ * windows are not required for transparent memory
+ * access when default outbound window configuration
+ * is set for memory access.
+ */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL2_REG);
+ reg |= PCIE_CORE_CTRL2_ADDRWIN_MAP_ENABLE;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);
+
+ /*
+ * Bypass the address window mapping for PIO:
+ * Since PIO access already contains all required
+ * info over AXI interface by PIO registers, the
+ * address window is not required.
+ */
+ reg = advk_readl(pcie, PIO_CTRL);
+ reg |= PIO_CTRL_ADDR_WIN_DISABLE;
+ advk_writel(pcie, reg, PIO_CTRL);
+
+ /*
+ * Set memory access in Default User Field so it
+ * is not required to configure PCIe address for
+ * transparent memory access.
+ */
+ advk_writel(pcie, OB_WIN_TYPE_MEM, OB_WIN_DEFAULT_ACTIONS);
+
+ /*
+ * Configure PCIe address windows for non-memory or
+ * non-transparent access as by default PCIe uses
+ * transparent memory access.
+ */
+ wins = 0;
+ pci_get_regions(pcie->dev, &io, &mem, &pref);
+ if (io)
+ pcie_advk_set_ob_region(pcie, &wins, io, OB_WIN_TYPE_IO);
+ if (mem && mem->phys_start != mem->bus_start)
+ pcie_advk_set_ob_region(pcie, &wins, mem, OB_WIN_TYPE_MEM);
+ if (pref && pref->phys_start != pref->bus_start)
+ pcie_advk_set_ob_region(pcie, &wins, pref, OB_WIN_TYPE_MEM);
+
+ /* Disable remaining PCIe outbound windows */
+ for (i = ((wins >= 0) ? wins : 0); i < OB_WIN_COUNT; i++)
+ pcie_advk_disable_ob_win(pcie, i);
+
+ if (wins == -1)
+ return -EINVAL;
+
+ /* Wait for PCIe link up */
+ if (pcie_advk_wait_for_link(pcie))
+ return -ENXIO;
+
+ reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
+ reg |= PCIE_CORE_CMD_MEM_ACCESS_EN |
+ PCIE_CORE_CMD_IO_ACCESS_EN |
+ PCIE_CORE_CMD_MEM_IO_REQ_EN;
+ advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG);
+
+ return 0;
+}
+
+/**
+ * pcie_advk_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int pcie_advk_probe(struct udevice *dev)
+{
+ struct pcie_advk *pcie = dev_get_priv(dev);
+
+ gpio_request_by_name(dev, "reset-gpios", 0, &pcie->reset_gpio,
+ GPIOD_IS_OUT);
+ /*
+ * Issue reset to add-in card through the dedicated GPIO.
+ * Some boards are connecting the card reset pin to common system
+ * reset wire and others are using separate GPIO port.
+ * In the last case we have to release a reset of the addon card
+ * using this GPIO.
+ *
+ * FIX-ME:
+ * The PCIe RESET signal is not supposed to be released along
+ * with the SOC RESET signal. It should be lowered as early as
+ * possible before PCIe PHY initialization. Moreover, the PCIe
+ * clock should be gated as well.
+ */
+ if (dm_gpio_is_valid(&pcie->reset_gpio)) {
+ dev_dbg(dev, "Toggle PCIE Reset GPIO ...\n");
+ dm_gpio_set_value(&pcie->reset_gpio, 1);
+ mdelay(200);
+ dm_gpio_set_value(&pcie->reset_gpio, 0);
+ } else {
+ dev_warn(dev, "PCIE Reset on GPIO support is missing\n");
+ }
+
+ pcie->first_busno = dev_seq(dev);
+ pcie->dev = pci_get_controller(dev);
+
+ return pcie_advk_setup_hw(pcie);
+}
+
+static int pcie_advk_remove(struct udevice *dev)
+{
+ struct pcie_advk *pcie = dev_get_priv(dev);
+ u32 reg;
+ int i;
+
+ for (i = 0; i < OB_WIN_COUNT; i++)
+ pcie_advk_disable_ob_win(pcie, i);
+
+ reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
+ reg &= ~(PCIE_CORE_CMD_MEM_ACCESS_EN |
+ PCIE_CORE_CMD_IO_ACCESS_EN |
+ PCIE_CORE_CMD_MEM_IO_REQ_EN);
+ advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG);
+
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg &= ~LINK_TRAINING_EN;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+ return 0;
+}
+
+/**
+ * pcie_advk_of_to_plat() - Translate from DT to device state
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Translate relevant data from the device tree pertaining to device @dev into
+ * state that the driver will later make use of. This state is stored in the
+ * device's private data structure.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+static int pcie_advk_of_to_plat(struct udevice *dev)
+{
+ struct pcie_advk *pcie = dev_get_priv(dev);
+
+ /* Get the register base address */
+ pcie->base = (void *)dev_read_addr_index(dev, 0);
+ if ((fdt_addr_t)pcie->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct dm_pci_ops pcie_advk_ops = {
+ .read_config = pcie_advk_read_config,
+ .write_config = pcie_advk_write_config,
+};
+
+static const struct udevice_id pcie_advk_ids[] = {
+ { .compatible = "marvell,armada-3700-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_advk) = {
+ .name = "pcie_advk",
+ .id = UCLASS_PCI,
+ .of_match = pcie_advk_ids,
+ .ops = &pcie_advk_ops,
+ .of_to_plat = pcie_advk_of_to_plat,
+ .probe = pcie_advk_probe,
+ .remove = pcie_advk_remove,
+ .flags = DM_FLAG_OS_PREPARE,
+ .priv_auto = sizeof(struct pcie_advk),
+};
diff --git a/roms/u-boot/drivers/pci/pci-emul-uclass.c b/roms/u-boot/drivers/pci/pci-emul-uclass.c
new file mode 100644
index 000000000..a0b8afb87
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci-emul-uclass.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <linux/libfdt.h>
+#include <pci.h>
+#include <dm/lists.h>
+
+struct sandbox_pci_emul_priv {
+ int dev_count;
+};
+
+int sandbox_pci_get_emul(const struct udevice *bus, pci_dev_t find_devfn,
+ struct udevice **containerp, struct udevice **emulp)
+{
+ struct pci_emul_uc_priv *upriv;
+ struct udevice *dev;
+ int ret;
+
+ *containerp = NULL;
+ ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(find_devfn), &dev);
+ if (ret) {
+ debug("%s: Could not find emulator for dev %x\n", __func__,
+ find_devfn);
+ return ret;
+ }
+ *containerp = dev;
+
+ ret = uclass_get_device_by_phandle(UCLASS_PCI_EMUL, dev, "sandbox,emul",
+ emulp);
+ if (!ret) {
+ upriv = dev_get_uclass_priv(*emulp);
+
+ upriv->client = dev;
+ } else if (device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) {
+ /*
+ * See commit 4345998ae9df,
+ * "pci: sandbox: Support dynamically binding device driver"
+ */
+ *emulp = dev;
+ }
+
+ return 0;
+}
+
+int sandbox_pci_get_client(struct udevice *emul, struct udevice **devp)
+{
+ struct pci_emul_uc_priv *upriv = dev_get_uclass_priv(emul);
+
+ if (!upriv->client)
+ return -ENOENT;
+ *devp = upriv->client;
+
+ return 0;
+}
+
+uint sandbox_pci_read_bar(u32 barval, int type, uint size)
+{
+ u32 result;
+
+ result = barval;
+ if (result == 0xffffffff) {
+ if (type == PCI_BASE_ADDRESS_SPACE_IO) {
+ result = (~(size - 1) &
+ PCI_BASE_ADDRESS_IO_MASK) |
+ PCI_BASE_ADDRESS_SPACE_IO;
+ } else {
+ result = (~(size - 1) &
+ PCI_BASE_ADDRESS_MEM_MASK) |
+ PCI_BASE_ADDRESS_MEM_TYPE_32;
+ }
+ }
+
+ return result;
+}
+
+static int sandbox_pci_emul_post_probe(struct udevice *dev)
+{
+ struct sandbox_pci_emul_priv *priv = uclass_get_priv(dev->uclass);
+
+ priv->dev_count++;
+ sandbox_set_enable_pci_map(true);
+
+ return 0;
+}
+
+static int sandbox_pci_emul_pre_remove(struct udevice *dev)
+{
+ struct sandbox_pci_emul_priv *priv = uclass_get_priv(dev->uclass);
+
+ priv->dev_count--;
+ sandbox_set_enable_pci_map(priv->dev_count > 0);
+
+ return 0;
+}
+
+UCLASS_DRIVER(pci_emul) = {
+ .id = UCLASS_PCI_EMUL,
+ .name = "pci_emul",
+ .post_probe = sandbox_pci_emul_post_probe,
+ .pre_remove = sandbox_pci_emul_pre_remove,
+ .priv_auto = sizeof(struct sandbox_pci_emul_priv),
+ .per_device_auto = sizeof(struct pci_emul_uc_priv),
+};
+
+/*
+ * This uclass is a child of the pci bus. Its plat is not defined here so
+ * is defined by its parent, UCLASS_PCI, which uses struct pci_child_plat.
+ * See per_child_plat_auto in UCLASS_DRIVER(pci).
+ */
+UCLASS_DRIVER(pci_emul_parent) = {
+ .id = UCLASS_PCI_EMUL_PARENT,
+ .name = "pci_emul_parent",
+ .post_bind = dm_scan_fdt_dev,
+};
+
+static const struct udevice_id pci_emul_parent_ids[] = {
+ { .compatible = "sandbox,pci-emul-parent" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_emul_parent_drv) = {
+ .name = "pci_emul_parent_drv",
+ .id = UCLASS_PCI_EMUL_PARENT,
+ .of_match = pci_emul_parent_ids,
+};
diff --git a/roms/u-boot/drivers/pci/pci-rcar-gen2.c b/roms/u-boot/drivers/pci/pci-rcar-gen2.c
new file mode 100644
index 000000000..dc1140278
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci-rcar-gen2.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RCar Gen2 PCIEC driver
+ *
+ * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <pci.h>
+#include <linux/bitops.h>
+
+/* AHB-PCI Bridge PCI communication registers */
+#define RCAR_AHBPCI_PCICOM_OFFSET 0x800
+
+#define RCAR_PCIAHB_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x00)
+#define RCAR_PCIAHB_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x04)
+#define RCAR_PCIAHB_PREFETCH0 0x0
+#define RCAR_PCIAHB_PREFETCH4 0x1
+#define RCAR_PCIAHB_PREFETCH8 0x2
+#define RCAR_PCIAHB_PREFETCH16 0x3
+
+#define RCAR_AHBPCI_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x10)
+#define RCAR_AHBPCI_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x14)
+#define RCAR_AHBPCI_WIN_CTR_MEM (3 << 1)
+#define RCAR_AHBPCI_WIN_CTR_CFG (5 << 1)
+#define RCAR_AHBPCI_WIN1_HOST BIT(30)
+#define RCAR_AHBPCI_WIN1_DEVICE BIT(31)
+
+#define RCAR_PCI_INT_ENABLE_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x20)
+#define RCAR_PCI_INT_STATUS_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x24)
+#define RCAR_PCI_INT_SIGTABORT BIT(0)
+#define RCAR_PCI_INT_SIGRETABORT BIT(1)
+#define RCAR_PCI_INT_REMABORT BIT(2)
+#define RCAR_PCI_INT_PERR BIT(3)
+#define RCAR_PCI_INT_SIGSERR BIT(4)
+#define RCAR_PCI_INT_RESERR BIT(5)
+#define RCAR_PCI_INT_WIN1ERR BIT(12)
+#define RCAR_PCI_INT_WIN2ERR BIT(13)
+#define RCAR_PCI_INT_A BIT(16)
+#define RCAR_PCI_INT_B BIT(17)
+#define RCAR_PCI_INT_PME BIT(19)
+#define RCAR_PCI_INT_ALLERRORS (RCAR_PCI_INT_SIGTABORT | \
+ RCAR_PCI_INT_SIGRETABORT | \
+ RCAR_PCI_INT_SIGRETABORT | \
+ RCAR_PCI_INT_REMABORT | \
+ RCAR_PCI_INT_PERR | \
+ RCAR_PCI_INT_SIGSERR | \
+ RCAR_PCI_INT_RESERR | \
+ RCAR_PCI_INT_WIN1ERR | \
+ RCAR_PCI_INT_WIN2ERR)
+
+#define RCAR_AHB_BUS_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x30)
+#define RCAR_AHB_BUS_MMODE_HTRANS BIT(0)
+#define RCAR_AHB_BUS_MMODE_BYTE_BURST BIT(1)
+#define RCAR_AHB_BUS_MMODE_WR_INCR BIT(2)
+#define RCAR_AHB_BUS_MMODE_HBUS_REQ BIT(7)
+#define RCAR_AHB_BUS_SMODE_READYCTR BIT(17)
+#define RCAR_AHB_BUS_MODE (RCAR_AHB_BUS_MMODE_HTRANS | \
+ RCAR_AHB_BUS_MMODE_BYTE_BURST | \
+ RCAR_AHB_BUS_MMODE_WR_INCR | \
+ RCAR_AHB_BUS_MMODE_HBUS_REQ | \
+ RCAR_AHB_BUS_SMODE_READYCTR)
+
+#define RCAR_USBCTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x34)
+#define RCAR_USBCTR_USBH_RST BIT(0)
+#define RCAR_USBCTR_PCICLK_MASK BIT(1)
+#define RCAR_USBCTR_PLL_RST BIT(2)
+#define RCAR_USBCTR_DIRPD BIT(8)
+#define RCAR_USBCTR_PCIAHB_WIN2_EN BIT(9)
+#define RCAR_USBCTR_PCIAHB_WIN1_256M (0 << 10)
+#define RCAR_USBCTR_PCIAHB_WIN1_512M (1 << 10)
+#define RCAR_USBCTR_PCIAHB_WIN1_1G (2 << 10)
+#define RCAR_USBCTR_PCIAHB_WIN1_2G (3 << 10)
+#define RCAR_USBCTR_PCIAHB_WIN1_MASK (3 << 10)
+
+#define RCAR_PCI_ARBITER_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x40)
+#define RCAR_PCI_ARBITER_PCIREQ0 BIT(0)
+#define RCAR_PCI_ARBITER_PCIREQ1 BIT(1)
+#define RCAR_PCI_ARBITER_PCIBP_MODE BIT(12)
+
+#define RCAR_PCI_UNIT_REV_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
+
+struct rcar_gen2_pci_priv {
+ fdt_addr_t cfg_base;
+ fdt_addr_t mem_base;
+};
+
+static int rcar_gen2_pci_addr_valid(pci_dev_t d, uint offset)
+{
+ u32 slot;
+
+ if (PCI_FUNC(d))
+ return -EINVAL;
+
+ /* Only one EHCI/OHCI device built-in */
+ slot = PCI_DEV(d);
+ if (slot != 1 && slot != 2)
+ return -EINVAL;
+
+ /* bridge logic only has registers to 0x40 */
+ if (slot == 0x0 && offset >= 0x40)
+ return -EINVAL;
+
+ return 0;
+}
+
+static u32 get_bus_address(const struct udevice *dev, pci_dev_t bdf, u32 offset)
+{
+ struct rcar_gen2_pci_priv *priv = dev_get_priv(dev);
+
+ return priv->cfg_base + (PCI_DEV(bdf) >> 1) * 0x100 + (offset & ~3);
+}
+
+static u32 setup_bus_address(struct udevice *dev, pci_dev_t bdf, u32 offset)
+{
+ struct rcar_gen2_pci_priv *priv = dev_get_priv(dev);
+ u32 reg;
+
+ reg = PCI_DEV(bdf) ? RCAR_AHBPCI_WIN1_DEVICE : RCAR_AHBPCI_WIN1_HOST;
+ reg |= RCAR_AHBPCI_WIN_CTR_CFG;
+ writel(reg, priv->cfg_base + RCAR_AHBPCI_WIN1_CTR_REG);
+
+ return get_bus_address(dev, bdf, offset);
+}
+
+static int rcar_gen2_pci_read_config(const struct udevice *dev, pci_dev_t bdf,
+ uint offset, ulong *value,
+ enum pci_size_t size)
+{
+ u32 addr, reg;
+ int ret;
+
+ ret = rcar_gen2_pci_addr_valid(bdf, offset);
+ if (ret) {
+ *value = pci_get_ff(size);
+ return 0;
+ }
+
+ addr = get_bus_address(dev, bdf, offset);
+ reg = readl(addr);
+ *value = pci_conv_32_to_size(reg, offset, size);
+
+ return 0;
+}
+
+static int rcar_gen2_pci_write_config(struct udevice *dev, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ u32 addr, reg, old;
+ int ret;
+
+ ret = rcar_gen2_pci_addr_valid(bdf, offset);
+ if (ret)
+ return ret;
+
+ addr = get_bus_address(dev, bdf, offset);
+
+ old = readl(addr);
+ reg = pci_conv_size_to_32(old, value, offset, size);
+ writel(reg, addr);
+
+ return 0;
+}
+
+static int rcar_gen2_pci_probe(struct udevice *dev)
+{
+ struct rcar_gen2_pci_priv *priv = dev_get_priv(dev);
+ struct clk pci_clk;
+ u32 devad;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &pci_clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&pci_clk);
+ if (ret)
+ return ret;
+
+ /* Clock & Reset & Direct Power Down */
+ clrsetbits_le32(priv->cfg_base + RCAR_USBCTR_REG,
+ RCAR_USBCTR_DIRPD | RCAR_USBCTR_PCICLK_MASK |
+ RCAR_USBCTR_USBH_RST,
+ RCAR_USBCTR_PCIAHB_WIN1_1G);
+ clrbits_le32(priv->cfg_base + RCAR_USBCTR_REG, RCAR_USBCTR_PLL_RST);
+
+ /* AHB-PCI Bridge Communication Registers */
+ writel(RCAR_AHB_BUS_MODE, priv->cfg_base + RCAR_AHB_BUS_CTR_REG);
+ writel((CONFIG_SYS_SDRAM_BASE & 0xf0000000) | RCAR_PCIAHB_PREFETCH16,
+ priv->cfg_base + RCAR_PCIAHB_WIN1_CTR_REG);
+ writel(0xf0000000 | RCAR_PCIAHB_PREFETCH16,
+ priv->cfg_base + RCAR_PCIAHB_WIN2_CTR_REG);
+ writel(priv->mem_base | RCAR_AHBPCI_WIN_CTR_MEM,
+ priv->cfg_base + RCAR_AHBPCI_WIN2_CTR_REG);
+ setbits_le32(priv->cfg_base + RCAR_PCI_ARBITER_CTR_REG,
+ RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
+ RCAR_PCI_ARBITER_PCIBP_MODE);
+
+ /* PCI Configuration Registers for AHBPCI */
+ devad = setup_bus_address(dev, PCI_BDF(0, 0, 0), 0);
+ writel(priv->cfg_base + 0x800, devad + PCI_BASE_ADDRESS_0);
+ writel(CONFIG_SYS_SDRAM_BASE & 0xf0000000, devad + PCI_BASE_ADDRESS_1);
+ writel(0xf0000000, devad + PCI_BASE_ADDRESS_2);
+ writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_COMMAND_PARITY | PCI_COMMAND_SERR,
+ devad + PCI_COMMAND);
+
+ /* PCI Configuration Registers for OHCI */
+ devad = setup_bus_address(dev, PCI_BDF(0, 1, 0), 0);
+ writel(priv->mem_base + 0x0, devad + PCI_BASE_ADDRESS_0);
+ writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_COMMAND_PARITY | PCI_COMMAND_SERR,
+ devad + PCI_COMMAND);
+
+ /* PCI Configuration Registers for EHCI */
+ devad = setup_bus_address(dev, PCI_BDF(0, 2, 0), 0);
+ writel(priv->mem_base + 0x1000, devad + PCI_BASE_ADDRESS_0);
+ writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_COMMAND_PARITY | PCI_COMMAND_SERR,
+ devad + PCI_COMMAND);
+
+ /* Enable PCI interrupt */
+ setbits_le32(priv->cfg_base + RCAR_PCI_INT_ENABLE_REG,
+ RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME);
+
+ return 0;
+}
+
+static int rcar_gen2_pci_of_to_plat(struct udevice *dev)
+{
+ struct rcar_gen2_pci_priv *priv = dev_get_priv(dev);
+
+ priv->cfg_base = devfdt_get_addr_index(dev, 0);
+ priv->mem_base = devfdt_get_addr_index(dev, 1);
+ if (!priv->cfg_base || !priv->mem_base)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct dm_pci_ops rcar_gen2_pci_ops = {
+ .read_config = rcar_gen2_pci_read_config,
+ .write_config = rcar_gen2_pci_write_config,
+};
+
+static const struct udevice_id rcar_gen2_pci_ids[] = {
+ { .compatible = "renesas,pci-rcar-gen2" },
+ { }
+};
+
+U_BOOT_DRIVER(rcar_gen2_pci) = {
+ .name = "rcar_gen2_pci",
+ .id = UCLASS_PCI,
+ .of_match = rcar_gen2_pci_ids,
+ .ops = &rcar_gen2_pci_ops,
+ .probe = rcar_gen2_pci_probe,
+ .of_to_plat = rcar_gen2_pci_of_to_plat,
+ .priv_auto = sizeof(struct rcar_gen2_pci_priv),
+};
diff --git a/roms/u-boot/drivers/pci/pci-rcar-gen3.c b/roms/u-boot/drivers/pci/pci-rcar-gen3.c
new file mode 100644
index 000000000..34a561ef8
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci-rcar-gen3.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RCar Gen3 PCIEC driver
+ *
+ * Copyright (C) 2018-2019 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on Linux PCIe driver for Renesas R-Car SoCs
+ * Copyright (C) 2014 Renesas Electronics Europe Ltd
+ *
+ * Based on:
+ * arch/sh/drivers/pci/pcie-sh7786.c
+ * arch/sh/drivers/pci/ops-sh7786.c
+ * Copyright (C) 2009 - 2011 Paul Mundt
+ *
+ * Author: Phil Edworthy <phil.edworthy@renesas.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <pci.h>
+#include <wait_bit.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+
+#define PCIECAR 0x000010
+#define PCIECCTLR 0x000018
+#define CONFIG_SEND_ENABLE BIT(31)
+#define TYPE0 (0 << 8)
+#define TYPE1 BIT(8)
+#define PCIECDR 0x000020
+#define PCIEMSR 0x000028
+#define PCIEINTXR 0x000400
+#define PCIEPHYSR 0x0007f0
+#define PHYRDY BIT(0)
+#define PCIEMSITXR 0x000840
+
+/* Transfer control */
+#define PCIETCTLR 0x02000
+#define CFINIT 1
+#define PCIETSTR 0x02004
+#define DATA_LINK_ACTIVE 1
+#define PCIEERRFR 0x02020
+#define UNSUPPORTED_REQUEST BIT(4)
+#define PCIEMSIFR 0x02044
+#define PCIEMSIALR 0x02048
+#define MSIFE 1
+#define PCIEMSIAUR 0x0204c
+#define PCIEMSIIER 0x02050
+
+/* root port address */
+#define PCIEPRAR(x) (0x02080 + ((x) * 0x4))
+
+/* local address reg & mask */
+#define PCIELAR(x) (0x02200 + ((x) * 0x20))
+#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
+#define LAM_PREFETCH BIT(3)
+#define LAM_64BIT BIT(2)
+#define LAR_ENABLE BIT(1)
+
+/* PCIe address reg & mask */
+#define PCIEPALR(x) (0x03400 + ((x) * 0x20))
+#define PCIEPAUR(x) (0x03404 + ((x) * 0x20))
+#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
+#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
+#define PAR_ENABLE BIT(31)
+#define IO_SPACE BIT(8)
+
+/* Configuration */
+#define PCICONF(x) (0x010000 + ((x) * 0x4))
+#define PMCAP(x) (0x010040 + ((x) * 0x4))
+#define EXPCAP(x) (0x010070 + ((x) * 0x4))
+#define VCCAP(x) (0x010100 + ((x) * 0x4))
+
+/* link layer */
+#define IDSETR1 0x011004
+#define TLCTLR 0x011048
+#define MACSR 0x011054
+#define SPCHGFIN BIT(4)
+#define SPCHGFAIL BIT(6)
+#define SPCHGSUC BIT(7)
+#define LINK_SPEED (0xf << 16)
+#define LINK_SPEED_2_5GTS (1 << 16)
+#define LINK_SPEED_5_0GTS (2 << 16)
+#define MACCTLR 0x011058
+#define SPEED_CHANGE BIT(24)
+#define SCRAMBLE_DISABLE BIT(27)
+#define MACS2R 0x011078
+#define MACCGSPSETR 0x011084
+#define SPCNGRSN BIT(31)
+
+/* R-Car H1 PHY */
+#define H1_PCIEPHYADRR 0x04000c
+#define WRITE_CMD BIT(16)
+#define PHY_ACK BIT(24)
+#define RATE_POS 12
+#define LANE_POS 8
+#define ADR_POS 0
+#define H1_PCIEPHYDOUTR 0x040014
+
+/* R-Car Gen2 PHY */
+#define GEN2_PCIEPHYADDR 0x780
+#define GEN2_PCIEPHYDATA 0x784
+#define GEN2_PCIEPHYCTRL 0x78c
+
+#define INT_PCI_MSI_NR 32
+
+#define RCONF(x) (PCICONF(0) + (x))
+#define RPMCAP(x) (PMCAP(0) + (x))
+#define REXPCAP(x) (EXPCAP(0) + (x))
+#define RVCCAP(x) (VCCAP(0) + (x))
+
+#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
+#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
+#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
+
+#define RCAR_PCI_MAX_RESOURCES 4
+#define MAX_NR_INBOUND_MAPS 6
+
+enum {
+ RCAR_PCI_ACCESS_READ,
+ RCAR_PCI_ACCESS_WRITE,
+};
+
+struct rcar_gen3_pcie_priv {
+ fdt_addr_t regs;
+};
+
+static void rcar_rmw32(struct udevice *dev, int where, u32 mask, u32 data)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_plat(dev);
+ int shift = 8 * (where & 3);
+
+ clrsetbits_le32(priv->regs + (where & ~3),
+ mask << shift, data << shift);
+}
+
+static u32 rcar_read_conf(const struct udevice *dev, int where)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_plat(dev);
+ int shift = 8 * (where & 3);
+
+ return readl(priv->regs + (where & ~3)) >> shift;
+}
+
+static int rcar_pcie_config_access(const struct udevice *udev,
+ unsigned char access_type,
+ pci_dev_t bdf, int where, ulong *data)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_plat(udev);
+ u32 reg = where & ~3;
+
+ /* Root bus */
+ if (PCI_DEV(bdf) == 0) {
+ if (access_type == RCAR_PCI_ACCESS_READ)
+ *data = readl(priv->regs + PCICONF(where / 4));
+ else
+ writel(*data, priv->regs + PCICONF(where / 4));
+
+ return 0;
+ }
+
+ /* Clear errors */
+ clrbits_le32(priv->regs + PCIEERRFR, 0);
+
+ /* Set the PIO address */
+ writel((bdf << 8) | reg, priv->regs + PCIECAR);
+
+ /* Enable the configuration access */
+ if (!PCI_BUS(bdf))
+ writel(CONFIG_SEND_ENABLE | TYPE0, priv->regs + PCIECCTLR);
+ else
+ writel(CONFIG_SEND_ENABLE | TYPE1, priv->regs + PCIECCTLR);
+
+ /* Check for errors */
+ if (readl(priv->regs + PCIEERRFR) & UNSUPPORTED_REQUEST)
+ return -ENODEV;
+
+ /* Check for master and target aborts */
+ if (rcar_read_conf(udev, RCONF(PCI_STATUS)) &
+ (PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT))
+ return -ENODEV;
+
+ if (access_type == RCAR_PCI_ACCESS_READ)
+ *data = readl(priv->regs + PCIECDR);
+ else
+ writel(*data, priv->regs + PCIECDR);
+
+ /* Disable the configuration access */
+ writel(0, priv->regs + PCIECCTLR);
+
+ return 0;
+}
+
+static int rcar_gen3_pcie_addr_valid(pci_dev_t d, uint where)
+{
+ u32 slot;
+
+ if (PCI_BUS(d))
+ return -EINVAL;
+
+ if (PCI_FUNC(d))
+ return -EINVAL;
+
+ slot = PCI_DEV(d);
+ if (slot > 1)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int rcar_gen3_pcie_read_config(const struct udevice *dev, pci_dev_t bdf,
+ uint where, ulong *val,
+ enum pci_size_t size)
+{
+ ulong reg;
+ int ret;
+
+ ret = rcar_gen3_pcie_addr_valid(bdf, where);
+ if (ret) {
+ *val = pci_get_ff(size);
+ return 0;
+ }
+
+ ret = rcar_pcie_config_access(dev, RCAR_PCI_ACCESS_READ,
+ bdf, where, &reg);
+ if (ret != 0)
+ reg = 0xffffffffUL;
+
+ *val = pci_conv_32_to_size(reg, where, size);
+
+ return ret;
+}
+
+static int rcar_gen3_pcie_write_config(struct udevice *dev, pci_dev_t bdf,
+ uint where, ulong val,
+ enum pci_size_t size)
+{
+ ulong data;
+ int ret;
+
+ ret = rcar_gen3_pcie_addr_valid(bdf, where);
+ if (ret)
+ return ret;
+
+ data = pci_conv_32_to_size(val, where, size);
+
+ ret = rcar_pcie_config_access(dev, RCAR_PCI_ACCESS_WRITE,
+ bdf, where, &data);
+
+ return ret;
+}
+
+static int rcar_gen3_pcie_wait_for_phyrdy(struct udevice *dev)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_plat(dev);
+
+ return wait_for_bit_le32((void *)priv->regs + PCIEPHYSR, PHYRDY,
+ true, 50, false);
+}
+
+static int rcar_gen3_pcie_wait_for_dl(struct udevice *dev)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_plat(dev);
+
+ return wait_for_bit_le32((void *)priv->regs + PCIETSTR,
+ DATA_LINK_ACTIVE, true, 50, false);
+}
+
+static int rcar_gen3_pcie_hw_init(struct udevice *dev)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_plat(dev);
+ int ret;
+
+ /* Begin initialization */
+ writel(0, priv->regs + PCIETCTLR);
+
+ /* Set mode */
+ writel(1, priv->regs + PCIEMSR);
+
+ ret = rcar_gen3_pcie_wait_for_phyrdy(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Initial header for port config space is type 1, set the device
+ * class to match. Hardware takes care of propagating the IDSETR
+ * settings, so there is no need to bother with a quirk.
+ */
+ writel(PCI_CLASS_BRIDGE_PCI << 16, priv->regs + IDSETR1);
+
+ /*
+ * Setup Secondary Bus Number & Subordinate Bus Number, even though
+ * they aren't used, to avoid bridge being detected as broken.
+ */
+ rcar_rmw32(dev, RCONF(PCI_SECONDARY_BUS), 0xff, 1);
+ rcar_rmw32(dev, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1);
+
+ /* Initialize default capabilities. */
+ rcar_rmw32(dev, REXPCAP(0), 0xff, PCI_CAP_ID_EXP);
+ rcar_rmw32(dev, REXPCAP(PCI_EXP_FLAGS),
+ PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
+ rcar_rmw32(dev, RCONF(PCI_HEADER_TYPE), 0x7f,
+ PCI_HEADER_TYPE_BRIDGE);
+
+ /* Enable data link layer active state reporting */
+ rcar_rmw32(dev, REXPCAP(PCI_EXP_LNKCAP),
+ PCI_EXP_LNKCAP_DLLLARC, PCI_EXP_LNKCAP_DLLLARC);
+
+ /* Write out the physical slot number = 0 */
+ rcar_rmw32(dev, REXPCAP(PCI_EXP_SLTCAP),
+ PCI_EXP_SLTCAP_PSN, 0);
+
+ /* Set the completion timer timeout to the maximum 50ms. */
+ rcar_rmw32(dev, TLCTLR + 1, 0x3f, 50);
+
+ /* Terminate list of capabilities (Next Capability Offset=0) */
+ rcar_rmw32(dev, RVCCAP(0), 0xfff00000, 0);
+
+ /* Finish initialization - establish a PCI Express link */
+ writel(CFINIT, priv->regs + PCIETCTLR);
+
+ return rcar_gen3_pcie_wait_for_dl(dev);
+}
+
+static int rcar_gen3_pcie_probe(struct udevice *dev)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_plat(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(dev);
+ struct clk pci_clk;
+ u32 mask;
+ int i, cnt, ret;
+
+ ret = clk_get_by_index(dev, 0, &pci_clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&pci_clk);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < hose->region_count; i++) {
+ if (hose->regions[i].flags != PCI_REGION_SYS_MEMORY)
+ continue;
+
+ if (hose->regions[i].phys_start == 0)
+ continue;
+
+ mask = (roundup_pow_of_two(hose->regions[i].size) - 1) & ~0xf;
+ mask |= LAR_ENABLE;
+ writel(rounddown_pow_of_two(hose->regions[i].phys_start),
+ priv->regs + PCIEPRAR(0));
+ writel(rounddown_pow_of_two(hose->regions[i].phys_start),
+ priv->regs + PCIELAR(0));
+ writel(mask, priv->regs + PCIELAMR(0));
+ break;
+ }
+
+ writel(0, priv->regs + PCIEPRAR(1));
+ writel(0, priv->regs + PCIELAR(1));
+ writel(0, priv->regs + PCIELAMR(1));
+
+ ret = rcar_gen3_pcie_hw_init(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0, cnt = 0; i < hose->region_count; i++) {
+ if (hose->regions[i].flags == PCI_REGION_SYS_MEMORY)
+ continue;
+
+ writel(0, priv->regs + PCIEPTCTLR(cnt));
+ writel((hose->regions[i].size - 1) & ~0x7f,
+ priv->regs + PCIEPAMR(cnt));
+ writel(upper_32_bits(hose->regions[i].phys_start),
+ priv->regs + PCIEPAUR(cnt));
+ writel(lower_32_bits(hose->regions[i].phys_start),
+ priv->regs + PCIEPALR(cnt));
+ mask = PAR_ENABLE;
+ if (hose->regions[i].flags == PCI_REGION_IO)
+ mask |= IO_SPACE;
+ writel(mask, priv->regs + PCIEPTCTLR(cnt));
+
+ cnt++;
+ }
+
+ return 0;
+}
+
+static int rcar_gen3_pcie_of_to_plat(struct udevice *dev)
+{
+ struct rcar_gen3_pcie_priv *priv = dev_get_plat(dev);
+
+ priv->regs = devfdt_get_addr_index(dev, 0);
+ if (!priv->regs)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct dm_pci_ops rcar_gen3_pcie_ops = {
+ .read_config = rcar_gen3_pcie_read_config,
+ .write_config = rcar_gen3_pcie_write_config,
+};
+
+static const struct udevice_id rcar_gen3_pcie_ids[] = {
+ { .compatible = "renesas,pcie-rcar-gen3" },
+ { }
+};
+
+U_BOOT_DRIVER(rcar_gen3_pcie) = {
+ .name = "rcar_gen3_pcie",
+ .id = UCLASS_PCI,
+ .of_match = rcar_gen3_pcie_ids,
+ .ops = &rcar_gen3_pcie_ops,
+ .probe = rcar_gen3_pcie_probe,
+ .of_to_plat = rcar_gen3_pcie_of_to_plat,
+ .plat_auto = sizeof(struct rcar_gen3_pcie_priv),
+};
diff --git a/roms/u-boot/drivers/pci/pci-uclass.c b/roms/u-boot/drivers/pci/pci-uclass.c
new file mode 100644
index 000000000..22a033e63
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci-uclass.c
@@ -0,0 +1,1870 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <init.h>
+#include <log.h>
+#include <malloc.h>
+#include <pci.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
+#include <asm/fsp/fsp_support.h>
+#endif
+#include <linux/delay.h>
+#include "pci_internal.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int pci_get_bus(int busnum, struct udevice **busp)
+{
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, busp);
+
+ /* Since buses may not be numbered yet try a little harder with bus 0 */
+ if (ret == -ENODEV) {
+ ret = uclass_first_device_err(UCLASS_PCI, busp);
+ if (ret)
+ return ret;
+ ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, busp);
+ }
+
+ return ret;
+}
+
+struct udevice *pci_get_controller(struct udevice *dev)
+{
+ while (device_is_on_pci_bus(dev))
+ dev = dev->parent;
+
+ return dev;
+}
+
+pci_dev_t dm_pci_get_bdf(const struct udevice *dev)
+{
+ struct pci_child_plat *pplat = dev_get_parent_plat(dev);
+ struct udevice *bus = dev->parent;
+
+ /*
+ * This error indicates that @dev is a device on an unprobed PCI bus.
+ * The bus likely has bus=seq == -1, so the PCI_ADD_BUS() macro below
+ * will produce a bad BDF>
+ *
+ * A common cause of this problem is that this function is called in the
+ * of_to_plat() method of @dev. Accessing the PCI bus in that
+ * method is not allowed, since it has not yet been probed. To fix this,
+ * move that access to the probe() method of @dev instead.
+ */
+ if (!device_active(bus))
+ log_err("PCI: Device '%s' on unprobed bus '%s'\n", dev->name,
+ bus->name);
+ return PCI_ADD_BUS(dev_seq(bus), pplat->devfn);
+}
+
+/**
+ * pci_get_bus_max() - returns the bus number of the last active bus
+ *
+ * @return last bus number, or -1 if no active buses
+ */
+static int pci_get_bus_max(void)
+{
+ struct udevice *bus;
+ struct uclass *uc;
+ int ret = -1;
+
+ ret = uclass_get(UCLASS_PCI, &uc);
+ uclass_foreach_dev(bus, uc) {
+ if (dev_seq(bus) > ret)
+ ret = dev_seq(bus);
+ }
+
+ debug("%s: ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int pci_last_busno(void)
+{
+ return pci_get_bus_max();
+}
+
+int pci_get_ff(enum pci_size_t size)
+{
+ switch (size) {
+ case PCI_SIZE_8:
+ return 0xff;
+ case PCI_SIZE_16:
+ return 0xffff;
+ default:
+ return 0xffffffff;
+ }
+}
+
+static void pci_dev_find_ofnode(struct udevice *bus, phys_addr_t bdf,
+ ofnode *rnode)
+{
+ struct fdt_pci_addr addr;
+ ofnode node;
+ int ret;
+
+ dev_for_each_subnode(node, bus) {
+ ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg",
+ &addr);
+ if (ret)
+ continue;
+
+ if (PCI_MASK_BUS(addr.phys_hi) != PCI_MASK_BUS(bdf))
+ continue;
+
+ *rnode = node;
+ break;
+ }
+};
+
+int pci_bus_find_devfn(const struct udevice *bus, pci_dev_t find_devfn,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ for (device_find_first_child(bus, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ struct pci_child_plat *pplat;
+
+ pplat = dev_get_parent_plat(dev);
+ if (pplat && pplat->devfn == find_devfn) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int dm_pci_bus_find_bdf(pci_dev_t bdf, struct udevice **devp)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = pci_get_bus(PCI_BUS(bdf), &bus);
+ if (ret)
+ return ret;
+ return pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), devp);
+}
+
+static int pci_device_matches_ids(struct udevice *dev,
+ struct pci_device_id *ids)
+{
+ struct pci_child_plat *pplat;
+ int i;
+
+ pplat = dev_get_parent_plat(dev);
+ if (!pplat)
+ return -EINVAL;
+ for (i = 0; ids[i].vendor != 0; i++) {
+ if (pplat->vendor == ids[i].vendor &&
+ pplat->device == ids[i].device)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+int pci_bus_find_devices(struct udevice *bus, struct pci_device_id *ids,
+ int *indexp, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ /* Scan all devices on this bus */
+ for (device_find_first_child(bus, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ if (pci_device_matches_ids(dev, ids) >= 0) {
+ if ((*indexp)-- <= 0) {
+ *devp = dev;
+ return 0;
+ }
+ }
+ }
+
+ return -ENODEV;
+}
+
+int pci_find_device_id(struct pci_device_id *ids, int index,
+ struct udevice **devp)
+{
+ struct udevice *bus;
+
+ /* Scan all known buses */
+ for (uclass_first_device(UCLASS_PCI, &bus);
+ bus;
+ uclass_next_device(&bus)) {
+ if (!pci_bus_find_devices(bus, ids, &index, devp))
+ return 0;
+ }
+ *devp = NULL;
+
+ return -ENODEV;
+}
+
+static int dm_pci_bus_find_device(struct udevice *bus, unsigned int vendor,
+ unsigned int device, int *indexp,
+ struct udevice **devp)
+{
+ struct pci_child_plat *pplat;
+ struct udevice *dev;
+
+ for (device_find_first_child(bus, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ pplat = dev_get_parent_plat(dev);
+ if (pplat->vendor == vendor && pplat->device == device) {
+ if (!(*indexp)--) {
+ *devp = dev;
+ return 0;
+ }
+ }
+ }
+
+ return -ENODEV;
+}
+
+int dm_pci_find_device(unsigned int vendor, unsigned int device, int index,
+ struct udevice **devp)
+{
+ struct udevice *bus;
+
+ /* Scan all known buses */
+ for (uclass_first_device(UCLASS_PCI, &bus);
+ bus;
+ uclass_next_device(&bus)) {
+ if (!dm_pci_bus_find_device(bus, vendor, device, &index, devp))
+ return device_probe(*devp);
+ }
+ *devp = NULL;
+
+ return -ENODEV;
+}
+
+int dm_pci_find_class(uint find_class, int index, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ /* Scan all known buses */
+ for (pci_find_first_device(&dev);
+ dev;
+ pci_find_next_device(&dev)) {
+ struct pci_child_plat *pplat = dev_get_parent_plat(dev);
+
+ if (pplat->class == find_class && !index--) {
+ *devp = dev;
+ return device_probe(*devp);
+ }
+ }
+ *devp = NULL;
+
+ return -ENODEV;
+}
+
+int pci_bus_write_config(struct udevice *bus, pci_dev_t bdf, int offset,
+ unsigned long value, enum pci_size_t size)
+{
+ struct dm_pci_ops *ops;
+
+ ops = pci_get_ops(bus);
+ if (!ops->write_config)
+ return -ENOSYS;
+ return ops->write_config(bus, bdf, offset, value, size);
+}
+
+int pci_bus_clrset_config32(struct udevice *bus, pci_dev_t bdf, int offset,
+ u32 clr, u32 set)
+{
+ ulong val;
+ int ret;
+
+ ret = pci_bus_read_config(bus, bdf, offset, &val, PCI_SIZE_32);
+ if (ret)
+ return ret;
+ val &= ~clr;
+ val |= set;
+
+ return pci_bus_write_config(bus, bdf, offset, val, PCI_SIZE_32);
+}
+
+int pci_write_config(pci_dev_t bdf, int offset, unsigned long value,
+ enum pci_size_t size)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = pci_get_bus(PCI_BUS(bdf), &bus);
+ if (ret)
+ return ret;
+
+ return pci_bus_write_config(bus, bdf, offset, value, size);
+}
+
+int dm_pci_write_config(struct udevice *dev, int offset, unsigned long value,
+ enum pci_size_t size)
+{
+ struct udevice *bus;
+
+ for (bus = dev; device_is_on_pci_bus(bus);)
+ bus = bus->parent;
+ return pci_bus_write_config(bus, dm_pci_get_bdf(dev), offset, value,
+ size);
+}
+
+int pci_write_config32(pci_dev_t bdf, int offset, u32 value)
+{
+ return pci_write_config(bdf, offset, value, PCI_SIZE_32);
+}
+
+int pci_write_config16(pci_dev_t bdf, int offset, u16 value)
+{
+ return pci_write_config(bdf, offset, value, PCI_SIZE_16);
+}
+
+int pci_write_config8(pci_dev_t bdf, int offset, u8 value)
+{
+ return pci_write_config(bdf, offset, value, PCI_SIZE_8);
+}
+
+int dm_pci_write_config8(struct udevice *dev, int offset, u8 value)
+{
+ return dm_pci_write_config(dev, offset, value, PCI_SIZE_8);
+}
+
+int dm_pci_write_config16(struct udevice *dev, int offset, u16 value)
+{
+ return dm_pci_write_config(dev, offset, value, PCI_SIZE_16);
+}
+
+int dm_pci_write_config32(struct udevice *dev, int offset, u32 value)
+{
+ return dm_pci_write_config(dev, offset, value, PCI_SIZE_32);
+}
+
+int pci_bus_read_config(const struct udevice *bus, pci_dev_t bdf, int offset,
+ unsigned long *valuep, enum pci_size_t size)
+{
+ struct dm_pci_ops *ops;
+
+ ops = pci_get_ops(bus);
+ if (!ops->read_config)
+ return -ENOSYS;
+ return ops->read_config(bus, bdf, offset, valuep, size);
+}
+
+int pci_read_config(pci_dev_t bdf, int offset, unsigned long *valuep,
+ enum pci_size_t size)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = pci_get_bus(PCI_BUS(bdf), &bus);
+ if (ret)
+ return ret;
+
+ return pci_bus_read_config(bus, bdf, offset, valuep, size);
+}
+
+int dm_pci_read_config(const struct udevice *dev, int offset,
+ unsigned long *valuep, enum pci_size_t size)
+{
+ const struct udevice *bus;
+
+ for (bus = dev; device_is_on_pci_bus(bus);)
+ bus = bus->parent;
+ return pci_bus_read_config(bus, dm_pci_get_bdf(dev), offset, valuep,
+ size);
+}
+
+int pci_read_config32(pci_dev_t bdf, int offset, u32 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_read_config(bdf, offset, &value, PCI_SIZE_32);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int pci_read_config16(pci_dev_t bdf, int offset, u16 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_read_config(bdf, offset, &value, PCI_SIZE_16);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int pci_read_config8(pci_dev_t bdf, int offset, u8 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_read_config(bdf, offset, &value, PCI_SIZE_8);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int dm_pci_read_config8(const struct udevice *dev, int offset, u8 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = dm_pci_read_config(dev, offset, &value, PCI_SIZE_8);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int dm_pci_read_config16(const struct udevice *dev, int offset, u16 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = dm_pci_read_config(dev, offset, &value, PCI_SIZE_16);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int dm_pci_read_config32(const struct udevice *dev, int offset, u32 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = dm_pci_read_config(dev, offset, &value, PCI_SIZE_32);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int dm_pci_clrset_config8(struct udevice *dev, int offset, u32 clr, u32 set)
+{
+ u8 val;
+ int ret;
+
+ ret = dm_pci_read_config8(dev, offset, &val);
+ if (ret)
+ return ret;
+ val &= ~clr;
+ val |= set;
+
+ return dm_pci_write_config8(dev, offset, val);
+}
+
+int dm_pci_clrset_config16(struct udevice *dev, int offset, u32 clr, u32 set)
+{
+ u16 val;
+ int ret;
+
+ ret = dm_pci_read_config16(dev, offset, &val);
+ if (ret)
+ return ret;
+ val &= ~clr;
+ val |= set;
+
+ return dm_pci_write_config16(dev, offset, val);
+}
+
+int dm_pci_clrset_config32(struct udevice *dev, int offset, u32 clr, u32 set)
+{
+ u32 val;
+ int ret;
+
+ ret = dm_pci_read_config32(dev, offset, &val);
+ if (ret)
+ return ret;
+ val &= ~clr;
+ val |= set;
+
+ return dm_pci_write_config32(dev, offset, val);
+}
+
+static void set_vga_bridge_bits(struct udevice *dev)
+{
+ struct udevice *parent = dev->parent;
+ u16 bc;
+
+ while (dev_seq(parent) != 0) {
+ dm_pci_read_config16(parent, PCI_BRIDGE_CONTROL, &bc);
+ bc |= PCI_BRIDGE_CTL_VGA;
+ dm_pci_write_config16(parent, PCI_BRIDGE_CONTROL, bc);
+ parent = parent->parent;
+ }
+}
+
+int pci_auto_config_devices(struct udevice *bus)
+{
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ struct pci_child_plat *pplat;
+ unsigned int sub_bus;
+ struct udevice *dev;
+ int ret;
+
+ sub_bus = dev_seq(bus);
+ debug("%s: start\n", __func__);
+ pciauto_config_init(hose);
+ for (ret = device_find_first_child(bus, &dev);
+ !ret && dev;
+ ret = device_find_next_child(&dev)) {
+ unsigned int max_bus;
+ int ret;
+
+ debug("%s: device %s\n", __func__, dev->name);
+ if (dev_has_ofnode(dev) &&
+ dev_read_bool(dev, "pci,no-autoconfig"))
+ continue;
+ ret = dm_pciauto_config_device(dev);
+ if (ret < 0)
+ return log_msg_ret("auto", ret);
+ max_bus = ret;
+ sub_bus = max(sub_bus, max_bus);
+
+ pplat = dev_get_parent_plat(dev);
+ if (pplat->class == (PCI_CLASS_DISPLAY_VGA << 8))
+ set_vga_bridge_bits(dev);
+ }
+ debug("%s: done\n", __func__);
+
+ return log_msg_ret("sub", sub_bus);
+}
+
+int pci_generic_mmap_write_config(
+ const struct udevice *bus,
+ int (*addr_f)(const struct udevice *bus, pci_dev_t bdf, uint offset,
+ void **addrp),
+ pci_dev_t bdf,
+ uint offset,
+ ulong value,
+ enum pci_size_t size)
+{
+ void *address;
+
+ if (addr_f(bus, bdf, offset, &address) < 0)
+ return 0;
+
+ switch (size) {
+ case PCI_SIZE_8:
+ writeb(value, address);
+ return 0;
+ case PCI_SIZE_16:
+ writew(value, address);
+ return 0;
+ case PCI_SIZE_32:
+ writel(value, address);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+int pci_generic_mmap_read_config(
+ const struct udevice *bus,
+ int (*addr_f)(const struct udevice *bus, pci_dev_t bdf, uint offset,
+ void **addrp),
+ pci_dev_t bdf,
+ uint offset,
+ ulong *valuep,
+ enum pci_size_t size)
+{
+ void *address;
+
+ if (addr_f(bus, bdf, offset, &address) < 0) {
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ switch (size) {
+ case PCI_SIZE_8:
+ *valuep = readb(address);
+ return 0;
+ case PCI_SIZE_16:
+ *valuep = readw(address);
+ return 0;
+ case PCI_SIZE_32:
+ *valuep = readl(address);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+int dm_pci_hose_probe_bus(struct udevice *bus)
+{
+ int sub_bus;
+ int ret;
+ int ea_pos;
+ u8 reg;
+
+ debug("%s\n", __func__);
+
+ ea_pos = dm_pci_find_capability(bus, PCI_CAP_ID_EA);
+ if (ea_pos) {
+ dm_pci_read_config8(bus, ea_pos + sizeof(u32) + sizeof(u8),
+ &reg);
+ sub_bus = reg;
+ } else {
+ sub_bus = pci_get_bus_max() + 1;
+ }
+ debug("%s: bus = %d/%s\n", __func__, sub_bus, bus->name);
+ dm_pciauto_prescan_setup_bridge(bus, sub_bus);
+
+ ret = device_probe(bus);
+ if (ret) {
+ debug("%s: Cannot probe bus %s: %d\n", __func__, bus->name,
+ ret);
+ return log_msg_ret("probe", ret);
+ }
+
+ if (!ea_pos)
+ sub_bus = pci_get_bus_max();
+
+ dm_pciauto_postscan_setup_bridge(bus, sub_bus);
+
+ return sub_bus;
+}
+
+/**
+ * pci_match_one_device - Tell if a PCI device structure has a matching
+ * PCI device id structure
+ * @id: single PCI device id structure to match
+ * @find: the PCI device id structure to match against
+ *
+ * Returns true if the finding pci_device_id structure matched or false if
+ * there is no match.
+ */
+static bool pci_match_one_id(const struct pci_device_id *id,
+ const struct pci_device_id *find)
+{
+ if ((id->vendor == PCI_ANY_ID || id->vendor == find->vendor) &&
+ (id->device == PCI_ANY_ID || id->device == find->device) &&
+ (id->subvendor == PCI_ANY_ID || id->subvendor == find->subvendor) &&
+ (id->subdevice == PCI_ANY_ID || id->subdevice == find->subdevice) &&
+ !((id->class ^ find->class) & id->class_mask))
+ return true;
+
+ return false;
+}
+
+/**
+ * pci_find_and_bind_driver() - Find and bind the right PCI driver
+ *
+ * This only looks at certain fields in the descriptor.
+ *
+ * @parent: Parent bus
+ * @find_id: Specification of the driver to find
+ * @bdf: Bus/device/function addreess - see PCI_BDF()
+ * @devp: Returns a pointer to the device created
+ * @return 0 if OK, -EPERM if the device is not needed before relocation and
+ * therefore was not created, other -ve value on error
+ */
+static int pci_find_and_bind_driver(struct udevice *parent,
+ struct pci_device_id *find_id,
+ pci_dev_t bdf, struct udevice **devp)
+{
+ struct pci_driver_entry *start, *entry;
+ ofnode node = ofnode_null();
+ const char *drv;
+ int n_ents;
+ int ret;
+ char name[30], *str;
+ bool bridge;
+
+ *devp = NULL;
+
+ debug("%s: Searching for driver: vendor=%x, device=%x\n", __func__,
+ find_id->vendor, find_id->device);
+
+ /* Determine optional OF node */
+ if (ofnode_valid(dev_ofnode(parent)))
+ pci_dev_find_ofnode(parent, bdf, &node);
+
+ if (ofnode_valid(node) && !ofnode_is_available(node)) {
+ debug("%s: Ignoring disabled device\n", __func__);
+ return log_msg_ret("dis", -EPERM);
+ }
+
+ start = ll_entry_start(struct pci_driver_entry, pci_driver_entry);
+ n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry);
+ for (entry = start; entry != start + n_ents; entry++) {
+ const struct pci_device_id *id;
+ struct udevice *dev;
+ const struct driver *drv;
+
+ for (id = entry->match;
+ id->vendor || id->subvendor || id->class_mask;
+ id++) {
+ if (!pci_match_one_id(id, find_id))
+ continue;
+
+ drv = entry->driver;
+
+ /*
+ * In the pre-relocation phase, we only bind devices
+ * whose driver has the DM_FLAG_PRE_RELOC set, to save
+ * precious memory space as on some platforms as that
+ * space is pretty limited (ie: using Cache As RAM).
+ */
+ if (!(gd->flags & GD_FLG_RELOC) &&
+ !(drv->flags & DM_FLAG_PRE_RELOC))
+ return log_msg_ret("pre", -EPERM);
+
+ /*
+ * We could pass the descriptor to the driver as
+ * plat (instead of NULL) and allow its bind()
+ * method to return -ENOENT if it doesn't support this
+ * device. That way we could continue the search to
+ * find another driver. For now this doesn't seem
+ * necesssary, so just bind the first match.
+ */
+ ret = device_bind(parent, drv, drv->name, NULL, node,
+ &dev);
+ if (ret)
+ goto error;
+ debug("%s: Match found: %s\n", __func__, drv->name);
+ dev->driver_data = id->driver_data;
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ bridge = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI;
+ /*
+ * In the pre-relocation phase, we only bind bridge devices to save
+ * precious memory space as on some platforms as that space is pretty
+ * limited (ie: using Cache As RAM).
+ */
+ if (!(gd->flags & GD_FLG_RELOC) && !bridge)
+ return log_msg_ret("notbr", -EPERM);
+
+ /* Bind a generic driver so that the device can be used */
+ sprintf(name, "pci_%x:%x.%x", dev_seq(parent), PCI_DEV(bdf),
+ PCI_FUNC(bdf));
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ drv = bridge ? "pci_bridge_drv" : "pci_generic_drv";
+
+ ret = device_bind_driver_to_node(parent, drv, str, node, devp);
+ if (ret) {
+ debug("%s: Failed to bind generic driver: %d\n", __func__, ret);
+ free(str);
+ return ret;
+ }
+ debug("%s: No match found: bound generic driver instead\n", __func__);
+
+ return 0;
+
+error:
+ debug("%s: No match found: error %d\n", __func__, ret);
+ return ret;
+}
+
+__weak extern void board_pci_fixup_dev(struct udevice *bus, struct udevice *dev)
+{
+}
+
+int pci_bind_bus_devices(struct udevice *bus)
+{
+ ulong vendor, device;
+ ulong header_type;
+ pci_dev_t bdf, end;
+ bool found_multi;
+ int ari_off;
+ int ret;
+
+ found_multi = false;
+ end = PCI_BDF(dev_seq(bus), PCI_MAX_PCI_DEVICES - 1,
+ PCI_MAX_PCI_FUNCTIONS - 1);
+ for (bdf = PCI_BDF(dev_seq(bus), 0, 0); bdf <= end;
+ bdf += PCI_BDF(0, 0, 1)) {
+ struct pci_child_plat *pplat;
+ struct udevice *dev;
+ ulong class;
+
+ if (!PCI_FUNC(bdf))
+ found_multi = false;
+ if (PCI_FUNC(bdf) && !found_multi)
+ continue;
+
+ /* Check only the first access, we don't expect problems */
+ ret = pci_bus_read_config(bus, bdf, PCI_VENDOR_ID, &vendor,
+ PCI_SIZE_16);
+ if (ret)
+ goto error;
+
+ if (vendor == 0xffff || vendor == 0x0000)
+ continue;
+
+ pci_bus_read_config(bus, bdf, PCI_HEADER_TYPE,
+ &header_type, PCI_SIZE_8);
+
+ if (!PCI_FUNC(bdf))
+ found_multi = header_type & 0x80;
+
+ debug("%s: bus %d/%s: found device %x, function %d", __func__,
+ dev_seq(bus), bus->name, PCI_DEV(bdf), PCI_FUNC(bdf));
+ pci_bus_read_config(bus, bdf, PCI_DEVICE_ID, &device,
+ PCI_SIZE_16);
+ pci_bus_read_config(bus, bdf, PCI_CLASS_REVISION, &class,
+ PCI_SIZE_32);
+ class >>= 8;
+
+ /* Find this device in the device tree */
+ ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), &dev);
+ debug(": find ret=%d\n", ret);
+
+ /* If nothing in the device tree, bind a device */
+ if (ret == -ENODEV) {
+ struct pci_device_id find_id;
+ ulong val;
+
+ memset(&find_id, '\0', sizeof(find_id));
+ find_id.vendor = vendor;
+ find_id.device = device;
+ find_id.class = class;
+ if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) {
+ pci_bus_read_config(bus, bdf,
+ PCI_SUBSYSTEM_VENDOR_ID,
+ &val, PCI_SIZE_32);
+ find_id.subvendor = val & 0xffff;
+ find_id.subdevice = val >> 16;
+ }
+ ret = pci_find_and_bind_driver(bus, &find_id, bdf,
+ &dev);
+ }
+ if (ret == -EPERM)
+ continue;
+ else if (ret)
+ return ret;
+
+ /* Update the platform data */
+ pplat = dev_get_parent_plat(dev);
+ pplat->devfn = PCI_MASK_BUS(bdf);
+ pplat->vendor = vendor;
+ pplat->device = device;
+ pplat->class = class;
+
+ if (IS_ENABLED(CONFIG_PCI_ARID)) {
+ ari_off = dm_pci_find_ext_capability(dev,
+ PCI_EXT_CAP_ID_ARI);
+ if (ari_off) {
+ u16 ari_cap;
+
+ /*
+ * Read Next Function number in ARI Cap
+ * Register
+ */
+ dm_pci_read_config16(dev, ari_off + 4,
+ &ari_cap);
+ /*
+ * Update next scan on this function number,
+ * subtract 1 in BDF to satisfy loop increment.
+ */
+ if (ari_cap & 0xff00) {
+ bdf = PCI_BDF(PCI_BUS(bdf),
+ PCI_DEV(ari_cap),
+ PCI_FUNC(ari_cap));
+ bdf = bdf - 0x100;
+ }
+ }
+ }
+
+ board_pci_fixup_dev(bus, dev);
+ }
+
+ return 0;
+error:
+ printf("Cannot read bus configuration: %d\n", ret);
+
+ return ret;
+}
+
+static void decode_regions(struct pci_controller *hose, ofnode parent_node,
+ ofnode node)
+{
+ int pci_addr_cells, addr_cells, size_cells;
+ int cells_per_record;
+ struct bd_info *bd;
+ const u32 *prop;
+ int max_regions;
+ int len;
+ int i;
+
+ prop = ofnode_get_property(node, "ranges", &len);
+ if (!prop) {
+ debug("%s: Cannot decode regions\n", __func__);
+ return;
+ }
+
+ pci_addr_cells = ofnode_read_simple_addr_cells(node);
+ addr_cells = ofnode_read_simple_addr_cells(parent_node);
+ size_cells = ofnode_read_simple_size_cells(node);
+
+ /* PCI addresses are always 3-cells */
+ len /= sizeof(u32);
+ cells_per_record = pci_addr_cells + addr_cells + size_cells;
+ hose->region_count = 0;
+ debug("%s: len=%d, cells_per_record=%d\n", __func__, len,
+ cells_per_record);
+
+ /* Dynamically allocate the regions array */
+ max_regions = len / cells_per_record + CONFIG_NR_DRAM_BANKS;
+ hose->regions = (struct pci_region *)
+ calloc(1, max_regions * sizeof(struct pci_region));
+
+ for (i = 0; i < max_regions; i++, len -= cells_per_record) {
+ u64 pci_addr, addr, size;
+ int space_code;
+ u32 flags;
+ int type;
+ int pos;
+
+ if (len < cells_per_record)
+ break;
+ flags = fdt32_to_cpu(prop[0]);
+ space_code = (flags >> 24) & 3;
+ pci_addr = fdtdec_get_number(prop + 1, 2);
+ prop += pci_addr_cells;
+ addr = fdtdec_get_number(prop, addr_cells);
+ prop += addr_cells;
+ size = fdtdec_get_number(prop, size_cells);
+ prop += size_cells;
+ debug("%s: region %d, pci_addr=%llx, addr=%llx, size=%llx, space_code=%d\n",
+ __func__, hose->region_count, pci_addr, addr, size, space_code);
+ if (space_code & 2) {
+ type = flags & (1U << 30) ? PCI_REGION_PREFETCH :
+ PCI_REGION_MEM;
+ } else if (space_code & 1) {
+ type = PCI_REGION_IO;
+ } else {
+ continue;
+ }
+
+ if (!IS_ENABLED(CONFIG_SYS_PCI_64BIT) &&
+ type == PCI_REGION_MEM && upper_32_bits(pci_addr)) {
+ debug(" - beyond the 32-bit boundary, ignoring\n");
+ continue;
+ }
+
+ pos = -1;
+ if (!IS_ENABLED(CONFIG_PCI_REGION_MULTI_ENTRY)) {
+ for (i = 0; i < hose->region_count; i++) {
+ if (hose->regions[i].flags == type)
+ pos = i;
+ }
+ }
+
+ if (pos == -1)
+ pos = hose->region_count++;
+ debug(" - type=%d, pos=%d\n", type, pos);
+ pci_set_region(hose->regions + pos, pci_addr, addr, size, type);
+ }
+
+ /* Add a region for our local memory */
+ bd = gd->bd;
+ if (!bd)
+ return;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
+ if (bd->bi_dram[i].size) {
+ pci_set_region(hose->regions + hose->region_count++,
+ bd->bi_dram[i].start,
+ bd->bi_dram[i].start,
+ bd->bi_dram[i].size,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+ }
+ }
+
+ return;
+}
+
+static int pci_uclass_pre_probe(struct udevice *bus)
+{
+ struct pci_controller *hose;
+ struct uclass *uc;
+ int ret;
+
+ debug("%s, bus=%d/%s, parent=%s\n", __func__, dev_seq(bus), bus->name,
+ bus->parent->name);
+ hose = dev_get_uclass_priv(bus);
+
+ /*
+ * Set the sequence number, if device_bind() doesn't. We want control
+ * of this so that numbers are allocated as devices are probed. That
+ * ensures that sub-bus numbered is correct (sub-buses must get numbers
+ * higher than their parents)
+ */
+ if (dev_seq(bus) == -1) {
+ ret = uclass_get(UCLASS_PCI, &uc);
+ if (ret)
+ return ret;
+ bus->seq_ = uclass_find_next_free_seq(uc);
+ }
+
+ /* For bridges, use the top-level PCI controller */
+ if (!device_is_on_pci_bus(bus)) {
+ hose->ctlr = bus;
+ decode_regions(hose, dev_ofnode(bus->parent), dev_ofnode(bus));
+ } else {
+ struct pci_controller *parent_hose;
+
+ parent_hose = dev_get_uclass_priv(bus->parent);
+ hose->ctlr = parent_hose->bus;
+ }
+
+ hose->bus = bus;
+ hose->first_busno = dev_seq(bus);
+ hose->last_busno = dev_seq(bus);
+ if (dev_has_ofnode(bus)) {
+ hose->skip_auto_config_until_reloc =
+ dev_read_bool(bus,
+ "u-boot,skip-auto-config-until-reloc");
+ }
+
+ return 0;
+}
+
+static int pci_uclass_post_probe(struct udevice *bus)
+{
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ int ret;
+
+ debug("%s: probing bus %d\n", __func__, dev_seq(bus));
+ ret = pci_bind_bus_devices(bus);
+ if (ret)
+ return log_msg_ret("bind", ret);
+
+ if (CONFIG_IS_ENABLED(PCI_PNP) && ll_boot_init() &&
+ (!hose->skip_auto_config_until_reloc ||
+ (gd->flags & GD_FLG_RELOC))) {
+ ret = pci_auto_config_devices(bus);
+ if (ret < 0)
+ return log_msg_ret("cfg", ret);
+ }
+
+#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
+ /*
+ * Per Intel FSP specification, we should call FSP notify API to
+ * inform FSP that PCI enumeration has been done so that FSP will
+ * do any necessary initialization as required by the chipset's
+ * BIOS Writer's Guide (BWG).
+ *
+ * Unfortunately we have to put this call here as with driver model,
+ * the enumeration is all done on a lazy basis as needed, so until
+ * something is touched on PCI it won't happen.
+ *
+ * Note we only call this 1) after U-Boot is relocated, and 2)
+ * root bus has finished probing.
+ */
+ if ((gd->flags & GD_FLG_RELOC) && dev_seq(bus) == 0 && ll_boot_init()) {
+ ret = fsp_init_phase_pci();
+ if (ret)
+ return log_msg_ret("fsp", ret);
+ }
+#endif
+
+ return 0;
+}
+
+static int pci_uclass_child_post_bind(struct udevice *dev)
+{
+ struct pci_child_plat *pplat;
+
+ if (!dev_has_ofnode(dev))
+ return 0;
+
+ pplat = dev_get_parent_plat(dev);
+
+ /* Extract vendor id and device id if available */
+ ofnode_read_pci_vendev(dev_ofnode(dev), &pplat->vendor, &pplat->device);
+
+ /* Extract the devfn from fdt_pci_addr */
+ pplat->devfn = pci_get_devfn(dev);
+
+ return 0;
+}
+
+static int pci_bridge_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+
+ return pci_bus_read_config(hose->ctlr, bdf, offset, valuep, size);
+}
+
+static int pci_bridge_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+
+ return pci_bus_write_config(hose->ctlr, bdf, offset, value, size);
+}
+
+static int skip_to_next_device(struct udevice *bus, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret = 0;
+
+ /*
+ * Scan through all the PCI controllers. On x86 there will only be one
+ * but that is not necessarily true on other hardware.
+ */
+ do {
+ device_find_first_child(bus, &dev);
+ if (dev) {
+ *devp = dev;
+ return 0;
+ }
+ ret = uclass_next_device(&bus);
+ if (ret)
+ return ret;
+ } while (bus);
+
+ return 0;
+}
+
+int pci_find_next_device(struct udevice **devp)
+{
+ struct udevice *child = *devp;
+ struct udevice *bus = child->parent;
+ int ret;
+
+ /* First try all the siblings */
+ *devp = NULL;
+ while (child) {
+ device_find_next_child(&child);
+ if (child) {
+ *devp = child;
+ return 0;
+ }
+ }
+
+ /* We ran out of siblings. Try the next bus */
+ ret = uclass_next_device(&bus);
+ if (ret)
+ return ret;
+
+ return bus ? skip_to_next_device(bus, devp) : 0;
+}
+
+int pci_find_first_device(struct udevice **devp)
+{
+ struct udevice *bus;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_first_device(UCLASS_PCI, &bus);
+ if (ret)
+ return ret;
+
+ return skip_to_next_device(bus, devp);
+}
+
+ulong pci_conv_32_to_size(ulong value, uint offset, enum pci_size_t size)
+{
+ switch (size) {
+ case PCI_SIZE_8:
+ return (value >> ((offset & 3) * 8)) & 0xff;
+ case PCI_SIZE_16:
+ return (value >> ((offset & 2) * 8)) & 0xffff;
+ default:
+ return value;
+ }
+}
+
+ulong pci_conv_size_to_32(ulong old, ulong value, uint offset,
+ enum pci_size_t size)
+{
+ uint off_mask;
+ uint val_mask, shift;
+ ulong ldata, mask;
+
+ switch (size) {
+ case PCI_SIZE_8:
+ off_mask = 3;
+ val_mask = 0xff;
+ break;
+ case PCI_SIZE_16:
+ off_mask = 2;
+ val_mask = 0xffff;
+ break;
+ default:
+ return value;
+ }
+ shift = (offset & off_mask) * 8;
+ ldata = (value & val_mask) << shift;
+ mask = val_mask << shift;
+ value = (old & ~mask) | ldata;
+
+ return value;
+}
+
+int pci_get_dma_regions(struct udevice *dev, struct pci_region *memp, int index)
+{
+ int pci_addr_cells, addr_cells, size_cells;
+ int cells_per_record;
+ const u32 *prop;
+ int len;
+ int i = 0;
+
+ prop = ofnode_get_property(dev_ofnode(dev), "dma-ranges", &len);
+ if (!prop) {
+ log_err("PCI: Device '%s': Cannot decode dma-ranges\n",
+ dev->name);
+ return -EINVAL;
+ }
+
+ pci_addr_cells = ofnode_read_simple_addr_cells(dev_ofnode(dev));
+ addr_cells = ofnode_read_simple_addr_cells(dev_ofnode(dev->parent));
+ size_cells = ofnode_read_simple_size_cells(dev_ofnode(dev));
+
+ /* PCI addresses are always 3-cells */
+ len /= sizeof(u32);
+ cells_per_record = pci_addr_cells + addr_cells + size_cells;
+ debug("%s: len=%d, cells_per_record=%d\n", __func__, len,
+ cells_per_record);
+
+ while (len) {
+ memp->bus_start = fdtdec_get_number(prop + 1, 2);
+ prop += pci_addr_cells;
+ memp->phys_start = fdtdec_get_number(prop, addr_cells);
+ prop += addr_cells;
+ memp->size = fdtdec_get_number(prop, size_cells);
+ prop += size_cells;
+
+ if (i == index)
+ return 0;
+ i++;
+ len -= cells_per_record;
+ }
+
+ return -EINVAL;
+}
+
+int pci_get_regions(struct udevice *dev, struct pci_region **iop,
+ struct pci_region **memp, struct pci_region **prefp)
+{
+ struct udevice *bus = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ int i;
+
+ *iop = NULL;
+ *memp = NULL;
+ *prefp = NULL;
+ for (i = 0; i < hose->region_count; i++) {
+ switch (hose->regions[i].flags) {
+ case PCI_REGION_IO:
+ if (!*iop || (*iop)->size < hose->regions[i].size)
+ *iop = hose->regions + i;
+ break;
+ case PCI_REGION_MEM:
+ if (!*memp || (*memp)->size < hose->regions[i].size)
+ *memp = hose->regions + i;
+ break;
+ case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
+ if (!*prefp || (*prefp)->size < hose->regions[i].size)
+ *prefp = hose->regions + i;
+ break;
+ }
+ }
+
+ return (*iop != NULL) + (*memp != NULL) + (*prefp != NULL);
+}
+
+u32 dm_pci_read_bar32(const struct udevice *dev, int barnum)
+{
+ u32 addr;
+ int bar;
+
+ bar = PCI_BASE_ADDRESS_0 + barnum * 4;
+ dm_pci_read_config32(dev, bar, &addr);
+
+ /*
+ * If we get an invalid address, return this so that comparisons with
+ * FDT_ADDR_T_NONE work correctly
+ */
+ if (addr == 0xffffffff)
+ return addr;
+ else if (addr & PCI_BASE_ADDRESS_SPACE_IO)
+ return addr & PCI_BASE_ADDRESS_IO_MASK;
+ else
+ return addr & PCI_BASE_ADDRESS_MEM_MASK;
+}
+
+void dm_pci_write_bar32(struct udevice *dev, int barnum, u32 addr)
+{
+ int bar;
+
+ bar = PCI_BASE_ADDRESS_0 + barnum * 4;
+ dm_pci_write_config32(dev, bar, addr);
+}
+
+static int _dm_pci_bus_to_phys(struct udevice *ctlr,
+ pci_addr_t bus_addr, unsigned long flags,
+ unsigned long skip_mask, phys_addr_t *pa)
+{
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ struct pci_region *res;
+ int i;
+
+ if (hose->region_count == 0) {
+ *pa = bus_addr;
+ return 0;
+ }
+
+ for (i = 0; i < hose->region_count; i++) {
+ res = &hose->regions[i];
+
+ if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ continue;
+
+ if (res->flags & skip_mask)
+ continue;
+
+ if (bus_addr >= res->bus_start &&
+ (bus_addr - res->bus_start) < res->size) {
+ *pa = (bus_addr - res->bus_start + res->phys_start);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t bus_addr,
+ unsigned long flags)
+{
+ phys_addr_t phys_addr = 0;
+ struct udevice *ctlr;
+ int ret;
+
+ /* The root controller has the region information */
+ ctlr = pci_get_controller(dev);
+
+ /*
+ * if PCI_REGION_MEM is set we do a two pass search with preference
+ * on matches that don't have PCI_REGION_SYS_MEMORY set
+ */
+ if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
+ ret = _dm_pci_bus_to_phys(ctlr, bus_addr,
+ flags, PCI_REGION_SYS_MEMORY,
+ &phys_addr);
+ if (!ret)
+ return phys_addr;
+ }
+
+ ret = _dm_pci_bus_to_phys(ctlr, bus_addr, flags, 0, &phys_addr);
+
+ if (ret)
+ puts("pci_hose_bus_to_phys: invalid physical address\n");
+
+ return phys_addr;
+}
+
+int _dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr,
+ unsigned long flags, unsigned long skip_mask,
+ pci_addr_t *ba)
+{
+ struct pci_region *res;
+ struct udevice *ctlr;
+ pci_addr_t bus_addr;
+ int i;
+ struct pci_controller *hose;
+
+ /* The root controller has the region information */
+ ctlr = pci_get_controller(dev);
+ hose = dev_get_uclass_priv(ctlr);
+
+ if (hose->region_count == 0) {
+ *ba = phys_addr;
+ return 0;
+ }
+
+ for (i = 0; i < hose->region_count; i++) {
+ res = &hose->regions[i];
+
+ if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ continue;
+
+ if (res->flags & skip_mask)
+ continue;
+
+ bus_addr = phys_addr - res->phys_start + res->bus_start;
+
+ if (bus_addr >= res->bus_start &&
+ (bus_addr - res->bus_start) < res->size) {
+ *ba = bus_addr;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr,
+ unsigned long flags)
+{
+ pci_addr_t bus_addr = 0;
+ int ret;
+
+ /*
+ * if PCI_REGION_MEM is set we do a two pass search with preference
+ * on matches that don't have PCI_REGION_SYS_MEMORY set
+ */
+ if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
+ ret = _dm_pci_phys_to_bus(dev, phys_addr, flags,
+ PCI_REGION_SYS_MEMORY, &bus_addr);
+ if (!ret)
+ return bus_addr;
+ }
+
+ ret = _dm_pci_phys_to_bus(dev, phys_addr, flags, 0, &bus_addr);
+
+ if (ret)
+ puts("pci_hose_phys_to_bus: invalid physical address\n");
+
+ return bus_addr;
+}
+
+static phys_addr_t dm_pci_map_ea_virt(struct udevice *dev, int ea_off,
+ struct pci_child_plat *pdata)
+{
+ phys_addr_t addr = 0;
+
+ /*
+ * In the case of a Virtual Function device using BAR
+ * base and size, add offset for VFn BAR(1, 2, 3...n)
+ */
+ if (pdata->is_virtfn) {
+ size_t sz;
+ u32 ea_entry;
+
+ /* MaxOffset, 1st DW */
+ dm_pci_read_config32(dev, ea_off + 8, &ea_entry);
+ sz = ea_entry & PCI_EA_FIELD_MASK;
+ /* Fill up lower 2 bits */
+ sz |= (~PCI_EA_FIELD_MASK);
+
+ if (ea_entry & PCI_EA_IS_64) {
+ /* MaxOffset 2nd DW */
+ dm_pci_read_config32(dev, ea_off + 16, &ea_entry);
+ sz |= ((u64)ea_entry) << 32;
+ }
+
+ addr = (pdata->virtid - 1) * (sz + 1);
+ }
+
+ return addr;
+}
+
+static void *dm_pci_map_ea_bar(struct udevice *dev, int bar, int flags,
+ int ea_off, struct pci_child_plat *pdata)
+{
+ int ea_cnt, i, entry_size;
+ int bar_id = (bar - PCI_BASE_ADDRESS_0) >> 2;
+ u32 ea_entry;
+ phys_addr_t addr;
+
+ if (IS_ENABLED(CONFIG_PCI_SRIOV)) {
+ /*
+ * In the case of a Virtual Function device, device is
+ * Physical function, so pdata will point to required VF
+ * specific data.
+ */
+ if (pdata->is_virtfn)
+ bar_id += PCI_EA_BEI_VF_BAR0;
+ }
+
+ /* EA capability structure header */
+ dm_pci_read_config32(dev, ea_off, &ea_entry);
+ ea_cnt = (ea_entry >> 16) & PCI_EA_NUM_ENT_MASK;
+ ea_off += PCI_EA_FIRST_ENT;
+
+ for (i = 0; i < ea_cnt; i++, ea_off += entry_size) {
+ /* Entry header */
+ dm_pci_read_config32(dev, ea_off, &ea_entry);
+ entry_size = ((ea_entry & PCI_EA_ES) + 1) << 2;
+
+ if (((ea_entry & PCI_EA_BEI) >> 4) != bar_id)
+ continue;
+
+ /* Base address, 1st DW */
+ dm_pci_read_config32(dev, ea_off + 4, &ea_entry);
+ addr = ea_entry & PCI_EA_FIELD_MASK;
+ if (ea_entry & PCI_EA_IS_64) {
+ /* Base address, 2nd DW, skip over 4B MaxOffset */
+ dm_pci_read_config32(dev, ea_off + 12, &ea_entry);
+ addr |= ((u64)ea_entry) << 32;
+ }
+
+ if (IS_ENABLED(CONFIG_PCI_SRIOV))
+ addr += dm_pci_map_ea_virt(dev, ea_off, pdata);
+
+ /* size ignored for now */
+ return map_physmem(addr, 0, flags);
+ }
+
+ return 0;
+}
+
+void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
+{
+ struct pci_child_plat *pdata = dev_get_parent_plat(dev);
+ struct udevice *udev = dev;
+ pci_addr_t pci_bus_addr;
+ u32 bar_response;
+ int ea_off;
+
+ if (IS_ENABLED(CONFIG_PCI_SRIOV)) {
+ /*
+ * In case of Virtual Function devices, use PF udevice
+ * as EA capability is defined in Physical Function
+ */
+ if (pdata->is_virtfn)
+ udev = pdata->pfdev;
+ }
+
+ /*
+ * if the function supports Enhanced Allocation use that instead of
+ * BARs
+ * Incase of virtual functions, pdata will help read VF BEI
+ * and EA entry size.
+ */
+ ea_off = dm_pci_find_capability(udev, PCI_CAP_ID_EA);
+ if (ea_off)
+ return dm_pci_map_ea_bar(udev, bar, flags, ea_off, pdata);
+
+ /* read BAR address */
+ dm_pci_read_config32(udev, bar, &bar_response);
+ pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
+
+ /*
+ * Pass "0" as the length argument to pci_bus_to_virt. The arg
+ * isn't actually used on any platform because U-Boot assumes a static
+ * linear mapping. In the future, this could read the BAR size
+ * and pass that as the size if needed.
+ */
+ return dm_pci_bus_to_virt(udev, pci_bus_addr, flags, 0, MAP_NOCACHE);
+}
+
+static int _dm_pci_find_next_capability(struct udevice *dev, u8 pos, int cap)
+{
+ int ttl = PCI_FIND_CAP_TTL;
+ u8 id;
+ u16 ent;
+
+ dm_pci_read_config8(dev, pos, &pos);
+
+ while (ttl--) {
+ if (pos < PCI_STD_HEADER_SIZEOF)
+ break;
+ pos &= ~3;
+ dm_pci_read_config16(dev, pos, &ent);
+
+ id = ent & 0xff;
+ if (id == 0xff)
+ break;
+ if (id == cap)
+ return pos;
+ pos = (ent >> 8);
+ }
+
+ return 0;
+}
+
+int dm_pci_find_next_capability(struct udevice *dev, u8 start, int cap)
+{
+ return _dm_pci_find_next_capability(dev, start + PCI_CAP_LIST_NEXT,
+ cap);
+}
+
+int dm_pci_find_capability(struct udevice *dev, int cap)
+{
+ u16 status;
+ u8 header_type;
+ u8 pos;
+
+ dm_pci_read_config16(dev, PCI_STATUS, &status);
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
+ if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
+ pos = PCI_CB_CAPABILITY_LIST;
+ else
+ pos = PCI_CAPABILITY_LIST;
+
+ return _dm_pci_find_next_capability(dev, pos, cap);
+}
+
+int dm_pci_find_next_ext_capability(struct udevice *dev, int start, int cap)
+{
+ u32 header;
+ int ttl;
+ int pos = PCI_CFG_SPACE_SIZE;
+
+ /* minimum 8 bytes per capability */
+ ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+
+ if (start)
+ pos = start;
+
+ dm_pci_read_config32(dev, pos, &header);
+ /*
+ * If we have no capabilities, this is indicated by cap ID,
+ * cap version and next pointer all being 0.
+ */
+ if (header == 0)
+ return 0;
+
+ while (ttl--) {
+ if (PCI_EXT_CAP_ID(header) == cap)
+ return pos;
+
+ pos = PCI_EXT_CAP_NEXT(header);
+ if (pos < PCI_CFG_SPACE_SIZE)
+ break;
+
+ dm_pci_read_config32(dev, pos, &header);
+ }
+
+ return 0;
+}
+
+int dm_pci_find_ext_capability(struct udevice *dev, int cap)
+{
+ return dm_pci_find_next_ext_capability(dev, 0, cap);
+}
+
+int dm_pci_flr(struct udevice *dev)
+{
+ int pcie_off;
+ u32 cap;
+
+ /* look for PCI Express Capability */
+ pcie_off = dm_pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pcie_off)
+ return -ENOENT;
+
+ /* check FLR capability */
+ dm_pci_read_config32(dev, pcie_off + PCI_EXP_DEVCAP, &cap);
+ if (!(cap & PCI_EXP_DEVCAP_FLR))
+ return -ENOENT;
+
+ dm_pci_clrset_config16(dev, pcie_off + PCI_EXP_DEVCTL, 0,
+ PCI_EXP_DEVCTL_BCR_FLR);
+
+ /* wait 100ms, per PCI spec */
+ mdelay(100);
+
+ return 0;
+}
+
+#if defined(CONFIG_PCI_SRIOV)
+int pci_sriov_init(struct udevice *pdev, int vf_en)
+{
+ u16 vendor, device;
+ struct udevice *bus;
+ struct udevice *dev;
+ pci_dev_t bdf;
+ u16 ctrl;
+ u16 num_vfs;
+ u16 total_vf;
+ u16 vf_offset;
+ u16 vf_stride;
+ int vf, ret;
+ int pos;
+
+ pos = dm_pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (!pos) {
+ debug("Error: SRIOV capability not found\n");
+ return -ENOENT;
+ }
+
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_CTRL, &ctrl);
+
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_TOTAL_VF, &total_vf);
+ if (vf_en > total_vf)
+ vf_en = total_vf;
+ dm_pci_write_config16(pdev, pos + PCI_SRIOV_NUM_VF, vf_en);
+
+ ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
+ dm_pci_write_config16(pdev, pos + PCI_SRIOV_CTRL, ctrl);
+
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_NUM_VF, &num_vfs);
+ if (num_vfs > vf_en)
+ num_vfs = vf_en;
+
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_VF_OFFSET, &vf_offset);
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_VF_STRIDE, &vf_stride);
+
+ dm_pci_read_config16(pdev, PCI_VENDOR_ID, &vendor);
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_VF_DID, &device);
+
+ bdf = dm_pci_get_bdf(pdev);
+
+ pci_get_bus(PCI_BUS(bdf), &bus);
+
+ if (!bus)
+ return -ENODEV;
+
+ bdf += PCI_BDF(0, 0, vf_offset);
+
+ for (vf = 0; vf < num_vfs; vf++) {
+ struct pci_child_plat *pplat;
+ ulong class;
+
+ pci_bus_read_config(bus, bdf, PCI_CLASS_DEVICE,
+ &class, PCI_SIZE_16);
+
+ debug("%s: bus %d/%s: found VF %x:%x\n", __func__,
+ dev_seq(bus), bus->name, PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ /* Find this device in the device tree */
+ ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), &dev);
+
+ if (ret == -ENODEV) {
+ struct pci_device_id find_id;
+
+ memset(&find_id, '\0', sizeof(find_id));
+ find_id.vendor = vendor;
+ find_id.device = device;
+ find_id.class = class;
+
+ ret = pci_find_and_bind_driver(bus, &find_id,
+ bdf, &dev);
+
+ if (ret)
+ return ret;
+ }
+
+ /* Update the platform data */
+ pplat = dev_get_parent_plat(dev);
+ pplat->devfn = PCI_MASK_BUS(bdf);
+ pplat->vendor = vendor;
+ pplat->device = device;
+ pplat->class = class;
+ pplat->is_virtfn = true;
+ pplat->pfdev = pdev;
+ pplat->virtid = vf * vf_stride + vf_offset;
+
+ debug("%s: bus %d/%s: found VF %x:%x %x:%x class %lx id %x\n",
+ __func__, dev_seq(dev), dev->name, PCI_DEV(bdf),
+ PCI_FUNC(bdf), vendor, device, class, pplat->virtid);
+ bdf += PCI_BDF(0, 0, vf_stride);
+ }
+
+ return 0;
+}
+
+int pci_sriov_get_totalvfs(struct udevice *pdev)
+{
+ u16 total_vf;
+ int pos;
+
+ pos = dm_pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (!pos) {
+ debug("Error: SRIOV capability not found\n");
+ return -ENOENT;
+ }
+
+ dm_pci_read_config16(pdev, pos + PCI_SRIOV_TOTAL_VF, &total_vf);
+
+ return total_vf;
+}
+#endif /* SRIOV */
+
+UCLASS_DRIVER(pci) = {
+ .id = UCLASS_PCI,
+ .name = "pci",
+ .flags = DM_UC_FLAG_SEQ_ALIAS | DM_UC_FLAG_NO_AUTO_SEQ,
+ .post_bind = dm_scan_fdt_dev,
+ .pre_probe = pci_uclass_pre_probe,
+ .post_probe = pci_uclass_post_probe,
+ .child_post_bind = pci_uclass_child_post_bind,
+ .per_device_auto = sizeof(struct pci_controller),
+ .per_child_plat_auto = sizeof(struct pci_child_plat),
+};
+
+static const struct dm_pci_ops pci_bridge_ops = {
+ .read_config = pci_bridge_read_config,
+ .write_config = pci_bridge_write_config,
+};
+
+static const struct udevice_id pci_bridge_ids[] = {
+ { .compatible = "pci-bridge" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_bridge_drv) = {
+ .name = "pci_bridge_drv",
+ .id = UCLASS_PCI,
+ .of_match = pci_bridge_ids,
+ .ops = &pci_bridge_ops,
+};
+
+UCLASS_DRIVER(pci_generic) = {
+ .id = UCLASS_PCI_GENERIC,
+ .name = "pci_generic",
+};
+
+static const struct udevice_id pci_generic_ids[] = {
+ { .compatible = "pci-generic" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_generic_drv) = {
+ .name = "pci_generic_drv",
+ .id = UCLASS_PCI_GENERIC,
+ .of_match = pci_generic_ids,
+};
+
+int pci_init(void)
+{
+ struct udevice *bus;
+
+ /*
+ * Enumerate all known controller devices. Enumeration has the side-
+ * effect of probing them, so PCIe devices will be enumerated too.
+ */
+ for (uclass_first_device_check(UCLASS_PCI, &bus);
+ bus;
+ uclass_next_device_check(&bus)) {
+ ;
+ }
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/pci/pci.c b/roms/u-boot/drivers/pci/pci.c
new file mode 100644
index 000000000..d8f923952
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci.c
@@ -0,0 +1,588 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002, 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+/*
+ * Old PCI routines
+ *
+ * Do not change this file. Instead, convert your board to use CONFIG_DM_PCI
+ * and change pci-uclass.c.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+
+#include <command.h>
+#include <env.h>
+#include <errno.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PCI_HOSE_OP(rw, size, type) \
+int pci_hose_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, \
+ int offset, type value) \
+{ \
+ return hose->rw##_##size(hose, dev, offset, value); \
+}
+
+PCI_HOSE_OP(read, byte, u8 *)
+PCI_HOSE_OP(read, word, u16 *)
+PCI_HOSE_OP(read, dword, u32 *)
+PCI_HOSE_OP(write, byte, u8)
+PCI_HOSE_OP(write, word, u16)
+PCI_HOSE_OP(write, dword, u32)
+
+#define PCI_OP(rw, size, type, error_code) \
+int pci_##rw##_config_##size(pci_dev_t dev, int offset, type value) \
+{ \
+ struct pci_controller *hose = pci_bus_to_hose(PCI_BUS(dev)); \
+ \
+ if (!hose) \
+ { \
+ error_code; \
+ return -1; \
+ } \
+ \
+ return pci_hose_##rw##_config_##size(hose, dev, offset, value); \
+}
+
+PCI_OP(read, byte, u8 *, *value = 0xff)
+PCI_OP(read, word, u16 *, *value = 0xffff)
+PCI_OP(read, dword, u32 *, *value = 0xffffffff)
+PCI_OP(write, byte, u8, )
+PCI_OP(write, word, u16, )
+PCI_OP(write, dword, u32, )
+
+#define PCI_READ_VIA_DWORD_OP(size, type, off_mask) \
+int pci_hose_read_config_##size##_via_dword(struct pci_controller *hose,\
+ pci_dev_t dev, \
+ int offset, type val) \
+{ \
+ u32 val32; \
+ \
+ if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0) { \
+ *val = -1; \
+ return -1; \
+ } \
+ \
+ *val = (val32 >> ((offset & (int)off_mask) * 8)); \
+ \
+ return 0; \
+}
+
+#define PCI_WRITE_VIA_DWORD_OP(size, type, off_mask, val_mask) \
+int pci_hose_write_config_##size##_via_dword(struct pci_controller *hose,\
+ pci_dev_t dev, \
+ int offset, type val) \
+{ \
+ u32 val32, mask, ldata, shift; \
+ \
+ if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0)\
+ return -1; \
+ \
+ shift = ((offset & (int)off_mask) * 8); \
+ ldata = (((unsigned long)val) & val_mask) << shift; \
+ mask = val_mask << shift; \
+ val32 = (val32 & ~mask) | ldata; \
+ \
+ if (pci_hose_write_config_dword(hose, dev, offset & 0xfc, val32) < 0)\
+ return -1; \
+ \
+ return 0; \
+}
+
+PCI_READ_VIA_DWORD_OP(byte, u8 *, 0x03)
+PCI_READ_VIA_DWORD_OP(word, u16 *, 0x02)
+PCI_WRITE_VIA_DWORD_OP(byte, u8, 0x03, 0x000000ff)
+PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff)
+
+/*
+ *
+ */
+
+static struct pci_controller* hose_head;
+
+struct pci_controller *pci_get_hose_head(void)
+{
+ if (gd->hose)
+ return gd->hose;
+
+ return hose_head;
+}
+
+void pci_register_hose(struct pci_controller* hose)
+{
+ struct pci_controller **phose = &hose_head;
+
+ while(*phose)
+ phose = &(*phose)->next;
+
+ hose->next = NULL;
+
+ *phose = hose;
+}
+
+struct pci_controller *pci_bus_to_hose(int bus)
+{
+ struct pci_controller *hose;
+
+ for (hose = pci_get_hose_head(); hose; hose = hose->next) {
+ if (bus >= hose->first_busno && bus <= hose->last_busno)
+ return hose;
+ }
+
+ printf("pci_bus_to_hose() failed\n");
+ return NULL;
+}
+
+struct pci_controller *find_hose_by_cfg_addr(void *cfg_addr)
+{
+ struct pci_controller *hose;
+
+ for (hose = pci_get_hose_head(); hose; hose = hose->next) {
+ if (hose->cfg_addr == cfg_addr)
+ return hose;
+ }
+
+ return NULL;
+}
+
+int pci_last_busno(void)
+{
+ struct pci_controller *hose = pci_get_hose_head();
+
+ if (!hose)
+ return -1;
+
+ while (hose->next)
+ hose = hose->next;
+
+ return hose->last_busno;
+}
+
+pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
+{
+ struct pci_controller * hose;
+ pci_dev_t bdf;
+ int bus;
+
+ for (hose = pci_get_hose_head(); hose; hose = hose->next) {
+ for (bus = hose->first_busno; bus <= hose->last_busno; bus++) {
+ bdf = pci_hose_find_devices(hose, bus, ids, &index);
+ if (bdf != -1)
+ return bdf;
+ }
+ }
+
+ return -1;
+}
+
+static int pci_hose_config_device(struct pci_controller *hose, pci_dev_t dev,
+ ulong io, pci_addr_t mem, ulong command)
+{
+ u32 bar_response;
+ unsigned int old_command;
+ pci_addr_t bar_value;
+ pci_size_t bar_size;
+ unsigned char pin;
+ int bar, found_mem64;
+
+ debug("PCI Config: I/O=0x%lx, Memory=0x%llx, Command=0x%lx\n", io,
+ (u64)mem, command);
+
+ pci_hose_write_config_dword(hose, dev, PCI_COMMAND, 0);
+
+ for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar += 4) {
+ pci_hose_write_config_dword(hose, dev, bar, 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar, &bar_response);
+
+ if (!bar_response)
+ continue;
+
+ found_mem64 = 0;
+
+ /* Check the BAR type and set our address mask */
+ if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+ bar_size = ~(bar_response & PCI_BASE_ADDRESS_IO_MASK) + 1;
+ /* round up region base address to a multiple of size */
+ io = ((io - 1) | (bar_size - 1)) + 1;
+ bar_value = io;
+ /* compute new region base address */
+ io = io + bar_size;
+ } else {
+ if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ u32 bar_response_upper;
+ u64 bar64;
+ pci_hose_write_config_dword(hose, dev, bar + 4,
+ 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar + 4,
+ &bar_response_upper);
+
+ bar64 = ((u64)bar_response_upper << 32) | bar_response;
+
+ bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+ found_mem64 = 1;
+ } else {
+ bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
+ }
+
+ /* round up region base address to multiple of size */
+ mem = ((mem - 1) | (bar_size - 1)) + 1;
+ bar_value = mem;
+ /* compute new region base address */
+ mem = mem + bar_size;
+ }
+
+ /* Write it out and update our limit */
+ pci_hose_write_config_dword (hose, dev, bar, (u32)bar_value);
+
+ if (found_mem64) {
+ bar += 4;
+#ifdef CONFIG_SYS_PCI_64BIT
+ pci_hose_write_config_dword(hose, dev, bar,
+ (u32)(bar_value >> 32));
+#else
+ pci_hose_write_config_dword(hose, dev, bar, 0x00000000);
+#endif
+ }
+ }
+
+ /* Configure Cache Line Size Register */
+ pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+ /* Configure Latency Timer */
+ pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+
+ /* Disable interrupt line, if device says it wants to use interrupts */
+ pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin != 0) {
+ pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE,
+ PCI_INTERRUPT_LINE_DISABLE);
+ }
+
+ pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &old_command);
+ pci_hose_write_config_dword(hose, dev, PCI_COMMAND,
+ (old_command & 0xffff0000) | command);
+
+ return 0;
+}
+
+/*
+ *
+ */
+
+struct pci_config_table *pci_find_config(struct pci_controller *hose,
+ unsigned short class,
+ unsigned int vendor,
+ unsigned int device,
+ unsigned int bus,
+ unsigned int dev,
+ unsigned int func)
+{
+ struct pci_config_table *table;
+
+ for (table = hose->config_table; table && table->vendor; table++) {
+ if ((table->vendor == PCI_ANY_ID || table->vendor == vendor) &&
+ (table->device == PCI_ANY_ID || table->device == device) &&
+ (table->class == PCI_ANY_ID || table->class == class) &&
+ (table->bus == PCI_ANY_ID || table->bus == bus) &&
+ (table->dev == PCI_ANY_ID || table->dev == dev) &&
+ (table->func == PCI_ANY_ID || table->func == func)) {
+ return table;
+ }
+ }
+
+ return NULL;
+}
+
+void pci_cfgfunc_config_device(struct pci_controller *hose,
+ pci_dev_t dev,
+ struct pci_config_table *entry)
+{
+ pci_hose_config_device(hose, dev, entry->priv[0], entry->priv[1],
+ entry->priv[2]);
+}
+
+void pci_cfgfunc_do_nothing(struct pci_controller *hose,
+ pci_dev_t dev, struct pci_config_table *entry)
+{
+}
+
+/*
+ * HJF: Changed this to return int. I think this is required
+ * to get the correct result when scanning bridges
+ */
+extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+__weak int pci_print_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ if (dev == PCI_BDF(hose->first_busno, 0, 0))
+ return 0;
+
+ return 1;
+}
+#endif /* CONFIG_PCI_SCAN_SHOW */
+
+int pci_hose_scan_bus(struct pci_controller *hose, int bus)
+{
+ unsigned int sub_bus, found_multi = 0;
+ unsigned short vendor, device, class;
+ unsigned char header_type;
+#ifndef CONFIG_PCI_PNP
+ struct pci_config_table *cfg;
+#endif
+ pci_dev_t dev;
+#ifdef CONFIG_PCI_SCAN_SHOW
+ static int indent = 0;
+#endif
+
+ sub_bus = bus;
+
+ for (dev = PCI_BDF(bus,0,0);
+ dev < PCI_BDF(bus, PCI_MAX_PCI_DEVICES - 1,
+ PCI_MAX_PCI_FUNCTIONS - 1);
+ dev += PCI_BDF(0, 0, 1)) {
+
+ if (pci_skip_dev(hose, dev))
+ continue;
+
+ if (PCI_FUNC(dev) && !found_multi)
+ continue;
+
+ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type);
+
+ pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor);
+
+ if (vendor == 0xffff || vendor == 0x0000)
+ continue;
+
+ if (!PCI_FUNC(dev))
+ found_multi = header_type & 0x80;
+
+ debug("PCI Scan: Found Bus %d, Device %d, Function %d\n",
+ PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
+
+ pci_hose_read_config_word(hose, dev, PCI_DEVICE_ID, &device);
+ pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
+
+#ifdef CONFIG_PCI_FIXUP_DEV
+ board_pci_fixup_dev(hose, dev, vendor, device, class);
+#endif
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ indent++;
+
+ /* Print leading space, including bus indentation */
+ printf("%*c", indent + 1, ' ');
+
+ if (pci_print_dev(hose, dev)) {
+ printf("%02x:%02x.%-*x - %04x:%04x - %s\n",
+ PCI_BUS(dev), PCI_DEV(dev), 6 - indent, PCI_FUNC(dev),
+ vendor, device, pci_class_str(class >> 8));
+ }
+#endif
+
+#ifdef CONFIG_PCI_PNP
+ sub_bus = max((unsigned int)pciauto_config_device(hose, dev),
+ sub_bus);
+#else
+ cfg = pci_find_config(hose, class, vendor, device,
+ PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
+ if (cfg) {
+ cfg->config_device(hose, dev, cfg);
+ sub_bus = max(sub_bus,
+ (unsigned int)hose->current_busno);
+ }
+#endif
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ indent--;
+#endif
+
+ if (hose->fixup_irq)
+ hose->fixup_irq(hose, dev);
+ }
+
+ return sub_bus;
+}
+
+int pci_hose_scan(struct pci_controller *hose)
+{
+#if defined(CONFIG_PCI_BOOTDELAY)
+ char *s;
+ int i;
+
+ if (!gd->pcidelay_done) {
+ /* wait "pcidelay" ms (if defined)... */
+ s = env_get("pcidelay");
+ if (s) {
+ int val = simple_strtoul(s, NULL, 10);
+ for (i = 0; i < val; i++)
+ udelay(1000);
+ }
+ gd->pcidelay_done = 1;
+ }
+#endif /* CONFIG_PCI_BOOTDELAY */
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ puts("PCI:\n");
+#endif
+
+ /*
+ * Start scan at current_busno.
+ * PCIe will start scan at first_busno+1.
+ */
+ /* For legacy support, ensure current >= first */
+ if (hose->first_busno > hose->current_busno)
+ hose->current_busno = hose->first_busno;
+#ifdef CONFIG_PCI_PNP
+ pciauto_config_init(hose);
+#endif
+ return pci_hose_scan_bus(hose, hose->current_busno);
+}
+
+int pci_init(void)
+{
+ hose_head = NULL;
+
+ /* allow env to disable pci init/enum */
+ if (env_get("pcidisable") != NULL)
+ return 0;
+
+ /* now call board specific pci_init()... */
+ pci_init_board();
+
+ return 0;
+}
+
+/* Returns the address of the requested capability structure within the
+ * device's PCI configuration space or 0 in case the device does not
+ * support it.
+ * */
+int pci_hose_find_capability(struct pci_controller *hose, pci_dev_t dev,
+ int cap)
+{
+ int pos;
+ u8 hdr_type;
+
+ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &hdr_type);
+
+ pos = pci_hose_find_cap_start(hose, dev, hdr_type & 0x7F);
+
+ if (pos)
+ pos = pci_find_cap(hose, dev, pos, cap);
+
+ return pos;
+}
+
+/* Find the header pointer to the Capabilities*/
+int pci_hose_find_cap_start(struct pci_controller *hose, pci_dev_t dev,
+ u8 hdr_type)
+{
+ u16 status;
+
+ pci_hose_read_config_word(hose, dev, PCI_STATUS, &status);
+
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ switch (hdr_type) {
+ case PCI_HEADER_TYPE_NORMAL:
+ case PCI_HEADER_TYPE_BRIDGE:
+ return PCI_CAPABILITY_LIST;
+ case PCI_HEADER_TYPE_CARDBUS:
+ return PCI_CB_CAPABILITY_LIST;
+ default:
+ return 0;
+ }
+}
+
+int pci_find_cap(struct pci_controller *hose, pci_dev_t dev, int pos, int cap)
+{
+ int ttl = PCI_FIND_CAP_TTL;
+ u8 id;
+ u8 next_pos;
+
+ while (ttl--) {
+ pci_hose_read_config_byte(hose, dev, pos, &next_pos);
+ if (next_pos < CAP_START_POS)
+ break;
+ next_pos &= ~3;
+ pos = (int) next_pos;
+ pci_hose_read_config_byte(hose, dev,
+ pos + PCI_CAP_LIST_ID, &id);
+ if (id == 0xff)
+ break;
+ if (id == cap)
+ return pos;
+ pos += PCI_CAP_LIST_NEXT;
+ }
+ return 0;
+}
+
+/**
+ * pci_find_next_ext_capability - Find an extended capability
+ *
+ * Returns the address of the next matching extended capability structure
+ * within the device's PCI configuration space or 0 if the device does
+ * not support it. Some capabilities can occur several times, e.g., the
+ * vendor-specific capability, and this provides a way to find them all.
+ */
+int pci_find_next_ext_capability(struct pci_controller *hose, pci_dev_t dev,
+ int start, int cap)
+{
+ u32 header;
+ int ttl, pos = PCI_CFG_SPACE_SIZE;
+
+ /* minimum 8 bytes per capability */
+ ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+
+ if (start)
+ pos = start;
+
+ pci_hose_read_config_dword(hose, dev, pos, &header);
+ if (header == 0xffffffff || header == 0)
+ return 0;
+
+ while (ttl-- > 0) {
+ if (PCI_EXT_CAP_ID(header) == cap && pos != start)
+ return pos;
+
+ pos = PCI_EXT_CAP_NEXT(header);
+ if (pos < PCI_CFG_SPACE_SIZE)
+ break;
+
+ pci_hose_read_config_dword(hose, dev, pos, &header);
+ if (header == 0xffffffff || header == 0)
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * pci_hose_find_ext_capability - Find an extended capability
+ *
+ * Returns the address of the requested extended capability structure
+ * within the device's PCI configuration space or 0 if the device does
+ * not support it.
+ */
+int pci_hose_find_ext_capability(struct pci_controller *hose, pci_dev_t dev,
+ int cap)
+{
+ return pci_find_next_ext_capability(hose, dev, 0, cap);
+}
diff --git a/roms/u-boot/drivers/pci/pci_auto.c b/roms/u-boot/drivers/pci/pci_auto.c
new file mode 100644
index 000000000..05663c72b
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_auto.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCI autoconfiguration library
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <pci.h>
+
+/* the user can define CONFIG_SYS_PCI_CACHE_LINE_SIZE to avoid problems */
+#ifndef CONFIG_SYS_PCI_CACHE_LINE_SIZE
+#define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8
+#endif
+
+static void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
+ struct pci_region *mem,
+ struct pci_region *prefetch,
+ struct pci_region *io)
+{
+ u32 bar_response;
+ pci_size_t bar_size;
+ u16 cmdstat = 0;
+ int bar, bar_nr = 0;
+ u8 header_type;
+ int rom_addr;
+ pci_addr_t bar_value;
+ struct pci_region *bar_res = NULL;
+ int found_mem64 = 0;
+ u16 class;
+
+ dm_pci_read_config16(dev, PCI_COMMAND, &cmdstat);
+ cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) |
+ PCI_COMMAND_MASTER;
+
+ for (bar = PCI_BASE_ADDRESS_0;
+ bar < PCI_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) {
+ int ret = 0;
+
+ /* Tickle the BAR and get the response */
+ dm_pci_write_config32(dev, bar, 0xffffffff);
+ dm_pci_read_config32(dev, bar, &bar_response);
+
+ /* If BAR is not implemented (or invalid) go to the next BAR */
+ if (!bar_response || bar_response == 0xffffffff)
+ continue;
+
+ found_mem64 = 0;
+
+ /* Check the BAR type and set our address mask */
+ if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+ bar_size = bar_response & PCI_BASE_ADDRESS_IO_MASK;
+ bar_size &= ~(bar_size - 1);
+
+ bar_res = io;
+
+ debug("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ",
+ bar_nr, (unsigned long long)bar_size);
+ } else {
+ if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ u32 bar_response_upper;
+ u64 bar64;
+
+ dm_pci_write_config32(dev, bar + 4, 0xffffffff);
+ dm_pci_read_config32(dev, bar + 4,
+ &bar_response_upper);
+
+ bar64 = ((u64)bar_response_upper << 32) |
+ bar_response;
+
+ bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK)
+ + 1;
+ found_mem64 = 1;
+ } else {
+ bar_size = (u32)(~(bar_response &
+ PCI_BASE_ADDRESS_MEM_MASK) + 1);
+ }
+
+ if (prefetch &&
+ (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH))
+ bar_res = prefetch;
+ else
+ bar_res = mem;
+
+ debug("PCI Autoconfig: BAR %d, %s%s, size=0x%llx, ",
+ bar_nr, bar_res == prefetch ? "Prf" : "Mem",
+ found_mem64 ? "64" : "",
+ (unsigned long long)bar_size);
+ }
+
+ ret = pciauto_region_allocate(bar_res, bar_size,
+ &bar_value, found_mem64);
+ if (ret)
+ printf("PCI: Failed autoconfig bar %x\n", bar);
+
+ if (!ret) {
+ /* Write it out and update our limit */
+ dm_pci_write_config32(dev, bar, (u32)bar_value);
+
+ if (found_mem64) {
+ bar += 4;
+#ifdef CONFIG_SYS_PCI_64BIT
+ dm_pci_write_config32(dev, bar,
+ (u32)(bar_value >> 32));
+#else
+ /*
+ * If we are a 64-bit decoder then increment to
+ * the upper 32 bits of the bar and force it to
+ * locate in the lower 4GB of memory.
+ */
+ dm_pci_write_config32(dev, bar, 0x00000000);
+#endif
+ }
+ }
+
+ cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ?
+ PCI_COMMAND_IO : PCI_COMMAND_MEMORY;
+
+ debug("\n");
+
+ bar_nr++;
+ }
+
+ /* Configure the expansion ROM address */
+ dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
+ header_type &= 0x7f;
+ if (header_type != PCI_HEADER_TYPE_CARDBUS) {
+ rom_addr = (header_type == PCI_HEADER_TYPE_NORMAL) ?
+ PCI_ROM_ADDRESS : PCI_ROM_ADDRESS1;
+ dm_pci_write_config32(dev, rom_addr, 0xfffffffe);
+ dm_pci_read_config32(dev, rom_addr, &bar_response);
+ if (bar_response) {
+ bar_size = -(bar_response & ~1);
+ debug("PCI Autoconfig: ROM, size=%#x, ",
+ (unsigned int)bar_size);
+ if (pciauto_region_allocate(mem, bar_size, &bar_value,
+ false) == 0) {
+ dm_pci_write_config32(dev, rom_addr, bar_value);
+ }
+ cmdstat |= PCI_COMMAND_MEMORY;
+ debug("\n");
+ }
+ }
+
+ /* PCI_COMMAND_IO must be set for VGA device */
+ dm_pci_read_config16(dev, PCI_CLASS_DEVICE, &class);
+ if (class == PCI_CLASS_DISPLAY_VGA)
+ cmdstat |= PCI_COMMAND_IO;
+
+ dm_pci_write_config16(dev, PCI_COMMAND, cmdstat);
+ dm_pci_write_config8(dev, PCI_CACHE_LINE_SIZE,
+ CONFIG_SYS_PCI_CACHE_LINE_SIZE);
+ dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x80);
+}
+
+void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus)
+{
+ struct pci_region *pci_mem;
+ struct pci_region *pci_prefetch;
+ struct pci_region *pci_io;
+ u16 cmdstat, prefechable_64;
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr);
+
+ pci_mem = ctlr_hose->pci_mem;
+ pci_prefetch = ctlr_hose->pci_prefetch;
+ pci_io = ctlr_hose->pci_io;
+
+ dm_pci_read_config16(dev, PCI_COMMAND, &cmdstat);
+ dm_pci_read_config16(dev, PCI_PREF_MEMORY_BASE, &prefechable_64);
+ prefechable_64 &= PCI_PREF_RANGE_TYPE_MASK;
+
+ /* Configure bus number registers */
+ dm_pci_write_config8(dev, PCI_PRIMARY_BUS,
+ PCI_BUS(dm_pci_get_bdf(dev)) - dev_seq(ctlr));
+ dm_pci_write_config8(dev, PCI_SECONDARY_BUS, sub_bus - dev_seq(ctlr));
+ dm_pci_write_config8(dev, PCI_SUBORDINATE_BUS, 0xff);
+
+ if (pci_mem) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_mem, 0x100000);
+
+ /*
+ * Set up memory and I/O filter limits, assume 32-bit
+ * I/O space
+ */
+ dm_pci_write_config16(dev, PCI_MEMORY_BASE,
+ (pci_mem->bus_lower & 0xfff00000) >> 16);
+
+ cmdstat |= PCI_COMMAND_MEMORY;
+ }
+
+ if (pci_prefetch) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_prefetch, 0x100000);
+
+ /*
+ * Set up memory and I/O filter limits, assume 32-bit
+ * I/O space
+ */
+ dm_pci_write_config16(dev, PCI_PREF_MEMORY_BASE,
+ (pci_prefetch->bus_lower & 0xfff00000) >> 16);
+ if (prefechable_64 == PCI_PREF_RANGE_TYPE_64)
+#ifdef CONFIG_SYS_PCI_64BIT
+ dm_pci_write_config32(dev, PCI_PREF_BASE_UPPER32,
+ pci_prefetch->bus_lower >> 32);
+#else
+ dm_pci_write_config32(dev, PCI_PREF_BASE_UPPER32, 0x0);
+#endif
+
+ cmdstat |= PCI_COMMAND_MEMORY;
+ } else {
+ /* We don't support prefetchable memory for now, so disable */
+ dm_pci_write_config16(dev, PCI_PREF_MEMORY_BASE, 0x1000);
+ dm_pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT, 0x0);
+ if (prefechable_64 == PCI_PREF_RANGE_TYPE_64) {
+ dm_pci_write_config16(dev, PCI_PREF_BASE_UPPER32, 0x0);
+ dm_pci_write_config16(dev, PCI_PREF_LIMIT_UPPER32, 0x0);
+ }
+ }
+
+ if (pci_io) {
+ /* Round I/O allocator to 4KB boundary */
+ pciauto_region_align(pci_io, 0x1000);
+
+ dm_pci_write_config8(dev, PCI_IO_BASE,
+ (pci_io->bus_lower & 0x0000f000) >> 8);
+ dm_pci_write_config16(dev, PCI_IO_BASE_UPPER16,
+ (pci_io->bus_lower & 0xffff0000) >> 16);
+
+ cmdstat |= PCI_COMMAND_IO;
+ }
+
+ /* Enable memory and I/O accesses, enable bus master */
+ dm_pci_write_config16(dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER);
+}
+
+void dm_pciauto_postscan_setup_bridge(struct udevice *dev, int sub_bus)
+{
+ struct pci_region *pci_mem;
+ struct pci_region *pci_prefetch;
+ struct pci_region *pci_io;
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr);
+
+ pci_mem = ctlr_hose->pci_mem;
+ pci_prefetch = ctlr_hose->pci_prefetch;
+ pci_io = ctlr_hose->pci_io;
+
+ /* Configure bus number registers */
+ dm_pci_write_config8(dev, PCI_SUBORDINATE_BUS, sub_bus - dev_seq(ctlr));
+
+ if (pci_mem) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_mem, 0x100000);
+
+ dm_pci_write_config16(dev, PCI_MEMORY_LIMIT,
+ (pci_mem->bus_lower - 1) >> 16);
+ }
+
+ if (pci_prefetch) {
+ u16 prefechable_64;
+
+ dm_pci_read_config16(dev, PCI_PREF_MEMORY_LIMIT,
+ &prefechable_64);
+ prefechable_64 &= PCI_PREF_RANGE_TYPE_MASK;
+
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_prefetch, 0x100000);
+
+ dm_pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT,
+ (pci_prefetch->bus_lower - 1) >> 16);
+ if (prefechable_64 == PCI_PREF_RANGE_TYPE_64)
+#ifdef CONFIG_SYS_PCI_64BIT
+ dm_pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32,
+ (pci_prefetch->bus_lower - 1) >> 32);
+#else
+ dm_pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, 0x0);
+#endif
+ }
+
+ if (pci_io) {
+ /* Round I/O allocator to 4KB boundary */
+ pciauto_region_align(pci_io, 0x1000);
+
+ dm_pci_write_config8(dev, PCI_IO_LIMIT,
+ ((pci_io->bus_lower - 1) & 0x0000f000) >> 8);
+ dm_pci_write_config16(dev, PCI_IO_LIMIT_UPPER16,
+ ((pci_io->bus_lower - 1) & 0xffff0000) >> 16);
+ }
+}
+
+/*
+ * HJF: Changed this to return int. I think this is required
+ * to get the correct result when scanning bridges
+ */
+int dm_pciauto_config_device(struct udevice *dev)
+{
+ struct pci_region *pci_mem;
+ struct pci_region *pci_prefetch;
+ struct pci_region *pci_io;
+ unsigned int sub_bus = PCI_BUS(dm_pci_get_bdf(dev));
+ unsigned short class;
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr);
+ int ret;
+
+ pci_mem = ctlr_hose->pci_mem;
+ pci_prefetch = ctlr_hose->pci_prefetch;
+ pci_io = ctlr_hose->pci_io;
+
+ dm_pci_read_config16(dev, PCI_CLASS_DEVICE, &class);
+
+ switch (class) {
+ case PCI_CLASS_BRIDGE_PCI:
+ debug("PCI Autoconfig: Found P2P bridge, device %d\n",
+ PCI_DEV(dm_pci_get_bdf(dev)));
+
+ dm_pciauto_setup_device(dev, 2, pci_mem, pci_prefetch, pci_io);
+
+ ret = dm_pci_hose_probe_bus(dev);
+ if (ret < 0)
+ return log_msg_ret("probe", ret);
+ sub_bus = ret;
+ break;
+
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ /*
+ * just do a minimal setup of the bridge,
+ * let the OS take care of the rest
+ */
+ dm_pciauto_setup_device(dev, 0, pci_mem, pci_prefetch, pci_io);
+
+ debug("PCI Autoconfig: Found P2CardBus bridge, device %d\n",
+ PCI_DEV(dm_pci_get_bdf(dev)));
+
+ break;
+
+#if defined(CONFIG_PCIAUTO_SKIP_HOST_BRIDGE)
+ case PCI_CLASS_BRIDGE_OTHER:
+ debug("PCI Autoconfig: Skipping bridge device %d\n",
+ PCI_DEV(dm_pci_get_bdf(dev)));
+ break;
+#endif
+#if defined(CONFIG_ARCH_MPC834X) && !defined(CONFIG_TARGET_VME8349) && \
+ !defined(CONFIG_TARGET_CADDY2)
+ case PCI_CLASS_BRIDGE_OTHER:
+ /*
+ * The host/PCI bridge 1 seems broken in 8349 - it presents
+ * itself as 'PCI_CLASS_BRIDGE_OTHER' and appears as an _agent_
+ * device claiming resources io/mem/irq.. we only allow for
+ * the PIMMR window to be allocated (BAR0 - 1MB size)
+ */
+ debug("PCI Autoconfig: Broken bridge found, only minimal config\n");
+ dm_pciauto_setup_device(dev, 0, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+ break;
+#endif
+
+ case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */
+ debug("PCI AutoConfig: Found PowerPC device\n");
+ /* fall through */
+
+ default:
+ dm_pciauto_setup_device(dev, 6, pci_mem, pci_prefetch, pci_io);
+ break;
+ }
+
+ return sub_bus;
+}
diff --git a/roms/u-boot/drivers/pci/pci_auto_common.c b/roms/u-boot/drivers/pci/pci_auto_common.c
new file mode 100644
index 000000000..c0a53dcc9
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_auto_common.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCI auto-configuration library
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ *
+ * Modifications for driver model:
+ * Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <pci.h>
+
+void pciauto_region_init(struct pci_region *res)
+{
+ /*
+ * Avoid allocating PCI resources from address 0 -- this is illegal
+ * according to PCI 2.1 and moreover, this is known to cause Linux IDE
+ * drivers to fail. Use a reasonable starting value of 0x1000 instead
+ * if the bus start address is below 0x1000.
+ */
+ res->bus_lower = res->bus_start < 0x1000 ? 0x1000 : res->bus_start;
+}
+
+void pciauto_region_align(struct pci_region *res, pci_size_t size)
+{
+ res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1;
+}
+
+int pciauto_region_allocate(struct pci_region *res, pci_size_t size,
+ pci_addr_t *bar, bool supports_64bit)
+{
+ pci_addr_t addr;
+
+ if (!res) {
+ debug("No resource\n");
+ goto error;
+ }
+
+ addr = ((res->bus_lower - 1) | (size - 1)) + 1;
+
+ if (addr - res->bus_start + size > res->size) {
+ debug("No room in resource, avail start=%llx / size=%llx, "
+ "need=%llx\n", (unsigned long long)res->bus_lower,
+ (unsigned long long)res->size, (unsigned long long)size);
+ goto error;
+ }
+
+ if (upper_32_bits(addr) && !supports_64bit) {
+ debug("Cannot assign 64-bit address to 32-bit-only resource\n");
+ goto error;
+ }
+
+ res->bus_lower = addr + size;
+
+ debug("address=0x%llx bus_lower=0x%llx\n", (unsigned long long)addr,
+ (unsigned long long)res->bus_lower);
+
+ *bar = addr;
+ return 0;
+
+ error:
+ *bar = (pci_addr_t)-1;
+ return -1;
+}
+
+static void pciauto_show_region(const char *name, struct pci_region *region)
+{
+ pciauto_region_init(region);
+ debug("PCI Autoconfig: Bus %s region: [%llx-%llx],\n"
+ "\t\tPhysical Memory [%llx-%llxx]\n", name,
+ (unsigned long long)region->bus_start,
+ (unsigned long long)(region->bus_start + region->size - 1),
+ (unsigned long long)region->phys_start,
+ (unsigned long long)(region->phys_start + region->size - 1));
+}
+
+void pciauto_config_init(struct pci_controller *hose)
+{
+ int i;
+
+ hose->pci_io = NULL;
+ hose->pci_mem = NULL;
+ hose->pci_prefetch = NULL;
+
+ for (i = 0; i < hose->region_count; i++) {
+ switch (hose->regions[i].flags) {
+ case PCI_REGION_IO:
+ if (!hose->pci_io ||
+ hose->pci_io->size < hose->regions[i].size)
+ hose->pci_io = hose->regions + i;
+ break;
+ case PCI_REGION_MEM:
+ if (!hose->pci_mem ||
+ hose->pci_mem->size < hose->regions[i].size)
+ hose->pci_mem = hose->regions + i;
+ break;
+ case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
+ if (!hose->pci_prefetch ||
+ hose->pci_prefetch->size < hose->regions[i].size)
+ hose->pci_prefetch = hose->regions + i;
+ break;
+ }
+ }
+
+
+ if (hose->pci_mem)
+ pciauto_show_region("Memory", hose->pci_mem);
+ if (hose->pci_prefetch)
+ pciauto_show_region("Prefetchable Mem", hose->pci_prefetch);
+ if (hose->pci_io)
+ pciauto_show_region("I/O", hose->pci_io);
+}
diff --git a/roms/u-boot/drivers/pci/pci_auto_old.c b/roms/u-boot/drivers/pci/pci_auto_old.c
new file mode 100644
index 000000000..c56ff53c4
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_auto_old.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCI autoconfiguration library (legacy version, do not change)
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+#include <pci.h>
+
+/*
+ * Do not change this file. Instead, convert your board to use CONFIG_DM_PCI
+ * and change pci_auto.c.
+ */
+
+/* the user can define CONFIG_SYS_PCI_CACHE_LINE_SIZE to avoid problems */
+#ifndef CONFIG_SYS_PCI_CACHE_LINE_SIZE
+#define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8
+#endif
+
+/*
+ *
+ */
+
+void pciauto_setup_device(struct pci_controller *hose,
+ pci_dev_t dev, int bars_num,
+ struct pci_region *mem,
+ struct pci_region *prefetch,
+ struct pci_region *io)
+{
+ u32 bar_response;
+ pci_size_t bar_size;
+ u16 cmdstat = 0;
+ int bar, bar_nr = 0;
+ u8 header_type;
+ int rom_addr;
+ pci_addr_t bar_value;
+ struct pci_region *bar_res;
+ int found_mem64 = 0;
+ u16 class;
+
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &cmdstat);
+ cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | PCI_COMMAND_MASTER;
+
+ for (bar = PCI_BASE_ADDRESS_0;
+ bar < PCI_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) {
+ /* Tickle the BAR and get the response */
+ pci_hose_write_config_dword(hose, dev, bar, 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar, &bar_response);
+
+ /* If BAR is not implemented go to the next BAR */
+ if (!bar_response)
+ continue;
+
+ found_mem64 = 0;
+
+ /* Check the BAR type and set our address mask */
+ if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+ bar_size = ((~(bar_response & PCI_BASE_ADDRESS_IO_MASK))
+ & 0xffff) + 1;
+ bar_res = io;
+
+ debug("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ",
+ bar_nr, (unsigned long long)bar_size);
+ } else {
+ if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ u32 bar_response_upper;
+ u64 bar64;
+
+ pci_hose_write_config_dword(hose, dev, bar + 4,
+ 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar + 4,
+ &bar_response_upper);
+
+ bar64 = ((u64)bar_response_upper << 32) | bar_response;
+
+ bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+ found_mem64 = 1;
+ } else {
+ bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
+ }
+ if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH))
+ bar_res = prefetch;
+ else
+ bar_res = mem;
+
+ debug("PCI Autoconfig: BAR %d, %s, size=0x%llx, ",
+ bar_nr, bar_res == prefetch ? "Prf" : "Mem",
+ (unsigned long long)bar_size);
+ }
+
+ if (pciauto_region_allocate(bar_res, bar_size,
+ &bar_value, found_mem64) == 0) {
+ /* Write it out and update our limit */
+ pci_hose_write_config_dword(hose, dev, bar, (u32)bar_value);
+
+ if (found_mem64) {
+ bar += 4;
+#ifdef CONFIG_SYS_PCI_64BIT
+ pci_hose_write_config_dword(hose, dev, bar, (u32)(bar_value>>32));
+#else
+ /*
+ * If we are a 64-bit decoder then increment to the
+ * upper 32 bits of the bar and force it to locate
+ * in the lower 4GB of memory.
+ */
+ pci_hose_write_config_dword(hose, dev, bar, 0x00000000);
+#endif
+ }
+
+ }
+ cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ?
+ PCI_COMMAND_IO : PCI_COMMAND_MEMORY;
+
+ debug("\n");
+
+ bar_nr++;
+ }
+
+ /* Configure the expansion ROM address */
+ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type);
+ header_type &= 0x7f;
+ if (header_type != PCI_HEADER_TYPE_CARDBUS) {
+ rom_addr = (header_type == PCI_HEADER_TYPE_NORMAL) ?
+ PCI_ROM_ADDRESS : PCI_ROM_ADDRESS1;
+ pci_hose_write_config_dword(hose, dev, rom_addr, 0xfffffffe);
+ pci_hose_read_config_dword(hose, dev, rom_addr, &bar_response);
+ if (bar_response) {
+ bar_size = -(bar_response & ~1);
+ debug("PCI Autoconfig: ROM, size=%#x, ",
+ (unsigned int)bar_size);
+ if (pciauto_region_allocate(mem, bar_size,
+ &bar_value, false) == 0) {
+ pci_hose_write_config_dword(hose, dev, rom_addr,
+ bar_value);
+ }
+ cmdstat |= PCI_COMMAND_MEMORY;
+ debug("\n");
+ }
+ }
+
+ /* PCI_COMMAND_IO must be set for VGA device */
+ pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
+ if (class == PCI_CLASS_DISPLAY_VGA)
+ cmdstat |= PCI_COMMAND_IO;
+
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND, cmdstat);
+ pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE,
+ CONFIG_SYS_PCI_CACHE_LINE_SIZE);
+ pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+}
+
+void pciauto_prescan_setup_bridge(struct pci_controller *hose,
+ pci_dev_t dev, int sub_bus)
+{
+ struct pci_region *pci_mem;
+ struct pci_region *pci_prefetch;
+ struct pci_region *pci_io;
+ u16 cmdstat, prefechable_64;
+
+ pci_mem = hose->pci_mem;
+ pci_prefetch = hose->pci_prefetch;
+ pci_io = hose->pci_io;
+
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &cmdstat);
+ pci_hose_read_config_word(hose, dev, PCI_PREF_MEMORY_BASE,
+ &prefechable_64);
+ prefechable_64 &= PCI_PREF_RANGE_TYPE_MASK;
+
+ /* Configure bus number registers */
+ pci_hose_write_config_byte(hose, dev, PCI_PRIMARY_BUS,
+ PCI_BUS(dev) - hose->first_busno);
+ pci_hose_write_config_byte(hose, dev, PCI_SECONDARY_BUS,
+ sub_bus - hose->first_busno);
+ pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, 0xff);
+
+ if (pci_mem) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_mem, 0x100000);
+
+ /* Set up memory and I/O filter limits, assume 32-bit I/O space */
+ pci_hose_write_config_word(hose, dev, PCI_MEMORY_BASE,
+ (pci_mem->bus_lower & 0xfff00000) >> 16);
+
+ cmdstat |= PCI_COMMAND_MEMORY;
+ }
+
+ if (pci_prefetch) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_prefetch, 0x100000);
+
+ /* Set up memory and I/O filter limits, assume 32-bit I/O space */
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE,
+ (pci_prefetch->bus_lower & 0xfff00000) >> 16);
+ if (prefechable_64 == PCI_PREF_RANGE_TYPE_64)
+#ifdef CONFIG_SYS_PCI_64BIT
+ pci_hose_write_config_dword(hose, dev,
+ PCI_PREF_BASE_UPPER32,
+ pci_prefetch->bus_lower >> 32);
+#else
+ pci_hose_write_config_dword(hose, dev,
+ PCI_PREF_BASE_UPPER32,
+ 0x0);
+#endif
+
+ cmdstat |= PCI_COMMAND_MEMORY;
+ } else {
+ /* We don't support prefetchable memory for now, so disable */
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, 0x1000);
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, 0x0);
+ if (prefechable_64 == PCI_PREF_RANGE_TYPE_64) {
+ pci_hose_write_config_word(hose, dev, PCI_PREF_BASE_UPPER32, 0x0);
+ pci_hose_write_config_word(hose, dev, PCI_PREF_LIMIT_UPPER32, 0x0);
+ }
+ }
+
+ if (pci_io) {
+ /* Round I/O allocator to 4KB boundary */
+ pciauto_region_align(pci_io, 0x1000);
+
+ pci_hose_write_config_byte(hose, dev, PCI_IO_BASE,
+ (pci_io->bus_lower & 0x0000f000) >> 8);
+ pci_hose_write_config_word(hose, dev, PCI_IO_BASE_UPPER16,
+ (pci_io->bus_lower & 0xffff0000) >> 16);
+
+ cmdstat |= PCI_COMMAND_IO;
+ }
+
+ /* Enable memory and I/O accesses, enable bus master */
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND,
+ cmdstat | PCI_COMMAND_MASTER);
+}
+
+void pciauto_postscan_setup_bridge(struct pci_controller *hose,
+ pci_dev_t dev, int sub_bus)
+{
+ struct pci_region *pci_mem;
+ struct pci_region *pci_prefetch;
+ struct pci_region *pci_io;
+
+ pci_mem = hose->pci_mem;
+ pci_prefetch = hose->pci_prefetch;
+ pci_io = hose->pci_io;
+
+ /* Configure bus number registers */
+ pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS,
+ sub_bus - hose->first_busno);
+
+ if (pci_mem) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_mem, 0x100000);
+
+ pci_hose_write_config_word(hose, dev, PCI_MEMORY_LIMIT,
+ (pci_mem->bus_lower - 1) >> 16);
+ }
+
+ if (pci_prefetch) {
+ u16 prefechable_64;
+
+ pci_hose_read_config_word(hose, dev,
+ PCI_PREF_MEMORY_LIMIT,
+ &prefechable_64);
+ prefechable_64 &= PCI_PREF_RANGE_TYPE_MASK;
+
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_prefetch, 0x100000);
+
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT,
+ (pci_prefetch->bus_lower - 1) >> 16);
+ if (prefechable_64 == PCI_PREF_RANGE_TYPE_64)
+#ifdef CONFIG_SYS_PCI_64BIT
+ pci_hose_write_config_dword(hose, dev,
+ PCI_PREF_LIMIT_UPPER32,
+ (pci_prefetch->bus_lower - 1) >> 32);
+#else
+ pci_hose_write_config_dword(hose, dev,
+ PCI_PREF_LIMIT_UPPER32,
+ 0x0);
+#endif
+ }
+
+ if (pci_io) {
+ /* Round I/O allocator to 4KB boundary */
+ pciauto_region_align(pci_io, 0x1000);
+
+ pci_hose_write_config_byte(hose, dev, PCI_IO_LIMIT,
+ ((pci_io->bus_lower - 1) & 0x0000f000) >> 8);
+ pci_hose_write_config_word(hose, dev, PCI_IO_LIMIT_UPPER16,
+ ((pci_io->bus_lower - 1) & 0xffff0000) >> 16);
+ }
+}
+
+
+/*
+ * HJF: Changed this to return int. I think this is required
+ * to get the correct result when scanning bridges
+ */
+int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
+{
+ struct pci_region *pci_mem;
+ struct pci_region *pci_prefetch;
+ struct pci_region *pci_io;
+ unsigned int sub_bus = PCI_BUS(dev);
+ unsigned short class;
+ int n;
+
+ pci_mem = hose->pci_mem;
+ pci_prefetch = hose->pci_prefetch;
+ pci_io = hose->pci_io;
+
+ pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
+
+ switch (class) {
+ case PCI_CLASS_BRIDGE_PCI:
+ debug("PCI Autoconfig: Found P2P bridge, device %d\n",
+ PCI_DEV(dev));
+
+ pciauto_setup_device(hose, dev, 2, pci_mem,
+ pci_prefetch, pci_io);
+
+ /* Passing in current_busno allows for sibling P2P bridges */
+ hose->current_busno++;
+ pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
+ /*
+ * need to figure out if this is a subordinate bridge on the bus
+ * to be able to properly set the pri/sec/sub bridge registers.
+ */
+ n = pci_hose_scan_bus(hose, hose->current_busno);
+
+ /* figure out the deepest we've gone for this leg */
+ sub_bus = max((unsigned int)n, sub_bus);
+ pciauto_postscan_setup_bridge(hose, dev, sub_bus);
+
+ sub_bus = hose->current_busno;
+ break;
+
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ /*
+ * just do a minimal setup of the bridge,
+ * let the OS take care of the rest
+ */
+ pciauto_setup_device(hose, dev, 0, pci_mem,
+ pci_prefetch, pci_io);
+
+ debug("PCI Autoconfig: Found P2CardBus bridge, device %d\n",
+ PCI_DEV(dev));
+
+ hose->current_busno++;
+ break;
+
+#if defined(CONFIG_PCIAUTO_SKIP_HOST_BRIDGE)
+ case PCI_CLASS_BRIDGE_OTHER:
+ debug("PCI Autoconfig: Skipping bridge device %d\n",
+ PCI_DEV(dev));
+ break;
+#endif
+#if defined(CONFIG_ARCH_MPC834X) && !defined(CONFIG_TARGET_VME8349) && \
+ !defined(CONFIG_TARGET_CADDY2)
+ case PCI_CLASS_BRIDGE_OTHER:
+ /*
+ * The host/PCI bridge 1 seems broken in 8349 - it presents
+ * itself as 'PCI_CLASS_BRIDGE_OTHER' and appears as an _agent_
+ * device claiming resources io/mem/irq.. we only allow for
+ * the PIMMR window to be allocated (BAR0 - 1MB size)
+ */
+ debug("PCI Autoconfig: Broken bridge found, only minimal config\n");
+ pciauto_setup_device(hose, dev, 0, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+ break;
+#endif
+
+ case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */
+ debug("PCI AutoConfig: Found PowerPC device\n");
+
+ default:
+ pciauto_setup_device(hose, dev, 6, pci_mem,
+ pci_prefetch, pci_io);
+ break;
+ }
+
+ return sub_bus;
+}
diff --git a/roms/u-boot/drivers/pci/pci_common.c b/roms/u-boot/drivers/pci/pci_common.c
new file mode 100644
index 000000000..5231b69dc
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_common.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002, 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <env.h>
+#include <errno.h>
+#include <pci.h>
+#include <asm/io.h>
+
+const char *pci_class_str(u8 class)
+{
+ switch (class) {
+ case PCI_CLASS_NOT_DEFINED:
+ return "Build before PCI Rev2.0";
+ break;
+ case PCI_BASE_CLASS_STORAGE:
+ return "Mass storage controller";
+ break;
+ case PCI_BASE_CLASS_NETWORK:
+ return "Network controller";
+ break;
+ case PCI_BASE_CLASS_DISPLAY:
+ return "Display controller";
+ break;
+ case PCI_BASE_CLASS_MULTIMEDIA:
+ return "Multimedia device";
+ break;
+ case PCI_BASE_CLASS_MEMORY:
+ return "Memory controller";
+ break;
+ case PCI_BASE_CLASS_BRIDGE:
+ return "Bridge device";
+ break;
+ case PCI_BASE_CLASS_COMMUNICATION:
+ return "Simple comm. controller";
+ break;
+ case PCI_BASE_CLASS_SYSTEM:
+ return "Base system peripheral";
+ break;
+ case PCI_BASE_CLASS_INPUT:
+ return "Input device";
+ break;
+ case PCI_BASE_CLASS_DOCKING:
+ return "Docking station";
+ break;
+ case PCI_BASE_CLASS_PROCESSOR:
+ return "Processor";
+ break;
+ case PCI_BASE_CLASS_SERIAL:
+ return "Serial bus controller";
+ break;
+ case PCI_BASE_CLASS_INTELLIGENT:
+ return "Intelligent controller";
+ break;
+ case PCI_BASE_CLASS_SATELLITE:
+ return "Satellite controller";
+ break;
+ case PCI_BASE_CLASS_CRYPT:
+ return "Cryptographic device";
+ break;
+ case PCI_BASE_CLASS_SIGNAL_PROCESSING:
+ return "DSP";
+ break;
+ case PCI_CLASS_OTHERS:
+ return "Does not fit any class";
+ break;
+ default:
+ return "???";
+ break;
+ };
+}
+
+__weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ /*
+ * Check if pci device should be skipped in configuration
+ */
+ if (dev == PCI_BDF(hose->first_busno, 0, 0)) {
+#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */
+ /*
+ * Only skip configuration if "pciconfighost" is not set
+ */
+ if (env_get("pciconfighost") == NULL)
+ return 1;
+#else
+ return 1;
+#endif
+ }
+
+ return 0;
+}
+
+#if !defined(CONFIG_DM_PCI) || defined(CONFIG_DM_PCI_COMPAT)
+/* Get a virtual address associated with a BAR region */
+void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
+{
+ pci_addr_t pci_bus_addr;
+ u32 bar_response;
+
+ /* read BAR address */
+ pci_read_config_dword(pdev, bar, &bar_response);
+ pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
+
+ /*
+ * Pass "0" as the length argument to pci_bus_to_virt. The arg
+ * isn't actualy used on any platform because u-boot assumes a static
+ * linear mapping. In the future, this could read the BAR size
+ * and pass that as the size if needed.
+ */
+ return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
+}
+
+void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum,
+ u32 addr_and_ctrl)
+{
+ int bar;
+
+ bar = PCI_BASE_ADDRESS_0 + barnum * 4;
+ pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl);
+}
+
+u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum)
+{
+ u32 addr;
+ int bar;
+
+ bar = PCI_BASE_ADDRESS_0 + barnum * 4;
+ pci_hose_read_config_dword(hose, dev, bar, &addr);
+ if (addr & PCI_BASE_ADDRESS_SPACE_IO)
+ return addr & PCI_BASE_ADDRESS_IO_MASK;
+ else
+ return addr & PCI_BASE_ADDRESS_MEM_MASK;
+}
+
+int __pci_hose_bus_to_phys(struct pci_controller *hose,
+ pci_addr_t bus_addr,
+ unsigned long flags,
+ unsigned long skip_mask,
+ phys_addr_t *pa)
+{
+ struct pci_region *res;
+ int i;
+
+ for (i = 0; i < hose->region_count; i++) {
+ res = &hose->regions[i];
+
+ if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ continue;
+
+ if (res->flags & skip_mask)
+ continue;
+
+ if (bus_addr >= res->bus_start &&
+ (bus_addr - res->bus_start) < res->size) {
+ *pa = (bus_addr - res->bus_start + res->phys_start);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+phys_addr_t pci_hose_bus_to_phys(struct pci_controller *hose,
+ pci_addr_t bus_addr,
+ unsigned long flags)
+{
+ phys_addr_t phys_addr = 0;
+ int ret;
+
+ if (!hose) {
+ puts("pci_hose_bus_to_phys: invalid hose\n");
+ return phys_addr;
+ }
+
+ /*
+ * if PCI_REGION_MEM is set we do a two pass search with preference
+ * on matches that don't have PCI_REGION_SYS_MEMORY set
+ */
+ if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
+ ret = __pci_hose_bus_to_phys(hose, bus_addr,
+ flags, PCI_REGION_SYS_MEMORY, &phys_addr);
+ if (!ret)
+ return phys_addr;
+ }
+
+ ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
+
+ if (ret)
+ puts("pci_hose_bus_to_phys: invalid physical address\n");
+
+ return phys_addr;
+}
+
+int __pci_hose_phys_to_bus(struct pci_controller *hose,
+ phys_addr_t phys_addr,
+ unsigned long flags,
+ unsigned long skip_mask,
+ pci_addr_t *ba)
+{
+ struct pci_region *res;
+ pci_addr_t bus_addr;
+ int i;
+
+ for (i = 0; i < hose->region_count; i++) {
+ res = &hose->regions[i];
+
+ if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ continue;
+
+ if (res->flags & skip_mask)
+ continue;
+
+ bus_addr = phys_addr - res->phys_start + res->bus_start;
+
+ if (bus_addr >= res->bus_start &&
+ (bus_addr - res->bus_start) < res->size) {
+ *ba = bus_addr;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * pci_hose_phys_to_bus(): Convert physical address to bus address
+ * @hose: PCI hose of the root PCI controller
+ * @phys_addr: physical address to convert
+ * @flags: flags of pci regions
+ * @return bus address if OK, 0 on error
+ */
+pci_addr_t pci_hose_phys_to_bus(struct pci_controller *hose,
+ phys_addr_t phys_addr,
+ unsigned long flags)
+{
+ pci_addr_t bus_addr = 0;
+ int ret;
+
+ if (!hose) {
+ puts("pci_hose_phys_to_bus: invalid hose\n");
+ return bus_addr;
+ }
+
+ /*
+ * if PCI_REGION_MEM is set we do a two pass search with preference
+ * on matches that don't have PCI_REGION_SYS_MEMORY set
+ */
+ if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
+ ret = __pci_hose_phys_to_bus(hose, phys_addr,
+ flags, PCI_REGION_SYS_MEMORY, &bus_addr);
+ if (!ret)
+ return bus_addr;
+ }
+
+ ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr);
+
+ if (ret)
+ puts("pci_hose_phys_to_bus: invalid physical address\n");
+
+ return bus_addr;
+}
+
+pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
+{
+ struct pci_device_id ids[2] = { {}, {0, 0} };
+
+ ids[0].vendor = vendor;
+ ids[0].device = device;
+
+ return pci_find_devices(ids, index);
+}
+
+pci_dev_t pci_hose_find_devices(struct pci_controller *hose, int busnum,
+ struct pci_device_id *ids, int *indexp)
+{
+ int found_multi = 0;
+ u16 vendor, device;
+ u8 header_type;
+ pci_dev_t bdf;
+ int i;
+
+ for (bdf = PCI_BDF(busnum, 0, 0);
+ bdf < PCI_BDF(busnum + 1, 0, 0);
+ bdf += PCI_BDF(0, 0, 1)) {
+ if (pci_skip_dev(hose, bdf))
+ continue;
+
+ if (!PCI_FUNC(bdf)) {
+ pci_read_config_byte(bdf, PCI_HEADER_TYPE,
+ &header_type);
+ found_multi = header_type & 0x80;
+ } else {
+ if (!found_multi)
+ continue;
+ }
+
+ pci_read_config_word(bdf, PCI_VENDOR_ID, &vendor);
+ pci_read_config_word(bdf, PCI_DEVICE_ID, &device);
+
+ for (i = 0; ids[i].vendor != 0; i++) {
+ if (vendor == ids[i].vendor &&
+ device == ids[i].device) {
+ if ((*indexp) <= 0)
+ return bdf;
+
+ (*indexp)--;
+ }
+ }
+ }
+
+ return -1;
+}
+
+pci_dev_t pci_find_class(uint find_class, int index)
+{
+ int bus;
+ int devnum;
+ pci_dev_t bdf;
+ uint32_t class;
+
+ for (bus = 0; bus <= pci_last_busno(); bus++) {
+ for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES - 1; devnum++) {
+ pci_read_config_dword(PCI_BDF(bus, devnum, 0),
+ PCI_CLASS_REVISION, &class);
+ if (class >> 16 == 0xffff)
+ continue;
+
+ for (bdf = PCI_BDF(bus, devnum, 0);
+ bdf <= PCI_BDF(bus, devnum,
+ PCI_MAX_PCI_FUNCTIONS - 1);
+ bdf += PCI_BDF(0, 0, 1)) {
+ pci_read_config_dword(bdf, PCI_CLASS_REVISION,
+ &class);
+ class >>= 8;
+
+ if (class != find_class)
+ continue;
+ /*
+ * Decrement the index. We want to return the
+ * correct device, so index is 0 for the first
+ * matching device, 1 for the second, etc.
+ */
+ if (index) {
+ index--;
+ continue;
+ }
+ /* Return index'th controller. */
+ return bdf;
+ }
+ }
+ }
+
+ return -ENODEV;
+}
+#endif /* !CONFIG_DM_PCI || CONFIG_DM_PCI_COMPAT */
diff --git a/roms/u-boot/drivers/pci/pci_compat.c b/roms/u-boot/drivers/pci/pci_compat.c
new file mode 100644
index 000000000..9dddca8ef
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_compat.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Compatibility functions for pre-driver-model code
+ *
+ * Copyright (C) 2014 Google, Inc
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <pci.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include "pci_internal.h"
+
+#define PCI_HOSE_OP(rw, name, size, type) \
+int pci_hose_##rw##_config_##name(struct pci_controller *hose, \
+ pci_dev_t dev, \
+ int offset, type value) \
+{ \
+ return pci_##rw##_config##size(dev, offset, value); \
+}
+
+PCI_HOSE_OP(read, byte, 8, u8 *)
+PCI_HOSE_OP(read, word, 16, u16 *)
+PCI_HOSE_OP(read, dword, 32, u32 *)
+PCI_HOSE_OP(write, byte, 8, u8)
+PCI_HOSE_OP(write, word, 16, u16)
+PCI_HOSE_OP(write, dword, 32, u32)
+
+pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
+{
+ struct udevice *dev;
+
+ if (pci_find_device_id(ids, index, &dev))
+ return -1;
+ return dm_pci_get_bdf(dev);
+}
+
+struct pci_controller *pci_bus_to_hose(int busnum)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = pci_get_bus(busnum, &bus);
+ if (ret) {
+ debug("%s: Cannot get bus %d: ret=%d\n", __func__, busnum, ret);
+ return NULL;
+ }
+
+ return dev_get_uclass_priv(pci_get_controller(bus));
+}
diff --git a/roms/u-boot/drivers/pci/pci_ftpci100.c b/roms/u-boot/drivers/pci/pci_ftpci100.c
new file mode 100644
index 000000000..32fac878a
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_ftpci100.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Faraday FTPCI100 PCI Bridge Controller Device Driver Implementation
+ *
+ * Copyright (C) 2011 Andes Technology Corporation
+ * Gavin Guo, Andes Technology Corporation <gavinguo@andestech.com>
+ * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
+ */
+#include <common.h>
+#include <init.h>
+#include <log.h>
+#include <malloc.h>
+#include <pci.h>
+
+#include <faraday/ftpci100.h>
+
+#include <asm/io.h>
+#include <asm/types.h> /* u32, u16.... used by pci.h */
+
+struct ftpci100_data {
+ unsigned int reg_base;
+ unsigned int io_base;
+ unsigned int mem_base;
+ unsigned int mmio_base;
+ unsigned int ndevs;
+};
+
+static struct pci_config devs[FTPCI100_MAX_FUNCTIONS];
+static struct pci_controller local_hose;
+
+static void setup_pci_bar(unsigned int bus, unsigned int dev, unsigned func,
+ unsigned char header, struct ftpci100_data *priv)
+{
+ struct pci_controller *hose = (struct pci_controller *)&local_hose;
+ unsigned int i, tmp32, bar_no, iovsmem = 1;
+ pci_dev_t dev_nu;
+
+ /* A device is present, add an entry to the array */
+ devs[priv->ndevs].bus = bus;
+ devs[priv->ndevs].dev = dev;
+ devs[priv->ndevs].func = func;
+
+ dev_nu = PCI_BDF(bus, dev, func);
+
+ if ((header & 0x7f) == 0x01)
+ /* PCI-PCI Bridge */
+ bar_no = 2;
+ else
+ bar_no = 6;
+
+ /* Allocate address spaces by configuring BARs */
+ for (i = 0; i < bar_no; i++) {
+ pci_hose_write_config_dword(hose, dev_nu,
+ PCI_BASE_ADDRESS_0 + i * 4, 0xffffffff);
+ pci_hose_read_config_dword(hose, dev_nu,
+ PCI_BASE_ADDRESS_0 + i * 4, &tmp32);
+
+ if (tmp32 == 0x0)
+ continue;
+
+ /* IO space */
+ if (tmp32 & 0x1) {
+ iovsmem = 0;
+ unsigned int size_mask = ~(tmp32 & 0xfffffffc);
+
+ if (priv->io_base & size_mask)
+ priv->io_base = (priv->io_base & ~size_mask) + \
+ size_mask + 1;
+
+ devs[priv->ndevs].bar[i].addr = priv->io_base;
+ devs[priv->ndevs].bar[i].size = size_mask + 1;
+
+ pci_hose_write_config_dword(hose, dev_nu,
+ PCI_BASE_ADDRESS_0 + i * 4,
+ priv->io_base);
+
+ debug("Allocated IO address 0x%X-" \
+ "0x%X for Bus %d, Device %d, Function %d\n",
+ priv->io_base,
+ priv->io_base + size_mask, bus, dev, func);
+
+ priv->io_base += size_mask + 1;
+ } else {
+ /* Memory space */
+ unsigned int is_64bit = ((tmp32 & 0x6) == 0x4);
+ unsigned int is_pref = tmp32 & 0x8;
+ unsigned int size_mask = ~(tmp32 & 0xfffffff0);
+ unsigned int alloc_base;
+ unsigned int *addr_mem_base;
+
+ if (is_pref)
+ addr_mem_base = &priv->mem_base;
+ else
+ addr_mem_base = &priv->mmio_base;
+
+ alloc_base = *addr_mem_base;
+
+ if (alloc_base & size_mask)
+ alloc_base = (alloc_base & ~size_mask) \
+ + size_mask + 1;
+
+ pci_hose_write_config_dword(hose, dev_nu,
+ PCI_BASE_ADDRESS_0 + i * 4, alloc_base);
+
+ debug("Allocated %s address 0x%X-" \
+ "0x%X for Bus %d, Device %d, Function %d\n",
+ is_pref ? "MEM" : "MMIO", alloc_base,
+ alloc_base + size_mask, bus, dev, func);
+
+ devs[priv->ndevs].bar[i].addr = alloc_base;
+ devs[priv->ndevs].bar[i].size = size_mask + 1;
+
+ debug("BAR address BAR size\n");
+ debug("%010x %08d\n",
+ devs[priv->ndevs].bar[0].addr,
+ devs[priv->ndevs].bar[0].size);
+
+ alloc_base += size_mask + 1;
+ *addr_mem_base = alloc_base;
+
+ if (is_64bit) {
+ i++;
+ pci_hose_write_config_dword(hose, dev_nu,
+ PCI_BASE_ADDRESS_0 + i * 4, 0x0);
+ }
+ }
+ }
+
+ /* Enable Bus Master, Memory Space, and IO Space */
+ pci_hose_read_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, &tmp32);
+ pci_hose_write_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, 0x08);
+ pci_hose_read_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, &tmp32);
+
+ pci_hose_read_config_dword(hose, dev_nu, PCI_COMMAND, &tmp32);
+
+ tmp32 &= 0xffff;
+
+ if (iovsmem == 0)
+ tmp32 |= 0x5;
+ else
+ tmp32 |= 0x6;
+
+ pci_hose_write_config_dword(hose, dev_nu, PCI_COMMAND, tmp32);
+}
+
+static void pci_bus_scan(struct ftpci100_data *priv)
+{
+ struct pci_controller *hose = (struct pci_controller *)&local_hose;
+ unsigned int bus, dev, func;
+ pci_dev_t dev_nu;
+ unsigned int data32;
+ unsigned int tmp;
+ unsigned char header;
+ unsigned char int_pin;
+ unsigned int niobars;
+ unsigned int nmbars;
+
+ priv->ndevs = 1;
+
+ nmbars = 0;
+ niobars = 0;
+
+ for (bus = 0; bus < MAX_BUS_NUM; bus++)
+ for (dev = 0; dev < MAX_DEV_NUM; dev++)
+ for (func = 0; func < MAX_FUN_NUM; func++) {
+ dev_nu = PCI_BDF(bus, dev, func);
+ pci_hose_read_config_dword(hose, dev_nu,
+ PCI_VENDOR_ID, &data32);
+
+ /*
+ * some broken boards return 0 or ~0,
+ * if a slot is empty.
+ */
+ if (data32 == 0xffffffff ||
+ data32 == 0x00000000 ||
+ data32 == 0x0000ffff ||
+ data32 == 0xffff0000)
+ continue;
+
+ pci_hose_read_config_dword(hose, dev_nu,
+ PCI_HEADER_TYPE, &tmp);
+ header = (unsigned char)tmp;
+ setup_pci_bar(bus, dev, func, header, priv);
+
+ devs[priv->ndevs].v_id = (u16)(data32 & \
+ 0x0000ffff);
+
+ devs[priv->ndevs].d_id = (u16)((data32 & \
+ 0xffff0000) >> 16);
+
+ /* Figure out what INTX# line the card uses */
+ pci_hose_read_config_byte(hose, dev_nu,
+ PCI_INTERRUPT_PIN, &int_pin);
+
+ /* assign the appropriate irq line */
+ if (int_pin > PCI_IRQ_LINES) {
+ printf("more irq lines than expect\n");
+ } else if (int_pin != 0) {
+ /* This device uses an interrupt line */
+ devs[priv->ndevs].pin = int_pin;
+ }
+
+ pci_hose_read_config_dword(hose, dev_nu,
+ PCI_CLASS_DEVICE, &data32);
+
+ debug("%06d %03d %03d " \
+ "%04d %08x %08x " \
+ "%03d %08x %06d %08x\n",
+ priv->ndevs, devs[priv->ndevs].bus,
+ devs[priv->ndevs].dev,
+ devs[priv->ndevs].func,
+ devs[priv->ndevs].d_id,
+ devs[priv->ndevs].v_id,
+ devs[priv->ndevs].pin,
+ devs[priv->ndevs].bar[0].addr,
+ devs[priv->ndevs].bar[0].size,
+ data32 >> 8);
+
+ priv->ndevs++;
+ }
+}
+
+static void ftpci_preinit(struct ftpci100_data *priv)
+{
+ struct ftpci100_ahbc *ftpci100;
+ struct pci_controller *hose = (struct pci_controller *)&local_hose;
+ u32 pci_config_addr;
+ u32 pci_config_data;
+
+ priv->reg_base = CONFIG_FTPCI100_BASE;
+ priv->io_base = CONFIG_FTPCI100_BASE + CONFIG_FTPCI100_IO_SIZE;
+ priv->mmio_base = CONFIG_FTPCI100_MEM_BASE;
+ priv->mem_base = CONFIG_FTPCI100_MEM_BASE + CONFIG_FTPCI100_MEM_SIZE;
+
+ ftpci100 = (struct ftpci100_ahbc *)priv->reg_base;
+
+ pci_config_addr = (u32) &ftpci100->conf;
+ pci_config_data = (u32) &ftpci100->data;
+
+ /* print device name */
+ printf("FTPCI100\n");
+
+ /* dump basic configuration */
+ debug("%s: Config addr is %08X, data port is %08X\n",
+ __func__, pci_config_addr, pci_config_data);
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 0,
+ CONFIG_PCI_MEM_BUS,
+ CONFIG_PCI_MEM_PHYS,
+ CONFIG_PCI_MEM_SIZE,
+ PCI_REGION_MEM);
+ hose->region_count++;
+
+ /* PCI IO space */
+ pci_set_region(hose->regions + 1,
+ CONFIG_PCI_IO_BUS,
+ CONFIG_PCI_IO_PHYS,
+ CONFIG_PCI_IO_SIZE,
+ PCI_REGION_IO);
+ hose->region_count++;
+
+#if defined(CONFIG_PCI_SYS_BUS)
+ /* PCI System Memory space */
+ pci_set_region(hose->regions + 2,
+ CONFIG_PCI_SYS_BUS,
+ CONFIG_PCI_SYS_PHYS,
+ CONFIG_PCI_SYS_SIZE,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+ hose->region_count++;
+#endif
+
+ /* setup indirect read/write function */
+ pci_setup_indirect(hose, pci_config_addr, pci_config_data);
+
+ /* register hose */
+ pci_register_hose(hose);
+}
+
+void pci_ftpci_init(void)
+{
+ struct ftpci100_data *priv = NULL;
+ struct pci_controller *hose = (struct pci_controller *)&local_hose;
+ pci_dev_t bridge_num;
+
+ struct pci_device_id bridge_ids[] = {
+ {FTPCI100_BRIDGE_VENDORID, FTPCI100_BRIDGE_DEVICEID},
+ {0, 0}
+ };
+
+ priv = malloc(sizeof(struct ftpci100_data));
+
+ if (!priv) {
+ printf("%s(): failed to malloc priv\n", __func__);
+ return;
+ }
+
+ memset(priv, 0, sizeof(struct ftpci100_data));
+
+ ftpci_preinit(priv);
+
+ debug("Device bus dev func deviceID vendorID pin address" \
+ " size class\n");
+
+ pci_bus_scan(priv);
+
+ /*
+ * Setup the PCI Bridge Window to 1GB,
+ * it will cause USB OHCI Host controller Unrecoverable Error
+ * if it is not set.
+ */
+ bridge_num = pci_find_devices(bridge_ids, 0);
+ if (bridge_num == -1) {
+ printf("PCI Bridge not found\n");
+ return;
+ }
+ pci_hose_write_config_dword(hose, bridge_num, PCI_MEM_BASE_SIZE1,
+ FTPCI100_BASE_ADR_SIZE(1024));
+}
diff --git a/roms/u-boot/drivers/pci/pci_gt64120.c b/roms/u-boot/drivers/pci/pci_gt64120.c
new file mode 100644
index 000000000..80f11fedd
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_gt64120.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on the Linux implementation.
+ * Copyright (C) 1999, 2000, 2004 MIPS Technologies, Inc.
+ * Authors: Carsten Langgaard <carstenl@mips.com>
+ * Maciej W. Rozycki <macro@mips.com>
+ */
+
+#include <common.h>
+#include <gt64120.h>
+#include <init.h>
+#include <log.h>
+#include <pci.h>
+#include <pci_gt64120.h>
+
+#include <asm/io.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+struct gt64120_regs {
+ u8 unused_000[0xc18];
+ u32 intrcause;
+ u8 unused_c1c[0x0dc];
+ u32 pci0_cfgaddr;
+ u32 pci0_cfgdata;
+};
+
+struct gt64120_pci_controller {
+ struct pci_controller hose;
+ struct gt64120_regs *regs;
+};
+
+static inline struct gt64120_pci_controller *
+hose_to_gt64120(struct pci_controller *hose)
+{
+ return container_of(hose, struct gt64120_pci_controller, hose);
+}
+
+#define GT_INTRCAUSE_ABORT_BITS \
+ (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)
+
+static int gt_config_access(struct gt64120_pci_controller *gt,
+ unsigned char access_type, pci_dev_t bdf,
+ int where, u32 *data)
+{
+ unsigned int bus = PCI_BUS(bdf);
+ unsigned int dev = PCI_DEV(bdf);
+ unsigned int devfn = PCI_DEV(bdf) << 3 | PCI_FUNC(bdf);
+ u32 intr;
+ u32 addr;
+ u32 val;
+
+ if (bus == 0 && dev >= 31) {
+ /* Because of a bug in the galileo (for slot 31). */
+ return -1;
+ }
+
+ if (access_type == PCI_ACCESS_WRITE)
+ debug("PCI WR %02x:%02x.%x reg:%02d data:%08x\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), where, *data);
+
+ /* Clear cause register bits */
+ writel(~GT_INTRCAUSE_ABORT_BITS, &gt->regs->intrcause);
+
+ addr = GT_PCI0_CFGADDR_CONFIGEN_BIT;
+ addr |= bus << GT_PCI0_CFGADDR_BUSNUM_SHF;
+ addr |= devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF;
+ addr |= (where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF;
+
+ /* Setup address */
+ writel(addr, &gt->regs->pci0_cfgaddr);
+
+ if (access_type == PCI_ACCESS_WRITE) {
+ if (bus == 0 && dev == 0) {
+ /*
+ * The Galileo system controller is acting
+ * differently than other devices.
+ */
+ val = *data;
+ } else {
+ val = cpu_to_le32(*data);
+ }
+
+ writel(val, &gt->regs->pci0_cfgdata);
+ } else {
+ val = readl(&gt->regs->pci0_cfgdata);
+
+ if (bus == 0 && dev == 0) {
+ /*
+ * The Galileo system controller is acting
+ * differently than other devices.
+ */
+ *data = val;
+ } else {
+ *data = le32_to_cpu(val);
+ }
+ }
+
+ /* Check for master or target abort */
+ intr = readl(&gt->regs->intrcause);
+ if (intr & GT_INTRCAUSE_ABORT_BITS) {
+ /* Error occurred, clear abort bits */
+ writel(~GT_INTRCAUSE_ABORT_BITS, &gt->regs->intrcause);
+ return -1;
+ }
+
+ if (access_type == PCI_ACCESS_READ)
+ debug("PCI RD %02x:%02x.%x reg:%02d data:%08x\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), where, *data);
+
+ return 0;
+}
+
+static int gt_read_config_dword(struct pci_controller *hose, pci_dev_t dev,
+ int where, u32 *value)
+{
+ struct gt64120_pci_controller *gt = hose_to_gt64120(hose);
+
+ *value = 0xffffffff;
+ return gt_config_access(gt, PCI_ACCESS_READ, dev, where, value);
+}
+
+static int gt_write_config_dword(struct pci_controller *hose, pci_dev_t dev,
+ int where, u32 value)
+{
+ struct gt64120_pci_controller *gt = hose_to_gt64120(hose);
+ u32 data = value;
+
+ return gt_config_access(gt, PCI_ACCESS_WRITE, dev, where, &data);
+}
+
+void gt64120_pci_init(void *regs, unsigned long sys_bus, unsigned long sys_phys,
+ unsigned long sys_size, unsigned long mem_bus,
+ unsigned long mem_phys, unsigned long mem_size,
+ unsigned long io_bus, unsigned long io_phys,
+ unsigned long io_size)
+{
+ static struct gt64120_pci_controller global_gt;
+ struct gt64120_pci_controller *gt;
+ struct pci_controller *hose;
+
+ gt = &global_gt;
+ gt->regs = regs;
+
+ hose = &gt->hose;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0;
+
+ /* System memory space */
+ pci_set_region(&hose->regions[0], sys_bus, sys_phys, sys_size,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region(&hose->regions[1], mem_bus, mem_phys, mem_size,
+ PCI_REGION_MEM);
+
+ /* PCI I/O space */
+ pci_set_region(&hose->regions[2], io_bus, io_phys, io_size,
+ PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_set_ops(hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ gt_read_config_dword,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ gt_write_config_dword);
+
+ pci_register_hose(hose);
+ hose->last_busno = pci_hose_scan(hose);
+}
diff --git a/roms/u-boot/drivers/pci/pci_indirect.c b/roms/u-boot/drivers/pci/pci_indirect.c
new file mode 100644
index 000000000..6134c22d1
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_indirect.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ */
+
+#include <common.h>
+
+#if !defined(__I386__) && !defined(CONFIG_DM_PCI)
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define cfg_read(val, addr, type, op) *val = op((type)(addr))
+#define cfg_write(val, addr, type, op) op((type *)(addr), (val))
+
+#if defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d,f; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \
+ b = b - hose->first_busno; \
+ dev = PCI_BDF(b, d, f); \
+ *(hose->cfg_addr) = dev | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; \
+ sync(); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+#else
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d,f; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \
+ b = b - hose->first_busno; \
+ dev = PCI_BDF(b, d, f); \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+#endif
+
+INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3)
+INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2)
+INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0)
+INDIRECT_PCI_OP(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP(write, dword, u32, out_le32, 0)
+
+void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+ pci_set_ops(hose,
+ indirect_read_config_byte,
+ indirect_read_config_word,
+ indirect_read_config_dword,
+ indirect_write_config_byte,
+ indirect_write_config_word,
+ indirect_write_config_dword);
+
+ hose->cfg_addr = (unsigned int *) cfg_addr;
+ hose->cfg_data = (unsigned char *) cfg_data;
+}
+
+#endif /* !__I386__ */
diff --git a/roms/u-boot/drivers/pci/pci_internal.h b/roms/u-boot/drivers/pci/pci_internal.h
new file mode 100644
index 000000000..8b842f6fb
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_internal.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Internal PCI functions, not exported outside drivers/pci
+ *
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __pci_internal_h
+#define __pci_internal_h
+
+/**
+ * dm_pciauto_prescan_setup_bridge() - Set up a bridge for scanning
+ *
+ * This gets a bridge ready so that its downstream devices can be scanned.
+ * It sets up the bus number and memory range registers. Once the scan is
+ * completed, dm_pciauto_postscan_setup_bridge() should be called.
+ *
+ * @dev: Bridge device to be scanned
+ * @sub_bus: Bus number of the 'other side' of the bridge
+ */
+void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus);
+
+/**
+ * dm_pciauto_postscan_setup_bridge() - Finish set up of a bridge after scanning
+ *
+ * This should be called after a bus scan is complete. It adjusts the memory
+ * ranges to fit with the devices actually found on the other side (downstream)
+ * of the bridge.
+ *
+ * @dev: Bridge device that was scanned
+ * @sub_bus: Bus number of the 'other side' of the bridge
+ */
+void dm_pciauto_postscan_setup_bridge(struct udevice *dev, int sub_bus);
+
+/**
+ * dm_pciauto_config_device() - Configure a PCI device ready for use
+ *
+ * If the device is a bridge, downstream devices will be probed.
+ *
+ * @dev: Device to configure
+ * @return the maximum PCI bus number found by this device. If there are no
+ * bridges, this just returns the device's bus number. If the device is a
+ * bridge then it will return a larger number, depending on the devices on
+ * that bridge. On error, returns a -ve error number.
+ */
+int dm_pciauto_config_device(struct udevice *dev);
+
+/**
+ * pci_get_bus() - Get a pointer to a bus, given its number
+ *
+ * This looks up a PCI bus based on its bus number. The bus is probed if
+ * necessary.
+ *
+ * @busnum: PCI bus number to look up
+ * @busp: Returns PCI bus on success
+ * @return 0 on success, or -ve error
+ */
+int pci_get_bus(int busnum, struct udevice **busp);
+
+#endif
diff --git a/roms/u-boot/drivers/pci/pci_mpc85xx.c b/roms/u-boot/drivers/pci/pci_mpc85xx.c
new file mode 100644
index 000000000..574cb784a
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_mpc85xx.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2019
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ */
+#include <common.h>
+#include <asm/bitops.h>
+#include <asm/cpm_85xx.h>
+#include <pci.h>
+#include <dm.h>
+#include <asm/fsl_law.h>
+
+struct mpc85xx_pci_priv {
+ void __iomem *cfg_addr;
+ void __iomem *cfg_data;
+};
+
+static int mpc85xx_pci_dm_read_config(const struct udevice *dev, pci_dev_t bdf,
+ uint offset, ulong *value,
+ enum pci_size_t size)
+{
+ struct mpc85xx_pci_priv *priv = dev_get_priv(dev);
+ u32 addr;
+
+ addr = bdf | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000;
+ out_be32(priv->cfg_addr, addr);
+ sync();
+ *value = pci_conv_32_to_size(in_le32(priv->cfg_data), offset, size);
+
+ return 0;
+}
+
+static int mpc85xx_pci_dm_write_config(struct udevice *dev, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct mpc85xx_pci_priv *priv = dev_get_priv(dev);
+ u32 addr;
+
+ addr = bdf | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000;
+ out_be32(priv->cfg_addr, addr);
+ sync();
+ out_le32(priv->cfg_data, pci_conv_size_to_32(0, value, offset, size));
+
+ return 0;
+}
+
+#ifdef CONFIG_FSL_LAW
+static int
+mpc85xx_pci_dm_setup_laws(struct pci_region *io, struct pci_region *mem,
+ struct pci_region *pre)
+{
+ /*
+ * Unfortunately we have defines for this addresse,
+ * as we have to setup the TLB, and at this stage
+ * we have no access to DT ... may we check here
+ * if the value in the define is the same ?
+ */
+ if (mem)
+ set_next_law(mem->phys_start, law_size_bits(mem->size),
+ LAW_TRGT_IF_PCI);
+ if (io)
+ set_next_law(io->phys_start, law_size_bits(io->size),
+ LAW_TRGT_IF_PCI);
+ if (pre)
+ set_next_law(pre->phys_start, law_size_bits(pre->size),
+ LAW_TRGT_IF_PCI);
+
+ return 0;
+}
+#endif
+
+static int mpc85xx_pci_dm_probe(struct udevice *dev)
+{
+ struct mpc85xx_pci_priv *priv = dev_get_priv(dev);
+ struct pci_region *io;
+ struct pci_region *mem;
+ struct pci_region *pre;
+ int count;
+ ccsr_pcix_t *pcix;
+
+ count = pci_get_regions(dev, &io, &mem, &pre);
+ if (count != 2) {
+ printf("%s: wrong count of regions %d only 2 allowed\n",
+ __func__, count);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_FSL_LAW
+ mpc85xx_pci_dm_setup_laws(io, mem, pre);
+#endif
+
+ pcix = priv->cfg_addr;
+ /* BAR 1: memory */
+ out_be32(&pcix->potar1, mem->bus_start >> 12);
+ out_be32(&pcix->potear1, (u64)mem->bus_start >> 44);
+ out_be32(&pcix->powbar1, mem->phys_start >> 12);
+ out_be32(&pcix->powbear1, (u64)mem->phys_start >> 44);
+ out_be32(&pcix->powar1, (POWAR_EN | POWAR_MEM_READ |
+ POWAR_MEM_WRITE | (__ilog2(mem->size) - 1)));
+
+ /* BAR 1: IO */
+ out_be32(&pcix->potar2, io->bus_start >> 12);
+ out_be32(&pcix->potear2, (u64)io->bus_start >> 44);
+ out_be32(&pcix->powbar2, io->phys_start >> 12);
+ out_be32(&pcix->powbear2, (u64)io->phys_start >> 44);
+ out_be32(&pcix->powar2, (POWAR_EN | POWAR_IO_READ |
+ POWAR_IO_WRITE | (__ilog2(io->size) - 1)));
+
+ out_be32(&pcix->pitar1, 0);
+ out_be32(&pcix->piwbar1, 0);
+ out_be32(&pcix->piwar1, (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL |
+ PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G));
+
+ out_be32(&pcix->powar3, 0);
+ out_be32(&pcix->powar4, 0);
+ out_be32(&pcix->piwar2, 0);
+ out_be32(&pcix->piwar3, 0);
+
+ return 0;
+}
+
+static int mpc85xx_pci_dm_remove(struct udevice *dev)
+{
+ return 0;
+}
+
+static int mpc85xx_pci_of_to_plat(struct udevice *dev)
+{
+ struct mpc85xx_pci_priv *priv = dev_get_priv(dev);
+ fdt_addr_t addr;
+
+ addr = devfdt_get_addr_index(dev, 0);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ priv->cfg_addr = (void __iomem *)map_physmem(addr, 0, MAP_NOCACHE);
+ priv->cfg_data = (void __iomem *)((ulong)priv->cfg_addr + 4);
+
+ return 0;
+}
+
+static const struct dm_pci_ops mpc85xx_pci_ops = {
+ .read_config = mpc85xx_pci_dm_read_config,
+ .write_config = mpc85xx_pci_dm_write_config,
+};
+
+static const struct udevice_id mpc85xx_pci_ids[] = {
+ { .compatible = "fsl,mpc8540-pci" },
+ { }
+};
+
+U_BOOT_DRIVER(mpc85xx_pci) = {
+ .name = "mpc85xx_pci",
+ .id = UCLASS_PCI,
+ .of_match = mpc85xx_pci_ids,
+ .ops = &mpc85xx_pci_ops,
+ .probe = mpc85xx_pci_dm_probe,
+ .remove = mpc85xx_pci_dm_remove,
+ .of_to_plat = mpc85xx_pci_of_to_plat,
+ .priv_auto = sizeof(struct mpc85xx_pci_priv),
+};
diff --git a/roms/u-boot/drivers/pci/pci_msc01.c b/roms/u-boot/drivers/pci/pci_msc01.c
new file mode 100644
index 000000000..04838200a
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_msc01.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@mips.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <msc01.h>
+#include <pci.h>
+#include <pci_msc01.h>
+#include <asm/io.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+struct msc01_pci_controller {
+ struct pci_controller hose;
+ void *base;
+};
+
+static inline struct msc01_pci_controller *
+hose_to_msc01(struct pci_controller *hose)
+{
+ return container_of(hose, struct msc01_pci_controller, hose);
+}
+
+static int msc01_config_access(struct msc01_pci_controller *msc01,
+ unsigned char access_type, pci_dev_t bdf,
+ int where, u32 *data)
+{
+ const u32 aborts = MSC01_PCI_INTSTAT_MA_MSK | MSC01_PCI_INTSTAT_TA_MSK;
+ void *intstat = msc01->base + MSC01_PCI_INTSTAT_OFS;
+ void *cfgdata = msc01->base + MSC01_PCI_CFGDATA_OFS;
+ unsigned int bus = PCI_BUS(bdf);
+ unsigned int dev = PCI_DEV(bdf);
+ unsigned int devfn = PCI_DEV(bdf) << 3 | PCI_FUNC(bdf);
+
+ /* clear abort status */
+ __raw_writel(aborts, intstat);
+
+ /* setup address */
+ __raw_writel((bus << MSC01_PCI_CFGADDR_BNUM_SHF) |
+ (dev << MSC01_PCI_CFGADDR_DNUM_SHF) |
+ (devfn << MSC01_PCI_CFGADDR_FNUM_SHF) |
+ ((where / 4) << MSC01_PCI_CFGADDR_RNUM_SHF),
+ msc01->base + MSC01_PCI_CFGADDR_OFS);
+
+ /* perform access */
+ if (access_type == PCI_ACCESS_WRITE)
+ __raw_writel(*data, cfgdata);
+ else
+ *data = __raw_readl(cfgdata);
+
+ /* check for aborts */
+ if (__raw_readl(intstat) & aborts) {
+ /* clear abort status */
+ __raw_writel(aborts, intstat);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int msc01_read_config_dword(struct pci_controller *hose, pci_dev_t dev,
+ int where, u32 *value)
+{
+ struct msc01_pci_controller *msc01 = hose_to_msc01(hose);
+
+ *value = 0xffffffff;
+ return msc01_config_access(msc01, PCI_ACCESS_READ, dev, where, value);
+}
+
+static int msc01_write_config_dword(struct pci_controller *hose, pci_dev_t dev,
+ int where, u32 value)
+{
+ struct msc01_pci_controller *gt = hose_to_msc01(hose);
+ u32 data = value;
+
+ return msc01_config_access(gt, PCI_ACCESS_WRITE, dev, where, &data);
+}
+
+void msc01_pci_init(void *base, unsigned long sys_bus, unsigned long sys_phys,
+ unsigned long sys_size, unsigned long mem_bus,
+ unsigned long mem_phys, unsigned long mem_size,
+ unsigned long io_bus, unsigned long io_phys,
+ unsigned long io_size)
+{
+ static struct msc01_pci_controller global_msc01;
+ struct msc01_pci_controller *msc01;
+ struct pci_controller *hose;
+
+ msc01 = &global_msc01;
+ msc01->base = base;
+
+ hose = &msc01->hose;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0;
+
+ /* System memory space */
+ pci_set_region(&hose->regions[0], sys_bus, sys_phys, sys_size,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region(&hose->regions[1], mem_bus, mem_phys, mem_size,
+ PCI_REGION_MEM);
+
+ /* PCI I/O space */
+ pci_set_region(&hose->regions[2], io_bus, io_phys, io_size,
+ PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_set_ops(hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ msc01_read_config_dword,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ msc01_write_config_dword);
+
+ pci_register_hose(hose);
+ hose->last_busno = pci_hose_scan(hose);
+}
diff --git a/roms/u-boot/drivers/pci/pci_mvebu.c b/roms/u-boot/drivers/pci/pci_mvebu.c
new file mode 100644
index 000000000..0c1d7cd77
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_mvebu.c
@@ -0,0 +1,541 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe driver for Marvell MVEBU SoCs
+ *
+ * Based on Barebox drivers/pci/pci-mvebu.c
+ *
+ * Ported to U-Boot by:
+ * Anton Schubert <anton.schubert@gmx.de>
+ * Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/of_access.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/mbus.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* PCIe unit register offsets */
+#define SELECT(x, n) ((x >> n) & 1UL)
+
+#define PCIE_DEV_ID_OFF 0x0000
+#define PCIE_CMD_OFF 0x0004
+#define PCIE_DEV_REV_OFF 0x0008
+#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3))
+#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3))
+#define PCIE_CAPAB_OFF 0x0060
+#define PCIE_CTRL_STAT_OFF 0x0068
+#define PCIE_HEADER_LOG_4_OFF 0x0128
+#define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4))
+#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
+#define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4))
+#define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4))
+#define PCIE_WIN5_CTRL_OFF 0x1880
+#define PCIE_WIN5_BASE_OFF 0x1884
+#define PCIE_WIN5_REMAP_OFF 0x188c
+#define PCIE_CONF_ADDR_OFF 0x18f8
+#define PCIE_CONF_ADDR_EN BIT(31)
+#define PCIE_CONF_REG(r) ((((r) & 0xf00) << 16) | ((r) & 0xfc))
+#define PCIE_CONF_BUS(b) (((b) & 0xff) << 16)
+#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 11)
+#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8)
+#define PCIE_CONF_ADDR(dev, reg) \
+ (PCIE_CONF_BUS(PCI_BUS(dev)) | PCIE_CONF_DEV(PCI_DEV(dev)) | \
+ PCIE_CONF_FUNC(PCI_FUNC(dev)) | PCIE_CONF_REG(reg) | \
+ PCIE_CONF_ADDR_EN)
+#define PCIE_CONF_DATA_OFF 0x18fc
+#define PCIE_MASK_OFF 0x1910
+#define PCIE_MASK_ENABLE_INTS (0xf << 24)
+#define PCIE_CTRL_OFF 0x1a00
+#define PCIE_CTRL_X1_MODE BIT(0)
+#define PCIE_STAT_OFF 0x1a04
+#define PCIE_STAT_BUS (0xff << 8)
+#define PCIE_STAT_DEV (0x1f << 16)
+#define PCIE_STAT_LINK_DOWN BIT(0)
+#define PCIE_DEBUG_CTRL 0x1a60
+#define PCIE_DEBUG_SOFT_RESET BIT(20)
+
+struct mvebu_pcie {
+ struct pci_controller hose;
+ void __iomem *base;
+ void __iomem *membase;
+ struct resource mem;
+ void __iomem *iobase;
+ struct resource io;
+ u32 port;
+ u32 lane;
+ int devfn;
+ u32 lane_mask;
+ int first_busno;
+ int local_dev;
+ char name[16];
+ unsigned int mem_target;
+ unsigned int mem_attr;
+ unsigned int io_target;
+ unsigned int io_attr;
+};
+
+/*
+ * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
+ * into SoCs address space. Each controller will map 128M of MEM
+ * and 64K of I/O space when registered.
+ */
+static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE;
+#define PCIE_MEM_SIZE (128 << 20)
+static void __iomem *mvebu_pcie_iobase = (void __iomem *)MBUS_PCI_IO_BASE;
+
+static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
+{
+ u32 val;
+ val = readl(pcie->base + PCIE_STAT_OFF);
+ return !(val & PCIE_STAT_LINK_DOWN);
+}
+
+static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno)
+{
+ u32 stat;
+
+ stat = readl(pcie->base + PCIE_STAT_OFF);
+ stat &= ~PCIE_STAT_BUS;
+ stat |= busno << 8;
+ writel(stat, pcie->base + PCIE_STAT_OFF);
+}
+
+static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie *pcie, int devno)
+{
+ u32 stat;
+
+ stat = readl(pcie->base + PCIE_STAT_OFF);
+ stat &= ~PCIE_STAT_DEV;
+ stat |= devno << 16;
+ writel(stat, pcie->base + PCIE_STAT_OFF);
+}
+
+static int mvebu_pcie_get_local_bus_nr(struct mvebu_pcie *pcie)
+{
+ u32 stat;
+
+ stat = readl(pcie->base + PCIE_STAT_OFF);
+ return (stat & PCIE_STAT_BUS) >> 8;
+}
+
+static int mvebu_pcie_get_local_dev_nr(struct mvebu_pcie *pcie)
+{
+ u32 stat;
+
+ stat = readl(pcie->base + PCIE_STAT_OFF);
+ return (stat & PCIE_STAT_DEV) >> 16;
+}
+
+static inline struct mvebu_pcie *hose_to_pcie(struct pci_controller *hose)
+{
+ return container_of(hose, struct mvebu_pcie, hose);
+}
+
+static int mvebu_pcie_valid_addr(struct mvebu_pcie *pcie, pci_dev_t bdf)
+{
+ /*
+ * There are two devices visible on local bus:
+ * * on slot configured by function mvebu_pcie_set_local_dev_nr()
+ * (by default this register is set to 0) there is a
+ * "Marvell Memory controller", which isn't useful in root complex
+ * mode,
+ * * on all other slots the real PCIe card connected to the PCIe slot.
+ *
+ * We therefore allow access only to the real PCIe card.
+ */
+ if (PCI_BUS(bdf) == pcie->first_busno &&
+ PCI_DEV(bdf) != !pcie->local_dev)
+ return 0;
+
+ return 1;
+}
+
+static int mvebu_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct mvebu_pcie *pcie = dev_get_plat(bus);
+ u32 data;
+
+ debug("PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ if (!mvebu_pcie_valid_addr(pcie, bdf)) {
+ debug("- out of range\n");
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ /* write address */
+ writel(PCIE_CONF_ADDR(bdf, offset), pcie->base + PCIE_CONF_ADDR_OFF);
+
+ /* read data */
+ data = readl(pcie->base + PCIE_CONF_DATA_OFF);
+ debug("(addr,size,val)=(0x%04x, %d, 0x%08x)\n", offset, size, data);
+ *valuep = pci_conv_32_to_size(data, offset, size);
+
+ return 0;
+}
+
+static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct mvebu_pcie *pcie = dev_get_plat(bus);
+ u32 data;
+
+ debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ debug("(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", offset, size, value);
+
+ if (!mvebu_pcie_valid_addr(pcie, bdf)) {
+ debug("- out of range\n");
+ return 0;
+ }
+
+ /* write address */
+ writel(PCIE_CONF_ADDR(bdf, offset), pcie->base + PCIE_CONF_ADDR_OFF);
+
+ /* write data */
+ data = pci_conv_size_to_32(0, value, offset, size);
+ writel(data, pcie->base + PCIE_CONF_DATA_OFF);
+
+ return 0;
+}
+
+/*
+ * Setup PCIE BARs and Address Decode Wins:
+ * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
+ * WIN[0-3] -> DRAM bank[0-3]
+ */
+static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
+{
+ const struct mbus_dram_target_info *dram = mvebu_mbus_dram_info();
+ u32 size;
+ int i;
+
+ /* First, disable and clear BARs and windows. */
+ for (i = 1; i < 3; i++) {
+ writel(0, pcie->base + PCIE_BAR_CTRL_OFF(i));
+ writel(0, pcie->base + PCIE_BAR_LO_OFF(i));
+ writel(0, pcie->base + PCIE_BAR_HI_OFF(i));
+ }
+
+ for (i = 0; i < 5; i++) {
+ writel(0, pcie->base + PCIE_WIN04_CTRL_OFF(i));
+ writel(0, pcie->base + PCIE_WIN04_BASE_OFF(i));
+ writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i));
+ }
+
+ writel(0, pcie->base + PCIE_WIN5_CTRL_OFF);
+ writel(0, pcie->base + PCIE_WIN5_BASE_OFF);
+ writel(0, pcie->base + PCIE_WIN5_REMAP_OFF);
+
+ /* Setup windows for DDR banks. Count total DDR size on the fly. */
+ size = 0;
+ for (i = 0; i < dram->num_cs; i++) {
+ const struct mbus_dram_window *cs = dram->cs + i;
+
+ writel(cs->base & 0xffff0000,
+ pcie->base + PCIE_WIN04_BASE_OFF(i));
+ writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i));
+ writel(((cs->size - 1) & 0xffff0000) |
+ (cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ pcie->base + PCIE_WIN04_CTRL_OFF(i));
+
+ size += cs->size;
+ }
+
+ /* Round up 'size' to the nearest power of two. */
+ if ((size & (size - 1)) != 0)
+ size = 1 << fls(size);
+
+ /* Setup BAR[1] to all DRAM banks. */
+ writel(dram->cs[0].base | 0xc, pcie->base + PCIE_BAR_LO_OFF(1));
+ writel(0, pcie->base + PCIE_BAR_HI_OFF(1));
+ writel(((size - 1) & 0xffff0000) | 0x1,
+ pcie->base + PCIE_BAR_CTRL_OFF(1));
+}
+
+static int mvebu_pcie_probe(struct udevice *dev)
+{
+ struct mvebu_pcie *pcie = dev_get_plat(dev);
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ int bus = dev_seq(dev);
+ u32 reg;
+
+ debug("%s: PCIe %d.%d - up, base %08x\n", __func__,
+ pcie->port, pcie->lane, (u32)pcie->base);
+
+ /* Read Id info and local bus/dev */
+ debug("direct conf read %08x, local bus %d, local dev %d\n",
+ readl(pcie->base), mvebu_pcie_get_local_bus_nr(pcie),
+ mvebu_pcie_get_local_dev_nr(pcie));
+
+ pcie->first_busno = bus;
+ pcie->local_dev = 1;
+
+ mvebu_pcie_set_local_bus_nr(pcie, bus);
+ mvebu_pcie_set_local_dev_nr(pcie, pcie->local_dev);
+
+ pcie->mem.start = (u32)mvebu_pcie_membase;
+ pcie->mem.end = pcie->mem.start + PCIE_MEM_SIZE - 1;
+ mvebu_pcie_membase += PCIE_MEM_SIZE;
+
+ if (mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
+ (phys_addr_t)pcie->mem.start,
+ PCIE_MEM_SIZE)) {
+ printf("PCIe unable to add mbus window for mem at %08x+%08x\n",
+ (u32)pcie->mem.start, PCIE_MEM_SIZE);
+ }
+
+ pcie->io.start = (u32)mvebu_pcie_iobase;
+ pcie->io.end = pcie->io.start + MBUS_PCI_IO_SIZE - 1;
+ mvebu_pcie_iobase += MBUS_PCI_IO_SIZE;
+
+ if (mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
+ (phys_addr_t)pcie->io.start,
+ MBUS_PCI_IO_SIZE)) {
+ printf("PCIe unable to add mbus window for IO at %08x+%08x\n",
+ (u32)pcie->io.start, MBUS_PCI_IO_SIZE);
+ }
+
+ /* Setup windows and configure host bridge */
+ mvebu_pcie_setup_wins(pcie);
+
+ /* Master + slave enable. */
+ reg = readl(pcie->base + PCIE_CMD_OFF);
+ reg |= PCI_COMMAND_MEMORY;
+ reg |= PCI_COMMAND_IO;
+ reg |= PCI_COMMAND_MASTER;
+ reg |= BIT(10); /* disable interrupts */
+ writel(reg, pcie->base + PCIE_CMD_OFF);
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 0, pcie->mem.start,
+ pcie->mem.start, PCIE_MEM_SIZE, PCI_REGION_MEM);
+ pci_set_region(hose->regions + 1,
+ 0, 0,
+ gd->ram_size,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+ pci_set_region(hose->regions + 2, pcie->io.start,
+ pcie->io.start, MBUS_PCI_IO_SIZE, PCI_REGION_IO);
+ hose->region_count = 3;
+
+ /* Set BAR0 to internal registers */
+ writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0));
+ writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
+
+ return 0;
+}
+
+static int mvebu_pcie_port_parse_dt(ofnode node, struct mvebu_pcie *pcie)
+{
+ const u32 *addr;
+ int len;
+
+ addr = ofnode_get_property(node, "assigned-addresses", &len);
+ if (!addr) {
+ pr_err("property \"assigned-addresses\" not found");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ pcie->base = (void *)(fdt32_to_cpu(addr[2]) + SOC_REGS_PHY_BASE);
+
+ return 0;
+}
+
+#define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03)
+#define DT_TYPE_IO 0x1
+#define DT_TYPE_MEM32 0x2
+#define DT_CPUADDR_TO_TARGET(cpuaddr) (((cpuaddr) >> 56) & 0xFF)
+#define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF)
+
+static int mvebu_get_tgt_attr(ofnode node, int devfn,
+ unsigned long type,
+ unsigned int *tgt,
+ unsigned int *attr)
+{
+ const int na = 3, ns = 2;
+ const __be32 *range;
+ int rlen, nranges, rangesz, pna, i;
+
+ *tgt = -1;
+ *attr = -1;
+
+ range = ofnode_get_property(node, "ranges", &rlen);
+ if (!range)
+ return -EINVAL;
+
+ /*
+ * Linux uses of_n_addr_cells() to get the number of address cells
+ * here. Currently this function is only available in U-Boot when
+ * CONFIG_OF_LIVE is enabled. Until this is enabled for MVEBU in
+ * general, lets't hardcode the "pna" value in the U-Boot code.
+ */
+ pna = 2; /* hardcoded for now because of lack of of_n_addr_cells() */
+ rangesz = pna + na + ns;
+ nranges = rlen / sizeof(__be32) / rangesz;
+
+ for (i = 0; i < nranges; i++, range += rangesz) {
+ u32 flags = of_read_number(range, 1);
+ u32 slot = of_read_number(range + 1, 1);
+ u64 cpuaddr = of_read_number(range + na, pna);
+ unsigned long rtype;
+
+ if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_IO)
+ rtype = IORESOURCE_IO;
+ else if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_MEM32)
+ rtype = IORESOURCE_MEM;
+ else
+ continue;
+
+ /*
+ * The Linux code used PCI_SLOT() here, which expects devfn
+ * in bits 7..0. PCI_DEV() in U-Boot is similar to PCI_SLOT(),
+ * only expects devfn in 15..8, where its saved in this driver.
+ */
+ if (slot == PCI_DEV(devfn) && type == rtype) {
+ *tgt = DT_CPUADDR_TO_TARGET(cpuaddr);
+ *attr = DT_CPUADDR_TO_ATTR(cpuaddr);
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static int mvebu_pcie_of_to_plat(struct udevice *dev)
+{
+ struct mvebu_pcie *pcie = dev_get_plat(dev);
+ int ret = 0;
+
+ /* Get port number, lane number and memory target / attr */
+ if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port",
+ &pcie->port)) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-lane", &pcie->lane))
+ pcie->lane = 0;
+
+ sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane);
+
+ /* pci_get_devfn() returns devfn in bits 15..8, see PCI_DEV usage */
+ pcie->devfn = pci_get_devfn(dev);
+ if (pcie->devfn < 0) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn,
+ IORESOURCE_MEM,
+ &pcie->mem_target, &pcie->mem_attr);
+ if (ret < 0) {
+ printf("%s: cannot get tgt/attr for mem window\n", pcie->name);
+ goto err;
+ }
+
+ ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn,
+ IORESOURCE_IO,
+ &pcie->io_target, &pcie->io_attr);
+ if (ret < 0) {
+ printf("%s: cannot get tgt/attr for IO window\n", pcie->name);
+ goto err;
+ }
+
+ /* Parse PCIe controller register base from DT */
+ ret = mvebu_pcie_port_parse_dt(dev_ofnode(dev), pcie);
+ if (ret < 0)
+ goto err;
+
+ /* Check link and skip ports that have no link */
+ if (!mvebu_pcie_link_up(pcie)) {
+ debug("%s: %s - down\n", __func__, pcie->name);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ return ret;
+}
+
+static const struct dm_pci_ops mvebu_pcie_ops = {
+ .read_config = mvebu_pcie_read_config,
+ .write_config = mvebu_pcie_write_config,
+};
+
+static struct driver pcie_mvebu_drv = {
+ .name = "pcie_mvebu",
+ .id = UCLASS_PCI,
+ .ops = &mvebu_pcie_ops,
+ .probe = mvebu_pcie_probe,
+ .of_to_plat = mvebu_pcie_of_to_plat,
+ .plat_auto = sizeof(struct mvebu_pcie),
+};
+
+/*
+ * Use a MISC device to bind the n instances (child nodes) of the
+ * PCIe base controller in UCLASS_PCI.
+ */
+static int mvebu_pcie_bind(struct udevice *parent)
+{
+ struct mvebu_pcie *pcie;
+ struct uclass_driver *drv;
+ struct udevice *dev;
+ ofnode subnode;
+
+ /* Lookup eth driver */
+ drv = lists_uclass_lookup(UCLASS_PCI);
+ if (!drv) {
+ puts("Cannot find PCI driver\n");
+ return -ENOENT;
+ }
+
+ ofnode_for_each_subnode(subnode, dev_ofnode(parent)) {
+ if (!ofnode_is_available(subnode))
+ continue;
+
+ pcie = calloc(1, sizeof(*pcie));
+ if (!pcie)
+ return -ENOMEM;
+
+ /* Create child device UCLASS_PCI and bind it */
+ device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode,
+ &dev);
+ }
+
+ return 0;
+}
+
+static const struct udevice_id mvebu_pcie_ids[] = {
+ { .compatible = "marvell,armada-xp-pcie" },
+ { .compatible = "marvell,armada-370-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_mvebu_base) = {
+ .name = "pcie_mvebu_base",
+ .id = UCLASS_MISC,
+ .of_match = mvebu_pcie_ids,
+ .bind = mvebu_pcie_bind,
+};
diff --git a/roms/u-boot/drivers/pci/pci_octeontx.c b/roms/u-boot/drivers/pci/pci_octeontx.c
new file mode 100644
index 000000000..46855c5cd
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_octeontx.c
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * https://spdx.org/licenses
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <malloc.h>
+#include <pci.h>
+#include <asm/global_data.h>
+
+#include <asm/io.h>
+
+#include <linux/ioport.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * This driver supports multiple types of operations / host bridges / busses:
+ *
+ * OTX_ECAM: Octeon TX & TX2 ECAM (Enhanced Configuration Access Mechanism)
+ * Used to access the internal on-chip devices which are connected
+ * to internal buses
+ * OTX_PEM: Octeon TX PEM (PCI Express MAC)
+ * Used to access the external (off-chip) PCI devices
+ * OTX2_PEM: Octeon TX2 PEM (PCI Express MAC)
+ * Used to access the external (off-chip) PCI devices
+ */
+enum {
+ OTX_ECAM,
+ OTX_PEM,
+ OTX2_PEM,
+};
+
+/**
+ * struct octeontx_pci - Driver private data
+ * @type: Device type matched via compatible (e.g. OTX_ECAM etc)
+ * @cfg: Config resource
+ * @bus: Bus resource
+ */
+struct octeontx_pci {
+ unsigned int type;
+
+ struct resource cfg;
+ struct resource bus;
+};
+
+static uintptr_t octeontx_cfg_addr(struct octeontx_pci *pcie,
+ int bus_offs, int shift_offs,
+ pci_dev_t bdf, uint offset)
+{
+ u32 bus, dev, func;
+ uintptr_t address;
+
+ bus = PCI_BUS(bdf) + bus_offs;
+ dev = PCI_DEV(bdf);
+ func = PCI_FUNC(bdf);
+
+ address = (bus << (20 + shift_offs)) |
+ (dev << (15 + shift_offs)) |
+ (func << (12 + shift_offs)) | offset;
+ address += pcie->cfg.start;
+
+ return address;
+}
+
+static ulong readl_size(uintptr_t addr, enum pci_size_t size)
+{
+ ulong val;
+
+ switch (size) {
+ case PCI_SIZE_8:
+ val = readb(addr);
+ break;
+ case PCI_SIZE_16:
+ val = readw(addr);
+ break;
+ case PCI_SIZE_32:
+ val = readl(addr);
+ break;
+ default:
+ printf("Invalid size\n");
+ return -EINVAL;
+ };
+
+ return val;
+}
+
+static void writel_size(uintptr_t addr, enum pci_size_t size, ulong valuep)
+{
+ switch (size) {
+ case PCI_SIZE_8:
+ writeb(valuep, addr);
+ break;
+ case PCI_SIZE_16:
+ writew(valuep, addr);
+ break;
+ case PCI_SIZE_32:
+ writel(valuep, addr);
+ break;
+ default:
+ printf("Invalid size\n");
+ };
+}
+
+static bool octeontx_bdf_invalid(pci_dev_t bdf)
+{
+ if (PCI_BUS(bdf) == 1 && PCI_DEV(bdf) > 0)
+ return true;
+
+ return false;
+}
+
+static int octeontx_ecam_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ uintptr_t address;
+
+ address = octeontx_cfg_addr(pcie, pcie->bus.start - hose->first_busno,
+ 0, bdf, offset);
+ *valuep = readl_size(address, size);
+
+ debug("%02x.%02x.%02x: u%d %x -> %lx\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, *valuep);
+
+ return 0;
+}
+
+static int octeontx_ecam_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ uintptr_t address;
+
+ address = octeontx_cfg_addr(pcie, pcie->bus.start - hose->first_busno,
+ 0, bdf, offset);
+ writel_size(address, size, value);
+
+ debug("%02x.%02x.%02x: u%d %x <- %lx\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, value);
+
+ return 0;
+}
+
+static int octeontx_pem_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ uintptr_t address;
+ u8 hdrtype;
+ u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
+ u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
+
+ address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 4,
+ bdf, 0);
+
+ *valuep = pci_conv_32_to_size(~0UL, offset, size);
+
+ if (octeontx_bdf_invalid(bdf))
+ return -EPERM;
+
+ *valuep = readl_size(address + offset, size);
+
+ hdrtype = readb(address + PCI_HEADER_TYPE);
+ if (hdrtype == PCI_HEADER_TYPE_BRIDGE &&
+ offset >= PCI_PRIMARY_BUS &&
+ offset <= PCI_SUBORDINATE_BUS &&
+ *valuep != pci_conv_32_to_size(~0UL, offset, size))
+ *valuep -= pci_conv_32_to_size(bus_offs, offset, size);
+
+ return 0;
+}
+
+static int octeontx_pem_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ uintptr_t address;
+ u8 hdrtype;
+ u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
+ u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
+
+ address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 4, bdf, 0);
+
+ hdrtype = readb(address + PCI_HEADER_TYPE);
+ if (hdrtype == PCI_HEADER_TYPE_BRIDGE &&
+ offset >= PCI_PRIMARY_BUS &&
+ offset <= PCI_SUBORDINATE_BUS &&
+ value != pci_conv_32_to_size(~0UL, offset, size))
+ value += pci_conv_32_to_size(bus_offs, offset, size);
+
+ if (octeontx_bdf_invalid(bdf))
+ return -EPERM;
+
+ writel_size(address + offset, size, value);
+
+ debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
+ address, value);
+
+ return 0;
+}
+
+static int octeontx2_pem_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ uintptr_t address;
+
+ address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 0,
+ bdf, 0);
+
+ *valuep = pci_conv_32_to_size(~0UL, offset, size);
+
+ if (octeontx_bdf_invalid(bdf))
+ return -EPERM;
+
+ *valuep = readl_size(address + offset, size);
+
+ debug("%02x.%02x.%02x: u%d %x (%lx) -> %lx\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
+ address, *valuep);
+
+ return 0;
+}
+
+static int octeontx2_pem_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ uintptr_t address;
+
+ address = octeontx_cfg_addr(pcie, 1 - hose->first_busno, 0,
+ bdf, 0);
+
+ if (octeontx_bdf_invalid(bdf))
+ return -EPERM;
+
+ writel_size(address + offset, size, value);
+
+ debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
+ address, value);
+
+ return 0;
+}
+
+int pci_octeontx_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
+ int ret = -EIO;
+
+ switch (pcie->type) {
+ case OTX_ECAM:
+ ret = octeontx_ecam_read_config(bus, bdf, offset, valuep,
+ size);
+ break;
+ case OTX_PEM:
+ ret = octeontx_pem_read_config(bus, bdf, offset, valuep,
+ size);
+ break;
+ case OTX2_PEM:
+ ret = octeontx2_pem_read_config(bus, bdf, offset, valuep,
+ size);
+ break;
+ }
+
+ return ret;
+}
+
+int pci_octeontx_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
+ int ret = -EIO;
+
+ switch (pcie->type) {
+ case OTX_ECAM:
+ ret = octeontx_ecam_write_config(bus, bdf, offset, value,
+ size);
+ break;
+ case OTX_PEM:
+ ret = octeontx_pem_write_config(bus, bdf, offset, value,
+ size);
+ break;
+ case OTX2_PEM:
+ ret = octeontx2_pem_write_config(bus, bdf, offset, value,
+ size);
+ break;
+ }
+
+ return ret;
+}
+
+static int pci_octeontx_of_to_plat(struct udevice *dev)
+{
+ return 0;
+}
+
+static int pci_octeontx_probe(struct udevice *dev)
+{
+ struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(dev);
+ int err;
+
+ pcie->type = dev_get_driver_data(dev);
+
+ err = dev_read_resource(dev, 0, &pcie->cfg);
+ if (err) {
+ debug("Error reading resource: %s\n", fdt_strerror(err));
+ return err;
+ }
+
+ err = dev_read_pci_bus_range(dev, &pcie->bus);
+ if (err) {
+ debug("Error reading resource: %s\n", fdt_strerror(err));
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct dm_pci_ops pci_octeontx_ops = {
+ .read_config = pci_octeontx_read_config,
+ .write_config = pci_octeontx_write_config,
+};
+
+static const struct udevice_id pci_octeontx_ids[] = {
+ { .compatible = "cavium,pci-host-thunder-ecam", .data = OTX_ECAM },
+ { .compatible = "cavium,pci-host-octeontx-ecam", .data = OTX_ECAM },
+ { .compatible = "pci-host-ecam-generic", .data = OTX_ECAM },
+ { .compatible = "cavium,pci-host-thunder-pem", .data = OTX_PEM },
+ { .compatible = "marvell,pci-host-octeontx2-pem", .data = OTX2_PEM },
+ { }
+};
+
+U_BOOT_DRIVER(pci_octeontx) = {
+ .name = "pci_octeontx",
+ .id = UCLASS_PCI,
+ .of_match = pci_octeontx_ids,
+ .ops = &pci_octeontx_ops,
+ .of_to_plat = pci_octeontx_of_to_plat,
+ .probe = pci_octeontx_probe,
+ .priv_auto = sizeof(struct octeontx_pci),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/pci/pci_rom.c b/roms/u-boot/drivers/pci/pci_rom.c
new file mode 100644
index 000000000..7bad4c82c
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_rom.c
@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2014 Google, Inc
+ *
+ * From coreboot, originally based on the Linux kernel (drivers/pci/pci.c).
+ *
+ * Modifications are:
+ * Copyright (C) 2003-2004 Linux Networx
+ * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
+ * Copyright (C) 2003-2006 Ronald G. Minnich <rminnich@gmail.com>
+ * Copyright (C) 2004-2005 Li-Ta Lo <ollie@lanl.gov>
+ * Copyright (C) 2005-2006 Tyan
+ * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan)
+ * Copyright (C) 2005-2009 coresystems GmbH
+ * (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
+ *
+ * PCI Bus Services, see include/linux/pci.h for further explanation.
+ *
+ * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
+ * David Mosberger-Tang
+ *
+ * Copyright 1997 -- 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#define LOG_CATEGORY UCLASS_PCI
+
+#include <common.h>
+#include <bios_emul.h>
+#include <bootstage.h>
+#include <dm.h>
+#include <errno.h>
+#include <init.h>
+#include <log.h>
+#include <malloc.h>
+#include <pci.h>
+#include <pci_rom.h>
+#include <vbe.h>
+#include <video.h>
+#include <video_fb.h>
+#include <acpi/acpi_s3.h>
+#include <asm/global_data.h>
+#include <linux/screen_info.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+__weak bool board_should_run_oprom(struct udevice *dev)
+{
+#if defined(CONFIG_X86) && defined(CONFIG_HAVE_ACPI_RESUME)
+ if (gd->arch.prev_sleep_state == ACPI_S3) {
+ if (IS_ENABLED(CONFIG_S3_VGA_ROM_RUN))
+ return true;
+ else
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+__weak bool board_should_load_oprom(struct udevice *dev)
+{
+ return true;
+}
+
+__weak uint32_t board_map_oprom_vendev(uint32_t vendev)
+{
+ return vendev;
+}
+
+static int pci_rom_probe(struct udevice *dev, struct pci_rom_header **hdrp)
+{
+ struct pci_child_plat *pplat = dev_get_parent_plat(dev);
+ struct pci_rom_header *rom_header;
+ struct pci_rom_data *rom_data;
+ u16 rom_vendor, rom_device;
+ u32 rom_class;
+ u32 vendev;
+ u32 mapped_vendev;
+ u32 rom_address;
+
+ vendev = pplat->vendor << 16 | pplat->device;
+ mapped_vendev = board_map_oprom_vendev(vendev);
+ if (vendev != mapped_vendev)
+ debug("Device ID mapped to %#08x\n", mapped_vendev);
+
+#ifdef CONFIG_VGA_BIOS_ADDR
+ rom_address = CONFIG_VGA_BIOS_ADDR;
+#else
+
+ dm_pci_read_config32(dev, PCI_ROM_ADDRESS, &rom_address);
+ if (rom_address == 0x00000000 || rom_address == 0xffffffff) {
+ debug("%s: rom_address=%x\n", __func__, rom_address);
+ return -ENOENT;
+ }
+
+ /* Enable expansion ROM address decoding. */
+ dm_pci_write_config32(dev, PCI_ROM_ADDRESS,
+ rom_address | PCI_ROM_ADDRESS_ENABLE);
+#endif
+ debug("Option ROM address %x\n", rom_address);
+ rom_header = (struct pci_rom_header *)(unsigned long)rom_address;
+
+ debug("PCI expansion ROM, signature %#04x, INIT size %#04x, data ptr %#04x\n",
+ le16_to_cpu(rom_header->signature),
+ rom_header->size * 512, le16_to_cpu(rom_header->data));
+
+ if (le16_to_cpu(rom_header->signature) != PCI_ROM_HDR) {
+ printf("Incorrect expansion ROM header signature %04x\n",
+ le16_to_cpu(rom_header->signature));
+#ifndef CONFIG_VGA_BIOS_ADDR
+ /* Disable expansion ROM address decoding */
+ dm_pci_write_config32(dev, PCI_ROM_ADDRESS, rom_address);
+#endif
+ return -EINVAL;
+ }
+
+ rom_data = (((void *)rom_header) + le16_to_cpu(rom_header->data));
+ rom_vendor = le16_to_cpu(rom_data->vendor);
+ rom_device = le16_to_cpu(rom_data->device);
+
+ debug("PCI ROM image, vendor ID %04x, device ID %04x,\n",
+ rom_vendor, rom_device);
+
+ /* If the device id is mapped, a mismatch is expected */
+ if ((pplat->vendor != rom_vendor || pplat->device != rom_device) &&
+ (vendev == mapped_vendev)) {
+ printf("ID mismatch: vendor ID %04x, device ID %04x\n",
+ rom_vendor, rom_device);
+ /* Continue anyway */
+ }
+
+ rom_class = (le16_to_cpu(rom_data->class_hi) << 8) | rom_data->class_lo;
+ debug("PCI ROM image, Class Code %06x, Code Type %02x\n",
+ rom_class, rom_data->type);
+
+ if (pplat->class != rom_class) {
+ debug("Class Code mismatch ROM %06x, dev %06x\n",
+ rom_class, pplat->class);
+ }
+ *hdrp = rom_header;
+
+ return 0;
+}
+
+/**
+ * pci_rom_load() - Load a ROM image and return a pointer to it
+ *
+ * @rom_header: Pointer to ROM image
+ * @ram_headerp: Returns a pointer to the image in RAM
+ * @allocedp: Returns true if @ram_headerp was allocated and needs
+ * to be freed
+ * @return 0 if OK, -ve on error. Note that @allocedp is set up regardless of
+ * the error state. Even if this function returns an error, it may have
+ * allocated memory.
+ */
+static int pci_rom_load(struct pci_rom_header *rom_header,
+ struct pci_rom_header **ram_headerp, bool *allocedp)
+{
+ struct pci_rom_data *rom_data;
+ unsigned int rom_size;
+ unsigned int image_size = 0;
+ void *target;
+
+ *allocedp = false;
+ do {
+ /* Get next image, until we see an x86 version */
+ rom_header = (struct pci_rom_header *)((void *)rom_header +
+ image_size);
+
+ rom_data = (struct pci_rom_data *)((void *)rom_header +
+ le16_to_cpu(rom_header->data));
+
+ image_size = le16_to_cpu(rom_data->ilen) * 512;
+ } while ((rom_data->type != 0) && (rom_data->indicator == 0));
+
+ if (rom_data->type != 0)
+ return -EACCES;
+
+ rom_size = rom_header->size * 512;
+
+#ifdef PCI_VGA_RAM_IMAGE_START
+ target = (void *)PCI_VGA_RAM_IMAGE_START;
+#else
+ target = (void *)malloc(rom_size);
+ if (!target)
+ return -ENOMEM;
+ *allocedp = true;
+#endif
+ if (target != rom_header) {
+ ulong start = get_timer(0);
+
+ debug("Copying VGA ROM Image from %p to %p, 0x%x bytes\n",
+ rom_header, target, rom_size);
+ memcpy(target, rom_header, rom_size);
+ if (memcmp(target, rom_header, rom_size)) {
+ printf("VGA ROM copy failed\n");
+ return -EFAULT;
+ }
+ debug("Copy took %lums\n", get_timer(start));
+ }
+ *ram_headerp = target;
+
+ return 0;
+}
+
+struct vbe_mode_info mode_info;
+
+void setup_video(struct screen_info *screen_info)
+{
+ struct vesa_mode_info *vesa = &mode_info.vesa;
+
+ /* Sanity test on VESA parameters */
+ if (!vesa->x_resolution || !vesa->y_resolution)
+ return;
+
+ screen_info->orig_video_isVGA = VIDEO_TYPE_VLFB;
+
+ screen_info->lfb_width = vesa->x_resolution;
+ screen_info->lfb_height = vesa->y_resolution;
+ screen_info->lfb_depth = vesa->bits_per_pixel;
+ screen_info->lfb_linelength = vesa->bytes_per_scanline;
+ screen_info->lfb_base = vesa->phys_base_ptr;
+ screen_info->lfb_size =
+ ALIGN(screen_info->lfb_linelength * screen_info->lfb_height,
+ 65536);
+ screen_info->lfb_size >>= 16;
+ screen_info->red_size = vesa->red_mask_size;
+ screen_info->red_pos = vesa->red_mask_pos;
+ screen_info->green_size = vesa->green_mask_size;
+ screen_info->green_pos = vesa->green_mask_pos;
+ screen_info->blue_size = vesa->blue_mask_size;
+ screen_info->blue_pos = vesa->blue_mask_pos;
+ screen_info->rsvd_size = vesa->reserved_mask_size;
+ screen_info->rsvd_pos = vesa->reserved_mask_pos;
+}
+
+int dm_pci_run_vga_bios(struct udevice *dev, int (*int15_handler)(void),
+ int exec_method)
+{
+ struct pci_child_plat *pplat = dev_get_parent_plat(dev);
+ struct pci_rom_header *rom = NULL, *ram = NULL;
+ int vesa_mode = -1;
+ bool emulate, alloced;
+ int ret;
+
+ /* Only execute VGA ROMs */
+ if (((pplat->class >> 8) ^ PCI_CLASS_DISPLAY_VGA) & 0xff00) {
+ debug("%s: Class %#x, should be %#x\n", __func__, pplat->class,
+ PCI_CLASS_DISPLAY_VGA);
+ return -ENODEV;
+ }
+
+ if (!board_should_load_oprom(dev))
+ return log_msg_ret("Should not load OPROM", -ENXIO);
+
+ ret = pci_rom_probe(dev, &rom);
+ if (ret)
+ return ret;
+
+ ret = pci_rom_load(rom, &ram, &alloced);
+ if (ret)
+ goto err;
+
+ if (!board_should_run_oprom(dev)) {
+ ret = -ENXIO;
+ goto err;
+ }
+
+#if defined(CONFIG_FRAMEBUFFER_SET_VESA_MODE) && \
+ defined(CONFIG_FRAMEBUFFER_VESA_MODE)
+ vesa_mode = CONFIG_FRAMEBUFFER_VESA_MODE;
+#endif
+ debug("Selected vesa mode %#x\n", vesa_mode);
+
+ if (exec_method & PCI_ROM_USE_NATIVE) {
+#ifdef CONFIG_X86
+ emulate = false;
+#else
+ if (!(exec_method & PCI_ROM_ALLOW_FALLBACK)) {
+ printf("BIOS native execution is only available on x86\n");
+ ret = -ENOSYS;
+ goto err;
+ }
+ emulate = true;
+#endif
+ } else {
+#ifdef CONFIG_BIOSEMU
+ emulate = true;
+#else
+ if (!(exec_method & PCI_ROM_ALLOW_FALLBACK)) {
+ printf("BIOS emulation not available - see CONFIG_BIOSEMU\n");
+ ret = -ENOSYS;
+ goto err;
+ }
+ emulate = false;
+#endif
+ }
+
+ if (emulate) {
+#ifdef CONFIG_BIOSEMU
+ BE_VGAInfo *info;
+
+ ret = biosemu_setup(dev, &info);
+ if (ret)
+ goto err;
+ biosemu_set_interrupt_handler(0x15, int15_handler);
+ ret = biosemu_run(dev, (uchar *)ram, 1 << 16, info,
+ true, vesa_mode, &mode_info);
+ if (ret)
+ goto err;
+#endif
+ } else {
+#if defined(CONFIG_X86) && (CONFIG_IS_ENABLED(X86_32BIT_INIT) || CONFIG_TPL)
+ bios_set_interrupt_handler(0x15, int15_handler);
+
+ bios_run_on_x86(dev, (unsigned long)ram, vesa_mode,
+ &mode_info);
+#endif
+ }
+ debug("Final vesa mode %#x\n", mode_info.video_mode);
+ ret = 0;
+
+err:
+ if (alloced)
+ free(ram);
+ return ret;
+}
+
+#ifdef CONFIG_DM_VIDEO
+int vbe_setup_video_priv(struct vesa_mode_info *vesa,
+ struct video_priv *uc_priv,
+ struct video_uc_plat *plat)
+{
+ if (!vesa->x_resolution)
+ return log_msg_ret("No x resolution", -ENXIO);
+ uc_priv->xsize = vesa->x_resolution;
+ uc_priv->ysize = vesa->y_resolution;
+ uc_priv->line_length = vesa->bytes_per_scanline;
+ switch (vesa->bits_per_pixel) {
+ case 32:
+ case 24:
+ uc_priv->bpix = VIDEO_BPP32;
+ break;
+ case 16:
+ uc_priv->bpix = VIDEO_BPP16;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ /* Use double buffering if enabled */
+ if (IS_ENABLED(CONFIG_VIDEO_COPY) && plat->base)
+ plat->copy_base = vesa->phys_base_ptr;
+ else
+ plat->base = vesa->phys_base_ptr;
+ log_debug("base = %lx, copy_base = %lx\n", plat->base, plat->copy_base);
+ plat->size = vesa->bytes_per_scanline * vesa->y_resolution;
+
+ return 0;
+}
+
+int vbe_setup_video(struct udevice *dev, int (*int15_handler)(void))
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ /* If we are running from EFI or coreboot, this can't work */
+ if (!ll_boot_init()) {
+ printf("Not available (previous bootloader prevents it)\n");
+ return -EPERM;
+ }
+ bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "vesa display");
+ ret = dm_pci_run_vga_bios(dev, int15_handler, PCI_ROM_USE_NATIVE |
+ PCI_ROM_ALLOW_FALLBACK);
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_LCD);
+ if (ret) {
+ debug("failed to run video BIOS: %d\n", ret);
+ return ret;
+ }
+
+ ret = vbe_setup_video_priv(&mode_info.vesa, uc_priv, plat);
+ if (ret) {
+ if (ret == -ENFILE) {
+ /*
+ * See video-uclass.c for how to set up reserved memory
+ * in your video driver
+ */
+ log_err("CONFIG_VIDEO_COPY enabled but driver '%s' set up no reserved memory\n",
+ dev->driver->name);
+ }
+
+ debug("No video mode configured\n");
+ return ret;
+ }
+
+ printf("Video: %dx%dx%d\n", uc_priv->xsize, uc_priv->ysize,
+ mode_info.vesa.bits_per_pixel);
+
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/drivers/pci/pci_sandbox.c b/roms/u-boot/drivers/pci/pci_sandbox.c
new file mode 100644
index 000000000..ca44d0023
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_sandbox.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <pci.h>
+
+#define FDT_DEV_INFO_CELLS 4
+#define FDT_DEV_INFO_SIZE (FDT_DEV_INFO_CELLS * sizeof(u32))
+
+#define SANDBOX_PCI_DEVFN(d, f) ((d << 3) | f)
+
+struct sandbox_pci_priv {
+ struct {
+ u16 vendor;
+ u16 device;
+ } vendev[256];
+};
+
+static int sandbox_pci_write_config(struct udevice *bus, pci_dev_t devfn,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct dm_pci_emul_ops *ops;
+ struct udevice *container, *emul;
+ int ret;
+
+ ret = sandbox_pci_get_emul(bus, devfn, &container, &emul);
+ if (ret)
+ return ret == -ENODEV ? 0 : ret;
+ ops = pci_get_emul_ops(emul);
+ if (!ops || !ops->write_config)
+ return -ENOSYS;
+
+ return ops->write_config(emul, offset, value, size);
+}
+
+static int sandbox_pci_read_config(const struct udevice *bus, pci_dev_t devfn,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct dm_pci_emul_ops *ops;
+ struct udevice *container, *emul;
+ struct sandbox_pci_priv *priv = dev_get_priv(bus);
+ int ret;
+
+ /* Prepare the default response */
+ *valuep = pci_get_ff(size);
+ ret = sandbox_pci_get_emul(bus, devfn, &container, &emul);
+ if (ret) {
+ if (!container) {
+ u16 vendor, device;
+
+ devfn = SANDBOX_PCI_DEVFN(PCI_DEV(devfn),
+ PCI_FUNC(devfn));
+ vendor = priv->vendev[devfn].vendor;
+ device = priv->vendev[devfn].device;
+ if (offset == PCI_VENDOR_ID && vendor)
+ *valuep = vendor;
+ else if (offset == PCI_DEVICE_ID && device)
+ *valuep = device;
+
+ return 0;
+ } else {
+ return ret == -ENODEV ? 0 : ret;
+ }
+ }
+ ops = pci_get_emul_ops(emul);
+ if (!ops || !ops->read_config)
+ return -ENOSYS;
+
+ return ops->read_config(emul, offset, valuep, size);
+}
+
+static int sandbox_pci_probe(struct udevice *dev)
+{
+ struct sandbox_pci_priv *priv = dev_get_priv(dev);
+ const fdt32_t *cell;
+ u8 pdev, pfn, devfn;
+ int len;
+
+ cell = ofnode_get_property(dev_ofnode(dev), "sandbox,dev-info", &len);
+ if (!cell)
+ return 0;
+
+ if ((len % FDT_DEV_INFO_SIZE) == 0) {
+ int num = len / FDT_DEV_INFO_SIZE;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ debug("dev info #%d: %02x %02x %04x %04x\n", i,
+ fdt32_to_cpu(cell[0]), fdt32_to_cpu(cell[1]),
+ fdt32_to_cpu(cell[2]), fdt32_to_cpu(cell[3]));
+
+ pdev = fdt32_to_cpu(cell[0]);
+ pfn = fdt32_to_cpu(cell[1]);
+ if (pdev > 31 || pfn > 7)
+ continue;
+ devfn = SANDBOX_PCI_DEVFN(pdev, pfn);
+ priv->vendev[devfn].vendor = fdt32_to_cpu(cell[2]);
+ priv->vendev[devfn].device = fdt32_to_cpu(cell[3]);
+
+ cell += FDT_DEV_INFO_CELLS;
+ }
+ }
+
+ return 0;
+}
+
+static const struct dm_pci_ops sandbox_pci_ops = {
+ .read_config = sandbox_pci_read_config,
+ .write_config = sandbox_pci_write_config,
+};
+
+static const struct udevice_id sandbox_pci_ids[] = {
+ { .compatible = "sandbox,pci" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_sandbox) = {
+ .name = "pci_sandbox",
+ .id = UCLASS_PCI,
+ .of_match = sandbox_pci_ids,
+ .ops = &sandbox_pci_ops,
+ .probe = sandbox_pci_probe,
+ .priv_auto = sizeof(struct sandbox_pci_priv),
+
+ /* Attach an emulator if we can */
+ .child_post_bind = dm_scan_fdt_dev,
+ .per_child_plat_auto = sizeof(struct pci_child_plat),
+};
diff --git a/roms/u-boot/drivers/pci/pci_sh4.c b/roms/u-boot/drivers/pci/pci_sh4.c
new file mode 100644
index 000000000..aac9be055
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_sh4.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SH4 PCI Controller (PCIC) for U-Boot.
+ * (C) Dustin McIntire (dustin@sensoria.com)
+ * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ * (C) 2008 Yusuke Goda <goda.yusuke@renesas.com>
+ *
+ * u-boot/arch/sh/cpu/sh4/pci-sh4.c
+ */
+
+#include <common.h>
+#include <linux/delay.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <pci.h>
+
+int pci_sh4_init(struct pci_controller *hose)
+{
+ hose->first_busno = 0;
+ hose->region_count = 0;
+ hose->last_busno = 0xff;
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 0,
+ CONFIG_PCI_MEM_BUS,
+ CONFIG_PCI_MEM_PHYS,
+ CONFIG_PCI_MEM_SIZE,
+ PCI_REGION_MEM);
+ hose->region_count++;
+
+ /* PCI IO space */
+ pci_set_region(hose->regions + 1,
+ CONFIG_PCI_IO_BUS,
+ CONFIG_PCI_IO_PHYS,
+ CONFIG_PCI_IO_SIZE,
+ PCI_REGION_IO);
+ hose->region_count++;
+
+#if defined(CONFIG_PCI_SYS_BUS)
+ /* PCI System Memory space */
+ pci_set_region(hose->regions + 2,
+ CONFIG_PCI_SYS_BUS,
+ CONFIG_PCI_SYS_PHYS,
+ CONFIG_PCI_SYS_SIZE,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+ hose->region_count++;
+#endif
+
+ udelay(1000);
+
+ pci_set_ops(hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ pci_sh4_read_config_dword,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ pci_sh4_write_config_dword);
+
+ pci_register_hose(hose);
+
+ udelay(1000);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+ hose->last_busno = pci_hose_scan(hose);
+ return 0;
+}
+
+int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ return 0;
+}
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+int pci_print_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ return 1;
+}
+#endif /* CONFIG_PCI_SCAN_SHOW */
diff --git a/roms/u-boot/drivers/pci/pci_sh7751.c b/roms/u-boot/drivers/pci/pci_sh7751.c
new file mode 100644
index 000000000..e110550c7
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_sh7751.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SH7751 PCI Controller (PCIC) for U-Boot.
+ * (C) Dustin McIntire (dustin@sensoria.com)
+ * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+/* Register addresses and such */
+#define SH7751_BCR1 (vu_long *)0xFF800000
+#define SH7751_BCR2 (vu_short *)0xFF800004
+#define SH7751_WCR1 (vu_long *)0xFF800008
+#define SH7751_WCR2 (vu_long *)0xFF80000C
+#define SH7751_WCR3 (vu_long *)0xFF800010
+#define SH7751_MCR (vu_long *)0xFF800014
+#define SH7751_BCR3 (vu_short *)0xFF800050
+#define SH7751_PCICONF0 (vu_long *)0xFE200000
+#define SH7751_PCICONF1 (vu_long *)0xFE200004
+#define SH7751_PCICONF2 (vu_long *)0xFE200008
+#define SH7751_PCICONF3 (vu_long *)0xFE20000C
+#define SH7751_PCICONF4 (vu_long *)0xFE200010
+#define SH7751_PCICONF5 (vu_long *)0xFE200014
+#define SH7751_PCICONF6 (vu_long *)0xFE200018
+#define SH7751_PCICR (vu_long *)0xFE200100
+#define SH7751_PCILSR0 (vu_long *)0xFE200104
+#define SH7751_PCILSR1 (vu_long *)0xFE200108
+#define SH7751_PCILAR0 (vu_long *)0xFE20010C
+#define SH7751_PCILAR1 (vu_long *)0xFE200110
+#define SH7751_PCIMBR (vu_long *)0xFE2001C4
+#define SH7751_PCIIOBR (vu_long *)0xFE2001C8
+#define SH7751_PCIPINT (vu_long *)0xFE2001CC
+#define SH7751_PCIPINTM (vu_long *)0xFE2001D0
+#define SH7751_PCICLKR (vu_long *)0xFE2001D4
+#define SH7751_PCIBCR1 (vu_long *)0xFE2001E0
+#define SH7751_PCIBCR2 (vu_long *)0xFE2001E4
+#define SH7751_PCIWCR1 (vu_long *)0xFE2001E8
+#define SH7751_PCIWCR2 (vu_long *)0xFE2001EC
+#define SH7751_PCIWCR3 (vu_long *)0xFE2001F0
+#define SH7751_PCIMCR (vu_long *)0xFE2001F4
+#define SH7751_PCIBCR3 (vu_long *)0xFE2001F8
+
+#define BCR1_BREQEN 0x00080000
+#define PCI_SH7751_ID 0x35051054
+#define PCI_SH7751R_ID 0x350E1054
+#define SH7751_PCICONF1_WCC 0x00000080
+#define SH7751_PCICONF1_PER 0x00000040
+#define SH7751_PCICONF1_BUM 0x00000004
+#define SH7751_PCICONF1_MES 0x00000002
+#define SH7751_PCICONF1_CMDS 0x000000C6
+#define SH7751_PCI_HOST_BRIDGE 0x6
+#define SH7751_PCICR_PREFIX 0xa5000000
+#define SH7751_PCICR_PRST 0x00000002
+#define SH7751_PCICR_CFIN 0x00000001
+#define SH7751_PCIPINT_D3 0x00000002
+#define SH7751_PCIPINT_D0 0x00000001
+#define SH7751_PCICLKR_PREFIX 0xa5000000
+
+#define SH7751_PCI_MEM_BASE 0xFD000000
+#define SH7751_PCI_MEM_SIZE 0x01000000
+#define SH7751_PCI_IO_BASE 0xFE240000
+#define SH7751_PCI_IO_SIZE 0x00040000
+
+#define SH7751_PCIPAR (vu_long *)0xFE2001C0
+#define SH7751_PCIPDR (vu_long *)0xFE200220
+
+#define p4_in(addr) (*addr)
+#define p4_out(data, addr) (*addr) = (data)
+
+static int sh7751_pci_addr_valid(pci_dev_t d, uint offset)
+{
+ if (PCI_FUNC(d))
+ return -EINVAL;
+
+ return 0;
+}
+
+static u32 get_bus_address(const struct udevice *dev, pci_dev_t bdf, u32 offset)
+{
+ return BIT(31) | (PCI_DEV(bdf) << 8) | (offset & ~3);
+}
+
+static int sh7751_pci_read_config(const struct udevice *dev, pci_dev_t bdf,
+ uint offset, ulong *value,
+ enum pci_size_t size)
+{
+ u32 addr, reg;
+ int ret;
+
+ ret = sh7751_pci_addr_valid(bdf, offset);
+ if (ret) {
+ *value = pci_get_ff(size);
+ return 0;
+ }
+
+ addr = get_bus_address(dev, bdf, offset);
+ p4_out(addr, SH7751_PCIPAR);
+ reg = p4_in(SH7751_PCIPDR);
+ *value = pci_conv_32_to_size(reg, offset, size);
+
+ return 0;
+}
+
+static int sh7751_pci_write_config(struct udevice *dev, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ u32 addr, reg, old;
+ int ret;
+
+ ret = sh7751_pci_addr_valid(bdf, offset);
+ if (ret)
+ return ret;
+
+ addr = get_bus_address(dev, bdf, offset);
+ p4_out(addr, SH7751_PCIPAR);
+ old = p4_in(SH7751_PCIPDR);
+ reg = pci_conv_size_to_32(old, value, offset, size);
+ p4_out(reg, SH7751_PCIPDR);
+
+ return 0;
+}
+
+static int sh7751_pci_probe(struct udevice *dev)
+{
+ /* Double-check that we're a 7751 or 7751R chip */
+ if (p4_in(SH7751_PCICONF0) != PCI_SH7751_ID
+ && p4_in(SH7751_PCICONF0) != PCI_SH7751R_ID) {
+ printf("PCI: Unknown PCI host bridge.\n");
+ return 1;
+ }
+ printf("PCI: SH7751 PCI host bridge found.\n");
+
+ /* Double-check some BSC config settings */
+ /* (Area 3 non-MPX 32-bit, PCI bus pins) */
+ if ((p4_in(SH7751_BCR1) & 0x20008) == 0x20000) {
+ printf("SH7751_BCR1 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR1));
+ return 2;
+ }
+ if ((p4_in(SH7751_BCR2) & 0xC0) != 0xC0) {
+ printf("SH7751_BCR2 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR2));
+ return 3;
+ }
+ if (p4_in(SH7751_BCR2) & 0x01) {
+ printf("SH7751_BCR2 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR2));
+ return 4;
+ }
+
+ /* Force BREQEN in BCR1 to allow PCIC access */
+ p4_out((p4_in(SH7751_BCR1) | BCR1_BREQEN), SH7751_BCR1);
+
+ /* Toggle PCI reset pin */
+ p4_out((SH7751_PCICR_PREFIX | SH7751_PCICR_PRST), SH7751_PCICR);
+ udelay(32);
+ p4_out(SH7751_PCICR_PREFIX, SH7751_PCICR);
+
+ /* Set cmd bits: WCC, PER, BUM, MES */
+ /* (Addr/Data stepping, Parity enabled, Bus Master, Memory enabled) */
+ p4_out(0xfb900047, SH7751_PCICONF1); /* K.Kino */
+
+ /* Define this host as the host bridge */
+ p4_out((SH7751_PCI_HOST_BRIDGE << 24), SH7751_PCICONF2);
+
+ /* Force PCI clock(s) on */
+ p4_out(0, SH7751_PCICLKR);
+ p4_out(0x03, SH7751_PCICLKR);
+
+ /* Clear powerdown IRQs, also mask them (unused) */
+ p4_out((SH7751_PCIPINT_D0 | SH7751_PCIPINT_D3), SH7751_PCIPINT);
+ p4_out(0, SH7751_PCIPINTM);
+
+ p4_out(0xab000001, SH7751_PCICONF4);
+
+ /* Set up target memory mappings (for external DMA access) */
+ /* Map both P0 and P2 range to Area 3 RAM for ease of use */
+ p4_out(CONFIG_SYS_SDRAM_SIZE - 0x100000, SH7751_PCILSR0);
+ p4_out(CONFIG_SYS_SDRAM_BASE & 0x1FF00000, SH7751_PCILAR0);
+ p4_out(CONFIG_SYS_SDRAM_BASE & 0xFFF00000, SH7751_PCICONF5);
+
+ p4_out(0, SH7751_PCILSR1);
+ p4_out(0, SH7751_PCILAR1);
+ p4_out(0xd0000000, SH7751_PCICONF6);
+
+ /* Map memory window to same address on PCI bus */
+ p4_out(SH7751_PCI_MEM_BASE, SH7751_PCIMBR);
+
+ /* Map IO window to same address on PCI bus */
+ p4_out(SH7751_PCI_IO_BASE, SH7751_PCIIOBR);
+
+ /* set BREQEN */
+ p4_out(inl(SH7751_BCR1) | 0x00080000, SH7751_BCR1);
+
+ /* Copy BSC registers into PCI BSC */
+ p4_out(inl(SH7751_BCR1), SH7751_PCIBCR1);
+ p4_out(inw(SH7751_BCR2), SH7751_PCIBCR2);
+ p4_out(inw(SH7751_BCR3), SH7751_PCIBCR3);
+ p4_out(inl(SH7751_WCR1), SH7751_PCIWCR1);
+ p4_out(inl(SH7751_WCR2), SH7751_PCIWCR2);
+ p4_out(inl(SH7751_WCR3), SH7751_PCIWCR3);
+ p4_out(inl(SH7751_MCR), SH7751_PCIMCR);
+
+ /* Finally, set central function init complete */
+ p4_out((SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN), SH7751_PCICR);
+
+ return 0;
+}
+
+static const struct dm_pci_ops sh7751_pci_ops = {
+ .read_config = sh7751_pci_read_config,
+ .write_config = sh7751_pci_write_config,
+};
+
+static const struct udevice_id sh7751_pci_ids[] = {
+ { .compatible = "renesas,pci-sh7751" },
+ { }
+};
+
+U_BOOT_DRIVER(sh7751_pci) = {
+ .name = "sh7751_pci",
+ .id = UCLASS_PCI,
+ .of_match = sh7751_pci_ids,
+ .ops = &sh7751_pci_ops,
+ .probe = sh7751_pci_probe,
+};
diff --git a/roms/u-boot/drivers/pci/pci_sh7780.c b/roms/u-boot/drivers/pci/pci_sh7780.c
new file mode 100644
index 000000000..06d711a6c
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_sh7780.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SH7780 PCI Controller (PCIC) for U-Boot.
+ * (C) Dustin McIntire (dustin@sensoria.com)
+ * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ * (C) 2008 Yusuke Goda <goda.yusuke@renesas.com>
+ */
+
+#include <common.h>
+#include <linux/delay.h>
+
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+
+#define SH7780_VENDOR_ID 0x1912
+#define SH7780_DEVICE_ID 0x0002
+#define SH7780_PCICR_PREFIX 0xA5000000
+#define SH7780_PCICR_PFCS 0x00000800
+#define SH7780_PCICR_FTO 0x00000400
+#define SH7780_PCICR_PFE 0x00000200
+#define SH7780_PCICR_TBS 0x00000100
+#define SH7780_PCICR_ARBM 0x00000040
+#define SH7780_PCICR_IOCS 0x00000004
+#define SH7780_PCICR_PRST 0x00000002
+#define SH7780_PCICR_CFIN 0x00000001
+
+#define p4_in(addr) (*(vu_long *)addr)
+#define p4_out(data, addr) (*(vu_long *)addr) = (data)
+#define p4_inw(addr) (*(vu_short *)addr)
+#define p4_outw(data, addr) (*(vu_short *)addr) = (data)
+
+int pci_sh4_read_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 *value)
+{
+ u32 par_data = 0x80000000 | dev;
+
+ p4_out(par_data | (offset & 0xfc), SH7780_PCIPAR);
+ *value = p4_in(SH7780_PCIPDR);
+
+ return 0;
+}
+
+int pci_sh4_write_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 value)
+{
+ u32 par_data = 0x80000000 | dev;
+
+ p4_out(par_data | (offset & 0xfc), SH7780_PCIPAR);
+ p4_out(value, SH7780_PCIPDR);
+ return 0;
+}
+
+int pci_sh7780_init(struct pci_controller *hose)
+{
+ p4_out(0x01, SH7780_PCIECR);
+
+ if (p4_inw(SH7780_PCIVID) != SH7780_VENDOR_ID
+ && p4_inw(SH7780_PCIDID) != SH7780_DEVICE_ID) {
+ printf("PCI: Unknown PCI host bridge.\n");
+ return -1;
+ }
+ printf("PCI: SH7780 PCI host bridge found.\n");
+
+ /* Toggle PCI reset pin */
+ p4_out((SH7780_PCICR_PREFIX | SH7780_PCICR_PRST), SH7780_PCICR);
+ udelay(100000);
+ p4_out(SH7780_PCICR_PREFIX, SH7780_PCICR);
+ p4_outw(0x0047, SH7780_PCICMD);
+
+ p4_out(CONFIG_SH7780_PCI_LSR, SH7780_PCILSR0);
+ p4_out(CONFIG_SH7780_PCI_LAR, SH7780_PCILAR0);
+ p4_out(0x00000000, SH7780_PCILSR1);
+ p4_out(0, SH7780_PCILAR1);
+ p4_out(CONFIG_SH7780_PCI_BAR, SH7780_PCIMBAR0);
+ p4_out(0x00000000, SH7780_PCIMBAR1);
+
+ p4_out(0xFD000000, SH7780_PCIMBR0);
+ p4_out(0x00FC0000, SH7780_PCIMBMR0);
+
+ /* if use Operand Cache then enable PCICSCR Soonp bits. */
+ p4_out(0x08000000, SH7780_PCICSAR0);
+ p4_out(0x0000001B, SH7780_PCICSCR0); /* Snoop bit :On */
+
+ p4_out((SH7780_PCICR_PREFIX | SH7780_PCICR_CFIN | SH7780_PCICR_ARBM
+ | SH7780_PCICR_FTO | SH7780_PCICR_PFCS | SH7780_PCICR_PFE),
+ SH7780_PCICR);
+
+ pci_sh4_init(hose);
+ return 0;
+}
diff --git a/roms/u-boot/drivers/pci/pci_tegra.c b/roms/u-boot/drivers/pci/pci_tegra.c
new file mode 100644
index 000000000..9cb441483
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_tegra.c
@@ -0,0 +1,1203 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2010, CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on NVIDIA PCIe driver
+ * Copyright (c) 2008-2009, NVIDIA Corporation.
+ *
+ * Copyright (c) 2013-2014, NVIDIA Corporation.
+ */
+
+#define pr_fmt(fmt) "tegra-pcie: " fmt
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <pci.h>
+#include <pci_tegra.h>
+#include <power-domain.h>
+#include <reset.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+#include <linux/ioport.h>
+#include <linux/list.h>
+
+#ifndef CONFIG_TEGRA186
+#include <asm/arch/clock.h>
+#include <asm/arch/powergate.h>
+#include <asm/arch-tegra/xusb-padctl.h>
+#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
+#endif
+
+/*
+ * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that
+ * should not be present. These are needed because newer Tegra SoCs support
+ * only the standard clock/reset APIs, whereas older Tegra SoCs support only
+ * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be
+ * fixed to implement the standard APIs, and all drivers converted to solely
+ * use the new standard APIs, with no ifdefs.
+ */
+
+#define AFI_AXI_BAR0_SZ 0x00
+#define AFI_AXI_BAR1_SZ 0x04
+#define AFI_AXI_BAR2_SZ 0x08
+#define AFI_AXI_BAR3_SZ 0x0c
+#define AFI_AXI_BAR4_SZ 0x10
+#define AFI_AXI_BAR5_SZ 0x14
+
+#define AFI_AXI_BAR0_START 0x18
+#define AFI_AXI_BAR1_START 0x1c
+#define AFI_AXI_BAR2_START 0x20
+#define AFI_AXI_BAR3_START 0x24
+#define AFI_AXI_BAR4_START 0x28
+#define AFI_AXI_BAR5_START 0x2c
+
+#define AFI_FPCI_BAR0 0x30
+#define AFI_FPCI_BAR1 0x34
+#define AFI_FPCI_BAR2 0x38
+#define AFI_FPCI_BAR3 0x3c
+#define AFI_FPCI_BAR4 0x40
+#define AFI_FPCI_BAR5 0x44
+
+#define AFI_CACHE_BAR0_SZ 0x48
+#define AFI_CACHE_BAR0_ST 0x4c
+#define AFI_CACHE_BAR1_SZ 0x50
+#define AFI_CACHE_BAR1_ST 0x54
+
+#define AFI_MSI_BAR_SZ 0x60
+#define AFI_MSI_FPCI_BAR_ST 0x64
+#define AFI_MSI_AXI_BAR_ST 0x68
+
+#define AFI_CONFIGURATION 0xac
+#define AFI_CONFIGURATION_EN_FPCI (1 << 0)
+
+#define AFI_FPCI_ERROR_MASKS 0xb0
+
+#define AFI_INTR_MASK 0xb4
+#define AFI_INTR_MASK_INT_MASK (1 << 0)
+#define AFI_INTR_MASK_MSI_MASK (1 << 8)
+
+#define AFI_SM_INTR_ENABLE 0xc4
+#define AFI_SM_INTR_INTA_ASSERT (1 << 0)
+#define AFI_SM_INTR_INTB_ASSERT (1 << 1)
+#define AFI_SM_INTR_INTC_ASSERT (1 << 2)
+#define AFI_SM_INTR_INTD_ASSERT (1 << 3)
+#define AFI_SM_INTR_INTA_DEASSERT (1 << 4)
+#define AFI_SM_INTR_INTB_DEASSERT (1 << 5)
+#define AFI_SM_INTR_INTC_DEASSERT (1 << 6)
+#define AFI_SM_INTR_INTD_DEASSERT (1 << 7)
+
+#define AFI_AFI_INTR_ENABLE 0xc8
+#define AFI_INTR_EN_INI_SLVERR (1 << 0)
+#define AFI_INTR_EN_INI_DECERR (1 << 1)
+#define AFI_INTR_EN_TGT_SLVERR (1 << 2)
+#define AFI_INTR_EN_TGT_DECERR (1 << 3)
+#define AFI_INTR_EN_TGT_WRERR (1 << 4)
+#define AFI_INTR_EN_DFPCI_DECERR (1 << 5)
+#define AFI_INTR_EN_AXI_DECERR (1 << 6)
+#define AFI_INTR_EN_FPCI_TIMEOUT (1 << 7)
+#define AFI_INTR_EN_PRSNT_SENSE (1 << 8)
+
+#define AFI_PCIE_CONFIG 0x0f8
+#define AFI_PCIE_CONFIG_PCIE_DISABLE(x) (1 << ((x) + 1))
+#define AFI_PCIE_CONFIG_PCIE_DISABLE_ALL 0xe
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420 (0x0 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1 (0x0 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 (0x0 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 (0x1 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 (0x2 << 20)
+
+#define AFI_FUSE 0x104
+#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2)
+
+#define AFI_PEX0_CTRL 0x110
+#define AFI_PEX1_CTRL 0x118
+#define AFI_PEX2_CTRL 0x128
+#define AFI_PEX2_CTRL_T186 0x19c
+#define AFI_PEX_CTRL_RST (1 << 0)
+#define AFI_PEX_CTRL_CLKREQ_EN (1 << 1)
+#define AFI_PEX_CTRL_REFCLK_EN (1 << 3)
+#define AFI_PEX_CTRL_OVERRIDE_EN (1 << 4)
+
+#define AFI_PLLE_CONTROL 0x160
+#define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9)
+#define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1)
+
+#define AFI_PEXBIAS_CTRL_0 0x168
+
+#define PADS_CTL_SEL 0x0000009C
+
+#define PADS_CTL 0x000000A0
+#define PADS_CTL_IDDQ_1L (1 << 0)
+#define PADS_CTL_TX_DATA_EN_1L (1 << 6)
+#define PADS_CTL_RX_DATA_EN_1L (1 << 10)
+
+#define PADS_PLL_CTL_TEGRA20 0x000000B8
+#define PADS_PLL_CTL_TEGRA30 0x000000B4
+#define PADS_PLL_CTL_RST_B4SM (0x1 << 1)
+#define PADS_PLL_CTL_LOCKDET (0x1 << 8)
+#define PADS_PLL_CTL_REFCLK_MASK (0x3 << 16)
+#define PADS_PLL_CTL_REFCLK_INTERNAL_CML (0x0 << 16)
+#define PADS_PLL_CTL_REFCLK_INTERNAL_CMOS (0x1 << 16)
+#define PADS_PLL_CTL_REFCLK_EXTERNAL (0x2 << 16)
+#define PADS_PLL_CTL_TXCLKREF_MASK (0x1 << 20)
+#define PADS_PLL_CTL_TXCLKREF_DIV10 (0x0 << 20)
+#define PADS_PLL_CTL_TXCLKREF_DIV5 (0x1 << 20)
+#define PADS_PLL_CTL_TXCLKREF_BUF_EN (0x1 << 22)
+
+#define PADS_REFCLK_CFG0 0x000000C8
+#define PADS_REFCLK_CFG1 0x000000CC
+
+/*
+ * Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit
+ * entries, one entry per PCIe port. These field definitions and desired
+ * values aren't in the TRM, but do come from NVIDIA.
+ */
+#define PADS_REFCLK_CFG_TERM_SHIFT 2 /* 6:2 */
+#define PADS_REFCLK_CFG_E_TERM_SHIFT 7
+#define PADS_REFCLK_CFG_PREDI_SHIFT 8 /* 11:8 */
+#define PADS_REFCLK_CFG_DRVI_SHIFT 12 /* 15:12 */
+
+#define RP_VEND_XP 0x00000F00
+#define RP_VEND_XP_DL_UP (1 << 30)
+
+#define RP_VEND_CTL2 0x00000FA8
+#define RP_VEND_CTL2_PCA_ENABLE (1 << 7)
+
+#define RP_PRIV_MISC 0x00000FE0
+#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
+#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
+
+#define RP_LINK_CONTROL_STATUS 0x00000090
+#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
+#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
+
+enum tegra_pci_id {
+ TEGRA20_PCIE,
+ TEGRA30_PCIE,
+ TEGRA124_PCIE,
+ TEGRA210_PCIE,
+ TEGRA186_PCIE,
+};
+
+struct tegra_pcie_port {
+ struct tegra_pcie *pcie;
+
+ struct fdt_resource regs;
+ unsigned int num_lanes;
+ unsigned int index;
+
+ struct list_head list;
+};
+
+struct tegra_pcie_soc {
+ unsigned int num_ports;
+ unsigned long pads_pll_ctl;
+ unsigned long tx_ref_sel;
+ unsigned long afi_pex2_ctrl;
+ u32 pads_refclk_cfg0;
+ u32 pads_refclk_cfg1;
+ bool has_pex_clkreq_en;
+ bool has_pex_bias_ctrl;
+ bool has_cml_clk;
+ bool has_gen2;
+ bool force_pca_enable;
+};
+
+struct tegra_pcie {
+ struct resource pads;
+ struct resource afi;
+ struct resource cs;
+
+ struct list_head ports;
+ unsigned long xbar;
+
+ const struct tegra_pcie_soc *soc;
+
+#ifdef CONFIG_TEGRA186
+ struct clk clk_afi;
+ struct clk clk_pex;
+ struct reset_ctl reset_afi;
+ struct reset_ctl reset_pex;
+ struct reset_ctl reset_pcie_x;
+ struct power_domain pwrdom;
+#else
+ struct tegra_xusb_phy *phy;
+#endif
+};
+
+static void afi_writel(struct tegra_pcie *pcie, unsigned long value,
+ unsigned long offset)
+{
+ writel(value, pcie->afi.start + offset);
+}
+
+static unsigned long afi_readl(struct tegra_pcie *pcie, unsigned long offset)
+{
+ return readl(pcie->afi.start + offset);
+}
+
+static void pads_writel(struct tegra_pcie *pcie, unsigned long value,
+ unsigned long offset)
+{
+ writel(value, pcie->pads.start + offset);
+}
+
+#ifndef CONFIG_TEGRA186
+static unsigned long pads_readl(struct tegra_pcie *pcie, unsigned long offset)
+{
+ return readl(pcie->pads.start + offset);
+}
+#endif
+
+static unsigned long rp_readl(struct tegra_pcie_port *port,
+ unsigned long offset)
+{
+ return readl(port->regs.start + offset);
+}
+
+static void rp_writel(struct tegra_pcie_port *port, unsigned long value,
+ unsigned long offset)
+{
+ writel(value, port->regs.start + offset);
+}
+
+static unsigned long tegra_pcie_conf_offset(pci_dev_t bdf, int where)
+{
+ return ((where & 0xf00) << 16) | (PCI_BUS(bdf) << 16) |
+ (PCI_DEV(bdf) << 11) | (PCI_FUNC(bdf) << 8) |
+ (where & 0xfc);
+}
+
+static int tegra_pcie_conf_address(struct tegra_pcie *pcie, pci_dev_t bdf,
+ int where, unsigned long *address)
+{
+ unsigned int bus = PCI_BUS(bdf);
+
+ if (bus == 0) {
+ unsigned int dev = PCI_DEV(bdf);
+ struct tegra_pcie_port *port;
+
+ list_for_each_entry(port, &pcie->ports, list) {
+ if (port->index + 1 == dev) {
+ *address = port->regs.start + (where & ~3);
+ return 0;
+ }
+ }
+ return -EFAULT;
+ } else {
+#ifdef CONFIG_TEGRA20
+ unsigned int dev = PCI_DEV(bdf);
+ if (dev != 0)
+ return -EFAULT;
+#endif
+
+ *address = pcie->cs.start + tegra_pcie_conf_offset(bdf, where);
+ return 0;
+ }
+}
+
+static int pci_tegra_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct tegra_pcie *pcie = dev_get_priv(bus);
+ unsigned long address, value;
+ int err;
+
+ err = tegra_pcie_conf_address(pcie, bdf, offset, &address);
+ if (err < 0) {
+ value = 0xffffffff;
+ goto done;
+ }
+
+ value = readl(address);
+
+#ifdef CONFIG_TEGRA20
+ /* fixup root port class */
+ if (PCI_BUS(bdf) == 0) {
+ if ((offset & ~3) == PCI_CLASS_REVISION) {
+ value &= ~0x00ff0000;
+ value |= PCI_CLASS_BRIDGE_PCI << 16;
+ }
+ }
+#endif
+
+done:
+ *valuep = pci_conv_32_to_size(value, offset, size);
+
+ return 0;
+}
+
+static int pci_tegra_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct tegra_pcie *pcie = dev_get_priv(bus);
+ unsigned long address;
+ ulong old;
+ int err;
+
+ err = tegra_pcie_conf_address(pcie, bdf, offset, &address);
+ if (err < 0)
+ return 0;
+
+ old = readl(address);
+ value = pci_conv_size_to_32(old, value, offset, size);
+ writel(value, address);
+
+ return 0;
+}
+
+static int tegra_pcie_port_parse_dt(ofnode node, struct tegra_pcie_port *port)
+{
+ const u32 *addr;
+ int len;
+
+ addr = ofnode_get_property(node, "assigned-addresses", &len);
+ if (!addr) {
+ pr_err("property \"assigned-addresses\" not found");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ port->regs.start = fdt32_to_cpu(addr[2]);
+ port->regs.end = port->regs.start + fdt32_to_cpu(addr[4]);
+
+ return 0;
+}
+
+static int tegra_pcie_get_xbar_config(ofnode node, u32 lanes,
+ enum tegra_pci_id id, unsigned long *xbar)
+{
+ switch (id) {
+ case TEGRA20_PCIE:
+ switch (lanes) {
+ case 0x00000004:
+ debug("single-mode configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE;
+ return 0;
+
+ case 0x00000202:
+ debug("dual-mode configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
+ return 0;
+ }
+ break;
+ case TEGRA30_PCIE:
+ switch (lanes) {
+ case 0x00000204:
+ debug("4x1, 2x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420;
+ return 0;
+
+ case 0x00020202:
+ debug("2x3 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222;
+ return 0;
+
+ case 0x00010104:
+ debug("4x1, 1x2 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411;
+ return 0;
+ }
+ break;
+ case TEGRA124_PCIE:
+ case TEGRA210_PCIE:
+ switch (lanes) {
+ case 0x0000104:
+ debug("4x1, 1x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
+ return 0;
+
+ case 0x0000102:
+ debug("2x1, 1x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1;
+ return 0;
+ }
+ break;
+ case TEGRA186_PCIE:
+ switch (lanes) {
+ case 0x0010004:
+ debug("x4 x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401;
+ return 0;
+
+ case 0x0010102:
+ debug("x2 x1 x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211;
+ return 0;
+
+ case 0x0010101:
+ debug("x1 x1 x1 configuration\n");
+ *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111;
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+static int tegra_pcie_parse_port_info(ofnode node, uint *index, uint *lanes)
+{
+ struct fdt_pci_addr addr;
+ int err;
+
+ err = ofnode_read_u32_default(node, "nvidia,num-lanes", -1);
+ if (err < 0) {
+ pr_err("failed to parse \"nvidia,num-lanes\" property");
+ return err;
+ }
+
+ *lanes = err;
+
+ err = ofnode_read_pci_addr(node, 0, "reg", &addr);
+ if (err < 0) {
+ pr_err("failed to parse \"reg\" property");
+ return err;
+ }
+
+ *index = PCI_DEV(addr.phys_hi) - 1;
+
+ return 0;
+}
+
+int __weak tegra_pcie_board_init(void)
+{
+ return 0;
+}
+
+static int tegra_pcie_parse_dt(struct udevice *dev, enum tegra_pci_id id,
+ struct tegra_pcie *pcie)
+{
+ ofnode subnode;
+ u32 lanes = 0;
+ int err;
+
+ err = dev_read_resource(dev, 0, &pcie->pads);
+ if (err < 0) {
+ pr_err("resource \"pads\" not found");
+ return err;
+ }
+
+ err = dev_read_resource(dev, 1, &pcie->afi);
+ if (err < 0) {
+ pr_err("resource \"afi\" not found");
+ return err;
+ }
+
+ err = dev_read_resource(dev, 2, &pcie->cs);
+ if (err < 0) {
+ pr_err("resource \"cs\" not found");
+ return err;
+ }
+
+ err = tegra_pcie_board_init();
+ if (err < 0) {
+ pr_err("tegra_pcie_board_init() failed: err=%d", err);
+ return err;
+ }
+
+#ifndef CONFIG_TEGRA186
+ pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
+ if (pcie->phy) {
+ err = tegra_xusb_phy_prepare(pcie->phy);
+ if (err < 0) {
+ pr_err("failed to prepare PHY: %d", err);
+ return err;
+ }
+ }
+#endif
+
+ dev_for_each_subnode(subnode, dev) {
+ unsigned int index = 0, num_lanes = 0;
+ struct tegra_pcie_port *port;
+
+ err = tegra_pcie_parse_port_info(subnode, &index, &num_lanes);
+ if (err < 0) {
+ pr_err("failed to obtain root port info");
+ continue;
+ }
+
+ lanes |= num_lanes << (index << 3);
+
+ if (!ofnode_is_available(subnode))
+ continue;
+
+ port = malloc(sizeof(*port));
+ if (!port)
+ continue;
+
+ memset(port, 0, sizeof(*port));
+ port->num_lanes = num_lanes;
+ port->index = index;
+
+ err = tegra_pcie_port_parse_dt(subnode, port);
+ if (err < 0) {
+ free(port);
+ continue;
+ }
+
+ list_add_tail(&port->list, &pcie->ports);
+ port->pcie = pcie;
+ }
+
+ err = tegra_pcie_get_xbar_config(dev_ofnode(dev), lanes, id,
+ &pcie->xbar);
+ if (err < 0) {
+ pr_err("invalid lane configuration");
+ return err;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_TEGRA186
+static int tegra_pcie_power_on(struct tegra_pcie *pcie)
+{
+ int ret;
+
+ ret = power_domain_on(&pcie->pwrdom);
+ if (ret) {
+ pr_err("power_domain_on() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(&pcie->clk_afi);
+ if (ret) {
+ pr_err("clk_enable(afi) failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(&pcie->clk_pex);
+ if (ret) {
+ pr_err("clk_enable(pex) failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_deassert(&pcie->reset_afi);
+ if (ret) {
+ pr_err("reset_deassert(afi) failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_deassert(&pcie->reset_pex);
+ if (ret) {
+ pr_err("reset_deassert(pex) failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+#else
+static int tegra_pcie_power_on(struct tegra_pcie *pcie)
+{
+ const struct tegra_pcie_soc *soc = pcie->soc;
+ unsigned long value;
+ int err;
+
+ /* reset PCIEXCLK logic, AFI controller and PCIe controller */
+ reset_set_enable(PERIPH_ID_PCIEXCLK, 1);
+ reset_set_enable(PERIPH_ID_AFI, 1);
+ reset_set_enable(PERIPH_ID_PCIE, 1);
+
+ err = tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+ if (err < 0) {
+ pr_err("failed to power off PCIe partition: %d", err);
+ return err;
+ }
+
+ err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
+ PERIPH_ID_PCIE);
+ if (err < 0) {
+ pr_err("failed to power up PCIe partition: %d", err);
+ return err;
+ }
+
+ /* take AFI controller out of reset */
+ reset_set_enable(PERIPH_ID_AFI, 0);
+
+ /* enable AFI clock */
+ clock_enable(PERIPH_ID_AFI);
+
+ if (soc->has_cml_clk) {
+ /* enable CML clock */
+ value = readl(NV_PA_CLK_RST_BASE + 0x48c);
+ value |= (1 << 0);
+ value &= ~(1 << 1);
+ writel(value, NV_PA_CLK_RST_BASE + 0x48c);
+ }
+
+ err = tegra_plle_enable();
+ if (err < 0) {
+ pr_err("failed to enable PLLE: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout)
+{
+ const struct tegra_pcie_soc *soc = pcie->soc;
+ unsigned long start = get_timer(0);
+ u32 value;
+
+ while (get_timer(start) < timeout) {
+ value = pads_readl(pcie, soc->pads_pll_ctl);
+ if (value & PADS_PLL_CTL_LOCKDET)
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
+{
+ const struct tegra_pcie_soc *soc = pcie->soc;
+ u32 value;
+ int err;
+
+ /* initialize internal PHY, enable up to 16 PCIe lanes */
+ pads_writel(pcie, 0, PADS_CTL_SEL);
+
+ /* override IDDQ to 1 on all 4 lanes */
+ value = pads_readl(pcie, PADS_CTL);
+ value |= PADS_CTL_IDDQ_1L;
+ pads_writel(pcie, value, PADS_CTL);
+
+ /*
+ * Set up PHY PLL inputs select PLLE output as refclock, set TX
+ * ref sel to div10 (not div5).
+ */
+ value = pads_readl(pcie, soc->pads_pll_ctl);
+ value &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
+ value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel;
+ pads_writel(pcie, value, soc->pads_pll_ctl);
+
+ /* reset PLL */
+ value = pads_readl(pcie, soc->pads_pll_ctl);
+ value &= ~PADS_PLL_CTL_RST_B4SM;
+ pads_writel(pcie, value, soc->pads_pll_ctl);
+
+ udelay(20);
+
+ /* take PLL out of reset */
+ value = pads_readl(pcie, soc->pads_pll_ctl);
+ value |= PADS_PLL_CTL_RST_B4SM;
+ pads_writel(pcie, value, soc->pads_pll_ctl);
+
+ /* wait for the PLL to lock */
+ err = tegra_pcie_pll_wait(pcie, 500);
+ if (err < 0) {
+ pr_err("PLL failed to lock: %d", err);
+ return err;
+ }
+
+ /* turn off IDDQ override */
+ value = pads_readl(pcie, PADS_CTL);
+ value &= ~PADS_CTL_IDDQ_1L;
+ pads_writel(pcie, value, PADS_CTL);
+
+ /* enable TX/RX data */
+ value = pads_readl(pcie, PADS_CTL);
+ value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L;
+ pads_writel(pcie, value, PADS_CTL);
+
+ return 0;
+}
+#endif
+
+static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
+{
+ const struct tegra_pcie_soc *soc = pcie->soc;
+ struct tegra_pcie_port *port;
+ u32 value;
+ int err;
+
+#ifdef CONFIG_TEGRA186
+ {
+#else
+ if (pcie->phy) {
+#endif
+ value = afi_readl(pcie, AFI_PLLE_CONTROL);
+ value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
+ value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
+ afi_writel(pcie, value, AFI_PLLE_CONTROL);
+ }
+
+ if (soc->has_pex_bias_ctrl)
+ afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
+
+ value = afi_readl(pcie, AFI_PCIE_CONFIG);
+ value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
+ value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar;
+
+ list_for_each_entry(port, &pcie->ports, list)
+ value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
+
+ afi_writel(pcie, value, AFI_PCIE_CONFIG);
+
+ value = afi_readl(pcie, AFI_FUSE);
+
+ if (soc->has_gen2)
+ value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
+ else
+ value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
+
+ afi_writel(pcie, value, AFI_FUSE);
+
+#ifndef CONFIG_TEGRA186
+ if (pcie->phy)
+ err = tegra_xusb_phy_enable(pcie->phy);
+ else
+ err = tegra_pcie_phy_enable(pcie);
+
+ if (err < 0) {
+ pr_err("failed to power on PHY: %d\n", err);
+ return err;
+ }
+#endif
+
+ /* take the PCIEXCLK logic out of reset */
+#ifdef CONFIG_TEGRA186
+ err = reset_deassert(&pcie->reset_pcie_x);
+ if (err) {
+ pr_err("reset_deassert(pcie_x) failed: %d\n", err);
+ return err;
+ }
+#else
+ reset_set_enable(PERIPH_ID_PCIEXCLK, 0);
+#endif
+
+ /* finally enable PCIe */
+ value = afi_readl(pcie, AFI_CONFIGURATION);
+ value |= AFI_CONFIGURATION_EN_FPCI;
+ afi_writel(pcie, value, AFI_CONFIGURATION);
+
+ /* disable all interrupts */
+ afi_writel(pcie, 0, AFI_AFI_INTR_ENABLE);
+ afi_writel(pcie, 0, AFI_SM_INTR_ENABLE);
+ afi_writel(pcie, 0, AFI_INTR_MASK);
+ afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS);
+
+ return 0;
+}
+
+static int tegra_pcie_setup_translations(struct udevice *bus)
+{
+ struct tegra_pcie *pcie = dev_get_priv(bus);
+ unsigned long fpci, axi, size;
+ struct pci_region *io, *mem, *pref;
+ int count;
+
+ /* BAR 0: type 1 extended configuration space */
+ fpci = 0xfe100000;
+ size = resource_size(&pcie->cs);
+ axi = pcie->cs.start;
+
+ afi_writel(pcie, axi, AFI_AXI_BAR0_START);
+ afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ);
+ afi_writel(pcie, fpci, AFI_FPCI_BAR0);
+
+ count = pci_get_regions(bus, &io, &mem, &pref);
+ if (count != 3)
+ return -EINVAL;
+
+ /* BAR 1: downstream I/O */
+ fpci = 0xfdfc0000;
+ size = io->size;
+ axi = io->phys_start;
+
+ afi_writel(pcie, axi, AFI_AXI_BAR1_START);
+ afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
+ afi_writel(pcie, fpci, AFI_FPCI_BAR1);
+
+ /* BAR 2: prefetchable memory */
+ fpci = (((pref->phys_start >> 12) & 0x0fffffff) << 4) | 0x1;
+ size = pref->size;
+ axi = pref->phys_start;
+
+ afi_writel(pcie, axi, AFI_AXI_BAR2_START);
+ afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ);
+ afi_writel(pcie, fpci, AFI_FPCI_BAR2);
+
+ /* BAR 3: non-prefetchable memory */
+ fpci = (((mem->phys_start >> 12) & 0x0fffffff) << 4) | 0x1;
+ size = mem->size;
+ axi = mem->phys_start;
+
+ afi_writel(pcie, axi, AFI_AXI_BAR3_START);
+ afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ);
+ afi_writel(pcie, fpci, AFI_FPCI_BAR3);
+
+ /* NULL out the remaining BARs as they are not used */
+ afi_writel(pcie, 0, AFI_AXI_BAR4_START);
+ afi_writel(pcie, 0, AFI_AXI_BAR4_SZ);
+ afi_writel(pcie, 0, AFI_FPCI_BAR4);
+
+ afi_writel(pcie, 0, AFI_AXI_BAR5_START);
+ afi_writel(pcie, 0, AFI_AXI_BAR5_SZ);
+ afi_writel(pcie, 0, AFI_FPCI_BAR5);
+
+ /* map all upstream transactions as uncached */
+ afi_writel(pcie, NV_PA_SDRAM_BASE, AFI_CACHE_BAR0_ST);
+ afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ);
+ afi_writel(pcie, 0, AFI_CACHE_BAR1_ST);
+ afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ);
+
+ /* MSI translations are setup only when needed */
+ afi_writel(pcie, 0, AFI_MSI_FPCI_BAR_ST);
+ afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
+ afi_writel(pcie, 0, AFI_MSI_AXI_BAR_ST);
+ afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
+
+ return 0;
+}
+
+static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
+{
+ unsigned long ret = 0;
+
+ switch (port->index) {
+ case 0:
+ ret = AFI_PEX0_CTRL;
+ break;
+
+ case 1:
+ ret = AFI_PEX1_CTRL;
+ break;
+
+ case 2:
+ ret = port->pcie->soc->afi_pex2_ctrl;
+ break;
+ }
+
+ return ret;
+}
+
+void tegra_pcie_port_reset(struct tegra_pcie_port *port)
+{
+ unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
+ unsigned long value;
+
+ /* pulse reset signel */
+ value = afi_readl(port->pcie, ctrl);
+ value &= ~AFI_PEX_CTRL_RST;
+ afi_writel(port->pcie, value, ctrl);
+
+ udelay(2000);
+
+ value = afi_readl(port->pcie, ctrl);
+ value |= AFI_PEX_CTRL_RST;
+ afi_writel(port->pcie, value, ctrl);
+}
+
+int tegra_pcie_port_index_of_port(struct tegra_pcie_port *port)
+{
+ return port->index;
+}
+
+void __weak tegra_pcie_board_port_reset(struct tegra_pcie_port *port)
+{
+ tegra_pcie_port_reset(port);
+}
+
+static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
+{
+ struct tegra_pcie *pcie = port->pcie;
+ const struct tegra_pcie_soc *soc = pcie->soc;
+ unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
+ unsigned long value;
+
+ /* enable reference clock */
+ value = afi_readl(pcie, ctrl);
+ value |= AFI_PEX_CTRL_REFCLK_EN;
+
+ if (pcie->soc->has_pex_clkreq_en)
+ value |= AFI_PEX_CTRL_CLKREQ_EN;
+
+ value |= AFI_PEX_CTRL_OVERRIDE_EN;
+
+ afi_writel(pcie, value, ctrl);
+
+ tegra_pcie_board_port_reset(port);
+
+ if (soc->force_pca_enable) {
+ value = rp_readl(port, RP_VEND_CTL2);
+ value |= RP_VEND_CTL2_PCA_ENABLE;
+ rp_writel(port, value, RP_VEND_CTL2);
+ }
+
+ /* configure the reference clock driver */
+ pads_writel(pcie, soc->pads_refclk_cfg0, PADS_REFCLK_CFG0);
+ if (soc->num_ports > 2)
+ pads_writel(pcie, soc->pads_refclk_cfg1, PADS_REFCLK_CFG1);
+}
+
+static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
+{
+ unsigned int retries = 3;
+ unsigned long value;
+
+ value = rp_readl(port, RP_PRIV_MISC);
+ value &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
+ value |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
+ rp_writel(port, value, RP_PRIV_MISC);
+
+ do {
+ unsigned int timeout = 200;
+
+ do {
+ value = rp_readl(port, RP_VEND_XP);
+ if (value & RP_VEND_XP_DL_UP)
+ break;
+
+ udelay(2000);
+ } while (--timeout);
+
+ if (!timeout) {
+ debug("link %u down, retrying\n", port->index);
+ goto retry;
+ }
+
+ timeout = 200;
+
+ do {
+ value = rp_readl(port, RP_LINK_CONTROL_STATUS);
+ if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
+ return true;
+
+ udelay(2000);
+ } while (--timeout);
+
+retry:
+ tegra_pcie_board_port_reset(port);
+ } while (--retries);
+
+ return false;
+}
+
+static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
+{
+ unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
+ unsigned long value;
+
+ /* assert port reset */
+ value = afi_readl(port->pcie, ctrl);
+ value &= ~AFI_PEX_CTRL_RST;
+ afi_writel(port->pcie, value, ctrl);
+
+ /* disable reference clock */
+ value = afi_readl(port->pcie, ctrl);
+ value &= ~AFI_PEX_CTRL_REFCLK_EN;
+ afi_writel(port->pcie, value, ctrl);
+}
+
+static void tegra_pcie_port_free(struct tegra_pcie_port *port)
+{
+ list_del(&port->list);
+ free(port);
+}
+
+static int tegra_pcie_enable(struct tegra_pcie *pcie)
+{
+ struct tegra_pcie_port *port, *tmp;
+
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+ debug("probing port %u, using %u lanes\n", port->index,
+ port->num_lanes);
+
+ tegra_pcie_port_enable(port);
+
+ if (tegra_pcie_port_check_link(port))
+ continue;
+
+ debug("link %u down, ignoring\n", port->index);
+
+ tegra_pcie_port_disable(port);
+ tegra_pcie_port_free(port);
+ }
+
+ return 0;
+}
+
+static const struct tegra_pcie_soc pci_tegra_soc[] = {
+ [TEGRA20_PCIE] = {
+ .num_ports = 2,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
+ .pads_refclk_cfg0 = 0xfa5cfa5c,
+ .has_pex_clkreq_en = false,
+ .has_pex_bias_ctrl = false,
+ .has_cml_clk = false,
+ .has_gen2 = false,
+ },
+ [TEGRA30_PCIE] = {
+ .num_ports = 3,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+ .afi_pex2_ctrl = AFI_PEX2_CTRL,
+ .pads_refclk_cfg0 = 0xfa5cfa5c,
+ .pads_refclk_cfg1 = 0xfa5cfa5c,
+ .has_pex_clkreq_en = true,
+ .has_pex_bias_ctrl = true,
+ .has_cml_clk = true,
+ .has_gen2 = false,
+ },
+ [TEGRA124_PCIE] = {
+ .num_ports = 2,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+ .pads_refclk_cfg0 = 0x44ac44ac,
+ .has_pex_clkreq_en = true,
+ .has_pex_bias_ctrl = true,
+ .has_cml_clk = true,
+ .has_gen2 = true,
+ },
+ [TEGRA210_PCIE] = {
+ .num_ports = 2,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+ .pads_refclk_cfg0 = 0x90b890b8,
+ .has_pex_clkreq_en = true,
+ .has_pex_bias_ctrl = true,
+ .has_cml_clk = true,
+ .has_gen2 = true,
+ .force_pca_enable = true,
+ },
+ [TEGRA186_PCIE] = {
+ .num_ports = 3,
+ .afi_pex2_ctrl = AFI_PEX2_CTRL_T186,
+ .pads_refclk_cfg0 = 0x80b880b8,
+ .pads_refclk_cfg1 = 0x000480b8,
+ .has_pex_clkreq_en = true,
+ .has_pex_bias_ctrl = true,
+ .has_gen2 = true,
+ },
+};
+
+static int pci_tegra_of_to_plat(struct udevice *dev)
+{
+ struct tegra_pcie *pcie = dev_get_priv(dev);
+ enum tegra_pci_id id;
+
+ id = dev_get_driver_data(dev);
+ pcie->soc = &pci_tegra_soc[id];
+
+ INIT_LIST_HEAD(&pcie->ports);
+
+ if (tegra_pcie_parse_dt(dev, id, pcie))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int pci_tegra_probe(struct udevice *dev)
+{
+ struct tegra_pcie *pcie = dev_get_priv(dev);
+ int err;
+
+#ifdef CONFIG_TEGRA186
+ err = clk_get_by_name(dev, "afi", &pcie->clk_afi);
+ if (err) {
+ debug("clk_get_by_name(afi) failed: %d\n", err);
+ return err;
+ }
+
+ err = clk_get_by_name(dev, "pex", &pcie->clk_pex);
+ if (err) {
+ debug("clk_get_by_name(pex) failed: %d\n", err);
+ return err;
+ }
+
+ err = reset_get_by_name(dev, "afi", &pcie->reset_afi);
+ if (err) {
+ debug("reset_get_by_name(afi) failed: %d\n", err);
+ return err;
+ }
+
+ err = reset_get_by_name(dev, "pex", &pcie->reset_pex);
+ if (err) {
+ debug("reset_get_by_name(pex) failed: %d\n", err);
+ return err;
+ }
+
+ err = reset_get_by_name(dev, "pcie_x", &pcie->reset_pcie_x);
+ if (err) {
+ debug("reset_get_by_name(pcie_x) failed: %d\n", err);
+ return err;
+ }
+
+ err = power_domain_get(dev, &pcie->pwrdom);
+ if (err) {
+ debug("power_domain_get() failed: %d\n", err);
+ return err;
+ }
+#endif
+
+ err = tegra_pcie_power_on(pcie);
+ if (err < 0) {
+ pr_err("failed to power on");
+ return err;
+ }
+
+ err = tegra_pcie_enable_controller(pcie);
+ if (err < 0) {
+ pr_err("failed to enable controller");
+ return err;
+ }
+
+ err = tegra_pcie_setup_translations(dev);
+ if (err < 0) {
+ pr_err("failed to decode ranges");
+ return err;
+ }
+
+ err = tegra_pcie_enable(pcie);
+ if (err < 0) {
+ pr_err("failed to enable PCIe");
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct dm_pci_ops pci_tegra_ops = {
+ .read_config = pci_tegra_read_config,
+ .write_config = pci_tegra_write_config,
+};
+
+static const struct udevice_id pci_tegra_ids[] = {
+ { .compatible = "nvidia,tegra20-pcie", .data = TEGRA20_PCIE },
+ { .compatible = "nvidia,tegra30-pcie", .data = TEGRA30_PCIE },
+ { .compatible = "nvidia,tegra124-pcie", .data = TEGRA124_PCIE },
+ { .compatible = "nvidia,tegra210-pcie", .data = TEGRA210_PCIE },
+ { .compatible = "nvidia,tegra186-pcie", .data = TEGRA186_PCIE },
+ { }
+};
+
+U_BOOT_DRIVER(pci_tegra) = {
+ .name = "pci_tegra",
+ .id = UCLASS_PCI,
+ .of_match = pci_tegra_ids,
+ .ops = &pci_tegra_ops,
+ .of_to_plat = pci_tegra_of_to_plat,
+ .probe = pci_tegra_probe,
+ .priv_auto = sizeof(struct tegra_pcie),
+};
diff --git a/roms/u-boot/drivers/pci/pci_x86.c b/roms/u-boot/drivers/pci/pci_x86.c
new file mode 100644
index 000000000..8d036930e
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pci_x86.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/pci.h>
+
+static int _pci_x86_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ return pci_x86_read_config(bdf, offset, valuep, size);
+}
+
+static int _pci_x86_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value, enum pci_size_t size)
+{
+ return pci_x86_write_config(bdf, offset, value, size);
+}
+
+static const struct dm_pci_ops pci_x86_ops = {
+ .read_config = _pci_x86_read_config,
+ .write_config = _pci_x86_write_config,
+};
+
+static const struct udevice_id pci_x86_ids[] = {
+ { .compatible = "pci-x86" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_x86) = {
+ .name = "pci_x86",
+ .id = UCLASS_PCI,
+ .of_match = pci_x86_ids,
+ .ops = &pci_x86_ops,
+};
diff --git a/roms/u-boot/drivers/pci/pcie_brcmstb.c b/roms/u-boot/drivers/pci/pcie_brcmstb.c
new file mode 100644
index 000000000..90225f677
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_brcmstb.c
@@ -0,0 +1,641 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Broadcom STB PCIe controller driver
+ *
+ * Copyright (C) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Based on upstream Linux kernel driver:
+ * drivers/pci/controller/pcie-brcmstb.c
+ * Copyright (C) 2009 - 2017 Broadcom
+ *
+ * Based driver by Nicolas Saenz Julienne
+ * Copyright (C) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/ofnode.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <linux/bitfield.h>
+#include <linux/log2.h>
+#include <linux/iopoll.h>
+
+/* Offset of the mandatory PCIe capability config registers */
+#define BRCM_PCIE_CAP_REGS 0x00ac
+
+/* The PCIe controller register offsets */
+#define PCIE_RC_CFG_VENDOR_SPECIFIC_REG1 0x0188
+#define VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc
+#define VENDOR_SPECIFIC_REG1_LITTLE_ENDIAN 0x0
+
+#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c
+#define CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff
+
+#define PCIE_RC_DL_MDIO_ADDR 0x1100
+#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
+#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
+
+#define PCIE_MISC_MISC_CTRL 0x4008
+#define MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000
+#define MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000
+#define MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000
+#define MISC_CTRL_MAX_BURST_SIZE_128 0x0
+#define MISC_CTRL_SCB0_SIZE_MASK 0xf8000000
+
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
+#define PCIE_MEM_WIN0_LO(win) \
+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4)
+
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010
+#define PCIE_MEM_WIN0_HI(win) \
+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4)
+
+#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c
+#define RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f
+
+#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
+#define RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f
+#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
+
+#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
+#define RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f
+
+#define PCIE_MISC_PCIE_STATUS 0x4068
+#define STATUS_PCIE_PORT_MASK 0x80
+#define STATUS_PCIE_PORT_SHIFT 7
+#define STATUS_PCIE_DL_ACTIVE_MASK 0x20
+#define STATUS_PCIE_DL_ACTIVE_SHIFT 5
+#define STATUS_PCIE_PHYLINKUP_MASK 0x10
+#define STATUS_PCIE_PHYLINKUP_SHIFT 4
+
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070
+#define MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000
+#define MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0
+#define MEM_WIN0_BASE_LIMIT_BASE_HI_SHIFT 12
+#define PCIE_MEM_WIN0_BASE_LIMIT(win) \
+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((win) * 4)
+
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080
+#define MEM_WIN0_BASE_HI_BASE_MASK 0xff
+#define PCIE_MEM_WIN0_BASE_HI(win) \
+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((win) * 8)
+
+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
+#define PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff
+#define PCIE_MEM_WIN0_LIMIT_HI(win) \
+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8)
+
+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
+#define PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
+#define PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
+
+#define PCIE_MSI_INTR2_CLR 0x4508
+#define PCIE_MSI_INTR2_MASK_SET 0x4510
+
+#define PCIE_EXT_CFG_DATA 0x8000
+
+#define PCIE_EXT_CFG_INDEX 0x9000
+#define PCIE_EXT_BUSNUM_SHIFT 20
+#define PCIE_EXT_SLOT_SHIFT 15
+#define PCIE_EXT_FUNC_SHIFT 12
+
+#define PCIE_RGR1_SW_INIT_1 0x9210
+#define RGR1_SW_INIT_1_PERST_MASK 0x1
+#define RGR1_SW_INIT_1_INIT_MASK 0x2
+
+/* PCIe parameters */
+#define BRCM_NUM_PCIE_OUT_WINS 4
+
+/* MDIO registers */
+#define MDIO_PORT0 0x0
+#define MDIO_DATA_MASK 0x7fffffff
+#define MDIO_DATA_SHIFT 0
+#define MDIO_PORT_MASK 0xf0000
+#define MDIO_PORT_SHIFT 16
+#define MDIO_REGAD_MASK 0xffff
+#define MDIO_REGAD_SHIFT 0
+#define MDIO_CMD_MASK 0xfff00000
+#define MDIO_CMD_SHIFT 20
+#define MDIO_CMD_READ 0x1
+#define MDIO_CMD_WRITE 0x0
+#define MDIO_DATA_DONE_MASK 0x80000000
+#define SSC_REGS_ADDR 0x1100
+#define SET_ADDR_OFFSET 0x1f
+#define SSC_CNTL_OFFSET 0x2
+#define SSC_CNTL_OVRD_EN_MASK 0x8000
+#define SSC_CNTL_OVRD_VAL_MASK 0x4000
+#define SSC_STATUS_OFFSET 0x1
+#define SSC_STATUS_SSC_MASK 0x400
+#define SSC_STATUS_SSC_SHIFT 10
+#define SSC_STATUS_PLL_LOCK_MASK 0x800
+#define SSC_STATUS_PLL_LOCK_SHIFT 11
+
+/**
+ * struct brcm_pcie - the PCIe controller state
+ * @base: Base address of memory mapped IO registers of the controller
+ * @gen: Non-zero value indicates limitation of the PCIe controller operation
+ * to a specific generation (1, 2 or 3)
+ * @ssc: true indicates active Spread Spectrum Clocking operation
+ */
+struct brcm_pcie {
+ void __iomem *base;
+
+ int gen;
+ bool ssc;
+};
+
+/**
+ * brcm_pcie_encode_ibar_size() - Encode the inbound "BAR" region size
+ * @size: The inbound region size
+ *
+ * This function converts size of the inbound "BAR" region to the non-linear
+ * values of the PCIE_MISC_RC_BAR[123]_CONFIG_LO register SIZE field.
+ *
+ * Return: The encoded inbound region size
+ */
+static int brcm_pcie_encode_ibar_size(u64 size)
+{
+ int log2_in = ilog2(size);
+
+ if (log2_in >= 12 && log2_in <= 15)
+ /* Covers 4KB to 32KB (inclusive) */
+ return (log2_in - 12) + 0x1c;
+ else if (log2_in >= 16 && log2_in <= 37)
+ /* Covers 64KB to 32GB, (inclusive) */
+ return log2_in - 15;
+
+ /* Something is awry so disable */
+ return 0;
+}
+
+/**
+ * brcm_pcie_rc_mode() - Check if PCIe controller is in RC mode
+ * @pcie: Pointer to the PCIe controller state
+ *
+ * The controller is capable of serving in both RC and EP roles.
+ *
+ * Return: true for RC mode, false for EP mode.
+ */
+static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
+{
+ u32 val;
+
+ val = readl(pcie->base + PCIE_MISC_PCIE_STATUS);
+
+ return (val & STATUS_PCIE_PORT_MASK) >> STATUS_PCIE_PORT_SHIFT;
+}
+
+/**
+ * brcm_pcie_link_up() - Check whether the PCIe link is up
+ * @pcie: Pointer to the PCIe controller state
+ *
+ * Return: true if the link is up, false otherwise.
+ */
+static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
+{
+ u32 val, dla, plu;
+
+ val = readl(pcie->base + PCIE_MISC_PCIE_STATUS);
+ dla = (val & STATUS_PCIE_DL_ACTIVE_MASK) >> STATUS_PCIE_DL_ACTIVE_SHIFT;
+ plu = (val & STATUS_PCIE_PHYLINKUP_MASK) >> STATUS_PCIE_PHYLINKUP_SHIFT;
+
+ return dla && plu;
+}
+
+static int brcm_pcie_config_address(const struct udevice *dev, pci_dev_t bdf,
+ uint offset, void **paddress)
+{
+ struct brcm_pcie *pcie = dev_get_priv(dev);
+ unsigned int pci_bus = PCI_BUS(bdf);
+ unsigned int pci_dev = PCI_DEV(bdf);
+ unsigned int pci_func = PCI_FUNC(bdf);
+ int idx;
+
+ /*
+ * Busses 0 (host PCIe bridge) and 1 (its immediate child)
+ * are limited to a single device each
+ */
+ if (pci_bus < 2 && pci_dev > 0)
+ return -EINVAL;
+
+ /* Accesses to the RC go right to the RC registers */
+ if (pci_bus == 0) {
+ *paddress = pcie->base + offset;
+ return 0;
+ }
+
+ /* For devices, write to the config space index register */
+ idx = (pci_bus << PCIE_EXT_BUSNUM_SHIFT)
+ | (pci_dev << PCIE_EXT_SLOT_SHIFT)
+ | (pci_func << PCIE_EXT_FUNC_SHIFT);
+
+ writel(idx, pcie->base + PCIE_EXT_CFG_INDEX);
+ *paddress = pcie->base + PCIE_EXT_CFG_DATA + offset;
+
+ return 0;
+}
+
+static int brcm_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_read_config(bus, brcm_pcie_config_address,
+ bdf, offset, valuep, size);
+}
+
+static int brcm_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_write_config(bus, brcm_pcie_config_address,
+ bdf, offset, value, size);
+}
+
+static const char *link_speed_to_str(unsigned int cls)
+{
+ switch (cls) {
+ case PCI_EXP_LNKSTA_CLS_2_5GB: return "2.5";
+ case PCI_EXP_LNKSTA_CLS_5_0GB: return "5.0";
+ case PCI_EXP_LNKSTA_CLS_8_0GB: return "8.0";
+ default:
+ break;
+ }
+
+ return "??";
+}
+
+static u32 brcm_pcie_mdio_form_pkt(unsigned int port, unsigned int regad,
+ unsigned int cmd)
+{
+ u32 pkt;
+
+ pkt = (port << MDIO_PORT_SHIFT) & MDIO_PORT_MASK;
+ pkt |= (regad << MDIO_REGAD_SHIFT) & MDIO_REGAD_MASK;
+ pkt |= (cmd << MDIO_CMD_SHIFT) & MDIO_CMD_MASK;
+
+ return pkt;
+}
+
+/**
+ * brcm_pcie_mdio_read() - Perform a register read on the internal MDIO bus
+ * @base: Pointer to the PCIe controller IO registers
+ * @port: The MDIO port number
+ * @regad: The register address
+ * @val: A pointer at which to store the read value
+ *
+ * Return: 0 on success and register value in @val, negative error value
+ * on failure.
+ */
+static int brcm_pcie_mdio_read(void __iomem *base, unsigned int port,
+ unsigned int regad, u32 *val)
+{
+ u32 data, addr;
+ int ret;
+
+ addr = brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_READ);
+ writel(addr, base + PCIE_RC_DL_MDIO_ADDR);
+ readl(base + PCIE_RC_DL_MDIO_ADDR);
+
+ ret = readl_poll_timeout(base + PCIE_RC_DL_MDIO_RD_DATA, data,
+ (data & MDIO_DATA_DONE_MASK), 100);
+
+ *val = data & MDIO_DATA_MASK;
+
+ return ret;
+}
+
+/**
+ * brcm_pcie_mdio_write() - Perform a register write on the internal MDIO bus
+ * @base: Pointer to the PCIe controller IO registers
+ * @port: The MDIO port number
+ * @regad: Address of the register
+ * @wrdata: The value to write
+ *
+ * Return: 0 on success, negative error value on failure.
+ */
+static int brcm_pcie_mdio_write(void __iomem *base, unsigned int port,
+ unsigned int regad, u16 wrdata)
+{
+ u32 data, addr;
+
+ addr = brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_WRITE);
+ writel(addr, base + PCIE_RC_DL_MDIO_ADDR);
+ readl(base + PCIE_RC_DL_MDIO_ADDR);
+ writel(MDIO_DATA_DONE_MASK | wrdata, base + PCIE_RC_DL_MDIO_WR_DATA);
+
+ return readl_poll_timeout(base + PCIE_RC_DL_MDIO_WR_DATA, data,
+ !(data & MDIO_DATA_DONE_MASK), 100);
+}
+
+/**
+ * brcm_pcie_set_ssc() - Configure the controller for Spread Spectrum Clocking
+ * @base: pointer to the PCIe controller IO registers
+ *
+ * Return: 0 on success, negative error value on failure.
+ */
+static int brcm_pcie_set_ssc(void __iomem *base)
+{
+ int pll, ssc;
+ int ret;
+ u32 tmp;
+
+ ret = brcm_pcie_mdio_write(base, MDIO_PORT0, SET_ADDR_OFFSET,
+ SSC_REGS_ADDR);
+ if (ret < 0)
+ return ret;
+
+ ret = brcm_pcie_mdio_read(base, MDIO_PORT0, SSC_CNTL_OFFSET, &tmp);
+ if (ret < 0)
+ return ret;
+
+ tmp |= (SSC_CNTL_OVRD_EN_MASK | SSC_CNTL_OVRD_VAL_MASK);
+
+ ret = brcm_pcie_mdio_write(base, MDIO_PORT0, SSC_CNTL_OFFSET, tmp);
+ if (ret < 0)
+ return ret;
+
+ udelay(1000);
+ ret = brcm_pcie_mdio_read(base, MDIO_PORT0, SSC_STATUS_OFFSET, &tmp);
+ if (ret < 0)
+ return ret;
+
+ ssc = (tmp & SSC_STATUS_SSC_MASK) >> SSC_STATUS_SSC_SHIFT;
+ pll = (tmp & SSC_STATUS_PLL_LOCK_MASK) >> SSC_STATUS_PLL_LOCK_SHIFT;
+
+ return ssc && pll ? 0 : -EIO;
+}
+
+/**
+ * brcm_pcie_set_gen() - Limits operation to a specific generation (1, 2 or 3)
+ * @pcie: pointer to the PCIe controller state
+ * @gen: PCIe generation to limit the controller's operation to
+ */
+static void brcm_pcie_set_gen(struct brcm_pcie *pcie, unsigned int gen)
+{
+ void __iomem *cap_base = pcie->base + BRCM_PCIE_CAP_REGS;
+
+ u16 lnkctl2 = readw(cap_base + PCI_EXP_LNKCTL2);
+ u32 lnkcap = readl(cap_base + PCI_EXP_LNKCAP);
+
+ lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen;
+ writel(lnkcap, cap_base + PCI_EXP_LNKCAP);
+
+ lnkctl2 = (lnkctl2 & ~0xf) | gen;
+ writew(lnkctl2, cap_base + PCI_EXP_LNKCTL2);
+}
+
+static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie,
+ unsigned int win, u64 phys_addr,
+ u64 pcie_addr, u64 size)
+{
+ void __iomem *base = pcie->base;
+ u32 phys_addr_mb_high, limit_addr_mb_high;
+ phys_addr_t phys_addr_mb, limit_addr_mb;
+ int high_addr_shift;
+ u32 tmp;
+
+ /* Set the base of the pcie_addr window */
+ writel(lower_32_bits(pcie_addr), base + PCIE_MEM_WIN0_LO(win));
+ writel(upper_32_bits(pcie_addr), base + PCIE_MEM_WIN0_HI(win));
+
+ /* Write the addr base & limit lower bits (in MBs) */
+ phys_addr_mb = phys_addr / SZ_1M;
+ limit_addr_mb = (phys_addr + size - 1) / SZ_1M;
+
+ tmp = readl(base + PCIE_MEM_WIN0_BASE_LIMIT(win));
+ u32p_replace_bits(&tmp, phys_addr_mb,
+ MEM_WIN0_BASE_LIMIT_BASE_MASK);
+ u32p_replace_bits(&tmp, limit_addr_mb,
+ MEM_WIN0_BASE_LIMIT_LIMIT_MASK);
+ writel(tmp, base + PCIE_MEM_WIN0_BASE_LIMIT(win));
+
+ /* Write the cpu & limit addr upper bits */
+ high_addr_shift = MEM_WIN0_BASE_LIMIT_BASE_HI_SHIFT;
+ phys_addr_mb_high = phys_addr_mb >> high_addr_shift;
+ tmp = readl(base + PCIE_MEM_WIN0_BASE_HI(win));
+ u32p_replace_bits(&tmp, phys_addr_mb_high,
+ MEM_WIN0_BASE_HI_BASE_MASK);
+ writel(tmp, base + PCIE_MEM_WIN0_BASE_HI(win));
+
+ limit_addr_mb_high = limit_addr_mb >> high_addr_shift;
+ tmp = readl(base + PCIE_MEM_WIN0_LIMIT_HI(win));
+ u32p_replace_bits(&tmp, limit_addr_mb_high,
+ PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK);
+ writel(tmp, base + PCIE_MEM_WIN0_LIMIT_HI(win));
+}
+
+static int brcm_pcie_probe(struct udevice *dev)
+{
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ struct brcm_pcie *pcie = dev_get_priv(dev);
+ void __iomem *base = pcie->base;
+ struct pci_region region;
+ bool ssc_good = false;
+ int num_out_wins = 0;
+ u64 rc_bar2_offset, rc_bar2_size;
+ unsigned int scb_size_val;
+ int i, ret;
+ u16 nlw, cls, lnksta;
+ u32 tmp;
+
+ /*
+ * Reset the bridge, assert the fundamental reset. Note for some SoCs,
+ * e.g. BCM7278, the fundamental reset should not be asserted here.
+ * This will need to be changed when support for other SoCs is added.
+ */
+ setbits_le32(base + PCIE_RGR1_SW_INIT_1,
+ RGR1_SW_INIT_1_INIT_MASK | RGR1_SW_INIT_1_PERST_MASK);
+ /*
+ * The delay is a safety precaution to preclude the reset signal
+ * from looking like a glitch.
+ */
+ udelay(100);
+
+ /* Take the bridge out of reset */
+ clrbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_INIT_MASK);
+
+ clrbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG,
+ PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
+
+ /* Wait for SerDes to be stable */
+ udelay(100);
+
+ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
+ clrsetbits_le32(base + PCIE_MISC_MISC_CTRL,
+ MISC_CTRL_MAX_BURST_SIZE_MASK,
+ MISC_CTRL_SCB_ACCESS_EN_MASK |
+ MISC_CTRL_CFG_READ_UR_MODE_MASK |
+ MISC_CTRL_MAX_BURST_SIZE_128);
+
+ pci_get_dma_regions(dev, &region, 0);
+ rc_bar2_offset = region.bus_start - region.phys_start;
+ rc_bar2_size = 1ULL << fls64(region.size - 1);
+
+ tmp = lower_32_bits(rc_bar2_offset);
+ u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size),
+ RC_BAR2_CONFIG_LO_SIZE_MASK);
+ writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO);
+ writel(upper_32_bits(rc_bar2_offset),
+ base + PCIE_MISC_RC_BAR2_CONFIG_HI);
+
+ scb_size_val = rc_bar2_size ?
+ ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */
+
+ tmp = readl(base + PCIE_MISC_MISC_CTRL);
+ u32p_replace_bits(&tmp, scb_size_val,
+ MISC_CTRL_SCB0_SIZE_MASK);
+ writel(tmp, base + PCIE_MISC_MISC_CTRL);
+
+ /* Disable the PCIe->GISB memory window (RC_BAR1) */
+ clrbits_le32(base + PCIE_MISC_RC_BAR1_CONFIG_LO,
+ RC_BAR1_CONFIG_LO_SIZE_MASK);
+
+ /* Disable the PCIe->SCB memory window (RC_BAR3) */
+ clrbits_le32(base + PCIE_MISC_RC_BAR3_CONFIG_LO,
+ RC_BAR3_CONFIG_LO_SIZE_MASK);
+
+ /* Mask all interrupts since we are not handling any yet */
+ writel(0xffffffff, base + PCIE_MSI_INTR2_MASK_SET);
+
+ /* Clear any interrupts we find on boot */
+ writel(0xffffffff, base + PCIE_MSI_INTR2_CLR);
+
+ if (pcie->gen)
+ brcm_pcie_set_gen(pcie, pcie->gen);
+
+ /* Unassert the fundamental reset */
+ clrbits_le32(pcie->base + PCIE_RGR1_SW_INIT_1,
+ RGR1_SW_INIT_1_PERST_MASK);
+
+ /* Give the RC/EP time to wake up, before trying to configure RC.
+ * Intermittently check status for link-up, up to a total of 100ms.
+ */
+ for (i = 0; i < 100 && !brcm_pcie_link_up(pcie); i += 5)
+ mdelay(5);
+
+ if (!brcm_pcie_link_up(pcie)) {
+ printf("PCIe BRCM: link down\n");
+ return -EINVAL;
+ }
+
+ if (!brcm_pcie_rc_mode(pcie)) {
+ printf("PCIe misconfigured; is in EP mode\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < hose->region_count; i++) {
+ struct pci_region *reg = &hose->regions[i];
+
+ if (reg->flags != PCI_REGION_MEM)
+ continue;
+
+ if (num_out_wins >= BRCM_NUM_PCIE_OUT_WINS)
+ return -EINVAL;
+
+ brcm_pcie_set_outbound_win(pcie, num_out_wins, reg->phys_start,
+ reg->bus_start, reg->size);
+
+ num_out_wins++;
+ }
+
+ /*
+ * For config space accesses on the RC, show the right class for
+ * a PCIe-PCIe bridge (the default setting is to be EP mode).
+ */
+ clrsetbits_le32(base + PCIE_RC_CFG_PRIV1_ID_VAL3,
+ CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK, 0x060400);
+
+ if (pcie->ssc) {
+ ret = brcm_pcie_set_ssc(pcie->base);
+ if (!ret)
+ ssc_good = true;
+ else
+ printf("PCIe BRCM: failed attempt to enter SSC mode\n");
+ }
+
+ lnksta = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA);
+ cls = lnksta & PCI_EXP_LNKSTA_CLS;
+ nlw = (lnksta & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
+
+ printf("PCIe BRCM: link up, %s Gbps x%u %s\n", link_speed_to_str(cls),
+ nlw, ssc_good ? "(SSC)" : "(!SSC)");
+
+ /* PCIe->SCB endian mode for BAR */
+ clrsetbits_le32(base + PCIE_RC_CFG_VENDOR_SPECIFIC_REG1,
+ VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK,
+ VENDOR_SPECIFIC_REG1_LITTLE_ENDIAN);
+ /*
+ * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1
+ * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1.
+ */
+ setbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG,
+ PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK);
+
+ return 0;
+}
+
+static int brcm_pcie_remove(struct udevice *dev)
+{
+ struct brcm_pcie *pcie = dev_get_priv(dev);
+ void __iomem *base = pcie->base;
+
+ /* Assert fundamental reset */
+ setbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_PERST_MASK);
+
+ /* Turn off SerDes */
+ setbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG,
+ PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
+
+ /* Shutdown bridge */
+ setbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_INIT_MASK);
+
+ return 0;
+}
+
+static int brcm_pcie_of_to_plat(struct udevice *dev)
+{
+ struct brcm_pcie *pcie = dev_get_priv(dev);
+ ofnode dn = dev_ofnode(dev);
+ u32 max_link_speed;
+ int ret;
+
+ /* Get the controller base address */
+ pcie->base = dev_read_addr_ptr(dev);
+ if (!pcie->base)
+ return -EINVAL;
+
+ pcie->ssc = ofnode_read_bool(dn, "brcm,enable-ssc");
+
+ ret = ofnode_read_u32(dn, "max-link-speed", &max_link_speed);
+ if (ret < 0 || max_link_speed > 4)
+ pcie->gen = 0;
+ else
+ pcie->gen = max_link_speed;
+
+ return 0;
+}
+
+static const struct dm_pci_ops brcm_pcie_ops = {
+ .read_config = brcm_pcie_read_config,
+ .write_config = brcm_pcie_write_config,
+};
+
+static const struct udevice_id brcm_pcie_ids[] = {
+ { .compatible = "brcm,bcm2711-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_brcm_base) = {
+ .name = "pcie_brcm",
+ .id = UCLASS_PCI,
+ .ops = &brcm_pcie_ops,
+ .of_match = brcm_pcie_ids,
+ .probe = brcm_pcie_probe,
+ .remove = brcm_pcie_remove,
+ .of_to_plat = brcm_pcie_of_to_plat,
+ .priv_auto = sizeof(struct brcm_pcie),
+ .flags = DM_FLAG_OS_PREPARE,
+};
diff --git a/roms/u-boot/drivers/pci/pcie_dw_common.c b/roms/u-boot/drivers/pci/pcie_dw_common.c
new file mode 100644
index 000000000..e66fb1490
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_dw_common.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2021 Rockchip, Inc.
+ *
+ * Copyright (C) 2018 Texas Instruments, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <dm/device_compat.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include "pcie_dw_common.h"
+
+int pcie_dw_get_link_speed(struct pcie_dw *pci)
+{
+ return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
+ PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
+}
+
+int pcie_dw_get_link_width(struct pcie_dw *pci)
+{
+ return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) &
+ PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
+}
+
+static void dw_pcie_writel_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg,
+ u32 val)
+{
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+ void __iomem *base = pci->atu_base;
+
+ writel(val, base + offset + reg);
+}
+
+static u32 dw_pcie_readl_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg)
+{
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+ void __iomem *base = pci->atu_base;
+
+ return readl(base + offset + reg);
+}
+
+/**
+ * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @index: ATU region index
+ * @type: ATU accsess type
+ * @cpu_addr: the physical address for the translation entry
+ * @pci_addr: the pcie bus address for the translation entry
+ * @size: the size of the translation entry
+ *
+ * Return: 0 is successful and -1 is failure
+ */
+int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index,
+ int type, u64 cpu_addr,
+ u64 pci_addr, u32 size)
+{
+ u32 retries, val;
+
+ dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
+ index, type, cpu_addr, pci_addr, size);
+
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
+ lower_32_bits(cpu_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
+ upper_32_bits(cpu_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
+ lower_32_bits(cpu_addr + size - 1));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
+ lower_32_bits(pci_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
+ upper_32_bits(pci_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
+ type);
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
+ PCIE_ATU_ENABLE);
+
+ /*
+ * Make sure ATU enable takes effect before any subsequent config
+ * and I/O accesses.
+ */
+ for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+ val = dw_pcie_readl_ob_unroll(pci, index,
+ PCIE_ATU_UNR_REGION_CTRL2);
+ if (val & PCIE_ATU_ENABLE)
+ return 0;
+
+ udelay(LINK_WAIT_IATU);
+ }
+ dev_err(pci->dev, "outbound iATU is not being enabled\n");
+
+ return -1;
+}
+
+/**
+ * set_cfg_address() - Configure the PCIe controller config space access
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @d: PCI device to access
+ * @where: Offset in the configuration space
+ *
+ * Configures the PCIe controller to access the configuration space of
+ * a specific PCIe device and returns the address to use for this
+ * access.
+ *
+ * Return: Address that can be used to access the configation space
+ * of the requested device / offset
+ */
+static uintptr_t set_cfg_address(struct pcie_dw *pcie,
+ pci_dev_t d, uint where)
+{
+ int bus = PCI_BUS(d) - pcie->first_busno;
+ uintptr_t va_address;
+ u32 atu_type;
+ int ret;
+
+ /* Use dbi_base for own configuration read and write */
+ if (!bus) {
+ va_address = (uintptr_t)pcie->dbi_base;
+ goto out;
+ }
+
+ if (bus == 1)
+ /*
+ * For local bus whose primary bus number is root bridge,
+ * change TLP Type field to 4.
+ */
+ atu_type = PCIE_ATU_TYPE_CFG0;
+ else
+ /* Otherwise, change TLP Type field to 5. */
+ atu_type = PCIE_ATU_TYPE_CFG1;
+
+ /*
+ * Not accessing root port configuration space?
+ * Region #0 is used for Outbound CFG space access.
+ * Direction = Outbound
+ * Region Index = 0
+ */
+ d = PCI_MASK_BUS(d);
+ d = PCI_ADD_BUS(bus, d);
+ ret = pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+ atu_type, (u64)pcie->cfg_base,
+ d << 8, pcie->cfg_size);
+ if (ret)
+ return (uintptr_t)ret;
+
+ va_address = (uintptr_t)pcie->cfg_base;
+
+out:
+ va_address += where & ~0x3;
+
+ return va_address;
+}
+
+/**
+ * pcie_dw_addr_valid() - Check for valid bus address
+ *
+ * @d: The PCI device to access
+ * @first_busno: Bus number of the PCIe controller root complex
+ *
+ * Return 1 (true) if the PCI device can be accessed by this controller.
+ *
+ * Return: 1 on valid, 0 on invalid
+ */
+static int pcie_dw_addr_valid(pci_dev_t d, int first_busno)
+{
+ if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
+ return 0;
+ if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * pcie_dw_read_config() - Read from configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct pcie_dw *pcie = dev_get_priv(bus);
+ uintptr_t va_address;
+ ulong value;
+
+ dev_dbg(pcie->dev, "PCIE CFG read: bdf=%2x:%2x:%2x ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
+ debug("- out of range\n");
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ va_address = set_cfg_address(pcie, bdf, offset);
+
+ value = readl((void __iomem *)va_address);
+
+ debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+ *valuep = pci_conv_32_to_size(value, offset, size);
+
+ return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+ pcie->io.bus_start, pcie->io.size);
+}
+
+/**
+ * pcie_dw_write_config() - Write to configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct pcie_dw *pcie = dev_get_priv(bus);
+ uintptr_t va_address;
+ ulong old;
+
+ dev_dbg(pcie->dev, "PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ dev_dbg(pcie->dev, "(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+
+ if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
+ debug("- out of range\n");
+ return 0;
+ }
+
+ va_address = set_cfg_address(pcie, bdf, offset);
+
+ old = readl((void __iomem *)va_address);
+ value = pci_conv_size_to_32(old, value, offset, size);
+ writel(value, (void __iomem *)va_address);
+
+ return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+ pcie->io.bus_start, pcie->io.size);
+}
+
+/**
+ * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion
+ *
+ * @pcie: Pointer to the PCI controller state
+ *
+ * Configure the host BARs of the PCIe controller root port so that
+ * PCI(e) devices may access the system memory.
+ */
+void pcie_dw_setup_host(struct pcie_dw *pci)
+{
+ struct udevice *ctlr = pci_get_controller(pci->dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ u32 ret;
+
+ if (!pci->atu_base)
+ pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
+
+ /* setup RC BARs */
+ writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
+ pci->dbi_base + PCI_BASE_ADDRESS_0);
+ writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1);
+
+ /* setup interrupt pins */
+ clrsetbits_le32(pci->dbi_base + PCI_INTERRUPT_LINE,
+ 0xff00, 0x100);
+
+ /* setup bus numbers */
+ clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
+ 0xffffff, 0x00ff0100);
+
+ /* setup command register */
+ clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS,
+ 0xffff,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+
+ /* Enable write permission for the DBI read-only register */
+ dw_pcie_dbi_write_enable(pci, true);
+ /* program correct class for RC */
+ writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
+ /* Better disable write permission right after the update */
+ dw_pcie_dbi_write_enable(pci, false);
+
+ setbits_le32(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
+ PORT_LOGIC_SPEED_CHANGE);
+
+ for (ret = 0; ret < hose->region_count; ret++) {
+ if (hose->regions[ret].flags == PCI_REGION_IO) {
+ pci->io.phys_start = hose->regions[ret].phys_start; /* IO base */
+ pci->io.bus_start = hose->regions[ret].bus_start; /* IO_bus_addr */
+ pci->io.size = hose->regions[ret].size; /* IO size */
+ } else if (hose->regions[ret].flags == PCI_REGION_MEM) {
+ pci->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */
+ pci->mem.bus_start = hose->regions[ret].bus_start; /* MEM_bus_addr */
+ pci->mem.size = hose->regions[ret].size; /* MEM size */
+ } else if (hose->regions[ret].flags == PCI_REGION_PREFETCH) {
+ pci->prefetch.phys_start = hose->regions[ret].phys_start; /* PREFETCH base */
+ pci->prefetch.bus_start = hose->regions[ret].bus_start; /* PREFETCH_bus_addr */
+ pci->prefetch.size = hose->regions[ret].size; /* PREFETCH size */
+ } else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
+ pci->cfg_base = (void *)(pci->io.phys_start - pci->io.size);
+ pci->cfg_size = pci->io.size;
+ } else {
+ dev_err(pci->dev, "invalid flags type!\n");
+ }
+ }
+
+ dev_dbg(pci->dev, "Config space: [0x%llx - 0x%llx, size 0x%llx]\n",
+ (u64)pci->cfg_base, (u64)pci->cfg_base + pci->cfg_size,
+ (u64)pci->cfg_size);
+
+ dev_dbg(pci->dev, "IO space: [0x%llx - 0x%llx, size 0x%llx]\n",
+ (u64)pci->io.phys_start, (u64)pci->io.phys_start + pci->io.size,
+ (u64)pci->io.size);
+
+ dev_dbg(pci->dev, "IO bus: [0x%llx - 0x%llx, size 0x%llx]\n",
+ (u64)pci->io.bus_start, (u64)pci->io.bus_start + pci->io.size,
+ (u64)pci->io.size);
+
+ dev_dbg(pci->dev, "MEM space: [0x%llx - 0x%llx, size 0x%llx]\n",
+ (u64)pci->mem.phys_start,
+ (u64)pci->mem.phys_start + pci->mem.size,
+ (u64)pci->mem.size);
+
+ dev_dbg(pci->dev, "MEM bus: [0x%llx - 0x%llx, size 0x%llx]\n",
+ (u64)pci->mem.bus_start,
+ (u64)pci->mem.bus_start + pci->mem.size,
+ (u64)pci->mem.size);
+
+ if (pci->prefetch.size) {
+ dev_dbg(pci->dev, "PREFETCH space: [0x%llx - 0x%llx, size 0x%llx]\n",
+ (u64)pci->prefetch.phys_start,
+ (u64)pci->prefetch.phys_start + pci->prefetch.size,
+ (u64)pci->prefetch.size);
+
+ dev_dbg(pci->dev, "PREFETCH bus: [0x%llx - 0x%llx, size 0x%llx]\n",
+ (u64)pci->prefetch.bus_start,
+ (u64)pci->prefetch.bus_start + pci->prefetch.size,
+ (u64)pci->prefetch.size);
+ }
+}
diff --git a/roms/u-boot/drivers/pci/pcie_dw_common.h b/roms/u-boot/drivers/pci/pcie_dw_common.h
new file mode 100644
index 000000000..6b701645a
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_dw_common.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2021 Rockchip, Inc.
+ *
+ * Copyright (C) 2018 Texas Instruments, Inc
+ */
+
+#ifndef PCIE_DW_COMMON_H
+#define PCIE_DW_COMMON_H
+
+#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
+
+/* PCI DBICS registers */
+#define PCIE_LINK_STATUS_REG 0x80
+#define PCIE_LINK_STATUS_SPEED_OFF 16
+#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF)
+#define PCIE_LINK_STATUS_WIDTH_OFF 20
+#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
+
+/*
+ * iATU Unroll-specific register definitions
+ * From 4.80 core version the address translation will be made by unroll.
+ * The registers are offset from atu_base
+ */
+#define PCIE_ATU_UNR_REGION_CTRL1 0x00
+#define PCIE_ATU_UNR_REGION_CTRL2 0x04
+#define PCIE_ATU_UNR_LOWER_BASE 0x08
+#define PCIE_ATU_UNR_UPPER_BASE 0x0c
+#define PCIE_ATU_UNR_LIMIT 0x10
+#define PCIE_ATU_UNR_LOWER_TARGET 0x14
+#define PCIE_ATU_UNR_UPPER_TARGET 0x18
+
+#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
+#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
+#define PCIE_ATU_TYPE_MEM (0x0 << 0)
+#define PCIE_ATU_TYPE_IO (0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
+#define PCIE_ATU_ENABLE (0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
+#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
+#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
+#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
+
+/* Register address builder */
+#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((region) << 9)
+
+/* Parameters for the waiting for iATU enabled routine */
+#define LINK_WAIT_MAX_IATU_RETRIES 5
+#define LINK_WAIT_IATU_US 10000
+
+/* PCI DBICS registers */
+#define PCIE_LINK_STATUS_REG 0x80
+#define PCIE_LINK_STATUS_SPEED_OFF 16
+#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF)
+#define PCIE_LINK_STATUS_WIDTH_OFF 20
+#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
+
+#define PCIE_LINK_CAPABILITY 0x7c
+#define PCIE_LINK_CTL_2 0xa0
+#define TARGET_LINK_SPEED_MASK 0xf
+#define LINK_SPEED_GEN_1 0x1
+#define LINK_SPEED_GEN_2 0x2
+#define LINK_SPEED_GEN_3 0x3
+
+/* Synopsys-specific PCIe configuration registers */
+#define PCIE_PORT_LINK_CONTROL 0x710
+#define PORT_LINK_DLL_LINK_EN BIT(5)
+#define PORT_LINK_FAST_LINK_MODE BIT(7)
+#define PORT_LINK_MODE_MASK GENMASK(21, 16)
+#define PORT_LINK_MODE(n) FIELD_PREP(PORT_LINK_MODE_MASK, n)
+#define PORT_LINK_MODE_1_LANES PORT_LINK_MODE(0x1)
+#define PORT_LINK_MODE_2_LANES PORT_LINK_MODE(0x3)
+#define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7)
+#define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf)
+
+#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
+#define PORT_LOGIC_N_FTS_MASK GENMASK(7, 0)
+#define PORT_LOGIC_SPEED_CHANGE BIT(17)
+#define PORT_LOGIC_LINK_WIDTH_MASK GENMASK(12, 8)
+#define PORT_LOGIC_LINK_WIDTH(n) FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES PORT_LOGIC_LINK_WIDTH(0x1)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES PORT_LOGIC_LINK_WIDTH(0x2)
+#define PORT_LOGIC_LINK_WIDTH_4_LANES PORT_LOGIC_LINK_WIDTH(0x4)
+#define PORT_LOGIC_LINK_WIDTH_8_LANES PORT_LOGIC_LINK_WIDTH(0x8)
+
+#define PCIE_MISC_CONTROL_1_OFF 0x8bc
+#define PCIE_DBI_RO_WR_EN BIT(0)
+
+/* Parameters for the waiting for iATU enabled routine */
+#define LINK_WAIT_MAX_IATU_RETRIES 5
+#define LINK_WAIT_IATU 10000
+
+/**
+ * struct pcie_dw - DW PCIe controller state
+ *
+ * @dbi_base: The base address of dbi register space
+ * @cfg_base: The base address of configuration space
+ * @atu_base: The base address of ATU space
+ * @cfg_size: The size of the configuration space which is needed
+ * as it gets written into the PCIE_ATU_LIMIT register
+ * @first_busno: This driver supports multiple PCIe controllers.
+ * first_busno stores the bus number of the PCIe root-port
+ * number which may vary depending on the PCIe setup
+ * (PEX switches etc).
+ * @io: The IO space for EP's BAR
+ * @mem: The memory space for EP's BAR
+ * @prefetch: The prefetch space for EP's BAR
+ */
+struct pcie_dw {
+ struct udevice *dev;
+ void __iomem *dbi_base;
+ void __iomem *cfg_base;
+ void __iomem *atu_base;
+ fdt_size_t cfg_size;
+
+ int first_busno;
+
+ /* IO, MEM & PREFETCH PCI regions */
+ struct pci_region io;
+ struct pci_region mem;
+ struct pci_region prefetch;
+};
+
+int pcie_dw_get_link_speed(struct pcie_dw *pci);
+
+int pcie_dw_get_link_width(struct pcie_dw *pci);
+
+int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index, int type, u64 cpu_addr,
+ u64 pci_addr, u32 size);
+
+int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep,
+ enum pci_size_t size);
+
+int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value,
+ enum pci_size_t size);
+
+static inline void dw_pcie_dbi_write_enable(struct pcie_dw *pci, bool en)
+{
+ u32 val;
+
+ val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
+ if (en)
+ val |= PCIE_DBI_RO_WR_EN;
+ else
+ val &= ~PCIE_DBI_RO_WR_EN;
+ writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF);
+}
+
+void pcie_dw_setup_host(struct pcie_dw *pci);
+
+#endif
diff --git a/roms/u-boot/drivers/pci/pcie_dw_meson.c b/roms/u-boot/drivers/pci/pcie_dw_meson.c
new file mode 100644
index 000000000..0525ecbea
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_dw_meson.c
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Amlogic DesignWare based PCIe host controller driver
+ *
+ * Copyright (c) 2021 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Based on pcie_dw_rockchip.c
+ * Copyright (c) 2021 Rockchip, Inc.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <pci.h>
+#include <power-domain.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/bitfield.h>
+
+#include "pcie_dw_common.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct meson_pcie - Amlogic Meson DW PCIe controller state
+ *
+ * @pci: The common PCIe DW structure
+ * @meson_cfg_base: The base address of vendor regs
+ * @phy
+ * @clk_port
+ * @clk_general
+ * @clk_pclk
+ * @rsts
+ * @rst_gpio: The #PERST signal for slot
+ */
+struct meson_pcie {
+ /* Must be first member of the struct */
+ struct pcie_dw dw;
+ void *meson_cfg_base;
+ struct phy phy;
+ struct clk clk_port;
+ struct clk clk_general;
+ struct clk clk_pclk;
+ struct reset_ctl_bulk rsts;
+ struct gpio_desc rst_gpio;
+};
+
+#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */
+
+#define PCIE_CAP_MAX_PAYLOAD_SIZE(x) ((x) << 5)
+#define PCIE_CAP_MAX_READ_REQ_SIZE(x) ((x) << 12)
+
+/* PCIe specific config registers */
+#define PCIE_CFG0 0x0
+#define APP_LTSSM_ENABLE BIT(7)
+
+#define PCIE_CFG_STATUS12 0x30
+#define IS_SMLH_LINK_UP(x) ((x) & (1 << 6))
+#define IS_RDLH_LINK_UP(x) ((x) & (1 << 16))
+#define IS_LTSSM_UP(x) ((((x) >> 10) & 0x1f) == 0x11)
+
+#define PCIE_CFG_STATUS17 0x44
+#define PM_CURRENT_STATE(x) (((x) >> 7) & 0x1)
+
+#define WAIT_LINKUP_TIMEOUT 4000
+#define PORT_CLK_RATE 100000000UL
+#define MAX_PAYLOAD_SIZE 256
+#define MAX_READ_REQ_SIZE 256
+#define PCIE_RESET_DELAY 500
+#define PCIE_SHARED_RESET 1
+#define PCIE_NORMAL_RESET 0
+
+enum pcie_data_rate {
+ PCIE_GEN1,
+ PCIE_GEN2,
+ PCIE_GEN3,
+ PCIE_GEN4
+};
+
+/* Parameters for the waiting for #perst signal */
+#define PERST_WAIT_US 1000000
+
+static inline u32 meson_cfg_readl(struct meson_pcie *priv, u32 reg)
+{
+ return readl(priv->meson_cfg_base + reg);
+}
+
+static inline void meson_cfg_writel(struct meson_pcie *priv, u32 val, u32 reg)
+{
+ writel(val, priv->meson_cfg_base + reg);
+}
+
+/**
+ * meson_pcie_configure() - Configure link
+ *
+ * @meson_pcie: Pointer to the PCI controller state
+ *
+ * Configure the link mode and width
+ */
+static void meson_pcie_configure(struct meson_pcie *priv)
+{
+ u32 val;
+
+ dw_pcie_dbi_write_enable(&priv->dw, true);
+
+ val = readl(priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
+ val &= ~PORT_LINK_FAST_LINK_MODE;
+ val |= PORT_LINK_DLL_LINK_EN;
+ val &= ~PORT_LINK_MODE_MASK;
+ val |= PORT_LINK_MODE_1_LANES;
+ writel(val, priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
+
+ val = readl(priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+ val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
+ val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
+ writel(val, priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+
+ dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static inline void meson_pcie_enable_ltssm(struct meson_pcie *priv)
+{
+ u32 val;
+
+ val = meson_cfg_readl(priv, PCIE_CFG0);
+ val |= APP_LTSSM_ENABLE;
+ meson_cfg_writel(priv, val, PCIE_CFG0);
+}
+
+static int meson_pcie_wait_link_up(struct meson_pcie *priv)
+{
+ u32 speed_okay = 0;
+ u32 cnt = 0;
+ u32 state12, state17, smlh_up, ltssm_up, rdlh_up;
+
+ do {
+ state12 = meson_cfg_readl(priv, PCIE_CFG_STATUS12);
+ state17 = meson_cfg_readl(priv, PCIE_CFG_STATUS17);
+ smlh_up = IS_SMLH_LINK_UP(state12);
+ rdlh_up = IS_RDLH_LINK_UP(state12);
+ ltssm_up = IS_LTSSM_UP(state12);
+
+ if (PM_CURRENT_STATE(state17) < PCIE_GEN3)
+ speed_okay = 1;
+
+ if (smlh_up)
+ debug("%s: smlh_link_up is on\n", __func__);
+ if (rdlh_up)
+ debug("%s: rdlh_link_up is on\n", __func__);
+ if (ltssm_up)
+ debug("%s: ltssm_up is on\n", __func__);
+ if (speed_okay)
+ debug("%s: speed_okay\n", __func__);
+
+ if (smlh_up && rdlh_up && ltssm_up && speed_okay)
+ return 0;
+
+ cnt++;
+
+ udelay(10);
+ } while (cnt < WAIT_LINKUP_TIMEOUT);
+
+ printf("%s: error: wait linkup timeout\n", __func__);
+ return -EIO;
+}
+
+/**
+ * meson_pcie_link_up() - Wait for the link to come up
+ *
+ * @meson_pcie: Pointer to the PCI controller state
+ * @cap_speed: Desired link speed
+ *
+ * Return: 1 (true) for active line and negative (false) for no link (timeout)
+ */
+static int meson_pcie_link_up(struct meson_pcie *priv, u32 cap_speed)
+{
+ /* DW link configurations */
+ meson_pcie_configure(priv);
+
+ /* Reset the device */
+ if (dm_gpio_is_valid(&priv->rst_gpio)) {
+ dm_gpio_set_value(&priv->rst_gpio, 1);
+ /*
+ * Minimal is 100ms from spec but we see
+ * some wired devices need much more, such as 600ms.
+ * Add a enough delay to cover all cases.
+ */
+ udelay(PERST_WAIT_US);
+ dm_gpio_set_value(&priv->rst_gpio, 0);
+ }
+
+ /* Enable LTSSM */
+ meson_pcie_enable_ltssm(priv);
+
+ return meson_pcie_wait_link_up(priv);
+}
+
+static int meson_size_to_payload(int size)
+{
+ /*
+ * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1.
+ * So if input size is not 2^order alignment or less than 2^7 or bigger
+ * than 2^12, just set to default size 2^(1+7).
+ */
+ if (!is_power_of_2(size) || size < 128 || size > 4096) {
+ debug("%s: payload size %d, set to default 256\n", __func__, size);
+ return 1;
+ }
+
+ return fls(size) - 8;
+}
+
+static void meson_set_max_payload(struct meson_pcie *priv, int size)
+{
+ u32 val;
+ u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
+ int max_payload_size = meson_size_to_payload(size);
+
+ dw_pcie_dbi_write_enable(&priv->dw, true);
+
+ val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+ val &= ~PCI_EXP_DEVCTL_PAYLOAD;
+ writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+
+ val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+ val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
+ writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
+
+ dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static void meson_set_max_rd_req_size(struct meson_pcie *priv, int size)
+{
+ u32 val;
+ u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP);
+ int max_rd_req_size = meson_size_to_payload(size);
+
+ dw_pcie_dbi_write_enable(&priv->dw, true);
+
+ val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+ val &= ~PCI_EXP_DEVCTL_PAYLOAD;
+ writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+
+ val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL);
+ val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
+ writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL);
+
+ dw_pcie_dbi_write_enable(&priv->dw, false);
+}
+
+static int meson_pcie_init_port(struct udevice *dev)
+{
+ int ret;
+ struct meson_pcie *priv = dev_get_priv(dev);
+
+ ret = generic_phy_init(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to init phy (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to power on phy (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ ret = generic_phy_reset(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to reset phy (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ ret = reset_assert_bulk(&priv->rsts);
+ if (ret) {
+ dev_err(dev, "failed to assert resets (ret=%d)\n", ret);
+ goto err_power_off_phy;
+ }
+
+ udelay(PCIE_RESET_DELAY);
+
+ ret = reset_deassert_bulk(&priv->rsts);
+ if (ret) {
+ dev_err(dev, "failed to deassert resets (ret=%d)\n", ret);
+ goto err_power_off_phy;
+ }
+
+ udelay(PCIE_RESET_DELAY);
+
+ ret = clk_set_rate(&priv->clk_port, PORT_CLK_RATE);
+ if (ret) {
+ dev_err(dev, "failed to set port clk rate (ret=%d)\n", ret);
+ goto err_deassert_bulk;
+ }
+
+ ret = clk_enable(&priv->clk_general);
+ if (ret) {
+ dev_err(dev, "failed to enable clk general (ret=%d)\n", ret);
+ goto err_deassert_bulk;
+ }
+
+ ret = clk_enable(&priv->clk_pclk);
+ if (ret) {
+ dev_err(dev, "failed to enable pclk (ret=%d)\n", ret);
+ goto err_deassert_bulk;
+ }
+
+ meson_set_max_payload(priv, MAX_PAYLOAD_SIZE);
+ meson_set_max_rd_req_size(priv, MAX_READ_REQ_SIZE);
+
+ pcie_dw_setup_host(&priv->dw);
+
+ ret = meson_pcie_link_up(priv, LINK_SPEED_GEN_2);
+ if (ret < 0)
+ goto err_link_up;
+
+ return 0;
+err_link_up:
+ clk_disable(&priv->clk_port);
+ clk_disable(&priv->clk_general);
+ clk_disable(&priv->clk_pclk);
+err_deassert_bulk:
+ reset_assert_bulk(&priv->rsts);
+err_power_off_phy:
+ generic_phy_power_off(&priv->phy);
+err_exit_phy:
+ generic_phy_exit(&priv->phy);
+
+ return ret;
+}
+
+static int meson_pcie_parse_dt(struct udevice *dev)
+{
+ struct meson_pcie *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0);
+ if (!priv->dw.dbi_base)
+ return -ENODEV;
+
+ dev_dbg(dev, "ELBI address is 0x%p\n", priv->dw.dbi_base);
+
+ priv->meson_cfg_base = (void *)dev_read_addr_index(dev, 1);
+ if (!priv->meson_cfg_base)
+ return -ENODEV;
+
+ dev_dbg(dev, "CFG address is 0x%p\n", priv->meson_cfg_base);
+
+ ret = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->rst_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ dev_err(dev, "failed to find reset-gpios property\n");
+ return ret;
+ }
+
+ ret = reset_get_bulk(dev, &priv->rsts);
+ if (ret) {
+ dev_err(dev, "Can't get reset: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "port", &priv->clk_port);
+ if (ret) {
+ dev_err(dev, "Can't get port clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "general", &priv->clk_general);
+ if (ret) {
+ dev_err(dev, "Can't get port clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "pclk", &priv->clk_pclk);
+ if (ret) {
+ dev_err(dev, "Can't get port clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_get_by_index(dev, 0, &priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * meson_pcie_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int meson_pcie_probe(struct udevice *dev)
+{
+ struct meson_pcie *priv = dev_get_priv(dev);
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ int ret = 0;
+
+ priv->dw.first_busno = dev_seq(dev);
+ priv->dw.dev = dev;
+
+ ret = meson_pcie_parse_dt(dev);
+ if (ret)
+ return ret;
+
+ ret = meson_pcie_init_port(dev);
+ if (ret) {
+ dm_gpio_free(dev, &priv->rst_gpio);
+ return ret;
+ }
+
+ printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
+ dev_seq(dev), pcie_dw_get_link_speed(&priv->dw),
+ pcie_dw_get_link_width(&priv->dw),
+ hose->first_busno);
+
+ return pcie_dw_prog_outbound_atu_unroll(&priv->dw,
+ PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM,
+ priv->dw.mem.phys_start,
+ priv->dw.mem.bus_start,
+ priv->dw.mem.size);
+}
+
+static const struct dm_pci_ops meson_pcie_ops = {
+ .read_config = pcie_dw_read_config,
+ .write_config = pcie_dw_write_config,
+};
+
+static const struct udevice_id meson_pcie_ids[] = {
+ { .compatible = "amlogic,axg-pcie" },
+ { .compatible = "amlogic,g12a-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(meson_dw_pcie) = {
+ .name = "pcie_dw_meson",
+ .id = UCLASS_PCI,
+ .of_match = meson_pcie_ids,
+ .ops = &meson_pcie_ops,
+ .probe = meson_pcie_probe,
+ .priv_auto = sizeof(struct meson_pcie),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_dw_mvebu.c b/roms/u-boot/drivers/pci/pcie_dw_mvebu.c
new file mode 100644
index 000000000..0490fd337
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_dw_mvebu.c
@@ -0,0 +1,598 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Marvell International Ltd.
+ *
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ *
+ * Based on:
+ * - drivers/pci/pcie_imx.c
+ * - drivers/pci/pci_mvebu.c
+ * - drivers/pci/pcie_xilinx.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <linux/delay.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* PCI Config space registers */
+#define PCIE_CONFIG_BAR0 0x10
+#define PCIE_LINK_STATUS_REG 0x80
+#define PCIE_LINK_STATUS_SPEED_OFF 16
+#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF)
+#define PCIE_LINK_STATUS_WIDTH_OFF 20
+#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
+
+/* Resizable bar capability registers */
+#define RESIZABLE_BAR_CAP 0x250
+#define RESIZABLE_BAR_CTL0 0x254
+#define RESIZABLE_BAR_CTL1 0x258
+
+/* iATU registers */
+#define PCIE_ATU_VIEWPORT 0x900
+#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
+#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
+#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
+#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
+#define PCIE_ATU_CR1 0x904
+#define PCIE_ATU_TYPE_MEM (0x0 << 0)
+#define PCIE_ATU_TYPE_IO (0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
+#define PCIE_ATU_CR2 0x908
+#define PCIE_ATU_ENABLE (0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
+#define PCIE_ATU_LOWER_BASE 0x90C
+#define PCIE_ATU_UPPER_BASE 0x910
+#define PCIE_ATU_LIMIT 0x914
+#define PCIE_ATU_LOWER_TARGET 0x918
+#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
+#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
+#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
+#define PCIE_ATU_UPPER_TARGET 0x91C
+
+#define PCIE_LINK_CAPABILITY 0x7C
+#define PCIE_LINK_CTL_2 0xA0
+#define TARGET_LINK_SPEED_MASK 0xF
+#define LINK_SPEED_GEN_1 0x1
+#define LINK_SPEED_GEN_2 0x2
+#define LINK_SPEED_GEN_3 0x3
+
+#define PCIE_GEN3_RELATED 0x890
+#define GEN3_EQU_DISABLE (1 << 16)
+#define GEN3_ZRXDC_NON_COMP (1 << 0)
+
+#define PCIE_GEN3_EQU_CTRL 0x8A8
+#define GEN3_EQU_EVAL_2MS_DISABLE (1 << 5)
+
+#define PCIE_ROOT_COMPLEX_MODE_MASK (0xF << 4)
+
+#define PCIE_LINK_UP_TIMEOUT_MS 100
+
+#define PCIE_GLOBAL_CONTROL 0x8000
+#define PCIE_APP_LTSSM_EN (1 << 2)
+#define PCIE_DEVICE_TYPE_OFFSET (4)
+#define PCIE_DEVICE_TYPE_MASK (0xF)
+#define PCIE_DEVICE_TYPE_EP (0x0) /* Endpoint */
+#define PCIE_DEVICE_TYPE_LEP (0x1) /* Legacy endpoint */
+#define PCIE_DEVICE_TYPE_RC (0x4) /* Root complex */
+
+#define PCIE_GLOBAL_STATUS 0x8008
+#define PCIE_GLB_STS_RDLH_LINK_UP (1 << 1)
+#define PCIE_GLB_STS_PHY_LINK_UP (1 << 9)
+
+#define PCIE_ARCACHE_TRC 0x8050
+#define PCIE_AWCACHE_TRC 0x8054
+#define ARCACHE_SHAREABLE_CACHEABLE 0x3511
+#define AWCACHE_SHAREABLE_CACHEABLE 0x5311
+
+#define LINK_SPEED_GEN_1 0x1
+#define LINK_SPEED_GEN_2 0x2
+#define LINK_SPEED_GEN_3 0x3
+
+/**
+ * struct pcie_dw_mvebu - MVEBU DW PCIe controller state
+ *
+ * @ctrl_base: The base address of the register space
+ * @cfg_base: The base address of the configuration space
+ * @cfg_size: The size of the configuration space which is needed
+ * as it gets written into the PCIE_ATU_LIMIT register
+ * @first_busno: This driver supports multiple PCIe controllers.
+ * first_busno stores the bus number of the PCIe root-port
+ * number which may vary depending on the PCIe setup
+ * (PEX switches etc).
+ */
+struct pcie_dw_mvebu {
+ void *ctrl_base;
+ void *cfg_base;
+ fdt_size_t cfg_size;
+ int first_busno;
+
+ /* IO and MEM PCI regions */
+ int region_count;
+ struct pci_region io;
+ struct pci_region mem;
+};
+
+static int pcie_dw_get_link_speed(const void *regs_base)
+{
+ return (readl(regs_base + PCIE_LINK_STATUS_REG) &
+ PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
+}
+
+static int pcie_dw_get_link_width(const void *regs_base)
+{
+ return (readl(regs_base + PCIE_LINK_STATUS_REG) &
+ PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
+}
+
+/**
+ * pcie_dw_prog_outbound_atu() - Configure ATU for outbound accesses
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @index: ATU region index
+ * @type: ATU accsess type
+ * @cpu_addr: the physical address for the translation entry
+ * @pci_addr: the pcie bus address for the translation entry
+ * @size: the size of the translation entry
+ */
+static void pcie_dw_prog_outbound_atu(struct pcie_dw_mvebu *pcie, int index,
+ int type, u64 cpu_addr, u64 pci_addr,
+ u32 size)
+{
+ writel(PCIE_ATU_REGION_OUTBOUND | index,
+ pcie->ctrl_base + PCIE_ATU_VIEWPORT);
+ writel(lower_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_LOWER_BASE);
+ writel(upper_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_UPPER_BASE);
+ writel(lower_32_bits(cpu_addr + size - 1),
+ pcie->ctrl_base + PCIE_ATU_LIMIT);
+ writel(lower_32_bits(pci_addr),
+ pcie->ctrl_base + PCIE_ATU_LOWER_TARGET);
+ writel(upper_32_bits(pci_addr),
+ pcie->ctrl_base + PCIE_ATU_UPPER_TARGET);
+ writel(type, pcie->ctrl_base + PCIE_ATU_CR1);
+ writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2);
+}
+
+/**
+ * set_cfg_address() - Configure the PCIe controller config space access
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @d: PCI device to access
+ * @where: Offset in the configuration space
+ *
+ * Configures the PCIe controller to access the configuration space of
+ * a specific PCIe device and returns the address to use for this
+ * access.
+ *
+ * Return: Address that can be used to access the configation space
+ * of the requested device / offset
+ */
+static uintptr_t set_cfg_address(struct pcie_dw_mvebu *pcie,
+ pci_dev_t d, uint where)
+{
+ uintptr_t va_address;
+ u32 atu_type;
+
+ /*
+ * Region #0 is used for Outbound CFG space access.
+ * Direction = Outbound
+ * Region Index = 0
+ */
+
+ if (PCI_BUS(d) == (pcie->first_busno + 1))
+ /* For local bus, change TLP Type field to 4. */
+ atu_type = PCIE_ATU_TYPE_CFG0;
+ else
+ /* Otherwise, change TLP Type field to 5. */
+ atu_type = PCIE_ATU_TYPE_CFG1;
+
+ if (PCI_BUS(d) == pcie->first_busno) {
+ /* Accessing root port configuration space. */
+ va_address = (uintptr_t)pcie->ctrl_base;
+ } else {
+ d = PCI_MASK_BUS(d) | (PCI_BUS(d) - pcie->first_busno);
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+ atu_type, (u64)pcie->cfg_base,
+ d << 8, pcie->cfg_size);
+ va_address = (uintptr_t)pcie->cfg_base;
+ }
+
+ va_address += where & ~0x3;
+
+ return va_address;
+}
+
+/**
+ * pcie_dw_addr_valid() - Check for valid bus address
+ *
+ * @d: The PCI device to access
+ * @first_busno: Bus number of the PCIe controller root complex
+ *
+ * Return 1 (true) if the PCI device can be accessed by this controller.
+ *
+ * Return: 1 on valid, 0 on invalid
+ */
+static int pcie_dw_addr_valid(pci_dev_t d, int first_busno)
+{
+ if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
+ return 0;
+ if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * pcie_dw_mvebu_read_config() - Read from configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+static int pcie_dw_mvebu_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct pcie_dw_mvebu *pcie = dev_get_priv(bus);
+ uintptr_t va_address;
+ ulong value;
+
+ debug("PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
+ debug("- out of range\n");
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ va_address = set_cfg_address(pcie, bdf, offset);
+
+ value = readl(va_address);
+
+ debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+ *valuep = pci_conv_32_to_size(value, offset, size);
+
+ if (pcie->region_count > 1)
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+ pcie->io.bus_start, pcie->io.size);
+
+ return 0;
+}
+
+/**
+ * pcie_dw_mvebu_write_config() - Write to configuration space
+ *
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ *
+ * Return: 0 on success
+ */
+static int pcie_dw_mvebu_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct pcie_dw_mvebu *pcie = dev_get_priv(bus);
+ uintptr_t va_address;
+ ulong old;
+
+ debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+
+ if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) {
+ debug("- out of range\n");
+ return 0;
+ }
+
+ va_address = set_cfg_address(pcie, bdf, offset);
+
+ old = readl(va_address);
+ value = pci_conv_size_to_32(old, value, offset, size);
+ writel(value, va_address);
+
+ if (pcie->region_count > 1)
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+ pcie->io.bus_start, pcie->io.size);
+
+ return 0;
+}
+
+/**
+ * pcie_dw_configure() - Configure link capabilities and speed
+ *
+ * @regs_base: A pointer to the PCIe controller registers
+ * @cap_speed: The capabilities and speed to configure
+ *
+ * Configure the link capabilities and speed in the PCIe root complex.
+ */
+static void pcie_dw_configure(const void *regs_base, u32 cap_speed)
+{
+ /*
+ * TODO (shadi@marvell.com, sr@denx.de):
+ * Need to read the serdes speed from the dts and according to it
+ * configure the PCIe gen
+ */
+
+ /* Set link to GEN 3 */
+ clrsetbits_le32(regs_base + PCIE_LINK_CTL_2,
+ TARGET_LINK_SPEED_MASK, cap_speed);
+ clrsetbits_le32(regs_base + PCIE_LINK_CAPABILITY,
+ TARGET_LINK_SPEED_MASK, cap_speed);
+ setbits_le32(regs_base + PCIE_GEN3_EQU_CTRL, GEN3_EQU_EVAL_2MS_DISABLE);
+}
+
+/**
+ * is_link_up() - Return the link state
+ *
+ * @regs_base: A pointer to the PCIe controller registers
+ *
+ * Return: 1 (true) for active line and 0 (false) for no link
+ */
+static int is_link_up(const void *regs_base)
+{
+ u32 mask = PCIE_GLB_STS_RDLH_LINK_UP | PCIE_GLB_STS_PHY_LINK_UP;
+ u32 reg;
+
+ reg = readl(regs_base + PCIE_GLOBAL_STATUS);
+ if ((reg & mask) == mask)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * wait_link_up() - Wait for the link to come up
+ *
+ * @regs_base: A pointer to the PCIe controller registers
+ *
+ * Return: 1 (true) for active line and 0 (false) for no link (timeout)
+ */
+static int wait_link_up(const void *regs_base)
+{
+ unsigned long timeout;
+
+ timeout = get_timer(0) + PCIE_LINK_UP_TIMEOUT_MS;
+ while (!is_link_up(regs_base)) {
+ if (get_timer(0) > timeout)
+ return 0;
+ };
+
+ return 1;
+}
+
+/**
+ * pcie_dw_mvebu_pcie_link_up() - Configure the PCIe root port
+ *
+ * @regs_base: A pointer to the PCIe controller registers
+ * @cap_speed: The capabilities and speed to configure
+ *
+ * Configure the PCIe controller root complex depending on the
+ * requested link capabilities and speed.
+ *
+ * Return: 1 (true) for active line and 0 (false) for no link
+ */
+static int pcie_dw_mvebu_pcie_link_up(const void *regs_base, u32 cap_speed)
+{
+ if (!is_link_up(regs_base)) {
+ /* Disable LTSSM state machine to enable configuration */
+ clrbits_le32(regs_base + PCIE_GLOBAL_CONTROL,
+ PCIE_APP_LTSSM_EN);
+ }
+
+ clrsetbits_le32(regs_base + PCIE_GLOBAL_CONTROL,
+ PCIE_DEVICE_TYPE_MASK << PCIE_DEVICE_TYPE_OFFSET,
+ PCIE_DEVICE_TYPE_RC << PCIE_DEVICE_TYPE_OFFSET);
+
+ /* Set the PCIe master AXI attributes */
+ writel(ARCACHE_SHAREABLE_CACHEABLE, regs_base + PCIE_ARCACHE_TRC);
+ writel(AWCACHE_SHAREABLE_CACHEABLE, regs_base + PCIE_AWCACHE_TRC);
+
+ /* DW pre link configurations */
+ pcie_dw_configure(regs_base, cap_speed);
+
+ if (!is_link_up(regs_base)) {
+ /* Configuration done. Start LTSSM */
+ setbits_le32(regs_base + PCIE_GLOBAL_CONTROL,
+ PCIE_APP_LTSSM_EN);
+ }
+
+ /* Check that link was established */
+ if (!wait_link_up(regs_base))
+ return 0;
+
+ /*
+ * Link can be established in Gen 1. still need to wait
+ * till MAC nagaotiation is completed
+ */
+ udelay(100);
+
+ return 1;
+}
+
+/**
+ * pcie_dw_set_host_bars() - Configure the host BARs
+ *
+ * @regs_base: A pointer to the PCIe controller registers
+ *
+ * Configure the host BARs of the PCIe controller root port so that
+ * PCI(e) devices may access the system memory.
+ */
+static void pcie_dw_set_host_bars(const void *regs_base)
+{
+ u32 size = gd->ram_size;
+ u64 max_size;
+ u32 reg;
+ u32 bar0;
+
+ /* Verify the maximal BAR size */
+ reg = readl(regs_base + RESIZABLE_BAR_CAP);
+ max_size = 1ULL << (5 + (reg + (1 << 4)));
+
+ if (size > max_size) {
+ size = max_size;
+ printf("Warning: PCIe BARs can't map all DRAM space\n");
+ }
+
+ /* Set the BAR base and size towards DDR */
+ bar0 = CONFIG_SYS_SDRAM_BASE & ~0xf;
+ bar0 |= PCI_BASE_ADDRESS_MEM_TYPE_32;
+ writel(CONFIG_SYS_SDRAM_BASE, regs_base + PCIE_CONFIG_BAR0);
+
+ reg = ((size >> 20) - 1) << 12;
+ writel(size, regs_base + RESIZABLE_BAR_CTL0);
+}
+
+/**
+ * pcie_dw_mvebu_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int pcie_dw_mvebu_probe(struct udevice *dev)
+{
+ struct pcie_dw_mvebu *pcie = dev_get_priv(dev);
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+#if CONFIG_IS_ENABLED(DM_GPIO)
+ struct gpio_desc reset_gpio;
+
+ gpio_request_by_name(dev, "marvell,reset-gpio", 0, &reset_gpio,
+ GPIOD_IS_OUT);
+ /*
+ * Issue reset to add-in card trough the dedicated GPIO.
+ * Some boards are connecting the card reset pin to common system
+ * reset wire and others are using separate GPIO port.
+ * In the last case we have to release a reset of the addon card
+ * using this GPIO.
+ */
+ if (dm_gpio_is_valid(&reset_gpio)) {
+ dm_gpio_set_value(&reset_gpio, 1); /* assert */
+ mdelay(200);
+ dm_gpio_set_value(&reset_gpio, 0); /* de-assert */
+ mdelay(200);
+ }
+#else
+ debug("PCIE Reset on GPIO support is missing\n");
+#endif /* DM_GPIO */
+
+ pcie->first_busno = dev_seq(dev);
+
+ /* Don't register host if link is down */
+ if (!pcie_dw_mvebu_pcie_link_up(pcie->ctrl_base, LINK_SPEED_GEN_3)) {
+ printf("PCIE-%d: Link down\n", dev_seq(dev));
+ } else {
+ printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev),
+ pcie_dw_get_link_speed(pcie->ctrl_base),
+ pcie_dw_get_link_width(pcie->ctrl_base),
+ hose->first_busno);
+ }
+
+ pcie->region_count = hose->region_count - CONFIG_NR_DRAM_BANKS;
+
+ /* Store the IO and MEM windows settings for future use by the ATU */
+ if (pcie->region_count > 1) {
+ /* IO base */
+ pcie->io.phys_start = hose->regions[0].phys_start;
+ /* IO_bus_addr */
+ pcie->io.bus_start = hose->regions[0].bus_start;
+ /* IO size */
+ pcie->io.size = hose->regions[0].size;
+ }
+
+ /* MEM base */
+ pcie->mem.phys_start = hose->regions[pcie->region_count - 1].phys_start;
+ /* MEM_bus_addr */
+ pcie->mem.bus_start = hose->regions[pcie->region_count - 1].bus_start;
+ /* MEM size */
+ pcie->mem.size = hose->regions[pcie->region_count - 1].size;
+
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_MEM, pcie->mem.phys_start,
+ pcie->mem.bus_start, pcie->mem.size);
+
+ /* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */
+ clrsetbits_le32(pcie->ctrl_base + PCI_CLASS_REVISION,
+ 0xffff << 16, PCI_CLASS_BRIDGE_PCI << 16);
+
+ pcie_dw_set_host_bars(pcie->ctrl_base);
+
+ return 0;
+}
+
+/**
+ * pcie_dw_mvebu_of_to_plat() - Translate from DT to device state
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Translate relevant data from the device tree pertaining to device @dev into
+ * state that the driver will later make use of. This state is stored in the
+ * device's private data structure.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+static int pcie_dw_mvebu_of_to_plat(struct udevice *dev)
+{
+ struct pcie_dw_mvebu *pcie = dev_get_priv(dev);
+
+ /* Get the controller base address */
+ pcie->ctrl_base = (void *)devfdt_get_addr_index(dev, 0);
+ if ((fdt_addr_t)pcie->ctrl_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /* Get the config space base address and size */
+ pcie->cfg_base = (void *)devfdt_get_addr_size_index(dev, 1,
+ &pcie->cfg_size);
+ if ((fdt_addr_t)pcie->cfg_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct dm_pci_ops pcie_dw_mvebu_ops = {
+ .read_config = pcie_dw_mvebu_read_config,
+ .write_config = pcie_dw_mvebu_write_config,
+};
+
+static const struct udevice_id pcie_dw_mvebu_ids[] = {
+ { .compatible = "marvell,armada8k-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_dw_mvebu) = {
+ .name = "pcie_dw_mvebu",
+ .id = UCLASS_PCI,
+ .of_match = pcie_dw_mvebu_ids,
+ .ops = &pcie_dw_mvebu_ops,
+ .of_to_plat = pcie_dw_mvebu_of_to_plat,
+ .probe = pcie_dw_mvebu_probe,
+ .priv_auto = sizeof(struct pcie_dw_mvebu),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_dw_rockchip.c b/roms/u-boot/drivers/pci/pcie_dw_rockchip.c
new file mode 100644
index 000000000..bc22af423
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_dw_rockchip.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Rockchip DesignWare based PCIe host controller driver
+ *
+ * Copyright (c) 2021 Rockchip, Inc.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <pci.h>
+#include <power-domain.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+
+#include "pcie_dw_common.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct rk_pcie - RK DW PCIe controller state
+ *
+ * @vpcie3v3: The 3.3v power supply for slot
+ * @apb_base: The base address of vendor regs
+ * @rst_gpio: The #PERST signal for slot
+ */
+struct rk_pcie {
+ /* Must be first member of the struct */
+ struct pcie_dw dw;
+ struct udevice *vpcie3v3;
+ void *apb_base;
+ struct phy phy;
+ struct clk_bulk clks;
+ struct reset_ctl_bulk rsts;
+ struct gpio_desc rst_gpio;
+};
+
+/* Parameters for the waiting for iATU enabled routine */
+#define PCIE_CLIENT_GENERAL_DEBUG 0x104
+#define PCIE_CLIENT_HOT_RESET_CTRL 0x180
+#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4)
+#define PCIE_CLIENT_LTSSM_STATUS 0x300
+#define SMLH_LINKUP BIT(16)
+#define RDLH_LINKUP BIT(17)
+#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310
+#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320
+#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324
+#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328
+#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c
+#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350
+#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
+#define PCIE_CLIENT_DBF_EN 0xffff0003
+
+/* Parameters for the waiting for #perst signal */
+#define PERST_WAIT_MS 1000
+
+static int rk_pcie_read(void __iomem *addr, int size, u32 *val)
+{
+ if ((uintptr_t)addr & (size - 1)) {
+ *val = 0;
+ return PCIBIOS_UNSUPPORTED;
+ }
+
+ if (size == 4) {
+ *val = readl(addr);
+ } else if (size == 2) {
+ *val = readw(addr);
+ } else if (size == 1) {
+ *val = readb(addr);
+ } else {
+ *val = 0;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int rk_pcie_write(void __iomem *addr, int size, u32 val)
+{
+ if ((uintptr_t)addr & (size - 1))
+ return PCIBIOS_UNSUPPORTED;
+
+ if (size == 4)
+ writel(val, addr);
+ else if (size == 2)
+ writew(val, addr);
+ else if (size == 1)
+ writeb(val, addr);
+ else
+ return -ENODEV;
+
+ return 0;
+}
+
+static u32 __rk_pcie_read_apb(struct rk_pcie *rk_pcie, void __iomem *base,
+ u32 reg, size_t size)
+{
+ int ret;
+ u32 val;
+
+ ret = rk_pcie_read(base + reg, size, &val);
+ if (ret)
+ dev_err(rk_pcie->dw.dev, "Read APB address failed\n");
+
+ return val;
+}
+
+static void __rk_pcie_write_apb(struct rk_pcie *rk_pcie, void __iomem *base,
+ u32 reg, size_t size, u32 val)
+{
+ int ret;
+
+ ret = rk_pcie_write(base + reg, size, val);
+ if (ret)
+ dev_err(rk_pcie->dw.dev, "Write APB address failed\n");
+}
+
+/**
+ * rk_pcie_readl_apb() - Read vendor regs
+ *
+ * @rk_pcie: Pointer to the PCI controller state
+ * @reg: Offset of regs
+ */
+static inline u32 rk_pcie_readl_apb(struct rk_pcie *rk_pcie, u32 reg)
+{
+ return __rk_pcie_read_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4);
+}
+
+/**
+ * rk_pcie_writel_apb() - Write vendor regs
+ *
+ * @rk_pcie: Pointer to the PCI controller state
+ * @reg: Offset of regs
+ * @val: Value to be writen
+ */
+static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg,
+ u32 val)
+{
+ __rk_pcie_write_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4, val);
+}
+
+/**
+ * rk_pcie_configure() - Configure link capabilities and speed
+ *
+ * @rk_pcie: Pointer to the PCI controller state
+ * @cap_speed: The capabilities and speed to configure
+ *
+ * Configure the link capabilities and speed in the PCIe root complex.
+ */
+static void rk_pcie_configure(struct rk_pcie *pci, u32 cap_speed)
+{
+ u32 val;
+
+ dw_pcie_dbi_write_enable(&pci->dw, true);
+
+ clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CAPABILITY,
+ TARGET_LINK_SPEED_MASK, cap_speed);
+
+ clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CTL_2,
+ TARGET_LINK_SPEED_MASK, cap_speed);
+
+ dw_pcie_dbi_write_enable(&pci->dw, false);
+}
+
+static void rk_pcie_enable_debug(struct rk_pcie *rk_pcie)
+{
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0,
+ PCIE_CLIENT_DBG_TRANSITION_DATA);
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1,
+ PCIE_CLIENT_DBG_TRANSITION_DATA);
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0,
+ PCIE_CLIENT_DBG_TRANSITION_DATA);
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1,
+ PCIE_CLIENT_DBG_TRANSITION_DATA);
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_MODE_CON,
+ PCIE_CLIENT_DBF_EN);
+}
+
+static void rk_pcie_debug_dump(struct rk_pcie *rk_pcie)
+{
+ u32 loop;
+
+ debug("ltssm = 0x%x\n",
+ rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS));
+ for (loop = 0; loop < 64; loop++)
+ debug("fifo_status = 0x%x\n",
+ rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_STATUS));
+}
+
+static inline void rk_pcie_link_status_clear(struct rk_pcie *rk_pcie)
+{
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_GENERAL_DEBUG, 0x0);
+}
+
+static inline void rk_pcie_disable_ltssm(struct rk_pcie *rk_pcie)
+{
+ rk_pcie_writel_apb(rk_pcie, 0x0, 0xc0008);
+}
+
+static inline void rk_pcie_enable_ltssm(struct rk_pcie *rk_pcie)
+{
+ rk_pcie_writel_apb(rk_pcie, 0x0, 0xc000c);
+}
+
+static int is_link_up(struct rk_pcie *priv)
+{
+ u32 val;
+
+ val = rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS);
+ if ((val & (RDLH_LINKUP | SMLH_LINKUP)) == 0x30000 &&
+ (val & GENMASK(5, 0)) == 0x11)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * rk_pcie_link_up() - Wait for the link to come up
+ *
+ * @rk_pcie: Pointer to the PCI controller state
+ * @cap_speed: Desired link speed
+ *
+ * Return: 1 (true) for active line and negetive (false) for no link (timeout)
+ */
+static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed)
+{
+ int retries;
+
+ if (is_link_up(priv)) {
+ printf("PCI Link already up before configuration!\n");
+ return 1;
+ }
+
+ /* DW pre link configurations */
+ rk_pcie_configure(priv, cap_speed);
+
+ /* Rest the device */
+ if (dm_gpio_is_valid(&priv->rst_gpio)) {
+ dm_gpio_set_value(&priv->rst_gpio, 0);
+ /*
+ * Minimal is 100ms from spec but we see
+ * some wired devices need much more, such as 600ms.
+ * Add a enough delay to cover all cases.
+ */
+ msleep(PERST_WAIT_MS);
+ dm_gpio_set_value(&priv->rst_gpio, 1);
+ }
+
+ rk_pcie_disable_ltssm(priv);
+ rk_pcie_link_status_clear(priv);
+ rk_pcie_enable_debug(priv);
+
+ /* Enable LTSSM */
+ rk_pcie_enable_ltssm(priv);
+
+ for (retries = 0; retries < 5; retries++) {
+ if (is_link_up(priv)) {
+ dev_info(priv->dw.dev, "PCIe Link up, LTSSM is 0x%x\n",
+ rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
+ rk_pcie_debug_dump(priv);
+ return 0;
+ }
+
+ dev_info(priv->dw.dev, "PCIe Linking... LTSSM is 0x%x\n",
+ rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
+ rk_pcie_debug_dump(priv);
+ msleep(1000);
+ }
+
+ dev_err(priv->dw.dev, "PCIe-%d Link Fail\n", dev_seq(priv->dw.dev));
+ /* Link maybe in Gen switch recovery but we need to wait more 1s */
+ msleep(1000);
+ return -EIO;
+}
+
+static int rockchip_pcie_init_port(struct udevice *dev)
+{
+ int ret;
+ u32 val;
+ struct rk_pcie *priv = dev_get_priv(dev);
+
+ /* Set power and maybe external ref clk input */
+ if (priv->vpcie3v3) {
+ ret = regulator_set_value(priv->vpcie3v3, 3300000);
+ if (ret) {
+ dev_err(priv->dw.dev, "failed to enable vpcie3v3 (ret=%d)\n",
+ ret);
+ return ret;
+ }
+ }
+
+ msleep(1000);
+
+ ret = generic_phy_init(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to init phy (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to power on phy (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ ret = reset_deassert_bulk(&priv->rsts);
+ if (ret) {
+ dev_err(dev, "failed to deassert resets (ret=%d)\n", ret);
+ goto err_power_off_phy;
+ }
+
+ ret = clk_enable_bulk(&priv->clks);
+ if (ret) {
+ dev_err(dev, "failed to enable clks (ret=%d)\n", ret);
+ goto err_deassert_bulk;
+ }
+
+ /* LTSSM EN ctrl mode */
+ val = rk_pcie_readl_apb(priv, PCIE_CLIENT_HOT_RESET_CTRL);
+ val |= PCIE_LTSSM_ENABLE_ENHANCE | (PCIE_LTSSM_ENABLE_ENHANCE << 16);
+ rk_pcie_writel_apb(priv, PCIE_CLIENT_HOT_RESET_CTRL, val);
+
+ /* Set RC mode */
+ rk_pcie_writel_apb(priv, 0x0, 0xf00040);
+ pcie_dw_setup_host(&priv->dw);
+
+ ret = rk_pcie_link_up(priv, LINK_SPEED_GEN_3);
+ if (ret < 0)
+ goto err_link_up;
+
+ return 0;
+err_link_up:
+ clk_disable_bulk(&priv->clks);
+err_deassert_bulk:
+ reset_assert_bulk(&priv->rsts);
+err_power_off_phy:
+ generic_phy_power_off(&priv->phy);
+err_exit_phy:
+ generic_phy_exit(&priv->phy);
+
+ return ret;
+}
+
+static int rockchip_pcie_parse_dt(struct udevice *dev)
+{
+ struct rk_pcie *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0);
+ if (!priv->dw.dbi_base)
+ return -ENODEV;
+
+ dev_dbg(dev, "DBI address is 0x%p\n", priv->dw.dbi_base);
+
+ priv->apb_base = (void *)dev_read_addr_index(dev, 1);
+ if (!priv->apb_base)
+ return -ENODEV;
+
+ dev_dbg(dev, "APB address is 0x%p\n", priv->apb_base);
+
+ ret = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->rst_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ dev_err(dev, "failed to find reset-gpios property\n");
+ return ret;
+ }
+
+ ret = reset_get_bulk(dev, &priv->rsts);
+ if (ret) {
+ dev_err(dev, "Can't get reset: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_bulk(dev, &priv->clks);
+ if (ret) {
+ dev_err(dev, "Can't get clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vpcie3v3-supply",
+ &priv->vpcie3v3);
+ if (ret && ret != -ENOENT) {
+ dev_err(dev, "failed to get vpcie3v3 supply (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_get_by_index(dev, 0, &priv->phy);
+ if (ret) {
+ dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * rockchip_pcie_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int rockchip_pcie_probe(struct udevice *dev)
+{
+ struct rk_pcie *priv = dev_get_priv(dev);
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ int ret = 0;
+
+ priv->dw.first_busno = dev_seq(dev);
+ priv->dw.dev = dev;
+
+ ret = rockchip_pcie_parse_dt(dev);
+ if (ret)
+ return ret;
+
+ ret = rockchip_pcie_init_port(dev);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
+ dev_seq(dev), pcie_dw_get_link_speed(&priv->dw),
+ pcie_dw_get_link_width(&priv->dw),
+ hose->first_busno);
+
+
+ return pcie_dw_prog_outbound_atu_unroll(&priv->dw,
+ PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM,
+ priv->dw.mem.phys_start,
+ priv->dw.mem.bus_start,
+ priv->dw.mem.size);
+}
+
+static const struct dm_pci_ops rockchip_pcie_ops = {
+ .read_config = pcie_dw_read_config,
+ .write_config = pcie_dw_write_config,
+};
+
+static const struct udevice_id rockchip_pcie_ids[] = {
+ { .compatible = "rockchip,rk3568-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_dw_pcie) = {
+ .name = "pcie_dw_rockchip",
+ .id = UCLASS_PCI,
+ .of_match = rockchip_pcie_ids,
+ .ops = &rockchip_pcie_ops,
+ .probe = rockchip_pcie_probe,
+ .priv_auto = sizeof(struct rk_pcie),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_dw_sifive.c b/roms/u-boot/drivers/pci/pcie_dw_sifive.c
new file mode 100644
index 000000000..fac3f1823
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_dw_sifive.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SiFive FU740 DesignWare PCIe Controller
+ *
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ *
+ * Based in early part on the i.MX6 PCIe host controller shim which is:
+ *
+ * Copyright (C) 2013 Kosagi
+ * http://www.kosagi.com
+ *
+ * Based on driver from author: Alan Mikhak <amikhak@wirelessfabric.com>
+ */
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <generic-phy.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+#include <pci.h>
+#include <pci_ep.h>
+#include <pci_ids.h>
+#include <regmap.h>
+#include <reset.h>
+#include <syscon.h>
+
+#include "pcie_dw_common.h"
+
+struct pcie_sifive {
+ /* Must be first member of the struct */
+ struct pcie_dw dw;
+
+ /* private control regs */
+ void __iomem *priv_base;
+
+ /* reset, power, clock resources */
+ int sys_int_pin;
+ struct gpio_desc pwren_gpio;
+ struct gpio_desc reset_gpio;
+ struct clk aux_ck;
+ struct reset_ctl reset;
+};
+
+enum pcie_sifive_devtype {
+ SV_PCIE_UNKNOWN_TYPE = 0,
+ SV_PCIE_ENDPOINT_TYPE = 1,
+ SV_PCIE_HOST_TYPE = 3
+};
+
+#define ASSERTION_DELAY 100
+#define PCIE_PERST_ASSERT 0x0
+#define PCIE_PERST_DEASSERT 0x1
+#define PCIE_PHY_RESET 0x1
+#define PCIE_PHY_RESET_DEASSERT 0x0
+#define GPIO_LOW 0x0
+#define GPIO_HIGH 0x1
+#define PCIE_PHY_SEL 0x1
+
+#define sv_info(sv, fmt, arg...) printf(fmt, ## arg)
+#define sv_warn(sv, fmt, arg...) printf(fmt, ## arg)
+#define sv_debug(sv, fmt, arg...) debug(fmt, ## arg)
+#define sv_err(sv, fmt, arg...) printf(fmt, ## arg)
+
+/* Doorbell Interface */
+#define DBI_OFFSET 0x0
+#define DBI_SIZE 0x1000
+
+#define PL_OFFSET 0x700
+
+#define PHY_DEBUG_R0 (PL_OFFSET + 0x28)
+
+#define PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
+#define PHY_DEBUG_R1_LINK_UP (0x1 << 4)
+#define PHY_DEBUG_R1_LINK_IN_TRAINING (0x1 << 29)
+
+#define PCIE_MISC_CONTROL_1 0x8bc
+#define DBI_RO_WR_EN BIT(0)
+
+/* pcie reset */
+#define PCIEX8MGMT_PERST_N 0x0
+
+/* LTSSM */
+#define PCIEX8MGMT_APP_LTSSM_ENABLE 0x10
+#define LTSSM_ENABLE_BIT BIT(0)
+
+/* phy reset */
+#define PCIEX8MGMT_APP_HOLD_PHY_RST 0x18
+
+/* device type */
+#define PCIEX8MGMT_DEVICE_TYPE 0x708
+#define DEVICE_TYPE_EP 0x0
+#define DEVICE_TYPE_RC 0x4
+
+/* phy control registers*/
+#define PCIEX8MGMT_PHY0_CR_PARA_ADDR 0x860
+#define PCIEX8MGMT_PHY0_CR_PARA_RD_EN 0x870
+#define PCIEX8MGMT_PHY0_CR_PARA_RD_DATA 0x878
+#define PCIEX8MGMT_PHY0_CR_PARA_SEL 0x880
+#define PCIEX8MGMT_PHY0_CR_PARA_WR_DATA 0x888
+#define PCIEX8MGMT_PHY0_CR_PARA_WR_EN 0x890
+#define PCIEX8MGMT_PHY0_CR_PARA_ACK 0x898
+#define PCIEX8MGMT_PHY1_CR_PARA_ADDR 0x8a0
+#define PCIEX8MGMT_PHY1_CR_PARA_RD_EN 0x8b0
+#define PCIEX8MGMT_PHY1_CR_PARA_RD_DATA 0x8b8
+#define PCIEX8MGMT_PHY1_CR_PARA_SEL 0x8c0
+#define PCIEX8MGMT_PHY1_CR_PARA_WR_DATA 0x8c8
+#define PCIEX8MGMT_PHY1_CR_PARA_WR_EN 0x8d0
+#define PCIEX8MGMT_PHY1_CR_PARA_ACK 0x8d8
+
+#define PCIEX8MGMT_LANE_NUM 8
+#define PCIEX8MGMT_LANE 0x1008
+#define PCIEX8MGMT_LANE_OFF 0x100
+#define PCIEX8MGMT_TERM_MODE 0x0e21
+
+#define PCIE_CAP_BASE 0x70
+#define PCI_CONFIG(r) (DBI_OFFSET + (r))
+#define PCIE_CAPABILITIES(r) PCI_CONFIG(PCIE_CAP_BASE + (r))
+
+/* Link capability */
+#define PF0_PCIE_CAP_LINK_CAP PCIE_CAPABILITIES(0xc)
+#define PCIE_LINK_CAP_MAX_SPEED_MASK 0xf
+#define PCIE_LINK_CAP_MAX_SPEED_GEN1 BIT(0)
+#define PCIE_LINK_CAP_MAX_SPEED_GEN2 BIT(1)
+#define PCIE_LINK_CAP_MAX_SPEED_GEN3 BIT(2)
+#define PCIE_LINK_CAP_MAX_SPEED_GEN4 BIT(3)
+
+static enum pcie_sifive_devtype pcie_sifive_get_devtype(struct pcie_sifive *sv)
+{
+ u32 val;
+
+ val = readl(sv->priv_base + PCIEX8MGMT_DEVICE_TYPE);
+ switch (val) {
+ case DEVICE_TYPE_RC:
+ return SV_PCIE_HOST_TYPE;
+ case DEVICE_TYPE_EP:
+ return SV_PCIE_ENDPOINT_TYPE;
+ default:
+ return SV_PCIE_UNKNOWN_TYPE;
+ }
+}
+
+static void pcie_sifive_priv_set_state(struct pcie_sifive *sv, u32 reg,
+ u32 bits, int state)
+{
+ u32 val;
+
+ val = readl(sv->priv_base + reg);
+ val = state ? (val | bits) : (val & !bits);
+ writel(val, sv->priv_base + reg);
+}
+
+static void pcie_sifive_assert_reset(struct pcie_sifive *sv)
+{
+ dm_gpio_set_value(&sv->reset_gpio, GPIO_LOW);
+ writel(PCIE_PERST_ASSERT, sv->priv_base + PCIEX8MGMT_PERST_N);
+ mdelay(ASSERTION_DELAY);
+}
+
+static void pcie_sifive_power_on(struct pcie_sifive *sv)
+{
+ dm_gpio_set_value(&sv->pwren_gpio, GPIO_HIGH);
+ mdelay(ASSERTION_DELAY);
+}
+
+static void pcie_sifive_deassert_reset(struct pcie_sifive *sv)
+{
+ writel(PCIE_PERST_DEASSERT, sv->priv_base + PCIEX8MGMT_PERST_N);
+ dm_gpio_set_value(&sv->reset_gpio, GPIO_HIGH);
+ mdelay(ASSERTION_DELAY);
+}
+
+static int pcie_sifive_setphy(const u8 phy, const u8 write,
+ const u16 addr, const u16 wrdata,
+ u16 *rddata, struct pcie_sifive *sv)
+{
+ unsigned char ack = 0;
+
+ if (!(phy == 0 || phy == 1))
+ return -2;
+
+ /* setup phy para */
+ writel(addr, sv->priv_base +
+ (phy ? PCIEX8MGMT_PHY1_CR_PARA_ADDR :
+ PCIEX8MGMT_PHY0_CR_PARA_ADDR));
+
+ if (write)
+ writel(wrdata, sv->priv_base +
+ (phy ? PCIEX8MGMT_PHY1_CR_PARA_WR_DATA :
+ PCIEX8MGMT_PHY0_CR_PARA_WR_DATA));
+
+ /* enable access if write */
+ if (write)
+ writel(1, sv->priv_base +
+ (phy ? PCIEX8MGMT_PHY1_CR_PARA_WR_EN :
+ PCIEX8MGMT_PHY0_CR_PARA_WR_EN));
+ else
+ writel(1, sv->priv_base +
+ (phy ? PCIEX8MGMT_PHY1_CR_PARA_RD_EN :
+ PCIEX8MGMT_PHY0_CR_PARA_RD_EN));
+
+ /* wait for wait_idle */
+ do {
+ u32 val;
+
+ val = readl(sv->priv_base +
+ (phy ? PCIEX8MGMT_PHY1_CR_PARA_ACK :
+ PCIEX8MGMT_PHY0_CR_PARA_ACK));
+ if (val) {
+ ack = 1;
+ if (!write)
+ readl(sv->priv_base +
+ (phy ? PCIEX8MGMT_PHY1_CR_PARA_RD_DATA :
+ PCIEX8MGMT_PHY0_CR_PARA_RD_DATA));
+ mdelay(1);
+ }
+ } while (!ack);
+
+ /* clear */
+ if (write)
+ writel(0, sv->priv_base +
+ (phy ? PCIEX8MGMT_PHY1_CR_PARA_WR_EN :
+ PCIEX8MGMT_PHY0_CR_PARA_WR_EN));
+ else
+ writel(0, sv->priv_base +
+ (phy ? PCIEX8MGMT_PHY1_CR_PARA_RD_EN :
+ PCIEX8MGMT_PHY0_CR_PARA_RD_EN));
+
+ while (readl(sv->priv_base +
+ (phy ? PCIEX8MGMT_PHY1_CR_PARA_ACK :
+ PCIEX8MGMT_PHY0_CR_PARA_ACK))) {
+ /* wait for ~wait_idle */
+ }
+
+ return 0;
+}
+
+static void pcie_sifive_init_phy(struct pcie_sifive *sv)
+{
+ int lane;
+
+ /* enable phy cr_para_sel interfaces */
+ writel(PCIE_PHY_SEL, sv->priv_base + PCIEX8MGMT_PHY0_CR_PARA_SEL);
+ writel(PCIE_PHY_SEL, sv->priv_base + PCIEX8MGMT_PHY1_CR_PARA_SEL);
+ mdelay(1);
+
+ /* set PHY AC termination mode */
+ for (lane = 0; lane < PCIEX8MGMT_LANE_NUM; lane++) {
+ pcie_sifive_setphy(0, 1,
+ PCIEX8MGMT_LANE +
+ (PCIEX8MGMT_LANE_OFF * lane),
+ PCIEX8MGMT_TERM_MODE, NULL, sv);
+ pcie_sifive_setphy(1, 1,
+ PCIEX8MGMT_LANE +
+ (PCIEX8MGMT_LANE_OFF * lane),
+ PCIEX8MGMT_TERM_MODE, NULL, sv);
+ }
+}
+
+static int pcie_sifive_check_link(struct pcie_sifive *sv)
+{
+ u32 val;
+
+ val = readl(sv->dw.dbi_base + PHY_DEBUG_R1);
+ return (val & PHY_DEBUG_R1_LINK_UP) &&
+ !(val & PHY_DEBUG_R1_LINK_IN_TRAINING);
+}
+
+static void pcie_sifive_force_gen1(struct pcie_sifive *sv)
+{
+ u32 val, linkcap;
+
+ /*
+ * Force Gen1 operation when starting the link. In case the link is
+ * started in Gen2 mode, there is a possibility the devices on the
+ * bus will not be detected at all. This happens with PCIe switches.
+ */
+
+ /* ctrl_ro_wr_enable */
+ val = readl(sv->dw.dbi_base + PCIE_MISC_CONTROL_1);
+ val |= DBI_RO_WR_EN;
+ writel(val, sv->dw.dbi_base + PCIE_MISC_CONTROL_1);
+
+ /* configure link cap */
+ linkcap = readl(sv->dw.dbi_base + PF0_PCIE_CAP_LINK_CAP);
+ linkcap |= PCIE_LINK_CAP_MAX_SPEED_MASK;
+ writel(linkcap, sv->dw.dbi_base + PF0_PCIE_CAP_LINK_CAP);
+
+ /* ctrl_ro_wr_disable */
+ val &= ~DBI_RO_WR_EN;
+ writel(val, sv->dw.dbi_base + PCIE_MISC_CONTROL_1);
+}
+
+static void pcie_sifive_print_phy_debug(struct pcie_sifive *sv)
+{
+ sv_err(sv, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n",
+ readl(sv->dw.dbi_base + PHY_DEBUG_R0),
+ readl(sv->dw.dbi_base + PHY_DEBUG_R1));
+}
+
+static int pcie_sifive_wait_for_link(struct pcie_sifive *sv)
+{
+ u32 val;
+ int timeout;
+
+ /* Wait for the link to train */
+ mdelay(20);
+ timeout = 20;
+
+ do {
+ mdelay(1);
+ } while (--timeout && !pcie_sifive_check_link(sv));
+
+ val = readl(sv->dw.dbi_base + PHY_DEBUG_R1);
+ if (!(val & PHY_DEBUG_R1_LINK_UP) ||
+ (val & PHY_DEBUG_R1_LINK_IN_TRAINING)) {
+ sv_info(sv, "Failed to negotiate PCIe link!\n");
+ pcie_sifive_print_phy_debug(sv);
+ writel(PCIE_PHY_RESET,
+ sv->priv_base + PCIEX8MGMT_APP_HOLD_PHY_RST);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int pcie_sifive_start_link(struct pcie_sifive *sv)
+{
+ if (pcie_sifive_check_link(sv))
+ return -EALREADY;
+
+ pcie_sifive_force_gen1(sv);
+
+ /* set ltssm */
+ pcie_sifive_priv_set_state(sv, PCIEX8MGMT_APP_LTSSM_ENABLE,
+ LTSSM_ENABLE_BIT, 1);
+ return 0;
+}
+
+static int pcie_sifive_init_port(struct udevice *dev,
+ enum pcie_sifive_devtype mode)
+{
+ struct pcie_sifive *sv = dev_get_priv(dev);
+ int ret;
+
+ /* Power on reset */
+ pcie_sifive_assert_reset(sv);
+ pcie_sifive_power_on(sv);
+ pcie_sifive_deassert_reset(sv);
+
+ /* Enable pcieauxclk */
+ ret = clk_enable(&sv->aux_ck);
+ if (ret)
+ dev_err(dev, "unable to enable pcie_aux clock\n");
+
+ /*
+ * assert hold_phy_rst (hold the controller LTSSM in reset
+ * after power_up_rst_n for register programming with cr_para)
+ */
+ writel(PCIE_PHY_RESET, sv->priv_base + PCIEX8MGMT_APP_HOLD_PHY_RST);
+
+ /* deassert power_up_rst_n */
+ ret = reset_deassert(&sv->reset);
+ if (ret < 0) {
+ dev_err(dev, "failed to deassert reset");
+ return -EINVAL;
+ }
+
+ pcie_sifive_init_phy(sv);
+
+ /* disable pcieauxclk */
+ clk_disable(&sv->aux_ck);
+
+ /* deassert hold_phy_rst */
+ writel(PCIE_PHY_RESET_DEASSERT,
+ sv->priv_base + PCIEX8MGMT_APP_HOLD_PHY_RST);
+
+ /* enable pcieauxclk */
+ clk_enable(&sv->aux_ck);
+
+ /* Set desired mode while core is not operational */
+ if (mode == SV_PCIE_HOST_TYPE)
+ writel(DEVICE_TYPE_RC,
+ sv->priv_base + PCIEX8MGMT_DEVICE_TYPE);
+ else
+ writel(DEVICE_TYPE_EP,
+ sv->priv_base + PCIEX8MGMT_DEVICE_TYPE);
+
+ /* Confirm desired mode from operational core */
+ if (pcie_sifive_get_devtype(sv) != mode)
+ return -EINVAL;
+
+ pcie_dw_setup_host(&sv->dw);
+
+ if (pcie_sifive_start_link(sv) == -EALREADY)
+ sv_info(sv, "PCIe link is already up\n");
+ else if (pcie_sifive_wait_for_link(sv) == -ETIMEDOUT)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int pcie_sifive_probe(struct udevice *dev)
+{
+ struct pcie_sifive *sv = dev_get_priv(dev);
+ struct udevice *parent = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(parent);
+ int err;
+
+ sv->dw.first_busno = dev_seq(dev);
+ sv->dw.dev = dev;
+
+ err = pcie_sifive_init_port(dev, SV_PCIE_HOST_TYPE);
+ if (err) {
+ sv_info(sv, "Failed to init port.\n");
+ return err;
+ }
+
+ printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
+ dev_seq(dev), pcie_dw_get_link_speed(&sv->dw),
+ pcie_dw_get_link_width(&sv->dw),
+ hose->first_busno);
+
+ return pcie_dw_prog_outbound_atu_unroll(&sv->dw,
+ PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM,
+ sv->dw.mem.phys_start,
+ sv->dw.mem.bus_start,
+ sv->dw.mem.size);
+}
+
+static void __iomem *get_fdt_addr(struct udevice *dev, const char *name)
+{
+ fdt_addr_t addr;
+
+ addr = dev_read_addr_name(dev, name);
+
+ return (addr == FDT_ADDR_T_NONE) ? NULL : (void __iomem *)addr;
+}
+
+static int pcie_sifive_of_to_plat(struct udevice *dev)
+{
+ struct pcie_sifive *sv = dev_get_priv(dev);
+ int err;
+
+ /* get designware DBI base addr */
+ sv->dw.dbi_base = get_fdt_addr(dev, "dbi");
+ if (!sv->dw.dbi_base)
+ return -EINVAL;
+
+ /* get private control base addr */
+ sv->priv_base = get_fdt_addr(dev, "mgmt");
+ if (!sv->priv_base)
+ return -EINVAL;
+
+ gpio_request_by_name(dev, "pwren-gpios", 0, &sv->pwren_gpio,
+ GPIOD_IS_OUT);
+
+ if (!dm_gpio_is_valid(&sv->pwren_gpio)) {
+ sv_info(sv, "pwren_gpio is invalid\n");
+ return -EINVAL;
+ }
+
+ gpio_request_by_name(dev, "reset-gpios", 0, &sv->reset_gpio,
+ GPIOD_IS_OUT);
+
+ if (!dm_gpio_is_valid(&sv->reset_gpio)) {
+ sv_info(sv, "reset_gpio is invalid\n");
+ return -EINVAL;
+ }
+
+ err = clk_get_by_index(dev, 0, &sv->aux_ck);
+ if (err) {
+ sv_info(sv, "clk_get_by_index(aux_ck) failed: %d\n", err);
+ return err;
+ }
+
+ err = reset_get_by_index(dev, 0, &sv->reset);
+ if (err) {
+ sv_info(sv, "reset_get_by_index(reset) failed: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct dm_pci_ops pcie_sifive_ops = {
+ .read_config = pcie_dw_read_config,
+ .write_config = pcie_dw_write_config,
+};
+
+static const struct udevice_id pcie_sifive_ids[] = {
+ { .compatible = "sifive,fu740-pcie" },
+ {}
+};
+
+U_BOOT_DRIVER(pcie_sifive) = {
+ .name = "pcie_sifive",
+ .id = UCLASS_PCI,
+ .of_match = pcie_sifive_ids,
+ .ops = &pcie_sifive_ops,
+ .of_to_plat = pcie_sifive_of_to_plat,
+ .probe = pcie_sifive_probe,
+ .priv_auto = sizeof(struct pcie_sifive),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_dw_ti.c b/roms/u-boot/drivers/pci/pcie_dw_ti.c
new file mode 100644
index 000000000..4195a02de
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_dw_ti.c
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Texas Instruments, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <generic-phy.h>
+#include <power-domain.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include "pcie_dw_common.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PCIE_VENDORID_MASK GENMASK(15, 0)
+#define PCIE_DEVICEID_SHIFT 16
+
+#define PCIE_LINK_CAPABILITY 0x7c
+#define PCIE_LINK_CTL_2 0xa0
+#define TARGET_LINK_SPEED_MASK 0xf
+#define LINK_SPEED_GEN_1 0x1
+#define LINK_SPEED_GEN_2 0x2
+#define LINK_SPEED_GEN_3 0x3
+
+#define PCIE_MISC_CONTROL_1_OFF 0x8bc
+#define PCIE_DBI_RO_WR_EN BIT(0)
+
+#define PLR_OFFSET 0x700
+#define PCIE_PORT_DEBUG0 (PLR_OFFSET + 0x28)
+#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f
+#define PORT_LOGIC_LTSSM_STATE_L0 0x11
+
+#define PCIE_LINK_UP_TIMEOUT_MS 100
+
+/* Offsets from App base */
+#define PCIE_CMD_STATUS 0x04
+#define LTSSM_EN_VAL BIT(0)
+
+
+#define AM654_PCIE_DEV_TYPE_MASK 0x3
+#define EP 0x0
+#define LEG_EP 0x1
+#define RC 0x2
+
+/**
+ * struct pcie_dw_ti - TI DW PCIe controller state
+ *
+ * @pci: The common PCIe DW structure
+ * @app_base: The base address of application register space
+ */
+struct pcie_dw_ti {
+ /* Must be first member of the struct */
+ struct pcie_dw dw;
+ void *app_base;
+};
+
+enum dw_pcie_device_mode {
+ DW_PCIE_UNKNOWN_TYPE,
+ DW_PCIE_EP_TYPE,
+ DW_PCIE_LEG_EP_TYPE,
+ DW_PCIE_RC_TYPE,
+};
+
+/**
+ * pcie_dw_configure() - Configure link capabilities and speed
+ *
+ * @regs_base: A pointer to the PCIe controller registers
+ * @cap_speed: The capabilities and speed to configure
+ *
+ * Configure the link capabilities and speed in the PCIe root complex.
+ */
+static void pcie_dw_configure(struct pcie_dw_ti *pci, u32 cap_speed)
+{
+ u32 val;
+
+ dw_pcie_dbi_write_enable(&pci->dw, true);
+
+ val = readl(pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
+ val &= ~TARGET_LINK_SPEED_MASK;
+ val |= cap_speed;
+ writel(val, pci->dw.dbi_base + PCIE_LINK_CAPABILITY);
+
+ val = readl(pci->dw.dbi_base + PCIE_LINK_CTL_2);
+ val &= ~TARGET_LINK_SPEED_MASK;
+ val |= cap_speed;
+ writel(val, pci->dw.dbi_base + PCIE_LINK_CTL_2);
+
+ dw_pcie_dbi_write_enable(&pci->dw, false);
+}
+
+/**
+ * is_link_up() - Return the link state
+ *
+ * @regs_base: A pointer to the PCIe DBICS registers
+ *
+ * Return: 1 (true) for active line and 0 (false) for no link
+ */
+static int is_link_up(struct pcie_dw_ti *pci)
+{
+ u32 val;
+
+ val = readl(pci->dw.dbi_base + PCIE_PORT_DEBUG0);
+ val &= PORT_LOGIC_LTSSM_STATE_MASK;
+
+ return (val == PORT_LOGIC_LTSSM_STATE_L0);
+}
+
+/**
+ * wait_link_up() - Wait for the link to come up
+ *
+ * @regs_base: A pointer to the PCIe controller registers
+ *
+ * Return: 1 (true) for active line and 0 (false) for no link (timeout)
+ */
+static int wait_link_up(struct pcie_dw_ti *pci)
+{
+ unsigned long timeout;
+
+ timeout = get_timer(0) + PCIE_LINK_UP_TIMEOUT_MS;
+ while (!is_link_up(pci)) {
+ if (get_timer(0) > timeout)
+ return 0;
+ };
+
+ return 1;
+}
+
+static int pcie_dw_ti_pcie_link_up(struct pcie_dw_ti *pci, u32 cap_speed)
+{
+ u32 val;
+
+ if (is_link_up(pci)) {
+ printf("PCI Link already up before configuration!\n");
+ return 1;
+ }
+
+ /* DW pre link configurations */
+ pcie_dw_configure(pci, cap_speed);
+
+ /* Initiate link training */
+ val = readl(pci->app_base + PCIE_CMD_STATUS);
+ val |= LTSSM_EN_VAL;
+ writel(val, pci->app_base + PCIE_CMD_STATUS);
+
+ /* Check that link was established */
+ if (!wait_link_up(pci))
+ return 0;
+
+ /*
+ * Link can be established in Gen 1. still need to wait
+ * till MAC nagaotiation is completed
+ */
+ udelay(100);
+
+ return 1;
+}
+
+static int pcie_am654_set_mode(struct pcie_dw_ti *pci,
+ enum dw_pcie_device_mode mode)
+{
+ struct regmap *syscon;
+ u32 val;
+ u32 mask;
+ int ret;
+
+ syscon = syscon_regmap_lookup_by_phandle(pci->dw.dev,
+ "ti,syscon-pcie-mode");
+ if (IS_ERR(syscon))
+ return 0;
+
+ mask = AM654_PCIE_DEV_TYPE_MASK;
+
+ switch (mode) {
+ case DW_PCIE_RC_TYPE:
+ val = RC;
+ break;
+ case DW_PCIE_EP_TYPE:
+ val = EP;
+ break;
+ default:
+ dev_err(pci->dw.dev, "INVALID device type %d\n", mode);
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(syscon, 0, mask, val);
+ if (ret) {
+ dev_err(pci->dw.dev, "failed to set pcie mode\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pcie_dw_init_id(struct pcie_dw_ti *pci)
+{
+ struct regmap *devctrl_regs;
+ unsigned int id;
+ int ret;
+
+ devctrl_regs = syscon_regmap_lookup_by_phandle(pci->dw.dev,
+ "ti,syscon-pcie-id");
+ if (IS_ERR(devctrl_regs))
+ return PTR_ERR(devctrl_regs);
+
+ ret = regmap_read(devctrl_regs, 0, &id);
+ if (ret)
+ return ret;
+
+ dw_pcie_dbi_write_enable(&pci->dw, true);
+ writew(id & PCIE_VENDORID_MASK, pci->dw.dbi_base + PCI_VENDOR_ID);
+ writew(id >> PCIE_DEVICEID_SHIFT, pci->dw.dbi_base + PCI_DEVICE_ID);
+ dw_pcie_dbi_write_enable(&pci->dw, false);
+
+ return 0;
+}
+
+/**
+ * pcie_dw_ti_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int pcie_dw_ti_probe(struct udevice *dev)
+{
+ struct pcie_dw_ti *pci = dev_get_priv(dev);
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ struct power_domain pci_pwrdmn;
+ struct phy phy0, phy1;
+ int ret;
+
+ ret = power_domain_get_by_index(dev, &pci_pwrdmn, 0);
+ if (ret) {
+ dev_err(dev, "failed to get power domain\n");
+ return ret;
+ }
+
+ ret = power_domain_on(&pci_pwrdmn);
+ if (ret) {
+ dev_err(dev, "Power domain on failed\n");
+ return ret;
+ }
+
+ ret = generic_phy_get_by_name(dev, "pcie-phy0", &phy0);
+ if (ret) {
+ dev_err(dev, "Unable to get phy0");
+ return ret;
+ }
+ generic_phy_reset(&phy0);
+ generic_phy_init(&phy0);
+ generic_phy_power_on(&phy0);
+
+ ret = generic_phy_get_by_name(dev, "pcie-phy1", &phy1);
+ if (ret) {
+ dev_err(dev, "Unable to get phy1");
+ return ret;
+ }
+ generic_phy_reset(&phy1);
+ generic_phy_init(&phy1);
+ generic_phy_power_on(&phy1);
+
+ pci->dw.first_busno = dev_seq(dev);
+ pci->dw.dev = dev;
+
+ pcie_dw_setup_host(&pci->dw);
+ pcie_dw_init_id(pci);
+
+ if (device_is_compatible(dev, "ti,am654-pcie-rc"))
+ pcie_am654_set_mode(pci, DW_PCIE_RC_TYPE);
+
+ if (!pcie_dw_ti_pcie_link_up(pci, LINK_SPEED_GEN_2)) {
+ printf("PCIE-%d: Link down\n", dev_seq(dev));
+ return -ENODEV;
+ }
+
+ printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev),
+ pcie_dw_get_link_speed(&pci->dw),
+ pcie_dw_get_link_width(&pci->dw),
+ hose->first_busno);
+
+ pcie_dw_prog_outbound_atu_unroll(&pci->dw, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM,
+ pci->dw.mem.phys_start,
+ pci->dw.mem.bus_start, pci->dw.mem.size);
+
+ return 0;
+}
+
+/**
+ * pcie_dw_ti_of_to_plat() - Translate from DT to device state
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Translate relevant data from the device tree pertaining to device @dev into
+ * state that the driver will later make use of. This state is stored in the
+ * device's private data structure.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+static int pcie_dw_ti_of_to_plat(struct udevice *dev)
+{
+ struct pcie_dw_ti *pcie = dev_get_priv(dev);
+
+ /* Get the controller base address */
+ pcie->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbics");
+ if ((fdt_addr_t)pcie->dw.dbi_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /* Get the config space base address and size */
+ pcie->dw.cfg_base = (void *)dev_read_addr_size_name(dev, "config",
+ &pcie->dw.cfg_size);
+ if ((fdt_addr_t)pcie->dw.cfg_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /* Get the iATU base address and size */
+ pcie->dw.atu_base = (void *)dev_read_addr_name(dev, "atu");
+ if ((fdt_addr_t)pcie->dw.atu_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /* Get the app base address and size */
+ pcie->app_base = (void *)dev_read_addr_name(dev, "app");
+ if ((fdt_addr_t)pcie->app_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct dm_pci_ops pcie_dw_ti_ops = {
+ .read_config = pcie_dw_read_config,
+ .write_config = pcie_dw_write_config,
+};
+
+static const struct udevice_id pcie_dw_ti_ids[] = {
+ { .compatible = "ti,am654-pcie-rc" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_dw_ti) = {
+ .name = "pcie_dw_ti",
+ .id = UCLASS_PCI,
+ .of_match = pcie_dw_ti_ids,
+ .ops = &pcie_dw_ti_ops,
+ .of_to_plat = pcie_dw_ti_of_to_plat,
+ .probe = pcie_dw_ti_probe,
+ .priv_auto = sizeof(struct pcie_dw_ti),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_ecam_generic.c b/roms/u-boot/drivers/pci/pcie_ecam_generic.c
new file mode 100644
index 000000000..e83e5aff2
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_ecam_generic.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generic PCIE host provided by e.g. QEMU
+ *
+ * Heavily based on drivers/pci/pcie_xilinx.c
+ *
+ * Copyright (C) 2016 Imagination Technologies
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/global_data.h>
+
+#include <asm/io.h>
+
+/**
+ * struct generic_ecam_pcie - generic_ecam PCIe controller state
+ * @cfg_base: The base address of memory mapped configuration space
+ */
+struct generic_ecam_pcie {
+ void *cfg_base;
+ pci_size_t size;
+ int first_busno;
+};
+
+/**
+ * pci_generic_ecam_conf_address() - Calculate the address of a config access
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @paddress: Pointer to the pointer to write the calculates address to
+ *
+ * Calculates the address that should be accessed to perform a PCIe
+ * configuration space access for a given device identified by the PCIe
+ * controller device @pcie and the bus, device & function numbers in @bdf. If
+ * access to the device is not valid then the function will return an error
+ * code. Otherwise the address to access will be written to the pointer pointed
+ * to by @paddress.
+ */
+static int pci_generic_ecam_conf_address(const struct udevice *bus,
+ pci_dev_t bdf, uint offset,
+ void **paddress)
+{
+ struct generic_ecam_pcie *pcie = dev_get_priv(bus);
+ void *addr;
+
+ addr = pcie->cfg_base;
+ addr += (PCI_BUS(bdf) - pcie->first_busno) << 20;
+ addr += PCI_DEV(bdf) << 15;
+ addr += PCI_FUNC(bdf) << 12;
+ addr += offset;
+ *paddress = addr;
+
+ return 0;
+}
+
+static bool pci_generic_ecam_addr_valid(const struct udevice *bus,
+ pci_dev_t bdf)
+{
+ struct generic_ecam_pcie *pcie = dev_get_priv(bus);
+ int num_buses = DIV_ROUND_UP(pcie->size, 1 << 16);
+
+ return (PCI_BUS(bdf) >= pcie->first_busno &&
+ PCI_BUS(bdf) < pcie->first_busno + num_buses);
+}
+
+/**
+ * pci_generic_ecam_read_config() - Read from configuration space
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ */
+static int pci_generic_ecam_read_config(const struct udevice *bus,
+ pci_dev_t bdf, uint offset,
+ ulong *valuep, enum pci_size_t size)
+{
+ if (!pci_generic_ecam_addr_valid(bus, bdf)) {
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ return pci_generic_mmap_read_config(bus, pci_generic_ecam_conf_address,
+ bdf, offset, valuep, size);
+}
+
+/**
+ * pci_generic_ecam_write_config() - Write to configuration space
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ */
+static int pci_generic_ecam_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ if (!pci_generic_ecam_addr_valid(bus, bdf))
+ return 0;
+
+ return pci_generic_mmap_write_config(bus, pci_generic_ecam_conf_address,
+ bdf, offset, value, size);
+}
+
+/**
+ * pci_generic_ecam_of_to_plat() - Translate from DT to device state
+ * @dev: A pointer to the device being operated on
+ *
+ * Translate relevant data from the device tree pertaining to device @dev into
+ * state that the driver will later make use of. This state is stored in the
+ * device's private data structure.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+static int pci_generic_ecam_of_to_plat(struct udevice *dev)
+{
+ struct generic_ecam_pcie *pcie = dev_get_priv(dev);
+ struct fdt_resource reg_res;
+ DECLARE_GLOBAL_DATA_PTR;
+ int err;
+
+ err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg",
+ 0, &reg_res);
+ if (err < 0) {
+ pr_err("\"reg\" resource not found\n");
+ return err;
+ }
+
+ pcie->size = fdt_resource_size(&reg_res);
+ pcie->cfg_base = map_physmem(reg_res.start, pcie->size, MAP_NOCACHE);
+
+ return 0;
+}
+
+static int pci_generic_ecam_probe(struct udevice *dev)
+{
+ struct generic_ecam_pcie *pcie = dev_get_priv(dev);
+
+ pcie->first_busno = dev_seq(dev);
+
+ return 0;
+}
+
+static const struct dm_pci_ops pci_generic_ecam_ops = {
+ .read_config = pci_generic_ecam_read_config,
+ .write_config = pci_generic_ecam_write_config,
+};
+
+static const struct udevice_id pci_generic_ecam_ids[] = {
+ { .compatible = "pci-host-ecam-generic" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_generic_ecam) = {
+ .name = "pci_generic_ecam",
+ .id = UCLASS_PCI,
+ .of_match = pci_generic_ecam_ids,
+ .ops = &pci_generic_ecam_ops,
+ .probe = pci_generic_ecam_probe,
+ .of_to_plat = pci_generic_ecam_of_to_plat,
+ .priv_auto = sizeof(struct generic_ecam_pcie),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_fsl.c b/roms/u-boot/drivers/pci/pcie_fsl.c
new file mode 100644
index 000000000..3c2a2a476
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_fsl.c
@@ -0,0 +1,668 @@
+// SPDX-License-Identifier: GPL-2.0+ OR X11
+/*
+ * Copyright 2019 NXP
+ *
+ * PCIe DM U-Boot driver for Freescale PowerPC SoCs
+ * Author: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <pci.h>
+#include <asm/fsl_pci.h>
+#include <asm/fsl_serdes.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include "pcie_fsl.h"
+#include <dm/device_compat.h>
+
+LIST_HEAD(fsl_pcie_list);
+
+static int fsl_pcie_link_up(struct fsl_pcie *pcie);
+
+static int fsl_pcie_addr_valid(struct fsl_pcie *pcie, pci_dev_t bdf)
+{
+ struct udevice *bus = pcie->bus;
+
+ if (!pcie->enabled)
+ return -ENXIO;
+
+ if (PCI_BUS(bdf) < dev_seq(bus))
+ return -EINVAL;
+
+ if (PCI_BUS(bdf) > dev_seq(bus) && (!fsl_pcie_link_up(pcie) || pcie->mode))
+ return -EINVAL;
+
+ if (PCI_BUS(bdf) == dev_seq(bus) && (PCI_DEV(bdf) > 0 || PCI_FUNC(bdf) > 0))
+ return -EINVAL;
+
+ if (PCI_BUS(bdf) == (dev_seq(bus) + 1) && (PCI_DEV(bdf) > 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int fsl_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct fsl_pcie *pcie = dev_get_priv(bus);
+ ccsr_fsl_pci_t *regs = pcie->regs;
+ u32 val;
+
+ if (fsl_pcie_addr_valid(pcie, bdf)) {
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ bdf = bdf - PCI_BDF(dev_seq(bus), 0, 0);
+ val = bdf | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000;
+ out_be32(&regs->cfg_addr, val);
+
+ sync();
+
+ switch (size) {
+ case PCI_SIZE_8:
+ *valuep = in_8((u8 *)&regs->cfg_data + (offset & 3));
+ break;
+ case PCI_SIZE_16:
+ *valuep = in_le16((u16 *)((u8 *)&regs->cfg_data +
+ (offset & 2)));
+ break;
+ case PCI_SIZE_32:
+ *valuep = in_le32(&regs->cfg_data);
+ break;
+ }
+
+ return 0;
+}
+
+static int fsl_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct fsl_pcie *pcie = dev_get_priv(bus);
+ ccsr_fsl_pci_t *regs = pcie->regs;
+ u32 val;
+ u8 val_8;
+ u16 val_16;
+ u32 val_32;
+
+ if (fsl_pcie_addr_valid(pcie, bdf))
+ return 0;
+
+ bdf = bdf - PCI_BDF(dev_seq(bus), 0, 0);
+ val = bdf | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000;
+ out_be32(&regs->cfg_addr, val);
+
+ sync();
+
+ switch (size) {
+ case PCI_SIZE_8:
+ val_8 = value;
+ out_8((u8 *)&regs->cfg_data + (offset & 3), val_8);
+ break;
+ case PCI_SIZE_16:
+ val_16 = value;
+ out_le16((u16 *)((u8 *)&regs->cfg_data + (offset & 2)), val_16);
+ break;
+ case PCI_SIZE_32:
+ val_32 = value;
+ out_le32(&regs->cfg_data, val_32);
+ break;
+ }
+
+ return 0;
+}
+
+static int fsl_pcie_hose_read_config(struct fsl_pcie *pcie, uint offset,
+ ulong *valuep, enum pci_size_t size)
+{
+ int ret;
+ struct udevice *bus = pcie->bus;
+
+ ret = fsl_pcie_read_config(bus, PCI_BDF(dev_seq(bus), 0, 0),
+ offset, valuep, size);
+
+ return ret;
+}
+
+static int fsl_pcie_hose_write_config(struct fsl_pcie *pcie, uint offset,
+ ulong value, enum pci_size_t size)
+{
+ struct udevice *bus = pcie->bus;
+
+ return fsl_pcie_write_config(bus, PCI_BDF(dev_seq(bus), 0, 0),
+ offset, value, size);
+}
+
+static int fsl_pcie_hose_read_config_byte(struct fsl_pcie *pcie, uint offset,
+ u8 *valuep)
+{
+ ulong val;
+ int ret;
+
+ ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_8);
+ *valuep = val;
+
+ return ret;
+}
+
+static int fsl_pcie_hose_read_config_word(struct fsl_pcie *pcie, uint offset,
+ u16 *valuep)
+{
+ ulong val;
+ int ret;
+
+ ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_16);
+ *valuep = val;
+
+ return ret;
+}
+
+static int fsl_pcie_hose_read_config_dword(struct fsl_pcie *pcie, uint offset,
+ u32 *valuep)
+{
+ ulong val;
+ int ret;
+
+ ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_32);
+ *valuep = val;
+
+ return ret;
+}
+
+static int fsl_pcie_hose_write_config_byte(struct fsl_pcie *pcie, uint offset,
+ u8 value)
+{
+ return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_8);
+}
+
+static int fsl_pcie_hose_write_config_word(struct fsl_pcie *pcie, uint offset,
+ u16 value)
+{
+ return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_16);
+}
+
+static int fsl_pcie_hose_write_config_dword(struct fsl_pcie *pcie, uint offset,
+ u32 value)
+{
+ return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_32);
+}
+
+static int fsl_pcie_link_up(struct fsl_pcie *pcie)
+{
+ ccsr_fsl_pci_t *regs = pcie->regs;
+ u16 ltssm;
+
+ if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
+ ltssm = (in_be32(&regs->pex_csr0)
+ & PEX_CSR0_LTSSM_MASK) >> PEX_CSR0_LTSSM_SHIFT;
+ return ltssm == LTSSM_L0_REV3;
+ }
+
+ fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, &ltssm);
+
+ return ltssm == LTSSM_L0;
+}
+
+static bool fsl_pcie_is_agent(struct fsl_pcie *pcie)
+{
+ u8 header_type;
+
+ fsl_pcie_hose_read_config_byte(pcie, PCI_HEADER_TYPE, &header_type);
+
+ return (header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL;
+}
+
+static int fsl_pcie_setup_law(struct fsl_pcie *pcie)
+{
+ struct pci_region *io, *mem, *pref;
+
+ pci_get_regions(pcie->bus, &io, &mem, &pref);
+
+ if (mem)
+ set_next_law(mem->phys_start,
+ law_size_bits(mem->size),
+ pcie->law_trgt_if);
+
+ if (io)
+ set_next_law(io->phys_start,
+ law_size_bits(io->size),
+ pcie->law_trgt_if);
+
+ return 0;
+}
+
+static void fsl_pcie_config_ready(struct fsl_pcie *pcie)
+{
+ ccsr_fsl_pci_t *regs = pcie->regs;
+
+ if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
+ setbits_be32(&regs->config, FSL_PCIE_V3_CFG_RDY);
+ return;
+ }
+
+ fsl_pcie_hose_write_config_byte(pcie, FSL_PCIE_CFG_RDY, 0x1);
+}
+
+static int fsl_pcie_setup_outbound_win(struct fsl_pcie *pcie, int idx,
+ int type, u64 phys, u64 bus_addr,
+ pci_size_t size)
+{
+ ccsr_fsl_pci_t *regs = pcie->regs;
+ pot_t *po = &regs->pot[idx];
+ u32 war, sz;
+
+ if (idx < 0)
+ return -EINVAL;
+
+ out_be32(&po->powbar, phys >> 12);
+ out_be32(&po->potar, bus_addr >> 12);
+#ifdef CONFIG_SYS_PCI_64BIT
+ out_be32(&po->potear, bus_addr >> 44);
+#else
+ out_be32(&po->potear, 0);
+#endif
+
+ sz = (__ilog2_u64((u64)size) - 1);
+ war = POWAR_EN | sz;
+
+ if (type == PCI_REGION_IO)
+ war |= POWAR_IO_READ | POWAR_IO_WRITE;
+ else
+ war |= POWAR_MEM_READ | POWAR_MEM_WRITE;
+
+ out_be32(&po->powar, war);
+
+ return 0;
+}
+
+static int fsl_pcie_setup_inbound_win(struct fsl_pcie *pcie, int idx,
+ bool pf, u64 phys, u64 bus_addr,
+ pci_size_t size)
+{
+ ccsr_fsl_pci_t *regs = pcie->regs;
+ pit_t *pi = &regs->pit[idx];
+ u32 sz = (__ilog2_u64(size) - 1);
+ u32 flag = PIWAR_LOCAL;
+
+ if (idx < 0)
+ return -EINVAL;
+
+ out_be32(&pi->pitar, phys >> 12);
+ out_be32(&pi->piwbar, bus_addr >> 12);
+
+#ifdef CONFIG_SYS_PCI_64BIT
+ out_be32(&pi->piwbear, bus_addr >> 44);
+#else
+ out_be32(&pi->piwbear, 0);
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A005434
+ flag = 0;
+#endif
+
+ flag |= PIWAR_EN | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
+ if (pf)
+ flag |= PIWAR_PF;
+ out_be32(&pi->piwar, flag | sz);
+
+ return 0;
+}
+
+static int fsl_pcie_setup_outbound_wins(struct fsl_pcie *pcie)
+{
+ struct pci_region *io, *mem, *pref;
+ int idx = 1; /* skip 0 */
+
+ pci_get_regions(pcie->bus, &io, &mem, &pref);
+
+ if (io)
+ /* ATU : OUTBOUND : IO */
+ fsl_pcie_setup_outbound_win(pcie, idx++,
+ PCI_REGION_IO,
+ io->phys_start,
+ io->bus_start,
+ io->size);
+
+ if (mem)
+ /* ATU : OUTBOUND : MEM */
+ fsl_pcie_setup_outbound_win(pcie, idx++,
+ PCI_REGION_MEM,
+ mem->phys_start,
+ mem->bus_start,
+ mem->size);
+ return 0;
+}
+
+static int fsl_pcie_setup_inbound_wins(struct fsl_pcie *pcie)
+{
+ phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS;
+ pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS;
+ u64 sz = min((u64)gd->ram_size, (1ull << 32));
+ pci_size_t pci_sz;
+ int idx;
+
+ if (pcie->block_rev >= PEX_IP_BLK_REV_2_2)
+ idx = 2;
+ else
+ idx = 3;
+
+ pci_sz = 1ull << __ilog2_u64(sz);
+
+ dev_dbg(pcie->bus, "R0 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)sz);
+
+ /* if we aren't an exact power of two match, pci_sz is smaller
+ * round it up to the next power of two. We report the actual
+ * size to pci region tracking.
+ */
+ if (pci_sz != sz)
+ sz = 2ull << __ilog2_u64(sz);
+
+ fsl_pcie_setup_inbound_win(pcie, idx--, true,
+ CONFIG_SYS_PCI_MEMORY_PHYS,
+ CONFIG_SYS_PCI_MEMORY_BUS, sz);
+#if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
+ /*
+ * On 64-bit capable systems, set up a mapping for all of DRAM
+ * in high pci address space.
+ */
+ pci_sz = 1ull << __ilog2_u64(gd->ram_size);
+ /* round up to the next largest power of two */
+ if (gd->ram_size > pci_sz)
+ pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1);
+
+ dev_dbg(pcie->bus, "R64 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)CONFIG_SYS_PCI64_MEMORY_BUS,
+ (u64)CONFIG_SYS_PCI_MEMORY_PHYS, (u64)pci_sz);
+
+ fsl_pcie_setup_inbound_win(pcie, idx--, true,
+ CONFIG_SYS_PCI_MEMORY_PHYS,
+ CONFIG_SYS_PCI64_MEMORY_BUS, pci_sz);
+#endif
+
+ return 0;
+}
+
+static int fsl_pcie_init_atmu(struct fsl_pcie *pcie)
+{
+ fsl_pcie_setup_outbound_wins(pcie);
+ fsl_pcie_setup_inbound_wins(pcie);
+
+ return 0;
+}
+
+static void fsl_pcie_dbi_read_only_reg_write_enable(struct fsl_pcie *pcie,
+ bool enable)
+{
+ u32 val;
+
+ fsl_pcie_hose_read_config_dword(pcie, DBI_RO_WR_EN, &val);
+ if (enable)
+ val |= 1;
+ else
+ val &= ~1;
+ fsl_pcie_hose_write_config_dword(pcie, DBI_RO_WR_EN, val);
+}
+
+static int fsl_pcie_init_port(struct fsl_pcie *pcie)
+{
+ ccsr_fsl_pci_t *regs = pcie->regs;
+ u32 val_32;
+ u16 val_16;
+
+ fsl_pcie_init_atmu(pcie);
+
+#ifdef CONFIG_FSL_PCIE_DISABLE_ASPM
+ val_32 = 0;
+ fsl_pcie_hose_read_config_dword(pcie, PCI_LCR, &val_32);
+ val_32 &= ~0x03;
+ fsl_pcie_hose_write_config_dword(pcie, PCI_LCR, val_32);
+ udelay(1);
+#endif
+
+#ifdef CONFIG_FSL_PCIE_RESET
+ u16 ltssm;
+ int i;
+
+ if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
+ /* assert PCIe reset */
+ setbits_be32(&regs->pdb_stat, 0x08000000);
+ (void)in_be32(&regs->pdb_stat);
+ udelay(1000);
+ /* clear PCIe reset */
+ clrbits_be32(&regs->pdb_stat, 0x08000000);
+ asm("sync;isync");
+ for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++)
+ udelay(1000);
+ } else {
+ fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, &ltssm);
+ if (ltssm == 1) {
+ /* assert PCIe reset */
+ setbits_be32(&regs->pdb_stat, 0x08000000);
+ (void)in_be32(&regs->pdb_stat);
+ udelay(100);
+ /* clear PCIe reset */
+ clrbits_be32(&regs->pdb_stat, 0x08000000);
+ asm("sync;isync");
+ for (i = 0; i < 100 &&
+ !fsl_pcie_link_up(pcie); i++)
+ udelay(1000);
+ }
+ }
+#endif
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_PCIE_A003
+ if (!fsl_pcie_link_up(pcie)) {
+ serdes_corenet_t *srds_regs;
+
+ srds_regs = (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
+ val_32 = in_be32(&srds_regs->srdspccr0);
+
+ if ((val_32 >> 28) == 3) {
+ int i;
+
+ out_be32(&srds_regs->srdspccr0, 2 << 28);
+ setbits_be32(&regs->pdb_stat, 0x08000000);
+ in_be32(&regs->pdb_stat);
+ udelay(100);
+ clrbits_be32(&regs->pdb_stat, 0x08000000);
+ asm("sync;isync");
+ for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++)
+ udelay(1000);
+ }
+ }
+#endif
+
+ /*
+ * The Read-Only Write Enable bit defaults to 1 instead of 0.
+ * Set to 0 to protect the read-only registers.
+ */
+#ifdef CONFIG_SYS_FSL_ERRATUM_A007815
+ fsl_pcie_dbi_read_only_reg_write_enable(pcie, false);
+#endif
+
+ /*
+ * Enable All Error Interrupts except
+ * - Master abort (pci)
+ * - Master PERR (pci)
+ * - ICCA (PCIe)
+ */
+ out_be32(&regs->peer, ~0x20140);
+
+ /* set URR, FER, NFER (but not CER) */
+ fsl_pcie_hose_read_config_dword(pcie, PCI_DCR, &val_32);
+ val_32 |= 0xf000e;
+ fsl_pcie_hose_write_config_dword(pcie, PCI_DCR, val_32);
+
+ /* Clear all error indications */
+ out_be32(&regs->pme_msg_det, 0xffffffff);
+ out_be32(&regs->pme_msg_int_en, 0xffffffff);
+ out_be32(&regs->pedr, 0xffffffff);
+
+ fsl_pcie_hose_read_config_word(pcie, PCI_DSR, &val_16);
+ if (val_16)
+ fsl_pcie_hose_write_config_word(pcie, PCI_DSR, 0xffff);
+
+ fsl_pcie_hose_read_config_word(pcie, PCI_SEC_STATUS, &val_16);
+ if (val_16)
+ fsl_pcie_hose_write_config_word(pcie, PCI_SEC_STATUS, 0xffff);
+
+ return 0;
+}
+
+static int fsl_pcie_fixup_classcode(struct fsl_pcie *pcie)
+{
+ u32 classcode_reg;
+ u32 val;
+
+ if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
+ classcode_reg = PCI_CLASS_REVISION;
+ fsl_pcie_dbi_read_only_reg_write_enable(pcie, true);
+ } else {
+ classcode_reg = CSR_CLASSCODE;
+ }
+
+ fsl_pcie_hose_read_config_dword(pcie, classcode_reg, &val);
+ val &= 0xff;
+ val |= PCI_CLASS_BRIDGE_PCI << 16;
+ fsl_pcie_hose_write_config_dword(pcie, classcode_reg, val);
+
+ if (pcie->block_rev >= PEX_IP_BLK_REV_3_0)
+ fsl_pcie_dbi_read_only_reg_write_enable(pcie, false);
+
+ return 0;
+}
+
+static int fsl_pcie_init_rc(struct fsl_pcie *pcie)
+{
+ return fsl_pcie_fixup_classcode(pcie);
+}
+
+static int fsl_pcie_init_ep(struct fsl_pcie *pcie)
+{
+ fsl_pcie_config_ready(pcie);
+
+ return 0;
+}
+
+static int fsl_pcie_probe(struct udevice *dev)
+{
+ struct fsl_pcie *pcie = dev_get_priv(dev);
+ ccsr_fsl_pci_t *regs = pcie->regs;
+ u16 val_16;
+
+ pcie->bus = dev;
+ pcie->block_rev = in_be32(&regs->block_rev1);
+
+ list_add(&pcie->list, &fsl_pcie_list);
+ pcie->enabled = is_serdes_configured(PCIE1 + pcie->idx);
+ if (!pcie->enabled) {
+ printf("PCIe%d: %s disabled\n", pcie->idx, dev->name);
+ return 0;
+ }
+
+ fsl_pcie_setup_law(pcie);
+
+ pcie->mode = fsl_pcie_is_agent(pcie);
+
+ fsl_pcie_init_port(pcie);
+
+ printf("PCIe%d: %s ", pcie->idx, dev->name);
+
+ if (pcie->mode) {
+ printf("Endpoint");
+ fsl_pcie_init_ep(pcie);
+ } else {
+ printf("Root Complex");
+ fsl_pcie_init_rc(pcie);
+ }
+
+ if (!fsl_pcie_link_up(pcie)) {
+ printf(": %s\n", pcie->mode ? "undetermined link" : "no link");
+ return 0;
+ }
+
+ fsl_pcie_hose_read_config_word(pcie, PCI_LSR, &val_16);
+ printf(": x%d gen%d\n", (val_16 & 0x3f0) >> 4, (val_16 & 0xf));
+
+ return 0;
+}
+
+static int fsl_pcie_of_to_plat(struct udevice *dev)
+{
+ struct fsl_pcie *pcie = dev_get_priv(dev);
+ struct fsl_pcie_data *info;
+ int ret;
+
+ pcie->regs = dev_remap_addr(dev);
+ if (!pcie->regs) {
+ pr_err("\"reg\" resource not found\n");
+ return -EINVAL;
+ }
+
+ ret = dev_read_u32(dev, "law_trgt_if", &pcie->law_trgt_if);
+ if (ret < 0) {
+ pr_err("\"law_trgt_if\" not found\n");
+ return ret;
+ }
+
+ info = (struct fsl_pcie_data *)dev_get_driver_data(dev);
+ pcie->info = info;
+ pcie->idx = abs((u32)(dev_read_addr(dev) & info->block_offset_mask) -
+ info->block_offset) / info->stride;
+
+ return 0;
+}
+
+static const struct dm_pci_ops fsl_pcie_ops = {
+ .read_config = fsl_pcie_read_config,
+ .write_config = fsl_pcie_write_config,
+};
+
+static struct fsl_pcie_data p1_p2_data = {
+ .block_offset = 0xa000,
+ .block_offset_mask = 0xffff,
+ .stride = 0x1000,
+};
+
+static struct fsl_pcie_data p2041_data = {
+ .block_offset = 0x200000,
+ .block_offset_mask = 0x3fffff,
+ .stride = 0x1000,
+};
+
+static struct fsl_pcie_data t2080_data = {
+ .block_offset = 0x240000,
+ .block_offset_mask = 0x3fffff,
+ .stride = 0x10000,
+};
+
+static const struct udevice_id fsl_pcie_ids[] = {
+ { .compatible = "fsl,pcie-mpc8548", .data = (ulong)&p1_p2_data },
+ { .compatible = "fsl,pcie-p1_p2", .data = (ulong)&p1_p2_data },
+ { .compatible = "fsl,pcie-p2041", .data = (ulong)&p2041_data },
+ { .compatible = "fsl,pcie-p3041", .data = (ulong)&p2041_data },
+ { .compatible = "fsl,pcie-p4080", .data = (ulong)&p2041_data },
+ { .compatible = "fsl,pcie-p5040", .data = (ulong)&p2041_data },
+ { .compatible = "fsl,pcie-t102x", .data = (ulong)&t2080_data },
+ { .compatible = "fsl,pcie-t104x", .data = (ulong)&t2080_data },
+ { .compatible = "fsl,pcie-t2080", .data = (ulong)&t2080_data },
+ { .compatible = "fsl,pcie-t4240", .data = (ulong)&t2080_data },
+ { }
+};
+
+U_BOOT_DRIVER(fsl_pcie) = {
+ .name = "fsl_pcie",
+ .id = UCLASS_PCI,
+ .of_match = fsl_pcie_ids,
+ .ops = &fsl_pcie_ops,
+ .of_to_plat = fsl_pcie_of_to_plat,
+ .probe = fsl_pcie_probe,
+ .priv_auto = sizeof(struct fsl_pcie),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_fsl.h b/roms/u-boot/drivers/pci/pcie_fsl.h
new file mode 100644
index 000000000..70c5f4e4c
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_fsl.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 NXP
+ *
+ * PCIe DM U-Boot driver for Freescale PowerPC SoCs
+ * Author: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+ */
+
+#ifndef _PCIE_FSL_H_
+#define _PCIE_FSL_H_
+
+/* GPEX CSR */
+#define CSR_CLASSCODE 0x474
+
+#ifdef CONFIG_SYS_FSL_PCI_VER_3_X
+#define FSL_PCIE_CAP_ID 0x70
+#else
+#define FSL_PCIE_CAP_ID 0x4c
+#endif
+/* PCIe Device Control Register */
+#define PCI_DCR (FSL_PCIE_CAP_ID + 0x08)
+/* PCIe Device Status Register */
+#define PCI_DSR (FSL_PCIE_CAP_ID + 0x0a)
+/* PCIe Link Control Register */
+#define PCI_LCR (FSL_PCIE_CAP_ID + 0x10)
+/* PCIe Link Status Register */
+#define PCI_LSR (FSL_PCIE_CAP_ID + 0x12)
+
+#define DBI_RO_WR_EN 0x8bc
+
+#ifndef CONFIG_SYS_PCI_MEMORY_BUS
+#define CONFIG_SYS_PCI_MEMORY_BUS 0
+#endif
+
+#ifndef CONFIG_SYS_PCI_MEMORY_PHYS
+#define CONFIG_SYS_PCI_MEMORY_PHYS 0
+#endif
+
+#if defined(CONFIG_SYS_PCI_64BIT) && !defined(CONFIG_SYS_PCI64_MEMORY_BUS)
+#define CONFIG_SYS_PCI64_MEMORY_BUS (64ull * 1024 * 1024 * 1024)
+#endif
+
+#define PEX_CSR0_LTSSM_MASK 0xFC
+#define PEX_CSR0_LTSSM_SHIFT 2
+#define LTSSM_L0_REV3 0x11
+#define LTSSM_L0 0x16
+
+struct fsl_pcie_data {
+ u32 block_offset; /* Offset from CCSR of 1st controller */
+ u32 block_offset_mask; /* Mask out the CCSR base */
+ u32 stride; /* Offset stride between controllers */
+};
+
+struct fsl_pcie {
+ int idx;
+ struct udevice *bus;
+ void __iomem *regs;
+ u32 law_trgt_if; /* LAW target ID */
+ u32 block_rev; /* IP block revision */
+ bool mode; /* RC&EP mode flag */
+ bool enabled; /* Enable status */
+ struct list_head list;
+ struct fsl_pcie_data *info;
+};
+
+extern struct list_head fsl_pcie_list;
+
+#endif /* _PCIE_FSL_H_ */
diff --git a/roms/u-boot/drivers/pci/pcie_fsl_fixup.c b/roms/u-boot/drivers/pci/pcie_fsl_fixup.c
new file mode 100644
index 000000000..f4e227895
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_fsl_fixup.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+ OR X11
+/*
+ * Copyright 2019 NXP
+ *
+ * PCIe Kernel DT fixup of DM U-Boot driver for Freescale PowerPC SoCs
+ * Author: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+ */
+
+#include <common.h>
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <dm.h>
+#include <fdt_support.h>
+#include <asm/fsl_pci.h>
+#include <linux/libfdt.h>
+#include "pcie_fsl.h"
+
+static void ft_fsl_pcie_setup(void *blob, struct fsl_pcie *pcie)
+{
+ struct pci_controller *hose = dev_get_uclass_priv(pcie->bus);
+ fdt_addr_t regs_addr;
+ int off;
+
+ regs_addr = dev_read_addr(pcie->bus);
+ off = fdt_node_offset_by_compat_reg(blob, FSL_PCIE_COMPAT, regs_addr);
+ if (off < 0) {
+ printf("%s: Fail to find PCIe node@0x%pa\n",
+ FSL_PCIE_COMPAT, &regs_addr);
+ return;
+ }
+
+ if (!hose || !pcie->enabled)
+ fdt_del_node(blob, off);
+ else
+ fdt_pci_dma_ranges(blob, off, hose);
+}
+
+/* Fixup Kernel DT for PCIe */
+void pci_of_setup(void *blob, struct bd_info *bd)
+{
+ struct fsl_pcie *pcie;
+
+ list_for_each_entry(pcie, &fsl_pcie_list, list)
+ ft_fsl_pcie_setup(blob, pcie);
+}
+
+#else
+void pci_of_setup(void *blob, struct bd_info *bd)
+{
+}
+#endif
diff --git a/roms/u-boot/drivers/pci/pcie_imx.c b/roms/u-boot/drivers/pci/pcie_imx.c
new file mode 100644
index 000000000..73875e00d
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_imx.c
@@ -0,0 +1,836 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Freescale i.MX6 PCI Express Root-Complex driver
+ *
+ * Copyright (C) 2013 Marek Vasut <marex@denx.de>
+ *
+ * Based on upstream Linux kernel driver:
+ * pci-imx6.c: Sean Cross <xobs@kosagi.com>
+ * pcie-designware.c: Jingoo Han <jg1.han@samsung.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <log.h>
+#include <malloc.h>
+#include <pci.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/iomux.h>
+#include <asm/arch/crm_regs.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <linux/sizes.h>
+#include <errno.h>
+#include <asm/arch/sys_proto.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+#ifdef CONFIG_MX6SX
+#define MX6_DBI_ADDR 0x08ffc000
+#define MX6_IO_ADDR 0x08000000
+#define MX6_MEM_ADDR 0x08100000
+#define MX6_ROOT_ADDR 0x08f00000
+#else
+#define MX6_DBI_ADDR 0x01ffc000
+#define MX6_IO_ADDR 0x01000000
+#define MX6_MEM_ADDR 0x01100000
+#define MX6_ROOT_ADDR 0x01f00000
+#endif
+#define MX6_DBI_SIZE 0x4000
+#define MX6_IO_SIZE 0x100000
+#define MX6_MEM_SIZE 0xe00000
+#define MX6_ROOT_SIZE 0xfc000
+
+/* PCIe Port Logic registers (memory-mapped) */
+#define PL_OFFSET 0x700
+#define PCIE_PL_PFLR (PL_OFFSET + 0x08)
+#define PCIE_PL_PFLR_LINK_STATE_MASK (0x3f << 16)
+#define PCIE_PL_PFLR_FORCE_LINK (1 << 15)
+#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
+#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
+#define PCIE_PHY_DEBUG_R1_LINK_UP (1 << 4)
+#define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING (1 << 29)
+
+#define PCIE_PHY_CTRL (PL_OFFSET + 0x114)
+#define PCIE_PHY_CTRL_DATA_LOC 0
+#define PCIE_PHY_CTRL_CAP_ADR_LOC 16
+#define PCIE_PHY_CTRL_CAP_DAT_LOC 17
+#define PCIE_PHY_CTRL_WR_LOC 18
+#define PCIE_PHY_CTRL_RD_LOC 19
+
+#define PCIE_PHY_STAT (PL_OFFSET + 0x110)
+#define PCIE_PHY_STAT_DATA_LOC 0
+#define PCIE_PHY_STAT_ACK_LOC 16
+
+/* PHY registers (not memory-mapped) */
+#define PCIE_PHY_RX_ASIC_OUT 0x100D
+
+#define PHY_RX_OVRD_IN_LO 0x1005
+#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
+#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
+
+#define PCIE_PHY_PUP_REQ (1 << 7)
+
+/* iATU registers */
+#define PCIE_ATU_VIEWPORT 0x900
+#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
+#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
+#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
+#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
+#define PCIE_ATU_CR1 0x904
+#define PCIE_ATU_TYPE_MEM (0x0 << 0)
+#define PCIE_ATU_TYPE_IO (0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
+#define PCIE_ATU_CR2 0x908
+#define PCIE_ATU_ENABLE (0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
+#define PCIE_ATU_LOWER_BASE 0x90C
+#define PCIE_ATU_UPPER_BASE 0x910
+#define PCIE_ATU_LIMIT 0x914
+#define PCIE_ATU_LOWER_TARGET 0x918
+#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
+#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
+#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
+#define PCIE_ATU_UPPER_TARGET 0x91C
+
+struct imx_pcie_priv {
+ void __iomem *dbi_base;
+ void __iomem *cfg_base;
+};
+
+/*
+ * PHY access functions
+ */
+static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
+{
+ u32 val;
+ u32 max_iterations = 10;
+ u32 wait_counter = 0;
+
+ do {
+ val = readl(dbi_base + PCIE_PHY_STAT);
+ val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1;
+ wait_counter++;
+
+ if (val == exp_val)
+ return 0;
+
+ udelay(1);
+ } while (wait_counter < max_iterations);
+
+ return -ETIMEDOUT;
+}
+
+static int pcie_phy_wait_ack(void __iomem *dbi_base, int addr)
+{
+ u32 val;
+ int ret;
+
+ val = addr << PCIE_PHY_CTRL_DATA_LOC;
+ writel(val, dbi_base + PCIE_PHY_CTRL);
+
+ val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC);
+ writel(val, dbi_base + PCIE_PHY_CTRL);
+
+ ret = pcie_phy_poll_ack(dbi_base, 1);
+ if (ret)
+ return ret;
+
+ val = addr << PCIE_PHY_CTRL_DATA_LOC;
+ writel(val, dbi_base + PCIE_PHY_CTRL);
+
+ ret = pcie_phy_poll_ack(dbi_base, 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */
+static int pcie_phy_read(void __iomem *dbi_base, int addr , int *data)
+{
+ u32 val, phy_ctl;
+ int ret;
+
+ ret = pcie_phy_wait_ack(dbi_base, addr);
+ if (ret)
+ return ret;
+
+ /* assert Read signal */
+ phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC;
+ writel(phy_ctl, dbi_base + PCIE_PHY_CTRL);
+
+ ret = pcie_phy_poll_ack(dbi_base, 1);
+ if (ret)
+ return ret;
+
+ val = readl(dbi_base + PCIE_PHY_STAT);
+ *data = val & 0xffff;
+
+ /* deassert Read signal */
+ writel(0x00, dbi_base + PCIE_PHY_CTRL);
+
+ ret = pcie_phy_poll_ack(dbi_base, 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int pcie_phy_write(void __iomem *dbi_base, int addr, int data)
+{
+ u32 var;
+ int ret;
+
+ /* write addr */
+ /* cap addr */
+ ret = pcie_phy_wait_ack(dbi_base, addr);
+ if (ret)
+ return ret;
+
+ var = data << PCIE_PHY_CTRL_DATA_LOC;
+ writel(var, dbi_base + PCIE_PHY_CTRL);
+
+ /* capture data */
+ var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC);
+ writel(var, dbi_base + PCIE_PHY_CTRL);
+
+ ret = pcie_phy_poll_ack(dbi_base, 1);
+ if (ret)
+ return ret;
+
+ /* deassert cap data */
+ var = data << PCIE_PHY_CTRL_DATA_LOC;
+ writel(var, dbi_base + PCIE_PHY_CTRL);
+
+ /* wait for ack de-assertion */
+ ret = pcie_phy_poll_ack(dbi_base, 0);
+ if (ret)
+ return ret;
+
+ /* assert wr signal */
+ var = 0x1 << PCIE_PHY_CTRL_WR_LOC;
+ writel(var, dbi_base + PCIE_PHY_CTRL);
+
+ /* wait for ack */
+ ret = pcie_phy_poll_ack(dbi_base, 1);
+ if (ret)
+ return ret;
+
+ /* deassert wr signal */
+ var = data << PCIE_PHY_CTRL_DATA_LOC;
+ writel(var, dbi_base + PCIE_PHY_CTRL);
+
+ /* wait for ack de-assertion */
+ ret = pcie_phy_poll_ack(dbi_base, 0);
+ if (ret)
+ return ret;
+
+ writel(0x0, dbi_base + PCIE_PHY_CTRL);
+
+ return 0;
+}
+
+static int imx6_pcie_link_up(struct imx_pcie_priv *priv)
+{
+ u32 rc, ltssm;
+ int rx_valid, temp;
+
+ /* link is debug bit 36, debug register 1 starts at bit 32 */
+ rc = readl(priv->dbi_base + PCIE_PHY_DEBUG_R1);
+ if ((rc & PCIE_PHY_DEBUG_R1_LINK_UP) &&
+ !(rc & PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING))
+ return -EAGAIN;
+
+ /*
+ * From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
+ * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
+ * If (MAC/LTSSM.state == Recovery.RcvrLock)
+ * && (PHY/rx_valid==0) then pulse PHY/rx_reset. Transition
+ * to gen2 is stuck
+ */
+ pcie_phy_read(priv->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
+ ltssm = readl(priv->dbi_base + PCIE_PHY_DEBUG_R0) & 0x3F;
+
+ if (rx_valid & 0x01)
+ return 0;
+
+ if (ltssm != 0x0d)
+ return 0;
+
+ printf("transition to gen2 is stuck, reset PHY!\n");
+
+ pcie_phy_read(priv->dbi_base, PHY_RX_OVRD_IN_LO, &temp);
+ temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN | PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+ pcie_phy_write(priv->dbi_base, PHY_RX_OVRD_IN_LO, temp);
+
+ udelay(3000);
+
+ pcie_phy_read(priv->dbi_base, PHY_RX_OVRD_IN_LO, &temp);
+ temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN | PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+ pcie_phy_write(priv->dbi_base, PHY_RX_OVRD_IN_LO, temp);
+
+ return 0;
+}
+
+/*
+ * iATU region setup
+ */
+static int imx_pcie_regions_setup(struct imx_pcie_priv *priv)
+{
+ /*
+ * i.MX6 defines 16MB in the AXI address map for PCIe.
+ *
+ * That address space excepted the pcie registers is
+ * split and defined into different regions by iATU,
+ * with sizes and offsets as follows:
+ *
+ * 0x0100_0000 --- 0x010F_FFFF 1MB IORESOURCE_IO
+ * 0x0110_0000 --- 0x01EF_FFFF 14MB IORESOURCE_MEM
+ * 0x01F0_0000 --- 0x01FF_FFFF 1MB Cfg + Registers
+ */
+
+ /* CMD reg:I/O space, MEM space, and Bus Master Enable */
+ setbits_le32(priv->dbi_base + PCI_COMMAND,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ /* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */
+ setbits_le32(priv->dbi_base + PCI_CLASS_REVISION,
+ PCI_CLASS_BRIDGE_PCI << 16);
+
+ /* Region #0 is used for Outbound CFG space access. */
+ writel(0, priv->dbi_base + PCIE_ATU_VIEWPORT);
+
+ writel(lower_32_bits((uintptr_t)priv->cfg_base),
+ priv->dbi_base + PCIE_ATU_LOWER_BASE);
+ writel(upper_32_bits((uintptr_t)priv->cfg_base),
+ priv->dbi_base + PCIE_ATU_UPPER_BASE);
+ writel(lower_32_bits((uintptr_t)priv->cfg_base + MX6_ROOT_SIZE),
+ priv->dbi_base + PCIE_ATU_LIMIT);
+
+ writel(0, priv->dbi_base + PCIE_ATU_LOWER_TARGET);
+ writel(0, priv->dbi_base + PCIE_ATU_UPPER_TARGET);
+ writel(PCIE_ATU_TYPE_CFG0, priv->dbi_base + PCIE_ATU_CR1);
+ writel(PCIE_ATU_ENABLE, priv->dbi_base + PCIE_ATU_CR2);
+
+ return 0;
+}
+
+/*
+ * PCI Express accessors
+ */
+static void __iomem *get_bus_address(struct imx_pcie_priv *priv,
+ pci_dev_t d, int where)
+{
+ void __iomem *va_address;
+
+ /* Reconfigure Region #0 */
+ writel(0, priv->dbi_base + PCIE_ATU_VIEWPORT);
+
+ if (PCI_BUS(d) < 2)
+ writel(PCIE_ATU_TYPE_CFG0, priv->dbi_base + PCIE_ATU_CR1);
+ else
+ writel(PCIE_ATU_TYPE_CFG1, priv->dbi_base + PCIE_ATU_CR1);
+
+ if (PCI_BUS(d) == 0) {
+ va_address = priv->dbi_base;
+ } else {
+ writel(d << 8, priv->dbi_base + PCIE_ATU_LOWER_TARGET);
+ va_address = priv->cfg_base;
+ }
+
+ va_address += (where & ~0x3);
+
+ return va_address;
+}
+
+static int imx_pcie_addr_valid(pci_dev_t d)
+{
+ if ((PCI_BUS(d) == 0) && (PCI_DEV(d) > 1))
+ return -EINVAL;
+ if ((PCI_BUS(d) == 1) && (PCI_DEV(d) > 0))
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * Replace the original ARM DABT handler with a simple jump-back one.
+ *
+ * The problem here is that if we have a PCIe bridge attached to this PCIe
+ * controller, but no PCIe device is connected to the bridges' downstream
+ * port, the attempt to read/write from/to the config space will produce
+ * a DABT. This is a behavior of the controller and can not be disabled
+ * unfortuatelly.
+ *
+ * To work around the problem, we backup the current DABT handler address
+ * and replace it with our own DABT handler, which only bounces right back
+ * into the code.
+ */
+static void imx_pcie_fix_dabt_handler(bool set)
+{
+ extern uint32_t *_data_abort;
+ uint32_t *data_abort_addr = (uint32_t *)&_data_abort;
+
+ static const uint32_t data_abort_bounce_handler = 0xe25ef004;
+ uint32_t data_abort_bounce_addr = (uint32_t)&data_abort_bounce_handler;
+
+ static uint32_t data_abort_backup;
+
+ if (set) {
+ data_abort_backup = *data_abort_addr;
+ *data_abort_addr = data_abort_bounce_addr;
+ } else {
+ *data_abort_addr = data_abort_backup;
+ }
+}
+
+static int imx_pcie_read_cfg(struct imx_pcie_priv *priv, pci_dev_t d,
+ int where, u32 *val)
+{
+ void __iomem *va_address;
+ int ret;
+
+ ret = imx_pcie_addr_valid(d);
+ if (ret) {
+ *val = 0xffffffff;
+ return 0;
+ }
+
+ va_address = get_bus_address(priv, d, where);
+
+ /*
+ * Read the PCIe config space. We must replace the DABT handler
+ * here in case we got data abort from the PCIe controller, see
+ * imx_pcie_fix_dabt_handler() description. Note that writing the
+ * "val" with valid value is also imperative here as in case we
+ * did got DABT, the val would contain random value.
+ */
+ imx_pcie_fix_dabt_handler(true);
+ writel(0xffffffff, val);
+ *val = readl(va_address);
+ imx_pcie_fix_dabt_handler(false);
+
+ return 0;
+}
+
+static int imx_pcie_write_cfg(struct imx_pcie_priv *priv, pci_dev_t d,
+ int where, u32 val)
+{
+ void __iomem *va_address = NULL;
+ int ret;
+
+ ret = imx_pcie_addr_valid(d);
+ if (ret)
+ return ret;
+
+ va_address = get_bus_address(priv, d, where);
+
+ /*
+ * Write the PCIe config space. We must replace the DABT handler
+ * here in case we got data abort from the PCIe controller, see
+ * imx_pcie_fix_dabt_handler() description.
+ */
+ imx_pcie_fix_dabt_handler(true);
+ writel(val, va_address);
+ imx_pcie_fix_dabt_handler(false);
+
+ return 0;
+}
+
+/*
+ * Initial bus setup
+ */
+static int imx6_pcie_assert_core_reset(struct imx_pcie_priv *priv,
+ bool prepare_for_boot)
+{
+ struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
+
+ if (is_mx6dqp())
+ setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_PCIE_SW_RST);
+
+#if defined(CONFIG_MX6SX)
+ struct gpc *gpc_regs = (struct gpc *)GPC_BASE_ADDR;
+
+ /* SSP_EN is not used on MX6SX anymore */
+ setbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_TEST_POWERDOWN);
+ /* Force PCIe PHY reset */
+ setbits_le32(&iomuxc_regs->gpr[5], IOMUXC_GPR5_PCIE_BTNRST);
+ /* Power up PCIe PHY */
+ setbits_le32(&gpc_regs->cntr, PCIE_PHY_PUP_REQ);
+#else
+ /*
+ * If the bootloader already enabled the link we need some special
+ * handling to get the core back into a state where it is safe to
+ * touch it for configuration. As there is no dedicated reset signal
+ * wired up for MX6QDL, we need to manually force LTSSM into "detect"
+ * state before completely disabling LTSSM, which is a prerequisite
+ * for core configuration.
+ *
+ * If both LTSSM_ENABLE and REF_SSP_ENABLE are active we have a strong
+ * indication that the bootloader activated the link.
+ */
+ if ((is_mx6dq() || is_mx6sdl()) && prepare_for_boot) {
+ u32 val, gpr1, gpr12;
+
+ gpr1 = readl(&iomuxc_regs->gpr[1]);
+ gpr12 = readl(&iomuxc_regs->gpr[12]);
+ if ((gpr1 & IOMUXC_GPR1_PCIE_REF_CLK_EN) &&
+ (gpr12 & IOMUXC_GPR12_PCIE_CTL_2)) {
+ val = readl(priv->dbi_base + PCIE_PL_PFLR);
+ val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
+ val |= PCIE_PL_PFLR_FORCE_LINK;
+
+ imx_pcie_fix_dabt_handler(true);
+ writel(val, priv->dbi_base + PCIE_PL_PFLR);
+ imx_pcie_fix_dabt_handler(false);
+
+ gpr12 &= ~IOMUXC_GPR12_PCIE_CTL_2;
+ writel(val, &iomuxc_regs->gpr[12]);
+ }
+ }
+ setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN);
+ clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_REF_SSP_EN);
+#endif
+
+ return 0;
+}
+
+static int imx6_pcie_init_phy(void)
+{
+ struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
+
+ clrbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_APPS_LTSSM_ENABLE);
+
+ clrsetbits_le32(&iomuxc_regs->gpr[12],
+ IOMUXC_GPR12_DEVICE_TYPE_MASK,
+ IOMUXC_GPR12_DEVICE_TYPE_RC);
+ clrsetbits_le32(&iomuxc_regs->gpr[12],
+ IOMUXC_GPR12_LOS_LEVEL_MASK,
+ IOMUXC_GPR12_LOS_LEVEL_9);
+
+#ifdef CONFIG_MX6SX
+ clrsetbits_le32(&iomuxc_regs->gpr[12],
+ IOMUXC_GPR12_RX_EQ_MASK,
+ IOMUXC_GPR12_RX_EQ_2);
+#endif
+
+ writel((0x0 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN1_OFFSET) |
+ (0x0 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB_OFFSET) |
+ (20 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_6DB_OFFSET) |
+ (127 << IOMUXC_GPR8_PCS_TX_SWING_FULL_OFFSET) |
+ (127 << IOMUXC_GPR8_PCS_TX_SWING_LOW_OFFSET),
+ &iomuxc_regs->gpr[8]);
+
+ return 0;
+}
+
+__weak int imx6_pcie_toggle_power(void)
+{
+#ifdef CONFIG_PCIE_IMX_POWER_GPIO
+ gpio_request(CONFIG_PCIE_IMX_POWER_GPIO, "pcie_power");
+ gpio_direction_output(CONFIG_PCIE_IMX_POWER_GPIO, 0);
+ mdelay(20);
+ gpio_set_value(CONFIG_PCIE_IMX_POWER_GPIO, 1);
+ mdelay(20);
+ gpio_free(CONFIG_PCIE_IMX_POWER_GPIO);
+#endif
+ return 0;
+}
+
+__weak int imx6_pcie_toggle_reset(void)
+{
+ /*
+ * See 'PCI EXPRESS BASE SPECIFICATION, REV 3.0, SECTION 6.6.1'
+ * for detailed understanding of the PCIe CR reset logic.
+ *
+ * The PCIe #PERST reset line _MUST_ be connected, otherwise your
+ * design does not conform to the specification. You must wait at
+ * least 20 ms after de-asserting the #PERST so the EP device can
+ * do self-initialisation.
+ *
+ * In case your #PERST pin is connected to a plain GPIO pin of the
+ * CPU, you can define CONFIG_PCIE_IMX_PERST_GPIO in your board's
+ * configuration file and the condition below will handle the rest
+ * of the reset toggling.
+ *
+ * In case your #PERST toggling logic is more complex, for example
+ * connected via CPLD or somesuch, you can override this function
+ * in your board file and implement reset logic as needed. You must
+ * not forget to wait at least 20 ms after de-asserting #PERST in
+ * this case either though.
+ *
+ * In case your #PERST line of the PCIe EP device is not connected
+ * at all, your design is broken and you should fix your design,
+ * otherwise you will observe problems like for example the link
+ * not coming up after rebooting the system back from running Linux
+ * that uses the PCIe as well OR the PCIe link might not come up in
+ * Linux at all in the first place since it's in some non-reset
+ * state due to being previously used in U-Boot.
+ */
+#ifdef CONFIG_PCIE_IMX_PERST_GPIO
+ gpio_request(CONFIG_PCIE_IMX_PERST_GPIO, "pcie_reset");
+ gpio_direction_output(CONFIG_PCIE_IMX_PERST_GPIO, 0);
+ mdelay(20);
+ gpio_set_value(CONFIG_PCIE_IMX_PERST_GPIO, 1);
+ mdelay(20);
+ gpio_free(CONFIG_PCIE_IMX_PERST_GPIO);
+#else
+ puts("WARNING: Make sure the PCIe #PERST line is connected!\n");
+#endif
+ return 0;
+}
+
+static int imx6_pcie_deassert_core_reset(void)
+{
+ struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
+
+ imx6_pcie_toggle_power();
+
+ enable_pcie_clock();
+
+ if (is_mx6dqp())
+ clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_PCIE_SW_RST);
+
+ /*
+ * Wait for the clock to settle a bit, when the clock are sourced
+ * from the CPU, we need about 30 ms to settle.
+ */
+ mdelay(50);
+
+#if defined(CONFIG_MX6SX)
+ /* SSP_EN is not used on MX6SX anymore */
+ clrbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_TEST_POWERDOWN);
+ /* Clear PCIe PHY reset bit */
+ clrbits_le32(&iomuxc_regs->gpr[5], IOMUXC_GPR5_PCIE_BTNRST);
+#else
+ /* Enable PCIe */
+ clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN);
+ setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_REF_SSP_EN);
+#endif
+
+ imx6_pcie_toggle_reset();
+
+ return 0;
+}
+
+static int imx_pcie_link_up(struct imx_pcie_priv *priv)
+{
+ struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
+ uint32_t tmp;
+ int count = 0;
+
+ imx6_pcie_assert_core_reset(priv, false);
+ imx6_pcie_init_phy();
+ imx6_pcie_deassert_core_reset();
+
+ imx_pcie_regions_setup(priv);
+
+ /*
+ * By default, the subordinate is set equally to the secondary
+ * bus (0x01) when the RC boots.
+ * This means that theoretically, only bus 1 is reachable from the RC.
+ * Force the PCIe RC subordinate to 0xff, otherwise no downstream
+ * devices will be detected if the enumeration is applied strictly.
+ */
+ tmp = readl(priv->dbi_base + 0x18);
+ tmp |= (0xff << 16);
+ writel(tmp, priv->dbi_base + 0x18);
+
+ /*
+ * FIXME: Force the PCIe RC to Gen1 operation
+ * The RC must be forced into Gen1 mode before bringing the link
+ * up, otherwise no downstream devices are detected. After the
+ * link is up, a managed Gen1->Gen2 transition can be initiated.
+ */
+ tmp = readl(priv->dbi_base + 0x7c);
+ tmp &= ~0xf;
+ tmp |= 0x1;
+ writel(tmp, priv->dbi_base + 0x7c);
+
+ /* LTSSM enable, starting link. */
+ setbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_APPS_LTSSM_ENABLE);
+
+ while (!imx6_pcie_link_up(priv)) {
+ udelay(10);
+ count++;
+ if (count >= 4000) {
+#ifdef CONFIG_PCI_SCAN_SHOW
+ puts("PCI: pcie phy link never came up\n");
+#endif
+ debug("DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
+ readl(priv->dbi_base + PCIE_PHY_DEBUG_R0),
+ readl(priv->dbi_base + PCIE_PHY_DEBUG_R1));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_PCI)
+static struct imx_pcie_priv imx_pcie_priv = {
+ .dbi_base = (void __iomem *)MX6_DBI_ADDR,
+ .cfg_base = (void __iomem *)MX6_ROOT_ADDR,
+};
+
+static struct imx_pcie_priv *priv = &imx_pcie_priv;
+
+static int imx_pcie_read_config(struct pci_controller *hose, pci_dev_t d,
+ int where, u32 *val)
+{
+ struct imx_pcie_priv *priv = hose->priv_data;
+
+ return imx_pcie_read_cfg(priv, d, where, val);
+}
+
+static int imx_pcie_write_config(struct pci_controller *hose, pci_dev_t d,
+ int where, u32 val)
+{
+ struct imx_pcie_priv *priv = hose->priv_data;
+
+ return imx_pcie_write_cfg(priv, d, where, val);
+}
+
+void imx_pcie_init(void)
+{
+ /* Static instance of the controller. */
+ static struct pci_controller pcc;
+ struct pci_controller *hose = &pcc;
+ int ret;
+
+ memset(&pcc, 0, sizeof(pcc));
+
+ hose->priv_data = priv;
+
+ /* PCI I/O space */
+ pci_set_region(&hose->regions[0],
+ MX6_IO_ADDR, MX6_IO_ADDR,
+ MX6_IO_SIZE, PCI_REGION_IO);
+
+ /* PCI memory space */
+ pci_set_region(&hose->regions[1],
+ MX6_MEM_ADDR, MX6_MEM_ADDR,
+ MX6_MEM_SIZE, PCI_REGION_MEM);
+
+ /* System memory space */
+ pci_set_region(&hose->regions[2],
+ MMDC0_ARB_BASE_ADDR, MMDC0_ARB_BASE_ADDR,
+ 0xefffffff, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ hose->region_count = 3;
+
+ pci_set_ops(hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ imx_pcie_read_config,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ imx_pcie_write_config);
+
+ /* Start the controller. */
+ ret = imx_pcie_link_up(priv);
+
+ if (!ret) {
+ pci_register_hose(hose);
+ hose->last_busno = pci_hose_scan(hose);
+ }
+}
+
+void imx_pcie_remove(void)
+{
+ imx6_pcie_assert_core_reset(priv, true);
+}
+
+/* Probe function. */
+void pci_init_board(void)
+{
+ imx_pcie_init();
+}
+#else
+static int imx_pcie_dm_read_config(const struct udevice *dev, pci_dev_t bdf,
+ uint offset, ulong *value,
+ enum pci_size_t size)
+{
+ struct imx_pcie_priv *priv = dev_get_priv(dev);
+ u32 tmpval;
+ int ret;
+
+ ret = imx_pcie_read_cfg(priv, bdf, offset, &tmpval);
+ if (ret)
+ return ret;
+
+ *value = pci_conv_32_to_size(tmpval, offset, size);
+ return 0;
+}
+
+static int imx_pcie_dm_write_config(struct udevice *dev, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct imx_pcie_priv *priv = dev_get_priv(dev);
+ u32 tmpval, newval;
+ int ret;
+
+ ret = imx_pcie_read_cfg(priv, bdf, offset, &tmpval);
+ if (ret)
+ return ret;
+
+ newval = pci_conv_size_to_32(tmpval, value, offset, size);
+ return imx_pcie_write_cfg(priv, bdf, offset, newval);
+}
+
+static int imx_pcie_dm_probe(struct udevice *dev)
+{
+ struct imx_pcie_priv *priv = dev_get_priv(dev);
+
+ return imx_pcie_link_up(priv);
+}
+
+static int imx_pcie_dm_remove(struct udevice *dev)
+{
+ struct imx_pcie_priv *priv = dev_get_priv(dev);
+
+ imx6_pcie_assert_core_reset(priv, true);
+
+ return 0;
+}
+
+static int imx_pcie_of_to_plat(struct udevice *dev)
+{
+ struct imx_pcie_priv *priv = dev_get_priv(dev);
+
+ priv->dbi_base = (void __iomem *)devfdt_get_addr_index(dev, 0);
+ priv->cfg_base = (void __iomem *)devfdt_get_addr_index(dev, 1);
+ if (!priv->dbi_base || !priv->cfg_base)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct dm_pci_ops imx_pcie_ops = {
+ .read_config = imx_pcie_dm_read_config,
+ .write_config = imx_pcie_dm_write_config,
+};
+
+static const struct udevice_id imx_pcie_ids[] = {
+ { .compatible = "fsl,imx6q-pcie" },
+ { .compatible = "fsl,imx6sx-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(imx_pcie) = {
+ .name = "imx_pcie",
+ .id = UCLASS_PCI,
+ .of_match = imx_pcie_ids,
+ .ops = &imx_pcie_ops,
+ .probe = imx_pcie_dm_probe,
+ .remove = imx_pcie_dm_remove,
+ .of_to_plat = imx_pcie_of_to_plat,
+ .priv_auto = sizeof(struct imx_pcie_priv),
+ .flags = DM_FLAG_OS_PREPARE,
+};
+#endif
diff --git a/roms/u-boot/drivers/pci/pcie_intel_fpga.c b/roms/u-boot/drivers/pci/pcie_intel_fpga.c
new file mode 100644
index 000000000..60195cfe1
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_intel_fpga.c
@@ -0,0 +1,435 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel FPGA PCIe host controller driver
+ *
+ * Copyright (C) 2013-2018 Intel Corporation. All rights reserved
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#define RP_TX_REG0 0x2000
+#define RP_TX_CNTRL 0x2004
+#define RP_TX_SOP BIT(0)
+#define RP_TX_EOP BIT(1)
+#define RP_RXCPL_STATUS 0x200C
+#define RP_RXCPL_SOP BIT(0)
+#define RP_RXCPL_EOP BIT(1)
+#define RP_RXCPL_REG 0x2008
+#define P2A_INT_STATUS 0x3060
+#define P2A_INT_STS_ALL 0xf
+#define P2A_INT_ENABLE 0x3070
+#define RP_CAP_OFFSET 0x70
+
+/* TLP configuration type 0 and 1 */
+#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */
+#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */
+#define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */
+#define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */
+#define TLP_PAYLOAD_SIZE 0x01
+#define TLP_READ_TAG 0x1d
+#define TLP_WRITE_TAG 0x10
+#define RP_DEVFN 0
+
+#define RP_CFG_ADDR(pcie, reg) \
+ ((pcie->hip_base) + (reg) + (1 << 20))
+#define RP_SECONDARY(pcie) \
+ readb(RP_CFG_ADDR(pcie, PCI_SECONDARY_BUS))
+#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn))
+
+#define TLP_CFGRD_DW0(pcie, bus) \
+ ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGRD1 \
+ : TLP_FMTTYPE_CFGRD0) << 24) | \
+ TLP_PAYLOAD_SIZE)
+
+#define TLP_CFGWR_DW0(pcie, bus) \
+ ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGWR1 \
+ : TLP_FMTTYPE_CFGWR0) << 24) | \
+ TLP_PAYLOAD_SIZE)
+
+#define TLP_CFG_DW1(pcie, tag, be) \
+ (((TLP_REQ_ID(pcie->first_busno, RP_DEVFN)) << 16) | (tag << 8) | (be))
+#define TLP_CFG_DW2(bus, dev, fn, offset) \
+ (((bus) << 24) | ((dev) << 19) | ((fn) << 16) | (offset))
+
+#define TLP_COMP_STATUS(s) (((s) >> 13) & 7)
+#define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff)
+#define TLP_HDR_SIZE 3
+#define TLP_LOOP 20000
+#define DWORD_MASK 3
+
+#define IS_ROOT_PORT(pcie, bdf) \
+ ((PCI_BUS(bdf) == pcie->first_busno) ? true : false)
+
+/**
+ * struct intel_fpga_pcie - Intel FPGA PCIe controller state
+ * @bus: Pointer to the PCI bus
+ * @cra_base: The base address of CRA register space
+ * @hip_base: The base address of Rootport configuration space
+ * @first_busno: This driver supports multiple PCIe controllers.
+ * first_busno stores the bus number of the PCIe root-port
+ * number which may vary depending on the PCIe setup.
+ */
+struct intel_fpga_pcie {
+ struct udevice *bus;
+ void __iomem *cra_base;
+ void __iomem *hip_base;
+ int first_busno;
+};
+
+/**
+ * Intel FPGA PCIe port uses BAR0 of RC's configuration space as the
+ * translation from PCI bus to native BUS. Entire DDR region is mapped
+ * into PCIe space using these registers, so it can be reached by DMA from
+ * EP devices.
+ * The BAR0 of bridge should be hidden during enumeration to avoid the
+ * sizing and resource allocation by PCIe core.
+ */
+static bool intel_fpga_pcie_hide_rc_bar(struct intel_fpga_pcie *pcie,
+ pci_dev_t bdf, int offset)
+{
+ if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) == 0 &&
+ PCI_FUNC(bdf) == 0 && offset == PCI_BASE_ADDRESS_0)
+ return true;
+
+ return false;
+}
+
+static inline void cra_writel(struct intel_fpga_pcie *pcie, const u32 value,
+ const u32 reg)
+{
+ writel(value, pcie->cra_base + reg);
+}
+
+static inline u32 cra_readl(struct intel_fpga_pcie *pcie, const u32 reg)
+{
+ return readl(pcie->cra_base + reg);
+}
+
+static bool intel_fpga_pcie_link_up(struct intel_fpga_pcie *pcie)
+{
+ return !!(readw(RP_CFG_ADDR(pcie, RP_CAP_OFFSET + PCI_EXP_LNKSTA))
+ & PCI_EXP_LNKSTA_DLLLA);
+}
+
+static bool intel_fpga_pcie_addr_valid(struct intel_fpga_pcie *pcie,
+ pci_dev_t bdf)
+{
+ /* If there is no link, then there is no device */
+ if (!IS_ROOT_PORT(pcie, bdf) && !intel_fpga_pcie_link_up(pcie))
+ return false;
+
+ /* access only one slot on each root port */
+ if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) > 0)
+ return false;
+
+ if ((PCI_BUS(bdf) == pcie->first_busno + 1) && PCI_DEV(bdf) > 0)
+ return false;
+
+ return true;
+}
+
+static void tlp_write_tx(struct intel_fpga_pcie *pcie, u32 reg0, u32 ctrl)
+{
+ cra_writel(pcie, reg0, RP_TX_REG0);
+ cra_writel(pcie, ctrl, RP_TX_CNTRL);
+}
+
+static int tlp_read_packet(struct intel_fpga_pcie *pcie, u32 *value)
+{
+ int i;
+ u32 ctrl;
+ u32 comp_status;
+ u32 dw[4];
+ u32 count = 0;
+
+ for (i = 0; i < TLP_LOOP; i++) {
+ ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
+ if (!(ctrl & RP_RXCPL_SOP))
+ continue;
+
+ /* read first DW */
+ dw[count++] = cra_readl(pcie, RP_RXCPL_REG);
+
+ /* Poll for EOP */
+ for (i = 0; i < TLP_LOOP; i++) {
+ ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
+ dw[count++] = cra_readl(pcie, RP_RXCPL_REG);
+ if (ctrl & RP_RXCPL_EOP) {
+ comp_status = TLP_COMP_STATUS(dw[1]);
+ if (comp_status) {
+ *value = pci_get_ff(PCI_SIZE_32);
+ return 0;
+ }
+
+ if (value &&
+ TLP_BYTE_COUNT(dw[1]) == sizeof(u32) &&
+ count >= 3)
+ *value = dw[3];
+
+ return 0;
+ }
+ }
+
+ udelay(5);
+ }
+
+ dev_err(pcie->dev, "read TLP packet timed out\n");
+ return -ENODEV;
+}
+
+static void tlp_write_packet(struct intel_fpga_pcie *pcie, u32 *headers,
+ u32 data)
+{
+ tlp_write_tx(pcie, headers[0], RP_TX_SOP);
+
+ tlp_write_tx(pcie, headers[1], 0);
+
+ tlp_write_tx(pcie, headers[2], 0);
+
+ tlp_write_tx(pcie, data, RP_TX_EOP);
+}
+
+static int tlp_cfg_dword_read(struct intel_fpga_pcie *pcie, pci_dev_t bdf,
+ int offset, u8 byte_en, u32 *value)
+{
+ u32 headers[TLP_HDR_SIZE];
+ u8 busno = PCI_BUS(bdf);
+
+ headers[0] = TLP_CFGRD_DW0(pcie, busno);
+ headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en);
+ headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
+
+ tlp_write_packet(pcie, headers, 0);
+
+ return tlp_read_packet(pcie, value);
+}
+
+static int tlp_cfg_dword_write(struct intel_fpga_pcie *pcie, pci_dev_t bdf,
+ int offset, u8 byte_en, u32 value)
+{
+ u32 headers[TLP_HDR_SIZE];
+ u8 busno = PCI_BUS(bdf);
+
+ headers[0] = TLP_CFGWR_DW0(pcie, busno);
+ headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en);
+ headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
+
+ tlp_write_packet(pcie, headers, value);
+
+ return tlp_read_packet(pcie, NULL);
+}
+
+int intel_fpga_rp_conf_addr(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, void **paddress)
+{
+ struct intel_fpga_pcie *pcie = dev_get_priv(bus);
+
+ *paddress = RP_CFG_ADDR(pcie, offset);
+
+ return 0;
+}
+
+static int intel_fpga_pcie_rp_rd_conf(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_read_config(bus, intel_fpga_rp_conf_addr,
+ bdf, offset, valuep, size);
+}
+
+static int intel_fpga_pcie_rp_wr_conf(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ int ret;
+ struct intel_fpga_pcie *pcie = dev_get_priv(bus);
+
+ ret = pci_generic_mmap_write_config(bus, intel_fpga_rp_conf_addr,
+ bdf, offset, value, size);
+ if (!ret) {
+ /* Monitor changes to PCI_PRIMARY_BUS register on root port
+ * and update local copy of root bus number accordingly.
+ */
+ if (offset == PCI_PRIMARY_BUS)
+ pcie->first_busno = (u8)(value);
+ }
+
+ return ret;
+}
+
+static u8 pcie_get_byte_en(uint offset, enum pci_size_t size)
+{
+ switch (size) {
+ case PCI_SIZE_8:
+ return 1 << (offset & 3);
+ case PCI_SIZE_16:
+ return 3 << (offset & 3);
+ default:
+ return 0xf;
+ }
+}
+
+static int _pcie_intel_fpga_read_config(struct intel_fpga_pcie *pcie,
+ pci_dev_t bdf, uint offset,
+ ulong *valuep, enum pci_size_t size)
+{
+ int ret;
+ u32 data;
+ u8 byte_en;
+
+ /* Uses memory mapped method to read rootport config registers */
+ if (IS_ROOT_PORT(pcie, bdf))
+ return intel_fpga_pcie_rp_rd_conf(pcie->bus, bdf,
+ offset, valuep, size);
+
+ byte_en = pcie_get_byte_en(offset, size);
+ ret = tlp_cfg_dword_read(pcie, bdf, offset & ~DWORD_MASK,
+ byte_en, &data);
+ if (ret)
+ return ret;
+
+ dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n",
+ offset, size, data);
+ *valuep = pci_conv_32_to_size(data, offset, size);
+
+ return 0;
+}
+
+static int _pcie_intel_fpga_write_config(struct intel_fpga_pcie *pcie,
+ pci_dev_t bdf, uint offset,
+ ulong value, enum pci_size_t size)
+{
+ u32 data;
+ u8 byte_en;
+
+ dev_dbg(pcie->dev, "PCIE CFG write: (b.d.f)=(%02d.%02d.%02d)\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n",
+ offset, size, value);
+
+ /* Uses memory mapped method to read rootport config registers */
+ if (IS_ROOT_PORT(pcie, bdf))
+ return intel_fpga_pcie_rp_wr_conf(pcie->bus, bdf, offset,
+ value, size);
+
+ byte_en = pcie_get_byte_en(offset, size);
+ data = pci_conv_size_to_32(0, value, offset, size);
+
+ return tlp_cfg_dword_write(pcie, bdf, offset & ~DWORD_MASK,
+ byte_en, data);
+}
+
+static int pcie_intel_fpga_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct intel_fpga_pcie *pcie = dev_get_priv(bus);
+
+ dev_dbg(pcie->dev, "PCIE CFG read: (b.d.f)=(%02d.%02d.%02d)\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) {
+ *valuep = (u32)pci_get_ff(size);
+ return 0;
+ }
+
+ if (!intel_fpga_pcie_addr_valid(pcie, bdf)) {
+ *valuep = (u32)pci_get_ff(size);
+ return 0;
+ }
+
+ return _pcie_intel_fpga_read_config(pcie, bdf, offset, valuep, size);
+}
+
+static int pcie_intel_fpga_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct intel_fpga_pcie *pcie = dev_get_priv(bus);
+
+ if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset))
+ return 0;
+
+ if (!intel_fpga_pcie_addr_valid(pcie, bdf))
+ return 0;
+
+ return _pcie_intel_fpga_write_config(pcie, bdf, offset, value,
+ size);
+}
+
+static int pcie_intel_fpga_probe(struct udevice *dev)
+{
+ struct intel_fpga_pcie *pcie = dev_get_priv(dev);
+
+ pcie->bus = pci_get_controller(dev);
+ pcie->first_busno = dev_seq(dev);
+
+ /* clear all interrupts */
+ cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS);
+ /* disable all interrupts */
+ cra_writel(pcie, 0, P2A_INT_ENABLE);
+
+ return 0;
+}
+
+static int pcie_intel_fpga_of_to_plat(struct udevice *dev)
+{
+ struct intel_fpga_pcie *pcie = dev_get_priv(dev);
+ struct fdt_resource reg_res;
+ int node = dev_of_offset(dev);
+ int ret;
+
+ DECLARE_GLOBAL_DATA_PTR;
+
+ ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names",
+ "Cra", &reg_res);
+ if (ret) {
+ dev_err(dev, "resource \"Cra\" not found\n");
+ return ret;
+ }
+
+ pcie->cra_base = map_physmem(reg_res.start,
+ fdt_resource_size(&reg_res),
+ MAP_NOCACHE);
+
+ ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names",
+ "Hip", &reg_res);
+ if (ret) {
+ dev_err(dev, "resource \"Hip\" not found\n");
+ return ret;
+ }
+
+ pcie->hip_base = map_physmem(reg_res.start,
+ fdt_resource_size(&reg_res),
+ MAP_NOCACHE);
+
+ return 0;
+}
+
+static const struct dm_pci_ops pcie_intel_fpga_ops = {
+ .read_config = pcie_intel_fpga_read_config,
+ .write_config = pcie_intel_fpga_write_config,
+};
+
+static const struct udevice_id pcie_intel_fpga_ids[] = {
+ { .compatible = "altr,pcie-root-port-2.0" },
+ {},
+};
+
+U_BOOT_DRIVER(pcie_intel_fpga) = {
+ .name = "pcie_intel_fpga",
+ .id = UCLASS_PCI,
+ .of_match = pcie_intel_fpga_ids,
+ .ops = &pcie_intel_fpga_ops,
+ .of_to_plat = pcie_intel_fpga_of_to_plat,
+ .probe = pcie_intel_fpga_probe,
+ .priv_auto = sizeof(struct intel_fpga_pcie),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_iproc.c b/roms/u-boot/drivers/pci/pcie_iproc.c
new file mode 100644
index 000000000..12ce9d525
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_iproc.c
@@ -0,0 +1,1287 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Broadcom
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <pci.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/log2.h>
+
+#define EP_PERST_SOURCE_SELECT_SHIFT 2
+#define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT)
+#define EP_MODE_SURVIVE_PERST_SHIFT 1
+#define EP_MODE_SURVIVE_PERST BIT(EP_MODE_SURVIVE_PERST_SHIFT)
+#define RC_PCIE_RST_OUTPUT_SHIFT 0
+#define RC_PCIE_RST_OUTPUT BIT(RC_PCIE_RST_OUTPUT_SHIFT)
+
+#define CFG_IND_ADDR_MASK 0x00001ffc
+
+#define CFG_ADDR_BUS_NUM_SHIFT 20
+#define CFG_ADDR_BUS_NUM_MASK 0x0ff00000
+#define CFG_ADDR_DEV_NUM_SHIFT 15
+#define CFG_ADDR_DEV_NUM_MASK 0x000f8000
+#define CFG_ADDR_FUNC_NUM_SHIFT 12
+#define CFG_ADDR_FUNC_NUM_MASK 0x00007000
+#define CFG_ADDR_REG_NUM_SHIFT 2
+#define CFG_ADDR_REG_NUM_MASK 0x00000ffc
+#define CFG_ADDR_CFG_TYPE_SHIFT 0
+#define CFG_ADDR_CFG_TYPE_MASK 0x00000003
+
+#define IPROC_PCI_PM_CAP 0x48
+#define IPROC_PCI_PM_CAP_MASK 0xffff
+#define IPROC_PCI_EXP_CAP 0xac
+
+#define IPROC_PCIE_REG_INVALID 0xffff
+
+#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */
+#define PCI_EXP_RTCTL 28 /* Root Control */
+/* CRS Software Visibility capability */
+#define PCI_EXP_RTCAP_CRSVIS 0x0001
+
+#define PCI_EXP_LNKSTA 18 /* Link Status */
+#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Negotiated Link Width */
+
+#define PCIE_PHYLINKUP_SHIFT 3
+#define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT)
+#define PCIE_DL_ACTIVE_SHIFT 2
+#define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT)
+
+/* derive the enum index of the outbound/inbound mapping registers */
+#define MAP_REG(base_reg, index) ((base_reg) + (index) * 2)
+
+/*
+ * Maximum number of outbound mapping window sizes that can be supported by any
+ * OARR/OMAP mapping pair
+ */
+#define MAX_NUM_OB_WINDOW_SIZES 4
+
+#define OARR_VALID_SHIFT 0
+#define OARR_VALID BIT(OARR_VALID_SHIFT)
+#define OARR_SIZE_CFG_SHIFT 1
+
+/*
+ * Maximum number of inbound mapping region sizes that can be supported by an
+ * IARR
+ */
+#define MAX_NUM_IB_REGION_SIZES 9
+
+#define IMAP_VALID_SHIFT 0
+#define IMAP_VALID BIT(IMAP_VALID_SHIFT)
+
+#define APB_ERR_EN_SHIFT 0
+#define APB_ERR_EN BIT(APB_ERR_EN_SHIFT)
+
+/**
+ * iProc PCIe host registers
+ */
+enum iproc_pcie_reg {
+ /* clock/reset signal control */
+ IPROC_PCIE_CLK_CTRL = 0,
+
+ /*
+ * To allow MSI to be steered to an external MSI controller (e.g., ARM
+ * GICv3 ITS)
+ */
+ IPROC_PCIE_MSI_GIC_MODE,
+
+ /*
+ * IPROC_PCIE_MSI_BASE_ADDR and IPROC_PCIE_MSI_WINDOW_SIZE define the
+ * window where the MSI posted writes are written, for the writes to be
+ * interpreted as MSI writes.
+ */
+ IPROC_PCIE_MSI_BASE_ADDR,
+ IPROC_PCIE_MSI_WINDOW_SIZE,
+
+ /*
+ * To hold the address of the register where the MSI writes are
+ * programed. When ARM GICv3 ITS is used, this should be programmed
+ * with the address of the GITS_TRANSLATER register.
+ */
+ IPROC_PCIE_MSI_ADDR_LO,
+ IPROC_PCIE_MSI_ADDR_HI,
+
+ /* enable MSI */
+ IPROC_PCIE_MSI_EN_CFG,
+
+ /* allow access to root complex configuration space */
+ IPROC_PCIE_CFG_IND_ADDR,
+ IPROC_PCIE_CFG_IND_DATA,
+
+ /* allow access to device configuration space */
+ IPROC_PCIE_CFG_ADDR,
+ IPROC_PCIE_CFG_DATA,
+
+ /* enable INTx */
+ IPROC_PCIE_INTX_EN,
+ IPROC_PCIE_INTX_CSR,
+
+ /* outbound address mapping */
+ IPROC_PCIE_OARR0,
+ IPROC_PCIE_OMAP0,
+ IPROC_PCIE_OARR1,
+ IPROC_PCIE_OMAP1,
+ IPROC_PCIE_OARR2,
+ IPROC_PCIE_OMAP2,
+ IPROC_PCIE_OARR3,
+ IPROC_PCIE_OMAP3,
+
+ /* inbound address mapping */
+ IPROC_PCIE_IARR0,
+ IPROC_PCIE_IMAP0,
+ IPROC_PCIE_IARR1,
+ IPROC_PCIE_IMAP1,
+ IPROC_PCIE_IARR2,
+ IPROC_PCIE_IMAP2,
+ IPROC_PCIE_IARR3,
+ IPROC_PCIE_IMAP3,
+ IPROC_PCIE_IARR4,
+ IPROC_PCIE_IMAP4,
+
+ /* config read status */
+ IPROC_PCIE_CFG_RD_STATUS,
+
+ /* link status */
+ IPROC_PCIE_LINK_STATUS,
+
+ /* enable APB error for unsupported requests */
+ IPROC_PCIE_APB_ERR_EN,
+
+ /* Ordering Mode configuration registers */
+ IPROC_PCIE_ORDERING_CFG,
+ IPROC_PCIE_IMAP0_RO_CONTROL,
+ IPROC_PCIE_IMAP1_RO_CONTROL,
+ IPROC_PCIE_IMAP2_RO_CONTROL,
+ IPROC_PCIE_IMAP3_RO_CONTROL,
+ IPROC_PCIE_IMAP4_RO_CONTROL,
+
+ /* total number of core registers */
+ IPROC_PCIE_MAX_NUM_REG,
+};
+
+/* iProc PCIe PAXB v2 registers */
+static const u16 iproc_pcie_reg_paxb_v2[] = {
+ [IPROC_PCIE_CLK_CTRL] = 0x000,
+ [IPROC_PCIE_CFG_IND_ADDR] = 0x120,
+ [IPROC_PCIE_CFG_IND_DATA] = 0x124,
+ [IPROC_PCIE_CFG_ADDR] = 0x1f8,
+ [IPROC_PCIE_CFG_DATA] = 0x1fc,
+ [IPROC_PCIE_INTX_EN] = 0x330,
+ [IPROC_PCIE_INTX_CSR] = 0x334,
+ [IPROC_PCIE_OARR0] = 0xd20,
+ [IPROC_PCIE_OMAP0] = 0xd40,
+ [IPROC_PCIE_OARR1] = 0xd28,
+ [IPROC_PCIE_OMAP1] = 0xd48,
+ [IPROC_PCIE_OARR2] = 0xd60,
+ [IPROC_PCIE_OMAP2] = 0xd68,
+ [IPROC_PCIE_OARR3] = 0xdf0,
+ [IPROC_PCIE_OMAP3] = 0xdf8,
+ [IPROC_PCIE_IARR0] = 0xd00,
+ [IPROC_PCIE_IMAP0] = 0xc00,
+ [IPROC_PCIE_IARR2] = 0xd10,
+ [IPROC_PCIE_IMAP2] = 0xcc0,
+ [IPROC_PCIE_IARR3] = 0xe00,
+ [IPROC_PCIE_IMAP3] = 0xe08,
+ [IPROC_PCIE_IARR4] = 0xe68,
+ [IPROC_PCIE_IMAP4] = 0xe70,
+ [IPROC_PCIE_CFG_RD_STATUS] = 0xee0,
+ [IPROC_PCIE_LINK_STATUS] = 0xf0c,
+ [IPROC_PCIE_APB_ERR_EN] = 0xf40,
+ [IPROC_PCIE_ORDERING_CFG] = 0x2000,
+ [IPROC_PCIE_IMAP0_RO_CONTROL] = 0x201c,
+ [IPROC_PCIE_IMAP1_RO_CONTROL] = 0x2020,
+ [IPROC_PCIE_IMAP2_RO_CONTROL] = 0x2024,
+ [IPROC_PCIE_IMAP3_RO_CONTROL] = 0x2028,
+ [IPROC_PCIE_IMAP4_RO_CONTROL] = 0x202c,
+};
+
+/* iProc PCIe PAXC v2 registers */
+static const u16 iproc_pcie_reg_paxc_v2[] = {
+ [IPROC_PCIE_MSI_GIC_MODE] = 0x050,
+ [IPROC_PCIE_MSI_BASE_ADDR] = 0x074,
+ [IPROC_PCIE_MSI_WINDOW_SIZE] = 0x078,
+ [IPROC_PCIE_MSI_ADDR_LO] = 0x07c,
+ [IPROC_PCIE_MSI_ADDR_HI] = 0x080,
+ [IPROC_PCIE_MSI_EN_CFG] = 0x09c,
+ [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0,
+ [IPROC_PCIE_CFG_IND_DATA] = 0x1f4,
+ [IPROC_PCIE_CFG_ADDR] = 0x1f8,
+ [IPROC_PCIE_CFG_DATA] = 0x1fc,
+};
+
+/**
+ * List of device IDs of controllers that have corrupted
+ * capability list that require SW fixup
+ */
+static const u16 iproc_pcie_corrupt_cap_did[] = {
+ 0x16cd,
+ 0x16f0,
+ 0xd802,
+ 0xd804
+};
+
+enum iproc_pcie_type {
+ IPROC_PCIE_PAXB_V2,
+ IPROC_PCIE_PAXC,
+ IPROC_PCIE_PAXC_V2,
+};
+
+/**
+ * struct iproc_pcie_ob - iProc PCIe outbound mapping
+ *
+ * @axi_offset: offset from the AXI address to the internal address used by
+ * the iProc PCIe core
+ * @nr_windows: total number of supported outbound mapping windows
+ */
+struct iproc_pcie_ob {
+ resource_size_t axi_offset;
+ unsigned int nr_windows;
+};
+
+/**
+ * struct iproc_pcie_ib - iProc PCIe inbound mapping
+ *
+ * @nr_regions: total number of supported inbound mapping regions
+ */
+struct iproc_pcie_ib {
+ unsigned int nr_regions;
+};
+
+/**
+ * struct iproc_pcie_ob_map - outbound mapping controller specific parameters
+ *
+ * @window_sizes: list of supported outbound mapping window sizes in MB
+ * @nr_sizes: number of supported outbound mapping window sizes
+ */
+struct iproc_pcie_ob_map {
+ resource_size_t window_sizes[MAX_NUM_OB_WINDOW_SIZES];
+ unsigned int nr_sizes;
+};
+
+static const struct iproc_pcie_ob_map paxb_v2_ob_map[] = {
+ {
+ /* OARR0/OMAP0 */
+ .window_sizes = { 128, 256 },
+ .nr_sizes = 2,
+ },
+ {
+ /* OARR1/OMAP1 */
+ .window_sizes = { 128, 256 },
+ .nr_sizes = 2,
+ },
+ {
+ /* OARR2/OMAP2 */
+ .window_sizes = { 128, 256, 512, 1024 },
+ .nr_sizes = 4,
+ },
+ {
+ /* OARR3/OMAP3 */
+ .window_sizes = { 128, 256, 512, 1024 },
+ .nr_sizes = 4,
+ },
+};
+
+/**
+ * iProc PCIe inbound mapping type
+ */
+enum iproc_pcie_ib_map_type {
+ /* for DDR memory */
+ IPROC_PCIE_IB_MAP_MEM = 0,
+
+ /* for device I/O memory */
+ IPROC_PCIE_IB_MAP_IO,
+
+ /* invalid or unused */
+ IPROC_PCIE_IB_MAP_INVALID
+};
+
+/**
+ * struct iproc_pcie_ib_map - inbound mapping controller specific parameters
+ *
+ * @type: inbound mapping region type
+ * @size_unit: inbound mapping region size unit, could be SZ_1K, SZ_1M, or SZ_1G
+ * @region_sizes: list of supported inbound mapping region sizes in KB, MB, or
+ * GB, depedning on the size unit
+ * @nr_sizes: number of supported inbound mapping region sizes
+ * @nr_windows: number of supported inbound mapping windows for the region
+ * @imap_addr_offset: register offset between the upper and lower 32-bit
+ * IMAP address registers
+ * @imap_window_offset: register offset between each IMAP window
+ */
+struct iproc_pcie_ib_map {
+ enum iproc_pcie_ib_map_type type;
+ unsigned int size_unit;
+ resource_size_t region_sizes[MAX_NUM_IB_REGION_SIZES];
+ unsigned int nr_sizes;
+ unsigned int nr_windows;
+ u16 imap_addr_offset;
+ u16 imap_window_offset;
+};
+
+static const struct iproc_pcie_ib_map paxb_v2_ib_map[] = {
+ {
+ /* IARR0/IMAP0 */
+ .type = IPROC_PCIE_IB_MAP_IO,
+ .size_unit = SZ_1K,
+ .region_sizes = { 32 },
+ .nr_sizes = 1,
+ .nr_windows = 8,
+ .imap_addr_offset = 0x40,
+ .imap_window_offset = 0x4,
+ },
+ {
+ /* IARR1/IMAP1 (currently unused) */
+ .type = IPROC_PCIE_IB_MAP_INVALID,
+ },
+ {
+ /* IARR2/IMAP2 */
+ .type = IPROC_PCIE_IB_MAP_MEM,
+ .size_unit = SZ_1M,
+ .region_sizes = { 64, 128, 256, 512, 1024, 2048, 4096, 8192,
+ 16384 },
+ .nr_sizes = 9,
+ .nr_windows = 1,
+ .imap_addr_offset = 0x4,
+ .imap_window_offset = 0x8,
+ },
+ {
+ /* IARR3/IMAP3 */
+ .type = IPROC_PCIE_IB_MAP_MEM,
+ .size_unit = SZ_1G,
+ .region_sizes = { 1, 2, 4, 8, 16, 32 },
+ .nr_sizes = 6,
+ .nr_windows = 8,
+ .imap_addr_offset = 0x4,
+ .imap_window_offset = 0x8,
+ },
+ {
+ /* IARR4/IMAP4 */
+ .type = IPROC_PCIE_IB_MAP_MEM,
+ .size_unit = SZ_1G,
+ .region_sizes = { 32, 64, 128, 256, 512 },
+ .nr_sizes = 5,
+ .nr_windows = 8,
+ .imap_addr_offset = 0x4,
+ .imap_window_offset = 0x8,
+ },
+};
+
+/**
+ * struct iproc_pcie - iproc pcie device instance
+ *
+ * @dev: pointer to pcie udevice
+ * @base: device I/O base address
+ * @type: pci device type, PAXC or PAXB
+ * @reg_offsets: pointer to pcie host register
+ * @fix_paxc_cap: paxc capability
+ * @need_ob_cfg: outbound mapping status
+ * @ob: pcie outbound mapping
+ * @ob_map: pointer to outbound mapping parameters
+ * @need_ib_cfg: inbound mapping status
+ * @ib: pcie inbound mapping
+ * @ib_map: pointer to inbound mapping parameters
+ * @ep_is_internal: ep status
+ * @phy: phy device
+ * @link_is_active: link up status
+ * @has_apb_err_disable: apb error status
+ */
+struct iproc_pcie {
+ struct udevice *dev;
+ void __iomem *base;
+ enum iproc_pcie_type type;
+ u16 *reg_offsets;
+ bool fix_paxc_cap;
+ bool need_ob_cfg;
+ struct iproc_pcie_ob ob;
+ const struct iproc_pcie_ob_map *ob_map;
+ bool need_ib_cfg;
+ struct iproc_pcie_ib ib;
+ const struct iproc_pcie_ib_map *ib_map;
+ bool ep_is_internal;
+ struct phy phy;
+ bool link_is_active;
+ bool has_apb_err_disable;
+};
+
+static inline bool iproc_pcie_reg_is_invalid(u16 reg_offset)
+{
+ return !!(reg_offset == IPROC_PCIE_REG_INVALID);
+}
+
+static inline u16 iproc_pcie_reg_offset(struct iproc_pcie *pcie,
+ enum iproc_pcie_reg reg)
+{
+ return pcie->reg_offsets[reg];
+}
+
+static inline u32 iproc_pcie_read_reg(struct iproc_pcie *pcie,
+ enum iproc_pcie_reg reg)
+{
+ u16 offset = iproc_pcie_reg_offset(pcie, reg);
+
+ if (iproc_pcie_reg_is_invalid(offset))
+ return 0;
+
+ return readl(pcie->base + offset);
+}
+
+static inline void iproc_pcie_write_reg(struct iproc_pcie *pcie,
+ enum iproc_pcie_reg reg, u32 val)
+{
+ u16 offset = iproc_pcie_reg_offset(pcie, reg);
+
+ if (iproc_pcie_reg_is_invalid(offset))
+ return;
+
+ writel(val, pcie->base + offset);
+}
+
+static int iproc_pcie_map_ep_cfg_reg(const struct udevice *udev, pci_dev_t bdf,
+ uint where, void **paddress)
+{
+ struct iproc_pcie *pcie = dev_get_priv(udev);
+ unsigned int busno = PCI_BUS(bdf);
+ unsigned int slot = PCI_DEV(bdf);
+ unsigned int fn = PCI_FUNC(bdf);
+
+ u16 offset;
+ u32 val;
+
+ /* root complex access */
+ if (busno == 0) {
+ if (slot > 0 || fn > 0)
+ return -ENODEV;
+
+ iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_IND_ADDR,
+ where & CFG_IND_ADDR_MASK);
+ offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_IND_DATA);
+ if (iproc_pcie_reg_is_invalid(offset))
+ return -ENODEV;
+
+ *paddress = (pcie->base + offset);
+ return 0;
+ }
+
+ if (!pcie->link_is_active)
+ return -ENODEV;
+
+ /* EP device access */
+ val = (busno << CFG_ADDR_BUS_NUM_SHIFT) |
+ (slot << CFG_ADDR_DEV_NUM_SHIFT) |
+ (fn << CFG_ADDR_FUNC_NUM_SHIFT) |
+ (where & CFG_ADDR_REG_NUM_MASK) |
+ (1 & CFG_ADDR_CFG_TYPE_MASK);
+
+ iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_ADDR, val);
+ offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA);
+
+ if (iproc_pcie_reg_is_invalid(offset))
+ return -ENODEV;
+
+ *paddress = (pcie->base + offset);
+
+ return 0;
+}
+
+static void iproc_pcie_fix_cap(struct iproc_pcie *pcie, int where, ulong *val)
+{
+ u32 i, dev_id;
+
+ switch (where & ~0x3) {
+ case PCI_VENDOR_ID:
+ dev_id = *val >> 16;
+
+ /*
+ * Activate fixup for those controllers that have corrupted
+ * capability list registers
+ */
+ for (i = 0; i < ARRAY_SIZE(iproc_pcie_corrupt_cap_did); i++)
+ if (dev_id == iproc_pcie_corrupt_cap_did[i])
+ pcie->fix_paxc_cap = true;
+ break;
+
+ case IPROC_PCI_PM_CAP:
+ if (pcie->fix_paxc_cap) {
+ /* advertise PM, force next capability to PCIe */
+ *val &= ~IPROC_PCI_PM_CAP_MASK;
+ *val |= IPROC_PCI_EXP_CAP << 8 | PCI_CAP_ID_PM;
+ }
+ break;
+
+ case IPROC_PCI_EXP_CAP:
+ if (pcie->fix_paxc_cap) {
+ /* advertise root port, version 2, terminate here */
+ *val = (PCI_EXP_TYPE_ROOT_PORT << 4 | 2) << 16 |
+ PCI_CAP_ID_EXP;
+ }
+ break;
+
+ case IPROC_PCI_EXP_CAP + PCI_EXP_RTCTL:
+ /* Don't advertise CRS SV support */
+ *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int iproc_pci_raw_config_read32(struct iproc_pcie *pcie,
+ unsigned int devfn, int where,
+ int size, u32 *val)
+{
+ void __iomem *addr;
+ int ret;
+
+ ret = iproc_pcie_map_ep_cfg_reg(pcie->dev, devfn, where & ~0x3, &addr);
+ if (ret) {
+ *val = ~0;
+ return -EINVAL;
+ }
+
+ *val = readl(addr);
+
+ if (size <= 2)
+ *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
+
+ return 0;
+}
+
+static int iproc_pci_raw_config_write32(struct iproc_pcie *pcie,
+ unsigned int devfn, int where,
+ int size, u32 val)
+{
+ void __iomem *addr;
+ int ret;
+ u32 mask, tmp;
+
+ ret = iproc_pcie_map_ep_cfg_reg(pcie->dev, devfn, where & ~0x3, &addr);
+ if (ret)
+ return -EINVAL;
+
+ if (size == 4) {
+ writel(val, addr);
+ return 0;
+ }
+
+ mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8));
+ tmp = readl(addr) & mask;
+ tmp |= val << ((where & 0x3) * 8);
+ writel(tmp, addr);
+ return 0;
+}
+
+/**
+ * iproc_pcie_apb_err_disable() - configure apb error
+ *
+ * APB error forwarding can be disabled during access of configuration
+ * registers of the endpoint device, to prevent unsupported requests
+ * (typically seen during enumeration with multi-function devices) from
+ * triggering a system exception.
+ *
+ * @bus: pcie udevice
+ * @bdf: pdf value
+ * @disabled: flag to enable/disabled apb error
+ */
+static inline void iproc_pcie_apb_err_disable(const struct udevice *bus,
+ pci_dev_t bdf, bool disable)
+{
+ struct iproc_pcie *pcie = dev_get_priv(bus);
+ u32 val;
+
+ if (PCI_BUS(bdf) && pcie->has_apb_err_disable) {
+ val = iproc_pcie_read_reg(pcie, IPROC_PCIE_APB_ERR_EN);
+ if (disable)
+ val &= ~APB_ERR_EN;
+ else
+ val |= APB_ERR_EN;
+ iproc_pcie_write_reg(pcie, IPROC_PCIE_APB_ERR_EN, val);
+ }
+}
+
+static int iproc_pcie_config_read32(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct iproc_pcie *pcie = dev_get_priv(bus);
+ int ret;
+ ulong data;
+
+ iproc_pcie_apb_err_disable(bus, bdf, true);
+ ret = pci_generic_mmap_read_config(bus, iproc_pcie_map_ep_cfg_reg,
+ bdf, offset, &data, PCI_SIZE_32);
+ iproc_pcie_apb_err_disable(bus, bdf, false);
+ if (size <= PCI_SIZE_16)
+ *valuep = (data >> (8 * (offset & 3))) &
+ ((1 << (BIT(size) * 8)) - 1);
+ else
+ *valuep = data;
+
+ if (!ret && PCI_BUS(bdf) == 0)
+ iproc_pcie_fix_cap(pcie, offset, valuep);
+
+ return ret;
+}
+
+static int iproc_pcie_config_write32(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ void *addr;
+ ulong mask, tmp;
+ int ret;
+
+ ret = iproc_pcie_map_ep_cfg_reg(bus, bdf, offset, &addr);
+ if (ret)
+ return ret;
+
+ if (size == PCI_SIZE_32) {
+ writel(value, addr);
+ return ret;
+ }
+
+ iproc_pcie_apb_err_disable(bus, bdf, true);
+ mask = ~(((1 << (BIT(size) * 8)) - 1) << ((offset & 0x3) * 8));
+ tmp = readl(addr) & mask;
+ tmp |= (value << ((offset & 0x3) * 8));
+ writel(tmp, addr);
+ iproc_pcie_apb_err_disable(bus, bdf, false);
+
+ return ret;
+}
+
+const static struct dm_pci_ops iproc_pcie_ops = {
+ .read_config = iproc_pcie_config_read32,
+ .write_config = iproc_pcie_config_write32,
+};
+
+static int iproc_pcie_rev_init(struct iproc_pcie *pcie)
+{
+ unsigned int reg_idx;
+ const u16 *regs;
+ u16 num_elements;
+
+ switch (pcie->type) {
+ case IPROC_PCIE_PAXC_V2:
+ pcie->ep_is_internal = true;
+ regs = iproc_pcie_reg_paxc_v2;
+ num_elements = ARRAY_SIZE(iproc_pcie_reg_paxc_v2);
+ break;
+ case IPROC_PCIE_PAXB_V2:
+ regs = iproc_pcie_reg_paxb_v2;
+ num_elements = ARRAY_SIZE(iproc_pcie_reg_paxb_v2);
+ pcie->has_apb_err_disable = true;
+ if (pcie->need_ob_cfg) {
+ pcie->ob.axi_offset = 0;
+ pcie->ob_map = paxb_v2_ob_map;
+ pcie->ob.nr_windows = ARRAY_SIZE(paxb_v2_ob_map);
+ }
+ pcie->need_ib_cfg = true;
+ pcie->ib.nr_regions = ARRAY_SIZE(paxb_v2_ib_map);
+ pcie->ib_map = paxb_v2_ib_map;
+ break;
+ default:
+ dev_dbg(pcie->dev, "incompatible iProc PCIe interface\n");
+ return -EINVAL;
+ }
+
+ pcie->reg_offsets = calloc(IPROC_PCIE_MAX_NUM_REG,
+ sizeof(*pcie->reg_offsets));
+ if (!pcie->reg_offsets)
+ return -ENOMEM;
+
+ /* go through the register table and populate all valid registers */
+ pcie->reg_offsets[0] = (pcie->type == IPROC_PCIE_PAXC_V2) ?
+ IPROC_PCIE_REG_INVALID : regs[0];
+ for (reg_idx = 1; reg_idx < num_elements; reg_idx++)
+ pcie->reg_offsets[reg_idx] = regs[reg_idx] ?
+ regs[reg_idx] : IPROC_PCIE_REG_INVALID;
+
+ return 0;
+}
+
+static inline bool iproc_pcie_ob_is_valid(struct iproc_pcie *pcie,
+ int window_idx)
+{
+ u32 val;
+
+ val = iproc_pcie_read_reg(pcie, MAP_REG(IPROC_PCIE_OARR0, window_idx));
+
+ return !!(val & OARR_VALID);
+}
+
+static inline int iproc_pcie_ob_write(struct iproc_pcie *pcie, int window_idx,
+ int size_idx, u64 axi_addr, u64 pci_addr)
+{
+ u16 oarr_offset, omap_offset;
+
+ /*
+ * Derive the OARR/OMAP offset from the first pair (OARR0/OMAP0) based
+ * on window index.
+ */
+ oarr_offset = iproc_pcie_reg_offset(pcie, MAP_REG(IPROC_PCIE_OARR0,
+ window_idx));
+ omap_offset = iproc_pcie_reg_offset(pcie, MAP_REG(IPROC_PCIE_OMAP0,
+ window_idx));
+ if (iproc_pcie_reg_is_invalid(oarr_offset) ||
+ iproc_pcie_reg_is_invalid(omap_offset))
+ return -EINVAL;
+
+ /*
+ * Program the OARR registers. The upper 32-bit OARR register is
+ * always right after the lower 32-bit OARR register.
+ */
+ writel(lower_32_bits(axi_addr) | (size_idx << OARR_SIZE_CFG_SHIFT) |
+ OARR_VALID, pcie->base + oarr_offset);
+ writel(upper_32_bits(axi_addr), pcie->base + oarr_offset + 4);
+
+ /* now program the OMAP registers */
+ writel(lower_32_bits(pci_addr), pcie->base + omap_offset);
+ writel(upper_32_bits(pci_addr), pcie->base + omap_offset + 4);
+
+ debug("ob window [%d]: offset 0x%x axi %pap pci %pap\n",
+ window_idx, oarr_offset, &axi_addr, &pci_addr);
+ debug("oarr lo 0x%x oarr hi 0x%x\n",
+ readl(pcie->base + oarr_offset),
+ readl(pcie->base + oarr_offset + 4));
+ debug("omap lo 0x%x omap hi 0x%x\n",
+ readl(pcie->base + omap_offset),
+ readl(pcie->base + omap_offset + 4));
+
+ return 0;
+}
+
+/**
+ * iproc_pcie_setup_ob() - setup outbound address mapping
+ *
+ * Some iProc SoCs require the SW to configure the outbound address mapping
+ * Outbound address translation:
+ *
+ * iproc_pcie_address = axi_address - axi_offset
+ * OARR = iproc_pcie_address
+ * OMAP = pci_addr
+ * axi_addr -> iproc_pcie_address -> OARR -> OMAP -> pci_address
+ *
+ * @pcie: pcie device
+ * @axi_addr: axi address to be translated
+ * @pci_addr: pci address
+ * @size: window size
+ *
+ * @return: 0 on success and -ve on failure
+ */
+static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr,
+ u64 pci_addr, resource_size_t size)
+{
+ struct iproc_pcie_ob *ob = &pcie->ob;
+ int ret = -EINVAL, window_idx, size_idx;
+
+ if (axi_addr < ob->axi_offset) {
+ pr_err("axi address %pap less than offset %pap\n",
+ &axi_addr, &ob->axi_offset);
+ return -EINVAL;
+ }
+
+ /*
+ * Translate the AXI address to the internal address used by the iProc
+ * PCIe core before programming the OARR
+ */
+ axi_addr -= ob->axi_offset;
+
+ /* iterate through all OARR/OMAP mapping windows */
+ for (window_idx = ob->nr_windows - 1; window_idx >= 0; window_idx--) {
+ const struct iproc_pcie_ob_map *ob_map =
+ &pcie->ob_map[window_idx];
+
+ /*
+ * If current outbound window is already in use, move on to the
+ * next one.
+ */
+ if (iproc_pcie_ob_is_valid(pcie, window_idx))
+ continue;
+
+ /*
+ * Iterate through all supported window sizes within the
+ * OARR/OMAP pair to find a match. Go through the window sizes
+ * in a descending order.
+ */
+ for (size_idx = ob_map->nr_sizes - 1; size_idx >= 0;
+ size_idx--) {
+ resource_size_t window_size =
+ ob_map->window_sizes[size_idx] * SZ_1M;
+
+ /*
+ * Keep iterating until we reach the last window and
+ * with the minimal window size at index zero. In this
+ * case, we take a compromise by mapping it using the
+ * minimum window size that can be supported
+ */
+ if (size < window_size) {
+ if (size_idx > 0 || window_idx > 0)
+ continue;
+
+ /*
+ * For the corner case of reaching the minimal
+ * window size that can be supported on the
+ * last window
+ */
+ axi_addr = ALIGN_DOWN(axi_addr, window_size);
+ pci_addr = ALIGN_DOWN(pci_addr, window_size);
+ size = window_size;
+ }
+
+ if (!IS_ALIGNED(axi_addr, window_size) ||
+ !IS_ALIGNED(pci_addr, window_size)) {
+ pr_err("axi %pap or pci %pap not aligned\n",
+ &axi_addr, &pci_addr);
+ return -EINVAL;
+ }
+
+ /*
+ * Match found! Program both OARR and OMAP and mark
+ * them as a valid entry.
+ */
+ ret = iproc_pcie_ob_write(pcie, window_idx, size_idx,
+ axi_addr, pci_addr);
+ if (ret)
+ goto err_ob;
+
+ size -= window_size;
+ if (size == 0)
+ return 0;
+
+ /*
+ * If we are here, we are done with the current window,
+ * but not yet finished all mappings. Need to move on
+ * to the next window.
+ */
+ axi_addr += window_size;
+ pci_addr += window_size;
+ break;
+ }
+ }
+
+err_ob:
+ pr_err("unable to configure outbound mapping\n");
+ pr_err("axi %pap, axi offset %pap, pci %pap, res size %pap\n",
+ &axi_addr, &ob->axi_offset, &pci_addr, &size);
+
+ return ret;
+}
+
+static int iproc_pcie_map_ranges(struct udevice *dev)
+{
+ struct iproc_pcie *pcie = dev_get_priv(dev);
+ struct udevice *bus = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ int i, ret;
+
+ for (i = 0; i < hose->region_count; i++) {
+ if (hose->regions[i].flags == PCI_REGION_MEM ||
+ hose->regions[i].flags == PCI_REGION_PREFETCH) {
+ debug("%d: bus_addr %p, axi_addr %p, size 0x%lx\n",
+ i, &hose->regions[i].bus_start,
+ &hose->regions[i].phys_start,
+ hose->regions[i].size);
+ ret = iproc_pcie_setup_ob(pcie,
+ hose->regions[i].phys_start,
+ hose->regions[i].bus_start,
+ hose->regions[i].size);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static inline bool iproc_pcie_ib_is_in_use(struct iproc_pcie *pcie,
+ int region_idx)
+{
+ const struct iproc_pcie_ib_map *ib_map = &pcie->ib_map[region_idx];
+ u32 val;
+
+ val = iproc_pcie_read_reg(pcie, MAP_REG(IPROC_PCIE_IARR0, region_idx));
+
+ return !!(val & (BIT(ib_map->nr_sizes) - 1));
+}
+
+static inline bool
+iproc_pcie_ib_check_type(const struct iproc_pcie_ib_map *ib_map,
+ enum iproc_pcie_ib_map_type type)
+{
+ return !!(ib_map->type == type);
+}
+
+static int iproc_pcie_ib_write(struct iproc_pcie *pcie, int region_idx,
+ int size_idx, int nr_windows, u64 axi_addr,
+ u64 pci_addr, resource_size_t size)
+{
+ const struct iproc_pcie_ib_map *ib_map = &pcie->ib_map[region_idx];
+ u16 iarr_offset, imap_offset;
+ u32 val;
+ int window_idx;
+
+ iarr_offset = iproc_pcie_reg_offset(pcie, MAP_REG(IPROC_PCIE_IARR0,
+ region_idx));
+ imap_offset = iproc_pcie_reg_offset(pcie, MAP_REG(IPROC_PCIE_IMAP0,
+ region_idx));
+ if (iproc_pcie_reg_is_invalid(iarr_offset) ||
+ iproc_pcie_reg_is_invalid(imap_offset))
+ return -EINVAL;
+
+ debug("ib region [%d]: offset 0x%x axi %pap pci %pap\n",
+ region_idx, iarr_offset, &axi_addr, &pci_addr);
+
+ /*
+ * Program the IARR registers. The upper 32-bit IARR register is
+ * always right after the lower 32-bit IARR register.
+ */
+ writel(lower_32_bits(pci_addr) | BIT(size_idx),
+ pcie->base + iarr_offset);
+ writel(upper_32_bits(pci_addr), pcie->base + iarr_offset + 4);
+
+ debug("iarr lo 0x%x iarr hi 0x%x\n",
+ readl(pcie->base + iarr_offset),
+ readl(pcie->base + iarr_offset + 4));
+
+ /*
+ * Now program the IMAP registers. Each IARR region may have one or
+ * more IMAP windows.
+ */
+ size >>= ilog2(nr_windows);
+ for (window_idx = 0; window_idx < nr_windows; window_idx++) {
+ val = readl(pcie->base + imap_offset);
+ val |= lower_32_bits(axi_addr) | IMAP_VALID;
+ writel(val, pcie->base + imap_offset);
+ writel(upper_32_bits(axi_addr),
+ pcie->base + imap_offset + ib_map->imap_addr_offset);
+
+ debug("imap window [%d] lo 0x%x hi 0x%x\n",
+ window_idx, readl(pcie->base + imap_offset),
+ readl(pcie->base + imap_offset +
+ ib_map->imap_addr_offset));
+
+ imap_offset += ib_map->imap_window_offset;
+ axi_addr += size;
+ }
+
+ return 0;
+}
+
+/**
+ * iproc_pcie_setup_ib() - setup inbound address mapping
+ *
+ * @pcie: pcie device
+ * @axi_addr: axi address to be translated
+ * @pci_addr: pci address
+ * @size: window size
+ * @type: inbound mapping type
+ *
+ * @return: 0 on success and -ve on failure
+ */
+static int iproc_pcie_setup_ib(struct iproc_pcie *pcie, u64 axi_addr,
+ u64 pci_addr, resource_size_t size,
+ enum iproc_pcie_ib_map_type type)
+{
+ struct iproc_pcie_ib *ib = &pcie->ib;
+ int ret;
+ unsigned int region_idx, size_idx;
+
+ /* iterate through all IARR mapping regions */
+ for (region_idx = 0; region_idx < ib->nr_regions; region_idx++) {
+ const struct iproc_pcie_ib_map *ib_map =
+ &pcie->ib_map[region_idx];
+
+ /*
+ * If current inbound region is already in use or not a
+ * compatible type, move on to the next.
+ */
+ if (iproc_pcie_ib_is_in_use(pcie, region_idx) ||
+ !iproc_pcie_ib_check_type(ib_map, type))
+ continue;
+
+ /* iterate through all supported region sizes to find a match */
+ for (size_idx = 0; size_idx < ib_map->nr_sizes; size_idx++) {
+ resource_size_t region_size =
+ ib_map->region_sizes[size_idx] * ib_map->size_unit;
+
+ if (size != region_size)
+ continue;
+
+ if (!IS_ALIGNED(axi_addr, region_size) ||
+ !IS_ALIGNED(pci_addr, region_size)) {
+ pr_err("axi %pap or pci %pap not aligned\n",
+ &axi_addr, &pci_addr);
+ return -EINVAL;
+ }
+
+ /* Match found! Program IARR and all IMAP windows. */
+ ret = iproc_pcie_ib_write(pcie, region_idx, size_idx,
+ ib_map->nr_windows, axi_addr,
+ pci_addr, size);
+ if (ret)
+ goto err_ib;
+ else
+ return 0;
+ }
+ }
+ ret = -EINVAL;
+
+err_ib:
+ pr_err("unable to configure inbound mapping\n");
+ pr_err("axi %pap, pci %pap, res size %pap\n",
+ &axi_addr, &pci_addr, &size);
+
+ return ret;
+}
+
+static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
+{
+ int ret;
+ struct pci_region regions;
+ int i = 0;
+
+ while (!pci_get_dma_regions(pcie->dev, &regions, i)) {
+ dev_dbg(pcie->dev,
+ "dma %d: bus_addr %#lx, axi_addr %#llx, size %#lx\n",
+ i, regions.bus_start, regions.phys_start, regions.size);
+
+ /* Each range entry corresponds to an inbound mapping region */
+ ret = iproc_pcie_setup_ib(pcie, regions.phys_start,
+ regions.bus_start,
+ regions.size,
+ IPROC_PCIE_IB_MAP_MEM);
+ if (ret)
+ return ret;
+ i++;
+ }
+ return 0;
+}
+
+static void iproc_pcie_reset_map_regs(struct iproc_pcie *pcie)
+{
+ struct iproc_pcie_ib *ib = &pcie->ib;
+ struct iproc_pcie_ob *ob = &pcie->ob;
+ int window_idx, region_idx;
+
+ if (pcie->ep_is_internal)
+ return;
+
+ /* iterate through all OARR mapping regions */
+ for (window_idx = ob->nr_windows - 1; window_idx >= 0; window_idx--) {
+ iproc_pcie_write_reg(pcie, MAP_REG(IPROC_PCIE_OARR0,
+ window_idx), 0);
+ }
+
+ /* iterate through all IARR mapping regions */
+ for (region_idx = 0; region_idx < ib->nr_regions; region_idx++) {
+ iproc_pcie_write_reg(pcie, MAP_REG(IPROC_PCIE_IARR0,
+ region_idx), 0);
+ }
+}
+
+static void iproc_pcie_reset(struct iproc_pcie *pcie)
+{
+ u32 val;
+
+ /*
+ * PAXC and the internal emulated endpoint device downstream should not
+ * be reset. If firmware has been loaded on the endpoint device at an
+ * earlier boot stage, reset here causes issues.
+ */
+ if (pcie->ep_is_internal)
+ return;
+
+ /*
+ * Select perst_b signal as reset source. Put the device into reset,
+ * and then bring it out of reset
+ */
+ val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL);
+ val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST &
+ ~RC_PCIE_RST_OUTPUT;
+ iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val);
+ udelay(250);
+
+ val |= RC_PCIE_RST_OUTPUT;
+ iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val);
+ mdelay(100);
+}
+
+static inline bool iproc_pcie_link_is_active(struct iproc_pcie *pcie)
+{
+ u32 val;
+
+ val = iproc_pcie_read_reg(pcie, IPROC_PCIE_LINK_STATUS);
+ return !!((val & PCIE_PHYLINKUP) && (val & PCIE_DL_ACTIVE));
+}
+
+static int iproc_pcie_check_link(struct iproc_pcie *pcie)
+{
+ u32 link_status, class;
+
+ pcie->link_is_active = false;
+ /* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */
+#define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c
+#define PCI_CLASS_BRIDGE_MASK 0xffff00
+#define PCI_CLASS_BRIDGE_SHIFT 8
+ iproc_pci_raw_config_read32(pcie, 0,
+ PCI_BRIDGE_CTRL_REG_OFFSET,
+ 4, &class);
+ class &= ~PCI_CLASS_BRIDGE_MASK;
+ class |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT);
+ iproc_pci_raw_config_write32(pcie, 0,
+ PCI_BRIDGE_CTRL_REG_OFFSET,
+ 4, class);
+
+ /*
+ * PAXC connects to emulated endpoint devices directly and does not
+ * have a Serdes. Therefore skip the link detection logic here.
+ */
+ if (pcie->ep_is_internal) {
+ pcie->link_is_active = true;
+ return 0;
+ }
+
+ if (!iproc_pcie_link_is_active(pcie)) {
+ pr_err("PHY or data link is INACTIVE!\n");
+ return -ENODEV;
+ }
+
+#define PCI_TARGET_LINK_SPEED_MASK 0xf
+#define PCI_TARGET_LINK_WIDTH_MASK 0x3f
+#define PCI_TARGET_LINK_WIDTH_OFFSET 0x4
+
+ /* check link status to see if link is active */
+ iproc_pci_raw_config_read32(pcie, 0,
+ IPROC_PCI_EXP_CAP + PCI_EXP_LNKSTA,
+ 2, &link_status);
+ if (link_status & PCI_EXP_LNKSTA_NLW)
+ pcie->link_is_active = true;
+
+ if (pcie->link_is_active)
+ pr_info("link UP @ Speed Gen-%d and width-x%d\n",
+ link_status & PCI_TARGET_LINK_SPEED_MASK,
+ (link_status >> PCI_TARGET_LINK_WIDTH_OFFSET) &
+ PCI_TARGET_LINK_WIDTH_MASK);
+ else
+ pr_info("link DOWN\n");
+
+ return 0;
+}
+
+static int iproc_pcie_probe(struct udevice *dev)
+{
+ struct iproc_pcie *pcie = dev_get_priv(dev);
+ int ret;
+
+ pcie->type = (enum iproc_pcie_type)dev_get_driver_data(dev);
+ debug("PAX type %d\n", pcie->type);
+ pcie->base = dev_read_addr_ptr(dev);
+ debug("PAX reg base %p\n", pcie->base);
+
+ if (!pcie->base)
+ return -ENODEV;
+
+ if (dev_read_bool(dev, "brcm,pcie-ob"))
+ pcie->need_ob_cfg = true;
+
+ pcie->dev = dev;
+ ret = iproc_pcie_rev_init(pcie);
+ if (ret)
+ return ret;
+
+ if (!pcie->ep_is_internal) {
+ ret = generic_phy_get_by_name(dev, "pcie-phy", &pcie->phy);
+ if (!ret) {
+ ret = generic_phy_init(&pcie->phy);
+ if (ret) {
+ pr_err("failed to init %s PHY\n", dev->name);
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&pcie->phy);
+ if (ret) {
+ pr_err("power on %s PHY failed\n", dev->name);
+ goto err_exit_phy;
+ }
+ }
+ }
+
+ iproc_pcie_reset(pcie);
+
+ if (pcie->need_ob_cfg) {
+ ret = iproc_pcie_map_ranges(dev);
+ if (ret) {
+ pr_err("outbound map failed\n");
+ goto err_power_off_phy;
+ }
+ }
+
+ if (pcie->need_ib_cfg) {
+ ret = iproc_pcie_map_dma_ranges(pcie);
+ if (ret) {
+ pr_err("inbound map failed\n");
+ goto err_power_off_phy;
+ }
+ }
+
+ if (iproc_pcie_check_link(pcie))
+ pr_info("no PCIe EP device detected\n");
+
+ return 0;
+
+err_power_off_phy:
+ generic_phy_power_off(&pcie->phy);
+err_exit_phy:
+ generic_phy_exit(&pcie->phy);
+ return ret;
+}
+
+static int iproc_pcie_remove(struct udevice *dev)
+{
+ struct iproc_pcie *pcie = dev_get_priv(dev);
+ int ret;
+
+ iproc_pcie_reset_map_regs(pcie);
+
+ if (generic_phy_valid(&pcie->phy)) {
+ ret = generic_phy_power_off(&pcie->phy);
+ if (ret) {
+ pr_err("failed to power off PCIe phy\n");
+ return ret;
+ }
+
+ ret = generic_phy_exit(&pcie->phy);
+ if (ret) {
+ pr_err("failed to power off PCIe phy\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct udevice_id pci_iproc_ids[] = {
+ { .compatible = "brcm,iproc-pcie-paxb-v2",
+ .data = IPROC_PCIE_PAXB_V2 },
+ { .compatible = "brcm,iproc-pcie-paxc-v2",
+ .data = IPROC_PCIE_PAXC_V2 },
+ { }
+};
+
+U_BOOT_DRIVER(pci_iproc) = {
+ .name = "pci_iproc",
+ .id = UCLASS_PCI,
+ .of_match = pci_iproc_ids,
+ .ops = &iproc_pcie_ops,
+ .probe = iproc_pcie_probe,
+ .remove = iproc_pcie_remove,
+ .priv_auto = sizeof(struct iproc_pcie),
+ .flags = DM_FLAG_OS_PREPARE,
+};
diff --git a/roms/u-boot/drivers/pci/pcie_layerscape.c b/roms/u-boot/drivers/pci/pcie_layerscape.c
new file mode 100644
index 000000000..3c7c4ca18
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_layerscape.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017-2020 NXP
+ * Copyright 2014-2015 Freescale Semiconductor, Inc.
+ * Layerscape PCIe driver
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <malloc.h>
+#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \
+ defined(CONFIG_ARM)
+#include <asm/arch/clock.h>
+#endif
+#include "pcie_layerscape.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+LIST_HEAD(ls_pcie_list);
+
+unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset)
+{
+ return in_le32(pcie->dbi + offset);
+}
+
+void dbi_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset)
+{
+ out_le32(pcie->dbi + offset, value);
+}
+
+unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset)
+{
+ if (pcie->big_endian)
+ return in_be32(pcie->ctrl + offset);
+ else
+ return in_le32(pcie->ctrl + offset);
+}
+
+void ctrl_writel(struct ls_pcie *pcie, unsigned int value,
+ unsigned int offset)
+{
+ if (pcie->big_endian)
+ out_be32(pcie->ctrl + offset, value);
+ else
+ out_le32(pcie->ctrl + offset, value);
+}
+
+void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie)
+{
+ u32 reg, val;
+
+ reg = PCIE_MISC_CONTROL_1_OFF;
+ val = dbi_readl(pcie, reg);
+ val |= PCIE_DBI_RO_WR_EN;
+ dbi_writel(pcie, val, reg);
+}
+
+void ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie)
+{
+ u32 reg, val;
+
+ reg = PCIE_MISC_CONTROL_1_OFF;
+ val = dbi_readl(pcie, reg);
+ val &= ~PCIE_DBI_RO_WR_EN;
+ dbi_writel(pcie, val, reg);
+}
+
+static int ls_pcie_ltssm(struct ls_pcie *pcie)
+{
+ u32 state;
+ uint svr;
+
+ svr = get_svr();
+ if (((svr >> SVR_VAR_PER_SHIFT) & SVR_LS102XA_MASK) == SVR_LS102XA) {
+ state = ctrl_readl(pcie, LS1021_PEXMSCPORTSR(pcie->idx));
+ state = (state >> LS1021_LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK;
+ } else {
+ state = ctrl_readl(pcie, PCIE_PF_DBG) & LTSSM_STATE_MASK;
+ }
+
+ return state;
+}
+
+int ls_pcie_link_up(struct ls_pcie *pcie)
+{
+ int ltssm;
+
+ ltssm = ls_pcie_ltssm(pcie);
+ if (ltssm < LTSSM_PCIE_L0)
+ return 0;
+
+ return 1;
+}
+
+void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type,
+ u64 phys, u64 bus_addr, u64 size)
+{
+ dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | idx, PCIE_ATU_VIEWPORT);
+ dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_BASE);
+ dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_BASE);
+ dbi_writel(pcie, (u32)phys + size - 1, PCIE_ATU_LIMIT);
+ dbi_writel(pcie, (u32)bus_addr, PCIE_ATU_LOWER_TARGET);
+ dbi_writel(pcie, bus_addr >> 32, PCIE_ATU_UPPER_TARGET);
+ dbi_writel(pcie, type, PCIE_ATU_CR1);
+ dbi_writel(pcie, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
+}
+
+/* Use bar match mode and MEM type as default */
+void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag,
+ int type, int idx, int bar, u64 phys)
+{
+ dbi_writel(pcie, PCIE_ATU_REGION_INBOUND | idx, PCIE_ATU_VIEWPORT);
+ dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_TARGET);
+ dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_TARGET);
+ dbi_writel(pcie, type | PCIE_ATU_FUNC_NUM(pf), PCIE_ATU_CR1);
+ dbi_writel(pcie, PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE |
+ (vf_flag ? PCIE_ATU_FUNC_NUM_MATCH_EN : 0) |
+ (vf_flag ? PCIE_ATU_VFBAR_MATCH_MODE_EN : 0) |
+ PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2);
+}
+
+void ls_pcie_dump_atu(struct ls_pcie *pcie, u32 win_num, u32 type)
+{
+ int win_idx;
+
+ for (win_idx = 0; win_idx < win_num; win_idx++) {
+ dbi_writel(pcie, type | win_idx, PCIE_ATU_VIEWPORT);
+ debug("iATU%d:\n", win_idx);
+ debug("\tLOWER PHYS 0x%08x\n",
+ dbi_readl(pcie, PCIE_ATU_LOWER_BASE));
+ debug("\tUPPER PHYS 0x%08x\n",
+ dbi_readl(pcie, PCIE_ATU_UPPER_BASE));
+ if (type == PCIE_ATU_REGION_OUTBOUND) {
+ debug("\tLOWER BUS 0x%08x\n",
+ dbi_readl(pcie, PCIE_ATU_LOWER_TARGET));
+ debug("\tUPPER BUS 0x%08x\n",
+ dbi_readl(pcie, PCIE_ATU_UPPER_TARGET));
+ debug("\tLIMIT 0x%08x\n",
+ dbi_readl(pcie, PCIE_ATU_LIMIT));
+ }
+ debug("\tCR1 0x%08x\n",
+ dbi_readl(pcie, PCIE_ATU_CR1));
+ debug("\tCR2 0x%08x\n",
+ dbi_readl(pcie, PCIE_ATU_CR2));
+ }
+}
diff --git a/roms/u-boot/drivers/pci/pcie_layerscape.h b/roms/u-boot/drivers/pci/pcie_layerscape.h
new file mode 100644
index 000000000..8cdf516d9
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_layerscape.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2017-2020 NXP
+ * Copyright 2014-2015 Freescale Semiconductor, Inc.
+ * Layerscape PCIe driver
+ */
+
+#ifndef _PCIE_LAYERSCAPE_H_
+#define _PCIE_LAYERSCAPE_H_
+#include <pci.h>
+
+#include <linux/sizes.h>
+#include <asm/arch-fsl-layerscape/svr.h>
+#include <asm/arch-ls102xa/svr.h>
+
+#ifndef CONFIG_SYS_PCI_MEMORY_BUS
+#define CONFIG_SYS_PCI_MEMORY_BUS CONFIG_SYS_SDRAM_BASE
+#endif
+
+#ifndef CONFIG_SYS_PCI_MEMORY_PHYS
+#define CONFIG_SYS_PCI_MEMORY_PHYS CONFIG_SYS_SDRAM_BASE
+#endif
+
+#ifndef CONFIG_SYS_PCI_MEMORY_SIZE
+#define CONFIG_SYS_PCI_MEMORY_SIZE SZ_4G
+#endif
+
+#ifndef CONFIG_SYS_PCI_EP_MEMORY_BASE
+#define CONFIG_SYS_PCI_EP_MEMORY_BASE CONFIG_SYS_LOAD_ADDR
+#endif
+
+#define PCIE_PHYS_SIZE 0x200000000
+#define LS2088A_PCIE_PHYS_SIZE 0x800000000
+#define LS2088A_PCIE1_PHYS_ADDR 0x2000000000
+
+/* iATU registers */
+#define PCIE_ATU_VIEWPORT 0x900
+#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
+#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
+#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
+#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
+#define PCIE_ATU_REGION_INDEX2 (0x2 << 0)
+#define PCIE_ATU_REGION_INDEX3 (0x3 << 0)
+#define PCIE_ATU_REGION_NUM 6
+#define PCIE_ATU_REGION_NUM_SRIOV 24
+#define PCIE_ATU_CR1 0x904
+#define PCIE_ATU_TYPE_MEM (0x0 << 0)
+#define PCIE_ATU_TYPE_IO (0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
+#define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20)
+#define PCIE_ATU_CR2 0x908
+#define PCIE_ATU_ENABLE (0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
+#define PCIE_ATU_FUNC_NUM_MATCH_EN BIT(19)
+#define PCIE_ATU_VFBAR_MATCH_MODE_EN BIT(26)
+#define PCIE_ATU_BAR_NUM(bar) ((bar) << 8)
+#define PCIE_ATU_LOWER_BASE 0x90C
+#define PCIE_ATU_UPPER_BASE 0x910
+#define PCIE_ATU_LIMIT 0x914
+#define PCIE_ATU_LOWER_TARGET 0x918
+#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
+#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
+#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
+#define PCIE_ATU_UPPER_TARGET 0x91C
+
+/* DBI registers */
+#define PCIE_SRIOV 0x178
+#define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */
+#define PCIE_DBI_RO_WR_EN BIT(0)
+#define PCIE_MISC_CONTROL_1_OFF 0x8BC
+
+#define PCIE_LINK_CAP 0x7c
+#define PCIE_LINK_SPEED_MASK 0xf
+#define PCIE_LINK_WIDTH_MASK 0x3f0
+#define PCIE_LINK_STA 0x82
+
+#define LTSSM_STATE_MASK 0x3f
+#define LTSSM_PCIE_L0 0x11 /* L0 state */
+
+#define PCIE_DBI_SIZE 0x100000 /* 1M */
+
+#define PCIE_LCTRL0_CFG2_ENABLE (1 << 31)
+#define PCIE_LCTRL0_VF(vf) ((vf) << 22)
+#define PCIE_LCTRL0_PF(pf) ((pf) << 16)
+#define PCIE_LCTRL0_VF_ACTIVE (1 << 21)
+#define PCIE_LCTRL0_VAL(pf, vf) (PCIE_LCTRL0_PF(pf) | \
+ PCIE_LCTRL0_VF(vf) | \
+ ((vf) == 0 ? 0 : PCIE_LCTRL0_VF_ACTIVE) | \
+ PCIE_LCTRL0_CFG2_ENABLE)
+
+#define PCIE_NO_SRIOV_BAR_BASE 0x1000
+#define FSL_PCIE_EP_MIN_APERTURE 4096 /* 4 Kbytes */
+#define PCIE_PF_NUM 2
+#define PCIE_VF_NUM 64
+#define BAR_NUM 8
+
+#define PCIE_BAR0_SIZE SZ_4K
+#define PCIE_BAR1_SIZE SZ_8K
+#define PCIE_BAR2_SIZE SZ_4K
+#define PCIE_BAR4_SIZE SZ_1M
+
+#define PCIE_SRIOV_VFBAR0 0x19C
+
+#define PCIE_MASK_OFFSET(flag, pf, off) ((flag) ? 0 : (0x1000 + (off) * (pf)))
+
+/* LUT registers */
+#define PCIE_LUT_UDR(n) (0x800 + (n) * 8)
+#define PCIE_LUT_LDR(n) (0x804 + (n) * 8)
+#define PCIE_LUT_ENABLE (1 << 31)
+#define PCIE_LUT_ENTRY_COUNT 32
+
+/* PF Controll registers */
+#define PCIE_PF_CONFIG 0x14
+#define PCIE_PF_VF_CTRL 0x7F8
+#define PCIE_PF_DBG 0x7FC
+#define PCIE_CONFIG_READY (1 << 0)
+
+#define PCIE_SRDS_PRTCL(idx) (PCIE1 + (idx))
+#define PCIE_SYS_BASE_ADDR 0x3400000
+#define PCIE_CCSR_SIZE 0x0100000
+
+/* CS2 */
+#define PCIE_CS2_OFFSET 0x1000 /* For PCIe without SR-IOV */
+
+/* LS1021a PCIE space */
+#define LS1021_PCIE_SPACE_OFFSET 0x4000000000ULL
+#define LS1021_PCIE_SPACE_SIZE 0x0800000000ULL
+
+/* LS1021a PEX1/2 Misc Ports Status Register */
+#define LS1021_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4)
+#define LS1021_LTSSM_STATE_SHIFT 20
+
+/* LX2160a PF1 offset */
+#define LX2160_PCIE_PF1_OFFSET 0x8000
+
+/* layerscape PF1 offset */
+#define LS_PCIE_PF1_OFFSET 0x20000
+
+struct ls_pcie {
+ void __iomem *dbi;
+ void __iomem *lut;
+ void __iomem *ctrl;
+ int idx;
+ bool big_endian;
+ int mode;
+};
+
+struct ls_pcie_rc {
+ struct ls_pcie *pcie;
+ struct list_head list;
+ struct udevice *bus;
+ struct fdt_resource dbi_res;
+ struct fdt_resource lut_res;
+ struct fdt_resource ctrl_res;
+ struct fdt_resource cfg_res;
+ void __iomem *cfg0;
+ void __iomem *cfg1;
+ bool enabled;
+ int next_lut_index;
+ int stream_id_cur;
+};
+
+struct ls_pcie_ep {
+ struct fdt_resource addr_res;
+ struct ls_pcie *pcie;
+ struct udevice *bus;
+ void __iomem *addr;
+ u32 cfg2_flag;
+ u32 sriov_flag;
+ u32 pf1_offset;
+ u32 num_ib_wins;
+ u32 num_ob_wins;
+ u8 max_functions;
+};
+
+extern struct list_head ls_pcie_list;
+
+unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset);
+void dbi_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset);
+unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset);
+void ctrl_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset);
+void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type,
+ u64 phys, u64 bus_addr, u64 size);
+void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag,
+ int type, int idx, int bar, u64 phys);
+void ls_pcie_dump_atu(struct ls_pcie *pcie, u32 win_num, u32 type);
+int ls_pcie_link_up(struct ls_pcie *pcie);
+void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie);
+void ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie);
+
+#endif /* _PCIE_LAYERSCAPE_H_ */
diff --git a/roms/u-boot/drivers/pci/pcie_layerscape_ep.c b/roms/u-boot/drivers/pci/pcie_layerscape_ep.c
new file mode 100644
index 000000000..f2813aeef
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_layerscape_ep.c
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ * Layerscape PCIe EP driver
+ */
+
+#include <common.h>
+#include <asm/arch/fsl_serdes.h>
+#include <dm.h>
+#include <asm/global_data.h>
+#include <dm/devres.h>
+#include <errno.h>
+#include <pci_ep.h>
+#include <asm/io.h>
+#include <linux/sizes.h>
+#include <linux/log2.h>
+#include "pcie_layerscape.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void ls_pcie_ep_enable_cfg(struct ls_pcie_ep *pcie_ep)
+{
+ struct ls_pcie *pcie = pcie_ep->pcie;
+ u32 config;
+
+ config = ctrl_readl(pcie, PCIE_PF_CONFIG);
+ config |= PCIE_CONFIG_READY;
+ ctrl_writel(pcie, config, PCIE_PF_CONFIG);
+}
+
+static int ls_ep_set_bar(struct udevice *dev, uint fn, struct pci_bar *ep_bar)
+{
+ struct ls_pcie_ep *pcie_ep = dev_get_priv(dev);
+ struct ls_pcie *pcie = pcie_ep->pcie;
+ dma_addr_t bar_phys = ep_bar->phys_addr;
+ enum pci_barno bar = ep_bar->barno;
+ u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
+ int flags = ep_bar->flags;
+ int type, idx;
+ u64 size;
+
+ idx = bar;
+ /* BAR size is 2^(aperture + 11) */
+ size = max_t(size_t, ep_bar->size, FSL_PCIE_EP_MIN_APERTURE);
+
+ if (!(flags & PCI_BASE_ADDRESS_SPACE))
+ type = PCIE_ATU_TYPE_MEM;
+ else
+ type = PCIE_ATU_TYPE_IO;
+
+ ls_pcie_atu_inbound_set(pcie, fn, 0, type, idx, bar, bar_phys);
+
+ dbi_writel(pcie, lower_32_bits(size - 1), reg + PCIE_NO_SRIOV_BAR_BASE);
+ dbi_writel(pcie, flags, reg);
+
+ if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ dbi_writel(pcie, upper_32_bits(size - 1),
+ reg + 4 + PCIE_NO_SRIOV_BAR_BASE);
+ dbi_writel(pcie, 0, reg + 4);
+ }
+
+ return 0;
+}
+
+static struct pci_ep_ops ls_pcie_ep_ops = {
+ .set_bar = ls_ep_set_bar,
+};
+
+static void ls_pcie_ep_setup_atu(struct ls_pcie_ep *pcie_ep, u32 pf)
+{
+ struct ls_pcie *pcie = pcie_ep->pcie;
+ u32 vf_flag = 0;
+ u64 phys = 0;
+
+ phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + pf * SZ_64M;
+
+ phys = ALIGN(phys, PCIE_BAR0_SIZE);
+ /* ATU 0 : INBOUND : map BAR0 */
+ ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
+ 0 + pf * BAR_NUM, 0, phys);
+ /* ATU 1 : INBOUND : map BAR1 */
+ phys = ALIGN(phys + PCIE_BAR0_SIZE, PCIE_BAR1_SIZE);
+ ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
+ 1 + pf * BAR_NUM, 1, phys);
+ /* ATU 2 : INBOUND : map BAR2 */
+ phys = ALIGN(phys + PCIE_BAR1_SIZE, PCIE_BAR2_SIZE);
+ ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
+ 2 + pf * BAR_NUM, 2, phys);
+ /* ATU 3 : INBOUND : map BAR2 */
+ phys = ALIGN(phys + PCIE_BAR2_SIZE, PCIE_BAR4_SIZE);
+ ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
+ 3 + pf * BAR_NUM, 4, phys);
+
+ if (pcie_ep->sriov_flag) {
+ vf_flag = 1;
+ /* ATU 4 : INBOUND : map BAR0 */
+ phys = ALIGN(phys + PCIE_BAR4_SIZE, PCIE_BAR0_SIZE);
+ ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
+ 4 + pf * BAR_NUM, 0, phys);
+ /* ATU 5 : INBOUND : map BAR1 */
+ phys = ALIGN(phys + PCIE_BAR0_SIZE * PCIE_VF_NUM,
+ PCIE_BAR1_SIZE);
+ ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
+ 5 + pf * BAR_NUM, 1, phys);
+ /* ATU 6 : INBOUND : map BAR2 */
+ phys = ALIGN(phys + PCIE_BAR1_SIZE * PCIE_VF_NUM,
+ PCIE_BAR2_SIZE);
+ ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
+ 6 + pf * BAR_NUM, 2, phys);
+ /* ATU 7 : INBOUND : map BAR4 */
+ phys = ALIGN(phys + PCIE_BAR2_SIZE * PCIE_VF_NUM,
+ PCIE_BAR4_SIZE);
+ ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
+ 7 + pf * BAR_NUM, 4, phys);
+ }
+
+ /* ATU: OUTBOUND : map MEM */
+ ls_pcie_atu_outbound_set(pcie, pf, PCIE_ATU_TYPE_MEM,
+ (u64)pcie_ep->addr_res.start +
+ pf * CONFIG_SYS_PCI_MEMORY_SIZE,
+ 0, CONFIG_SYS_PCI_MEMORY_SIZE);
+}
+
+/* BAR0 and BAR1 are 32bit BAR2 and BAR4 are 64bit */
+static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size)
+{
+ u32 mask;
+
+ /* The least inbound window is 4KiB */
+ if (size < SZ_4K)
+ mask = 0;
+ else
+ mask = size - 1;
+
+ switch (bar) {
+ case 0:
+ writel(mask, bar_base + PCI_BASE_ADDRESS_0);
+ break;
+ case 1:
+ writel(mask, bar_base + PCI_BASE_ADDRESS_1);
+ break;
+ case 2:
+ writel(mask, bar_base + PCI_BASE_ADDRESS_2);
+ writel(0, bar_base + PCI_BASE_ADDRESS_3);
+ break;
+ case 4:
+ writel(mask, bar_base + PCI_BASE_ADDRESS_4);
+ writel(0, bar_base + PCI_BASE_ADDRESS_5);
+ break;
+ default:
+ break;
+ }
+}
+
+static void ls_pcie_ep_setup_bars(void *bar_base)
+{
+ /* BAR0 - 32bit - MEM */
+ ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE);
+ /* BAR1 - 32bit - MEM*/
+ ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE);
+ /* BAR2 - 64bit - MEM */
+ ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE);
+ /* BAR4 - 64bit - MEM */
+ ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE);
+}
+
+static void ls_pcie_ep_setup_vf_bars(void *bar_base)
+{
+ /* VF BAR0 MASK register at offset 0x19c*/
+ bar_base += PCIE_SRIOV_VFBAR0 - PCI_BASE_ADDRESS_0;
+
+ /* VF-BAR0 - 32bit - MEM */
+ ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE);
+ /* VF-BAR1 - 32bit - MEM*/
+ ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE);
+ /* VF-BAR2 - 64bit - MEM */
+ ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE);
+ /* VF-BAR4 - 64bit - MEM */
+ ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE);
+}
+
+static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep)
+{
+ u32 sriov;
+ u32 pf, vf;
+ void *bar_base = NULL;
+ struct ls_pcie *pcie = pcie_ep->pcie;
+
+ sriov = readl(pcie->dbi + PCIE_SRIOV);
+ if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) {
+ pcie_ep->sriov_flag = 1;
+ for (pf = 0; pf < PCIE_PF_NUM; pf++) {
+ /*
+ * The VF_BARn_REG register's Prefetchable and Type bit
+ * fields are overwritten by a write to VF's BAR Mask
+ * register. Before writing to the VF_BARn_MASK_REG
+ * register, write 0b to the PCIE_MISC_CONTROL_1_OFF
+ * register.
+ */
+ writel(0, pcie->dbi + PCIE_MISC_CONTROL_1_OFF);
+
+ bar_base = pcie->dbi +
+ PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf,
+ pcie_ep->pf1_offset);
+
+ if (pcie_ep->cfg2_flag) {
+ ctrl_writel(pcie,
+ PCIE_LCTRL0_VAL(pf, 0),
+ PCIE_PF_VF_CTRL);
+ ls_pcie_ep_setup_bars(bar_base);
+
+ for (vf = 1; vf <= PCIE_VF_NUM; vf++) {
+ ctrl_writel(pcie,
+ PCIE_LCTRL0_VAL(pf, vf),
+ PCIE_PF_VF_CTRL);
+ ls_pcie_ep_setup_vf_bars(bar_base);
+ }
+ } else {
+ ls_pcie_ep_setup_bars(bar_base);
+ ls_pcie_ep_setup_vf_bars(bar_base);
+ }
+
+ ls_pcie_ep_setup_atu(pcie_ep, pf);
+ }
+
+ if (pcie_ep->cfg2_flag) /* Disable CFG2 */
+ ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL);
+ } else {
+ ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE);
+ ls_pcie_ep_setup_atu(pcie_ep, 0);
+ }
+
+ ls_pcie_dump_atu(pcie, PCIE_ATU_REGION_NUM_SRIOV,
+ PCIE_ATU_REGION_INBOUND);
+
+ ls_pcie_ep_enable_cfg(pcie_ep);
+}
+
+static int ls_pcie_ep_probe(struct udevice *dev)
+{
+ struct ls_pcie_ep *pcie_ep = dev_get_priv(dev);
+ struct ls_pcie *pcie;
+ u16 link_sta;
+ int ret;
+ u32 svr;
+
+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ pcie_ep->pcie = pcie;
+
+ pcie->dbi = (void __iomem *)devfdt_get_addr_index(dev, 0);
+ if (!pcie->dbi)
+ return -ENOMEM;
+
+ pcie->ctrl = (void __iomem *)devfdt_get_addr_index(dev, 1);
+ if (!pcie->ctrl)
+ return -ENOMEM;
+
+ ret = fdt_get_named_resource(gd->fdt_blob, dev_of_offset(dev),
+ "reg", "reg-names",
+ "addr_space", &pcie_ep->addr_res);
+ if (ret) {
+ printf("%s: resource \"addr_space\" not found\n", dev->name);
+ return ret;
+ }
+
+ pcie->idx = ((unsigned long)pcie->dbi - PCIE_SYS_BASE_ADDR) /
+ PCIE_CCSR_SIZE;
+
+ /* This controller is disabled by RCW */
+ if (!is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx)))
+ return 0;
+
+ pcie->big_endian = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "big-endian");
+
+ svr = SVR_SOC_VER(get_svr());
+
+ if (svr == SVR_LX2160A || svr == SVR_LX2162A ||
+ svr == SVR_LX2120A || svr == SVR_LX2080A ||
+ svr == SVR_LX2122A || svr == SVR_LX2082A)
+ pcie_ep->pf1_offset = LX2160_PCIE_PF1_OFFSET;
+ else
+ pcie_ep->pf1_offset = LS_PCIE_PF1_OFFSET;
+
+ if (svr == SVR_LS2080A || svr == SVR_LS2085A)
+ pcie_ep->cfg2_flag = 1;
+ else
+ pcie_ep->cfg2_flag = 0;
+
+ pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f;
+ if (pcie->mode != PCI_HEADER_TYPE_NORMAL)
+ return 0;
+
+ pcie_ep->max_functions = fdtdec_get_int(gd->fdt_blob,
+ dev_of_offset(dev),
+ "max-functions", 1);
+ pcie_ep->num_ib_wins = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "num-ib-windows", 8);
+ pcie_ep->num_ob_wins = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "num-ob-windows", 8);
+
+ printf("PCIe%u: %s %s", PCIE_SRDS_PRTCL(pcie->idx), dev->name,
+ "Endpoint");
+ ls_pcie_setup_ep(pcie_ep);
+
+ if (!ls_pcie_link_up(pcie)) {
+ /* Let the user know there's no PCIe link */
+ printf(": no link\n");
+ return 0;
+ }
+
+ /* Print the negotiated PCIe link width */
+ link_sta = readw(pcie->dbi + PCIE_LINK_STA);
+ printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4,
+ link_sta & PCIE_LINK_SPEED_MASK);
+
+ return 0;
+}
+
+static int ls_pcie_ep_remove(struct udevice *dev)
+{
+ return 0;
+}
+
+const struct udevice_id ls_pcie_ep_ids[] = {
+ { .compatible = "fsl,ls-pcie-ep" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_layerscape_ep) = {
+ .name = "pci_layerscape_ep",
+ .id = UCLASS_PCI_EP,
+ .of_match = ls_pcie_ep_ids,
+ .ops = &ls_pcie_ep_ops,
+ .probe = ls_pcie_ep_probe,
+ .remove = ls_pcie_ep_remove,
+ .priv_auto = sizeof(struct ls_pcie_ep),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_layerscape_fixup.c b/roms/u-boot/drivers/pci/pcie_layerscape_fixup.c
new file mode 100644
index 000000000..a58e7a389
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_layerscape_fixup.c
@@ -0,0 +1,629 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017-2020 NXP
+ * Copyright 2014-2015 Freescale Semiconductor, Inc.
+ * Layerscape PCIe driver
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <init.h>
+#include <log.h>
+#include <pci.h>
+#include <asm/arch/fsl_serdes.h>
+#include <asm/io.h>
+#include <errno.h>
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <linux/libfdt.h>
+#include <fdt_support.h>
+#ifdef CONFIG_ARM
+#include <asm/arch/clock.h>
+#endif
+#include <malloc.h>
+#include <env.h>
+#include "pcie_layerscape.h"
+#include "pcie_layerscape_fixup_common.h"
+
+static int fdt_pcie_get_nodeoffset(void *blob, struct ls_pcie_rc *pcie_rc)
+{
+ int nodeoffset;
+ uint svr;
+ char *compat = NULL;
+
+ /* find pci controller node */
+ nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
+ pcie_rc->dbi_res.start);
+ if (nodeoffset < 0) {
+#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */
+ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
+ if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
+ svr == SVR_LS2048A || svr == SVR_LS2044A ||
+ svr == SVR_LS2081A || svr == SVR_LS2041A)
+ compat = "fsl,ls2088a-pcie";
+ else
+ compat = CONFIG_FSL_PCIE_COMPAT;
+
+ nodeoffset =
+ fdt_node_offset_by_compat_reg(blob, compat,
+ pcie_rc->dbi_res.start);
+#endif
+ }
+
+ return nodeoffset;
+}
+
+#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
+/*
+ * Return next available LUT index.
+ */
+static int ls_pcie_next_lut_index(struct ls_pcie_rc *pcie_rc)
+{
+ if (pcie_rc->next_lut_index < PCIE_LUT_ENTRY_COUNT)
+ return pcie_rc->next_lut_index++;
+ else
+ return -ENOSPC; /* LUT is full */
+}
+
+static void lut_writel(struct ls_pcie_rc *pcie_rc, unsigned int value,
+ unsigned int offset)
+{
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ if (pcie->big_endian)
+ out_be32(pcie->lut + offset, value);
+ else
+ out_le32(pcie->lut + offset, value);
+}
+
+/*
+ * Program a single LUT entry
+ */
+static void ls_pcie_lut_set_mapping(struct ls_pcie_rc *pcie_rc, int index,
+ u32 devid, u32 streamid)
+{
+ /* leave mask as all zeroes, want to match all bits */
+ lut_writel(pcie_rc, devid << 16, PCIE_LUT_UDR(index));
+ lut_writel(pcie_rc, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index));
+}
+
+/*
+ * An msi-map is a property to be added to the pci controller
+ * node. It is a table, where each entry consists of 4 fields
+ * e.g.:
+ *
+ * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count]
+ * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>;
+ */
+static void fdt_pcie_set_msi_map_entry_ls(void *blob,
+ struct ls_pcie_rc *pcie_rc,
+ u32 devid, u32 streamid)
+{
+ u32 *prop;
+ u32 phandle;
+ int nodeoffset;
+ uint svr;
+ char *compat = NULL;
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ /* find pci controller node */
+ nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
+ pcie_rc->dbi_res.start);
+ if (nodeoffset < 0) {
+#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */
+ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
+ if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
+ svr == SVR_LS2048A || svr == SVR_LS2044A ||
+ svr == SVR_LS2081A || svr == SVR_LS2041A)
+ compat = "fsl,ls2088a-pcie";
+ else
+ compat = CONFIG_FSL_PCIE_COMPAT;
+ if (compat)
+ nodeoffset = fdt_node_offset_by_compat_reg(blob,
+ compat, pcie_rc->dbi_res.start);
+#endif
+ if (nodeoffset < 0)
+ return;
+ }
+
+ /* get phandle to MSI controller */
+ prop = (u32 *)fdt_getprop(blob, nodeoffset, "msi-parent", 0);
+ if (prop == NULL) {
+ debug("\n%s: ERROR: missing msi-parent: PCIe%d\n",
+ __func__, pcie->idx);
+ return;
+ }
+ phandle = fdt32_to_cpu(*prop);
+
+ /* set one msi-map row */
+ fdt_appendprop_u32(blob, nodeoffset, "msi-map", devid);
+ fdt_appendprop_u32(blob, nodeoffset, "msi-map", phandle);
+ fdt_appendprop_u32(blob, nodeoffset, "msi-map", streamid);
+ fdt_appendprop_u32(blob, nodeoffset, "msi-map", 1);
+}
+
+/*
+ * An iommu-map is a property to be added to the pci controller
+ * node. It is a table, where each entry consists of 4 fields
+ * e.g.:
+ *
+ * iommu-map = <[devid] [phandle-to-iommu-ctrl] [stream-id] [count]
+ * [devid] [phandle-to-iommu-ctrl] [stream-id] [count]>;
+ */
+static void fdt_pcie_set_iommu_map_entry_ls(void *blob,
+ struct ls_pcie_rc *pcie_rc,
+ u32 devid, u32 streamid)
+{
+ u32 *prop;
+ u32 iommu_map[4];
+ int nodeoffset;
+ int lenp;
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ nodeoffset = fdt_pcie_get_nodeoffset(blob, pcie_rc);
+ if (nodeoffset < 0)
+ return;
+
+ /* get phandle to iommu controller */
+ prop = fdt_getprop_w(blob, nodeoffset, "iommu-map", &lenp);
+ if (prop == NULL) {
+ debug("\n%s: ERROR: missing iommu-map: PCIe%d\n",
+ __func__, pcie->idx);
+ return;
+ }
+
+ /* set iommu-map row */
+ iommu_map[0] = cpu_to_fdt32(devid);
+ iommu_map[1] = *++prop;
+ iommu_map[2] = cpu_to_fdt32(streamid);
+ iommu_map[3] = cpu_to_fdt32(1);
+
+ if (devid == 0) {
+ fdt_setprop_inplace(blob, nodeoffset, "iommu-map",
+ iommu_map, 16);
+ } else {
+ fdt_appendprop(blob, nodeoffset, "iommu-map", iommu_map, 16);
+ }
+}
+
+static int fdt_fixup_pcie_device_ls(void *blob, pci_dev_t bdf,
+ struct ls_pcie_rc *pcie_rc)
+{
+ int streamid, index;
+
+ streamid = pcie_next_streamid(pcie_rc->stream_id_cur,
+ pcie_rc->pcie->idx);
+ if (streamid < 0) {
+ printf("ERROR: out of stream ids for BDF %d.%d.%d\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ return -ENOENT;
+ }
+ pcie_rc->stream_id_cur++;
+
+ index = ls_pcie_next_lut_index(pcie_rc);
+ if (index < 0) {
+ printf("ERROR: out of LUT indexes for BDF %d.%d.%d\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ return -ENOENT;
+ }
+
+ /* map PCI b.d.f to streamID in LUT */
+ ls_pcie_lut_set_mapping(pcie_rc, index, bdf >> 8, streamid);
+ /* update msi-map in device tree */
+ fdt_pcie_set_msi_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid);
+ /* update iommu-map in device tree */
+ fdt_pcie_set_iommu_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid);
+
+ return 0;
+}
+
+struct extra_iommu_entry {
+ int action;
+ pci_dev_t bdf;
+ int num_vfs;
+ bool noari;
+};
+
+#define EXTRA_IOMMU_ENTRY_HOTPLUG 1
+#define EXTRA_IOMMU_ENTRY_VFS 2
+
+static struct extra_iommu_entry *get_extra_iommu_ents(void *blob,
+ int nodeoffset,
+ phys_addr_t addr,
+ int *cnt)
+{
+ const char *s, *p, *tok;
+ struct extra_iommu_entry *entries;
+ int i = 0, b, d, f;
+
+ /*
+ * Retrieve extra IOMMU configuration from env var or from device tree.
+ * Env var is given priority.
+ */
+ s = env_get("pci_iommu_extra");
+ if (!s) {
+ s = fdt_getprop(blob, nodeoffset, "pci-iommu-extra", NULL);
+ } else {
+ phys_addr_t pci_base;
+ char *endp;
+
+ /*
+ * In env var case the config string has "pci@0x..." in
+ * addition. Parse this part and match it by address against
+ * the input pci controller's registers base address.
+ */
+ tok = s;
+ p = strchrnul(s + 1, ',');
+ s = NULL;
+ do {
+ if (!strncmp(tok, "pci", 3)) {
+ pci_base = simple_strtoul(tok + 4, &endp, 0);
+ if (pci_base == addr) {
+ s = endp + 1;
+ break;
+ }
+ }
+ p = strchrnul(p + 1, ',');
+ tok = p + 1;
+ } while (*p);
+ }
+
+ /*
+ * If no env var or device tree property found or pci register base
+ * address mismatches, bail out
+ */
+ if (!s)
+ return NULL;
+
+ /*
+ * In order to find how many action entries to allocate, count number
+ * of actions by interating through the pairs of bdfs and actions.
+ */
+ *cnt = 0;
+ p = s;
+ while (*p && strncmp(p, "pci", 3)) {
+ if (*p == ',')
+ (*cnt)++;
+ p++;
+ }
+ if (!(*p))
+ (*cnt)++;
+
+ if (!(*cnt) || (*cnt) % 2) {
+ printf("ERROR: invalid or odd extra iommu token count %d\n",
+ *cnt);
+ return NULL;
+ }
+ *cnt = (*cnt) / 2;
+
+ entries = malloc((*cnt) * sizeof(*entries));
+ if (!entries) {
+ printf("ERROR: fail to allocate extra iommu entries\n");
+ return NULL;
+ }
+
+ /*
+ * Parse action entries one by one and store the information in the
+ * newly allocated actions array.
+ */
+ p = s;
+ while (p) {
+ /* Extract BDF */
+ b = simple_strtoul(p, (char **)&p, 0); p++;
+ d = simple_strtoul(p, (char **)&p, 0); p++;
+ f = simple_strtoul(p, (char **)&p, 0); p++;
+ entries[i].bdf = PCI_BDF(b, d, f);
+
+ /* Parse action */
+ if (!strncmp(p, "hp", 2)) {
+ /* Hot-plug entry */
+ entries[i].action = EXTRA_IOMMU_ENTRY_HOTPLUG;
+ p += 2;
+ } else if (!strncmp(p, "vfs", 3) ||
+ !strncmp(p, "noari_vfs", 9)) {
+ /* VFs or VFs with ARI disabled entry */
+ entries[i].action = EXTRA_IOMMU_ENTRY_VFS;
+ entries[i].noari = !strncmp(p, "noari_vfs", 9);
+
+ /*
+ * Parse and store total number of VFs to allocate
+ * IOMMU entries for.
+ */
+ p = strchr(p, '=');
+ entries[i].num_vfs = simple_strtoul(p + 1, (char **)&p,
+ 0);
+ if (*p)
+ p++;
+ } else {
+ printf("ERROR: invalid action in extra iommu entry\n");
+ free(entries);
+
+ return NULL;
+ }
+
+ if (!(*p) || !strncmp(p, "pci", 3))
+ break;
+
+ i++;
+ }
+
+ return entries;
+}
+
+static void get_vf_offset_and_stride(struct udevice *dev, int sriov_pos,
+ struct extra_iommu_entry *entry,
+ u16 *offset, u16 *stride)
+{
+ u16 tmp16;
+ u32 tmp32;
+ bool have_ari = false;
+ int pos;
+ struct udevice *pf_dev;
+
+ dm_pci_read_config16(dev, sriov_pos + PCI_SRIOV_TOTAL_VF, &tmp16);
+ if (entry->num_vfs > tmp16) {
+ printf("WARN: requested no. of VFs %d exceeds total of %d\n",
+ entry->num_vfs, tmp16);
+ }
+
+ /*
+ * The code below implements the VF Discovery recomandations specified
+ * in PCIe base spec "9.2.1.2 VF Discovery", quoted below:
+ *
+ * VF Discovery
+ *
+ * The First VF Offset and VF Stride fields in the SR-IOV extended
+ * capability are 16-bit Routing ID offsets. These offsets are used to
+ * compute the Routing IDs for the VFs with the following restrictions:
+ * - The value in NumVFs in a PF (Section 9.3.3.7) may affect the
+ * values in First VF Offset (Section 9.3.3.9) and VF Stride
+ * (Section 9.3.3.10) of that PF.
+ * - The value in ARI Capable Hierarchy (Section 9.3.3.3.5) in the
+ * lowest-numbered PF of the Device (for example PF0) may affect
+ * the values in First VF Offset and VF Stride in all PFs of the
+ * Device.
+ * - NumVFs of a PF may only be changed when VF Enable
+ * (Section 9.3.3.3.1) of that PF is Clear.
+ * - ARI Capable Hierarchy (Section 9.3.3.3.5) may only be changed
+ * when VF Enable is Clear in all PFs of a Device.
+ */
+
+ /* Clear VF enable for all PFs */
+ device_foreach_child(pf_dev, dev->parent) {
+ dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
+ &tmp16);
+ tmp16 &= ~PCI_SRIOV_CTRL_VFE;
+ dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
+ tmp16);
+ }
+
+ /* Obtain a reference to PF0 device */
+ if (dm_pci_bus_find_bdf(PCI_BDF(PCI_BUS(entry->bdf),
+ PCI_DEV(entry->bdf), 0), &pf_dev)) {
+ printf("WARN: failed to get PF0\n");
+ }
+
+ if (entry->noari)
+ goto skip_ari;
+
+ /* Check that connected downstream port supports ARI Forwarding */
+ pos = dm_pci_find_capability(dev->parent, PCI_CAP_ID_EXP);
+ dm_pci_read_config32(dev->parent, pos + PCI_EXP_DEVCAP2, &tmp32);
+ if (!(tmp32 & PCI_EXP_DEVCAP2_ARI))
+ goto skip_ari;
+
+ /* Check that PF supports Alternate Routing ID */
+ if (!dm_pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI))
+ goto skip_ari;
+
+ /* Set ARI Capable Hierarcy for PF0 */
+ dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, &tmp16);
+ tmp16 |= PCI_SRIOV_CTRL_ARI;
+ dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, tmp16);
+ have_ari = true;
+
+skip_ari:
+ if (!have_ari) {
+ /*
+ * No ARI support or disabled so clear ARI Capable Hierarcy
+ * for PF0
+ */
+ dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
+ &tmp16);
+ tmp16 &= ~PCI_SRIOV_CTRL_ARI;
+ dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
+ tmp16);
+ }
+
+ /* Set requested number of VFs */
+ dm_pci_write_config16(dev, sriov_pos + PCI_SRIOV_NUM_VF,
+ entry->num_vfs);
+
+ /* Read VF stride and offset with the configs just made */
+ dm_pci_read_config16(dev, sriov_pos + PCI_SRIOV_VF_OFFSET, offset);
+ dm_pci_read_config16(dev, sriov_pos + PCI_SRIOV_VF_STRIDE, stride);
+
+ if (have_ari) {
+ /* Reset to default ARI Capable Hierarcy bit for PF0 */
+ dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
+ &tmp16);
+ tmp16 &= ~PCI_SRIOV_CTRL_ARI;
+ dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL,
+ tmp16);
+ }
+ /* Reset to default the number of VFs */
+ dm_pci_write_config16(dev, sriov_pos + PCI_SRIOV_NUM_VF, 0);
+}
+
+static int fdt_fixup_pci_vfs(void *blob, struct extra_iommu_entry *entry,
+ struct ls_pcie_rc *pcie_rc)
+{
+ struct udevice *dev, *bus;
+ u16 vf_offset, vf_stride;
+ int i, sriov_pos;
+ pci_dev_t bdf;
+
+ if (dm_pci_bus_find_bdf(entry->bdf, &dev)) {
+ printf("ERROR: BDF %d.%d.%d not found\n", PCI_BUS(entry->bdf),
+ PCI_DEV(entry->bdf), PCI_FUNC(entry->bdf));
+ return 0;
+ }
+
+ sriov_pos = dm_pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+ if (!sriov_pos) {
+ printf("WARN: trying to set VFs on non-SRIOV dev\n");
+ return 0;
+ }
+
+ get_vf_offset_and_stride(dev, sriov_pos, entry, &vf_offset, &vf_stride);
+
+ for (bus = dev; device_is_on_pci_bus(bus);)
+ bus = bus->parent;
+
+ bdf = entry->bdf - PCI_BDF(dev_seq(bus), 0, 0) + (vf_offset << 8);
+
+ for (i = 0; i < entry->num_vfs; i++) {
+ if (fdt_fixup_pcie_device_ls(blob, bdf, pcie_rc) < 0)
+ return -1;
+ bdf += vf_stride << 8;
+ }
+
+ printf("Added %d iommu VF mappings for PF %d.%d.%d\n",
+ entry->num_vfs, PCI_BUS(entry->bdf),
+ PCI_DEV(entry->bdf), PCI_FUNC(entry->bdf));
+
+ return 0;
+}
+
+static void fdt_fixup_pcie_ls(void *blob)
+{
+ struct udevice *dev, *bus;
+ struct ls_pcie_rc *pcie_rc;
+ pci_dev_t bdf;
+ struct extra_iommu_entry *entries;
+ int i, cnt, nodeoffset;
+
+
+ /* Scan all known buses */
+ for (pci_find_first_device(&dev);
+ dev;
+ pci_find_next_device(&dev)) {
+ for (bus = dev; device_is_on_pci_bus(bus);)
+ bus = bus->parent;
+
+ /* Only do the fixups for layerscape PCIe controllers */
+ if (!device_is_compatible(bus, "fsl,ls-pcie") &&
+ !device_is_compatible(bus, CONFIG_FSL_PCIE_COMPAT))
+ continue;
+
+ pcie_rc = dev_get_priv(bus);
+
+ /* the DT fixup must be relative to the hose first_busno */
+ bdf = dm_pci_get_bdf(dev) - PCI_BDF(dev_seq(bus), 0, 0);
+
+ if (fdt_fixup_pcie_device_ls(blob, bdf, pcie_rc) < 0)
+ break;
+ }
+
+ if (!IS_ENABLED(CONFIG_PCI_IOMMU_EXTRA_MAPPINGS))
+ goto skip;
+
+ list_for_each_entry(pcie_rc, &ls_pcie_list, list) {
+ nodeoffset = fdt_pcie_get_nodeoffset(blob, pcie_rc);
+ if (nodeoffset < 0) {
+ printf("ERROR: couldn't find pci node\n");
+ continue;
+ }
+
+ entries = get_extra_iommu_ents(blob, nodeoffset,
+ pcie_rc->dbi_res.start, &cnt);
+ if (!entries)
+ continue;
+
+ for (i = 0; i < cnt; i++) {
+ if (entries[i].action == EXTRA_IOMMU_ENTRY_HOTPLUG) {
+ bdf = entries[i].bdf;
+ printf("Added iommu map for hotplug %d.%d.%d\n",
+ PCI_BUS(bdf), PCI_DEV(bdf),
+ PCI_FUNC(bdf));
+ if (fdt_fixup_pcie_device_ls(blob, bdf,
+ pcie_rc) < 0) {
+ free(entries);
+ return;
+ }
+ } else if (entries[i].action == EXTRA_IOMMU_ENTRY_VFS) {
+ if (fdt_fixup_pci_vfs(blob, &entries[i],
+ pcie_rc) < 0) {
+ free(entries);
+ return;
+ }
+ } else {
+ printf("Invalid action %d for BDF %d.%d.%d\n",
+ entries[i].action,
+ PCI_BUS(entries[i].bdf),
+ PCI_DEV(entries[i].bdf),
+ PCI_FUNC(entries[i].bdf));
+ }
+ }
+ free(entries);
+ }
+
+skip:
+ pcie_board_fix_fdt(blob);
+}
+#endif
+
+static void ft_pcie_rc_fix(void *blob, struct ls_pcie_rc *pcie_rc)
+{
+ int off;
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ off = fdt_pcie_get_nodeoffset(blob, pcie_rc);
+ if (off < 0)
+ return;
+
+ if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE)
+ fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+ else
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+}
+
+static void ft_pcie_ep_fix(void *blob, struct ls_pcie_rc *pcie_rc)
+{
+ int off;
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_EP_COMPAT,
+ pcie_rc->dbi_res.start);
+ if (off < 0)
+ return;
+
+ if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL)
+ fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+ else
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+}
+
+static void ft_pcie_ls_setup(void *blob, struct ls_pcie_rc *pcie_rc)
+{
+ ft_pcie_ep_fix(blob, pcie_rc);
+ ft_pcie_rc_fix(blob, pcie_rc);
+}
+
+/* Fixup Kernel DT for PCIe */
+void ft_pci_setup_ls(void *blob, struct bd_info *bd)
+{
+ struct ls_pcie_rc *pcie_rc;
+
+ list_for_each_entry(pcie_rc, &ls_pcie_list, list)
+ ft_pcie_ls_setup(blob, pcie_rc);
+
+#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
+ fdt_fixup_pcie_ls(blob);
+#endif
+}
+
+#else /* !CONFIG_OF_BOARD_SETUP */
+void ft_pci_setup_ls(void *blob, struct bd_info *bd)
+{
+}
+#endif
diff --git a/roms/u-boot/drivers/pci/pcie_layerscape_fixup_common.c b/roms/u-boot/drivers/pci/pcie_layerscape_fixup_common.c
new file mode 100644
index 000000000..8b924d404
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_layerscape_fixup_common.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019-2020 NXP
+ *
+ * PCIe DT fixup for NXP Layerscape SoCs
+ * Author: Wasim Khan <wasim.khan@nxp.com>
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/soc.h>
+#include <linux/libfdt.h>
+#include "pcie_layerscape_fixup_common.h"
+
+void ft_pci_setup(void *blob, struct bd_info *bd)
+{
+#if defined(CONFIG_PCIE_LAYERSCAPE_GEN4)
+ uint svr;
+
+ svr = SVR_SOC_VER(get_svr());
+
+ if (svr == SVR_LX2160A && IS_SVR_REV(get_svr(), 1, 0))
+ ft_pci_setup_ls_gen4(blob, bd);
+ else
+#endif /* CONFIG_PCIE_LAYERSCAPE_GEN4 */
+ ft_pci_setup_ls(blob, bd);
+}
+
+#if defined(CONFIG_FSL_LAYERSCAPE)
+int lx2_board_fix_fdt(void *fdt)
+{
+ char *reg_name, *old_str, *new_str;
+ const char *reg_names;
+ int names_len, old_str_len, new_str_len, remaining_str_len;
+ struct str_map {
+ char *old_str;
+ char *new_str;
+ } reg_names_map[] = {
+ { "csr_axi_slave", "regs" },
+ { "config_axi_slave", "config" }
+ };
+ int off = -1, i;
+ const fdt32_t *prop;
+ u32 ob_wins, ib_wins;
+
+ off = fdt_node_offset_by_compatible(fdt, -1, "fsl,lx2160a-pcie");
+ while (off != -FDT_ERR_NOTFOUND) {
+ fdt_setprop(fdt, off, "compatible", "fsl,ls2088a-pcie",
+ strlen("fsl,ls2088a-pcie") + 1);
+
+ reg_names = fdt_getprop(fdt, off, "reg-names", &names_len);
+ if (!reg_names)
+ continue;
+ reg_name = (char *)reg_names;
+ remaining_str_len = names_len - (reg_name - reg_names);
+ i = 0;
+ while ((i < ARRAY_SIZE(reg_names_map)) && remaining_str_len) {
+ old_str = reg_names_map[i].old_str;
+ new_str = reg_names_map[i].new_str;
+ old_str_len = strlen(old_str);
+ new_str_len = strlen(new_str);
+ if (memcmp(reg_name, old_str, old_str_len) == 0) {
+ /* first only leave required bytes for new_str
+ * and copy rest of the string after it
+ */
+ memcpy(reg_name + new_str_len,
+ reg_name + old_str_len,
+ remaining_str_len - old_str_len);
+
+ /* Now copy new_str */
+ memcpy(reg_name, new_str, new_str_len);
+ names_len -= old_str_len;
+ names_len += new_str_len;
+ i++;
+ }
+
+ reg_name = memchr(reg_name, '\0', remaining_str_len);
+ if (!reg_name)
+ break;
+ reg_name += 1;
+
+ remaining_str_len = names_len - (reg_name - reg_names);
+ }
+ fdt_setprop(fdt, off, "reg-names", reg_names, names_len);
+ fdt_delprop(fdt, off, "apio-wins");
+ fdt_delprop(fdt, off, "ppio-wins");
+ off = fdt_node_offset_by_compatible(fdt, off,
+ "fsl,lx2160a-pcie");
+ }
+
+ /* Fixup PCIe EP nodes */
+ off = -1;
+ off = fdt_node_offset_by_compatible(fdt, off, "fsl,lx2160a-pcie-ep");
+ while (off != -FDT_ERR_NOTFOUND) {
+ fdt_setprop_string(fdt, off, "compatible",
+ "fsl,lx2160ar2-pcie-ep");
+ prop = fdt_getprop(fdt, off, "apio-wins", NULL);
+ if (!prop) {
+ printf("%s: Failed to fixup PCIe EP node @0x%x\n",
+ __func__, off);
+ off = fdt_node_offset_by_compatible(fdt, off,
+ "fsl,lx2160a-pcie-ep");
+ continue;
+ }
+
+ ob_wins = fdt32_to_cpu(*prop);
+ ib_wins = (ob_wins == 256) ? 24 : 8;
+ fdt_setprop_u32(fdt, off, "num-ib-windows", ib_wins);
+ fdt_setprop_u32(fdt, off, "num-ob-windows", ob_wins);
+ fdt_delprop(fdt, off, "apio-wins");
+
+ off = fdt_node_offset_by_compatible(fdt, off,
+ "fsl,lx2160a-pcie-ep");
+ }
+
+ return 0;
+}
+
+int pcie_board_fix_fdt(void *fdt)
+{
+ uint svr;
+
+ svr = SVR_SOC_VER(get_svr());
+
+ if ((svr == SVR_LX2160A || svr == SVR_LX2162A ||
+ svr == SVR_LX2120A || svr == SVR_LX2080A ||
+ svr == SVR_LX2122A || svr == SVR_LX2082A) &&
+ IS_SVR_REV(get_svr(), 2, 0))
+ return lx2_board_fix_fdt(fdt);
+
+ return 0;
+}
+
+#if defined(CONFIG_ARCH_LX2160A) || defined(CONFIG_ARCH_LX2162A)
+/* returns the next available streamid for pcie, -errno if failed */
+int pcie_next_streamid(int currentid, int idx)
+{
+ if (currentid > FSL_PEX_STREAM_ID_END)
+ return -EINVAL;
+
+ return currentid | ((idx + 1) << 11);
+}
+#else
+/* returns the next available streamid for pcie, -errno if failed */
+int pcie_next_streamid(int currentid, int idx)
+{
+ static int next_stream_id = FSL_PEX_STREAM_ID_START;
+
+ if (next_stream_id > FSL_PEX_STREAM_ID_END)
+ return -EINVAL;
+
+ return next_stream_id++;
+}
+#endif
+#endif /* CONFIG_FSL_LAYERSCAPE */
diff --git a/roms/u-boot/drivers/pci/pcie_layerscape_fixup_common.h b/roms/u-boot/drivers/pci/pcie_layerscape_fixup_common.h
new file mode 100644
index 000000000..70bd3f0cb
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_layerscape_fixup_common.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019-2020 NXP
+ *
+ * PCIe DT fixup for NXP Layerscape SoCs
+ * Author: Wasim Khan <wasim.khan@nxp.com>
+ *
+ */
+#ifndef _PCIE_LAYERSCAPE_FIXUP_COMMON_H_
+#define _PCIE_LAYERSCAPE_FIXUP_COMMON_H_
+
+#include <common.h>
+
+void ft_pci_setup_ls(void *blob, struct bd_info *bd);
+
+#ifdef CONFIG_PCIE_LAYERSCAPE_GEN4
+void ft_pci_setup_ls_gen4(void *blob, struct bd_info *bd);
+#endif /* CONFIG_PCIE_LAYERSCAPE_GEN4 */
+int pcie_next_streamid(int currentid, int id);
+int pcie_board_fix_fdt(void *fdt);
+
+#endif //_PCIE_LAYERSCAPE_FIXUP_COMMON_H_
diff --git a/roms/u-boot/drivers/pci/pcie_layerscape_gen4.c b/roms/u-boot/drivers/pci/pcie_layerscape_gen4.c
new file mode 100644
index 000000000..255e73181
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_layerscape_gen4.c
@@ -0,0 +1,585 @@
+// SPDX-License-Identifier: GPL-2.0+ OR X11
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * PCIe Gen4 driver for NXP Layerscape SoCs
+ * Author: Hou Zhiqiang <Minder.Hou@gmail.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/arch/fsl_serdes.h>
+#include <pci.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <malloc.h>
+#include <dm.h>
+#include <linux/sizes.h>
+
+#include "pcie_layerscape_gen4.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+LIST_HEAD(ls_pcie_g4_list);
+
+static u64 bar_size[4] = {
+ PCIE_BAR0_SIZE,
+ PCIE_BAR1_SIZE,
+ PCIE_BAR2_SIZE,
+ PCIE_BAR4_SIZE
+};
+
+static int ls_pcie_g4_ltssm(struct ls_pcie_g4 *pcie)
+{
+ u32 state;
+
+ state = pf_ctrl_readl(pcie, PCIE_LTSSM_STA) & LTSSM_STATE_MASK;
+
+ return state;
+}
+
+static int ls_pcie_g4_link_up(struct ls_pcie_g4 *pcie)
+{
+ int ltssm;
+
+ ltssm = ls_pcie_g4_ltssm(pcie);
+ if (ltssm != LTSSM_PCIE_L0)
+ return 0;
+
+ return 1;
+}
+
+static void ls_pcie_g4_ep_enable_cfg(struct ls_pcie_g4 *pcie)
+{
+ ccsr_writel(pcie, GPEX_CFG_READY, PCIE_CONFIG_READY);
+}
+
+static void ls_pcie_g4_cfg_set_target(struct ls_pcie_g4 *pcie, u32 target)
+{
+ ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_L(0), target);
+ ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_H(0), 0);
+}
+
+static int ls_pcie_g4_outbound_win_set(struct ls_pcie_g4 *pcie, int idx,
+ int type, u64 phys, u64 bus_addr,
+ pci_size_t size)
+{
+ u32 val;
+ u32 size_h, size_l;
+
+ if (idx >= PAB_WINS_NUM)
+ return -EINVAL;
+
+ size_h = upper_32_bits(~(size - 1));
+ size_l = lower_32_bits(~(size - 1));
+
+ val = ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(idx));
+ val &= ~((AXI_AMAP_CTRL_TYPE_MASK << AXI_AMAP_CTRL_TYPE_SHIFT) |
+ (AXI_AMAP_CTRL_SIZE_MASK << AXI_AMAP_CTRL_SIZE_SHIFT) |
+ AXI_AMAP_CTRL_EN);
+ val |= ((type & AXI_AMAP_CTRL_TYPE_MASK) << AXI_AMAP_CTRL_TYPE_SHIFT) |
+ ((size_l >> AXI_AMAP_CTRL_SIZE_SHIFT) <<
+ AXI_AMAP_CTRL_SIZE_SHIFT) | AXI_AMAP_CTRL_EN;
+
+ ccsr_writel(pcie, PAB_AXI_AMAP_CTRL(idx), val);
+
+ ccsr_writel(pcie, PAB_AXI_AMAP_AXI_WIN(idx), lower_32_bits(phys));
+ ccsr_writel(pcie, PAB_EXT_AXI_AMAP_AXI_WIN(idx), upper_32_bits(phys));
+ ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_L(idx), lower_32_bits(bus_addr));
+ ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_H(idx), upper_32_bits(bus_addr));
+ ccsr_writel(pcie, PAB_EXT_AXI_AMAP_SIZE(idx), size_h);
+
+ return 0;
+}
+
+static int ls_pcie_g4_rc_inbound_win_set(struct ls_pcie_g4 *pcie, int idx,
+ int type, u64 phys, u64 bus_addr,
+ pci_size_t size)
+{
+ u32 val;
+ pci_size_t win_size = ~(size - 1);
+
+ val = ccsr_readl(pcie, PAB_PEX_AMAP_CTRL(idx));
+
+ val &= ~(PEX_AMAP_CTRL_TYPE_MASK << PEX_AMAP_CTRL_TYPE_SHIFT);
+ val &= ~(PEX_AMAP_CTRL_EN_MASK << PEX_AMAP_CTRL_EN_SHIFT);
+ val = (val | (type << PEX_AMAP_CTRL_TYPE_SHIFT));
+ val = (val | (1 << PEX_AMAP_CTRL_EN_SHIFT));
+
+ ccsr_writel(pcie, PAB_PEX_AMAP_CTRL(idx),
+ val | lower_32_bits(win_size));
+
+ ccsr_writel(pcie, PAB_EXT_PEX_AMAP_SIZE(idx), upper_32_bits(win_size));
+ ccsr_writel(pcie, PAB_PEX_AMAP_AXI_WIN(idx), lower_32_bits(phys));
+ ccsr_writel(pcie, PAB_EXT_PEX_AMAP_AXI_WIN(idx), upper_32_bits(phys));
+ ccsr_writel(pcie, PAB_PEX_AMAP_PEX_WIN_L(idx), lower_32_bits(bus_addr));
+ ccsr_writel(pcie, PAB_PEX_AMAP_PEX_WIN_H(idx), upper_32_bits(bus_addr));
+
+ return 0;
+}
+
+static void ls_pcie_g4_dump_wins(struct ls_pcie_g4 *pcie, int wins)
+{
+ int i;
+
+ for (i = 0; i < wins; i++) {
+ debug("APIO Win%d:\n", i);
+ debug("\tLOWER PHYS: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_AXI_WIN(i)));
+ debug("\tUPPER PHYS: 0x%08x\n",
+ ccsr_readl(pcie, PAB_EXT_AXI_AMAP_AXI_WIN(i)));
+ debug("\tLOWER BUS: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_L(i)));
+ debug("\tUPPER BUS: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_H(i)));
+ debug("\tSIZE: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(i)) &
+ (AXI_AMAP_CTRL_SIZE_MASK << AXI_AMAP_CTRL_SIZE_SHIFT));
+ debug("\tEXT_SIZE: 0x%08x\n",
+ ccsr_readl(pcie, PAB_EXT_AXI_AMAP_SIZE(i)));
+ debug("\tPARAM: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(i)));
+ debug("\tCTRL: 0x%08x\n",
+ ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(i)));
+ }
+}
+
+static void ls_pcie_g4_setup_wins(struct ls_pcie_g4 *pcie)
+{
+ struct pci_region *io, *mem, *pref;
+ int idx = 1;
+
+ /* INBOUND WIN */
+ ls_pcie_g4_rc_inbound_win_set(pcie, 0, IB_TYPE_MEM_F, 0, 0, SIZE_1T);
+
+ /* OUTBOUND WIN 0: CFG */
+ ls_pcie_g4_outbound_win_set(pcie, 0, PAB_AXI_TYPE_CFG,
+ pcie->cfg_res.start, 0,
+ fdt_resource_size(&pcie->cfg_res));
+
+ pci_get_regions(pcie->bus, &io, &mem, &pref);
+
+ if (io)
+ /* OUTBOUND WIN: IO */
+ ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_IO,
+ io->phys_start, io->bus_start,
+ io->size);
+
+ if (mem)
+ /* OUTBOUND WIN: MEM */
+ ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_MEM,
+ mem->phys_start, mem->bus_start,
+ mem->size);
+
+ if (pref)
+ /* OUTBOUND WIN: perf MEM */
+ ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_MEM,
+ pref->phys_start, pref->bus_start,
+ pref->size);
+
+ ls_pcie_g4_dump_wins(pcie, idx);
+}
+
+/* Return 0 if the address is valid, -errno if not valid */
+static int ls_pcie_g4_addr_valid(struct ls_pcie_g4 *pcie, pci_dev_t bdf)
+{
+ struct udevice *bus = pcie->bus;
+
+ if (pcie->mode == PCI_HEADER_TYPE_NORMAL)
+ return -ENODEV;
+
+ if (!pcie->enabled)
+ return -ENXIO;
+
+ if (PCI_BUS(bdf) < dev_seq(bus))
+ return -EINVAL;
+
+ if ((PCI_BUS(bdf) > dev_seq(bus)) && (!ls_pcie_g4_link_up(pcie)))
+ return -EINVAL;
+
+ if (PCI_BUS(bdf) <= (dev_seq(bus) + 1) && (PCI_DEV(bdf) > 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+void *ls_pcie_g4_conf_address(struct ls_pcie_g4 *pcie, pci_dev_t bdf,
+ int offset)
+{
+ struct udevice *bus = pcie->bus;
+ u32 target;
+
+ if (PCI_BUS(bdf) == dev_seq(bus)) {
+ if (offset < INDIRECT_ADDR_BNDRY) {
+ ccsr_set_page(pcie, 0);
+ return pcie->ccsr + offset;
+ }
+
+ ccsr_set_page(pcie, OFFSET_TO_PAGE_IDX(offset));
+ return pcie->ccsr + OFFSET_TO_PAGE_ADDR(offset);
+ }
+
+ target = PAB_TARGET_BUS(PCI_BUS(bdf) - dev_seq(bus)) |
+ PAB_TARGET_DEV(PCI_DEV(bdf)) |
+ PAB_TARGET_FUNC(PCI_FUNC(bdf));
+
+ ls_pcie_g4_cfg_set_target(pcie, target);
+
+ return pcie->cfg + offset;
+}
+
+static int ls_pcie_g4_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct ls_pcie_g4 *pcie = dev_get_priv(bus);
+ void *address;
+ int ret = 0;
+
+ if (ls_pcie_g4_addr_valid(pcie, bdf)) {
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ address = ls_pcie_g4_conf_address(pcie, bdf, offset);
+
+ switch (size) {
+ case PCI_SIZE_8:
+ *valuep = readb(address);
+ break;
+ case PCI_SIZE_16:
+ *valuep = readw(address);
+ break;
+ case PCI_SIZE_32:
+ *valuep = readl(address);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ls_pcie_g4_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct ls_pcie_g4 *pcie = dev_get_priv(bus);
+ void *address;
+
+ if (ls_pcie_g4_addr_valid(pcie, bdf))
+ return 0;
+
+ address = ls_pcie_g4_conf_address(pcie, bdf, offset);
+
+ switch (size) {
+ case PCI_SIZE_8:
+ writeb(value, address);
+ return 0;
+ case PCI_SIZE_16:
+ writew(value, address);
+ return 0;
+ case PCI_SIZE_32:
+ writel(value, address);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void ls_pcie_g4_setup_ctrl(struct ls_pcie_g4 *pcie)
+{
+ u32 val;
+
+ /* Fix class code */
+ val = ccsr_readl(pcie, GPEX_CLASSCODE);
+ val &= ~(GPEX_CLASSCODE_MASK << GPEX_CLASSCODE_SHIFT);
+ val |= PCI_CLASS_BRIDGE_PCI << GPEX_CLASSCODE_SHIFT;
+ ccsr_writel(pcie, GPEX_CLASSCODE, val);
+
+ /* Enable APIO and Memory/IO/CFG Wins */
+ val = ccsr_readl(pcie, PAB_AXI_PIO_CTRL(0));
+ val |= APIO_EN | MEM_WIN_EN | IO_WIN_EN | CFG_WIN_EN;
+ ccsr_writel(pcie, PAB_AXI_PIO_CTRL(0), val);
+
+ ls_pcie_g4_setup_wins(pcie);
+
+ pcie->stream_id_cur = 0;
+}
+
+static void ls_pcie_g4_ep_inbound_win_set(struct ls_pcie_g4 *pcie, int pf,
+ int bar, u64 phys)
+{
+ u32 val;
+
+ /* PF BAR1 is for MSI-X and only need to enable */
+ if (bar == 1) {
+ ccsr_writel(pcie, PAB_PEX_BAR_AMAP(pf, bar), BAR_AMAP_EN);
+ return;
+ }
+
+ val = upper_32_bits(phys);
+ ccsr_writel(pcie, PAB_EXT_PEX_BAR_AMAP(pf, bar), val);
+ val = lower_32_bits(phys) | BAR_AMAP_EN;
+ ccsr_writel(pcie, PAB_PEX_BAR_AMAP(pf, bar), val);
+}
+
+static void ls_pcie_g4_ep_setup_wins(struct ls_pcie_g4 *pcie, int pf)
+{
+ u64 phys;
+ int bar;
+ u32 val;
+
+ if ((!pcie->sriov_support && pf > LS_G4_PF0) || pf > LS_G4_PF1)
+ return;
+
+ phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR_SIZE * 4 * pf;
+ for (bar = 0; bar < PF_BAR_NUM; bar++) {
+ ls_pcie_g4_ep_inbound_win_set(pcie, pf, bar, phys);
+ phys += PCIE_BAR_SIZE;
+ }
+
+ /* OUTBOUND: map MEM */
+ ls_pcie_g4_outbound_win_set(pcie, pf, PAB_AXI_TYPE_MEM,
+ pcie->cfg_res.start +
+ CONFIG_SYS_PCI_MEMORY_SIZE * pf, 0x0,
+ CONFIG_SYS_PCI_MEMORY_SIZE);
+
+ val = ccsr_readl(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(pf));
+ val &= ~FUNC_NUM_PCIE_MASK;
+ val |= pf;
+ ccsr_writel(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(pf), val);
+}
+
+static void ls_pcie_g4_ep_enable_bar(struct ls_pcie_g4 *pcie, int pf,
+ int bar, bool vf_bar, bool enable)
+{
+ u32 val;
+ u32 bar_pos = BAR_POS(bar, pf, vf_bar);
+
+ val = ccsr_readl(pcie, GPEX_BAR_ENABLE);
+ if (enable)
+ val |= 1 << bar_pos;
+ else
+ val &= ~(1 << bar_pos);
+ ccsr_writel(pcie, GPEX_BAR_ENABLE, val);
+}
+
+static void ls_pcie_g4_ep_set_bar_size(struct ls_pcie_g4 *pcie, int pf,
+ int bar, bool vf_bar, u64 size)
+{
+ u32 bar_pos = BAR_POS(bar, pf, vf_bar);
+ u32 mask_l = lower_32_bits(~(size - 1));
+ u32 mask_h = upper_32_bits(~(size - 1));
+
+ ccsr_writel(pcie, GPEX_BAR_SELECT, bar_pos);
+ ccsr_writel(pcie, GPEX_BAR_SIZE_LDW, mask_l);
+ ccsr_writel(pcie, GPEX_BAR_SIZE_UDW, mask_h);
+}
+
+static void ls_pcie_g4_ep_setup_bar(struct ls_pcie_g4 *pcie, int pf,
+ int bar, bool vf_bar, u64 size)
+{
+ bool en = size ? true : false;
+
+ ls_pcie_g4_ep_enable_bar(pcie, pf, bar, vf_bar, en);
+ ls_pcie_g4_ep_set_bar_size(pcie, pf, bar, vf_bar, size);
+}
+
+static void ls_pcie_g4_ep_setup_bars(struct ls_pcie_g4 *pcie, int pf)
+{
+ int bar;
+
+ /* Setup PF BARs */
+ for (bar = 0; bar < PF_BAR_NUM; bar++)
+ ls_pcie_g4_ep_setup_bar(pcie, pf, bar, false, bar_size[bar]);
+
+ if (!pcie->sriov_support)
+ return;
+
+ /* Setup VF BARs */
+ for (bar = 0; bar < VF_BAR_NUM; bar++)
+ ls_pcie_g4_ep_setup_bar(pcie, pf, bar, true, bar_size[bar]);
+}
+
+static void ls_pcie_g4_set_sriov(struct ls_pcie_g4 *pcie, int pf)
+{
+ unsigned int val;
+
+ val = ccsr_readl(pcie, GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf));
+ val &= ~(TTL_VF_MASK << TTL_VF_SHIFT);
+ val |= PCIE_VF_NUM << TTL_VF_SHIFT;
+ val &= ~(INI_VF_MASK << INI_VF_SHIFT);
+ val |= PCIE_VF_NUM << INI_VF_SHIFT;
+ ccsr_writel(pcie, GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf), val);
+
+ val = ccsr_readl(pcie, PCIE_SRIOV_VF_OFFSET_STRIDE);
+ val += PCIE_VF_NUM * pf - pf;
+ ccsr_writel(pcie, GPEX_SRIOV_VF_OFFSET_STRIDE(pf), val);
+}
+
+static void ls_pcie_g4_setup_ep(struct ls_pcie_g4 *pcie)
+{
+ u32 pf, sriov;
+ u32 val;
+ int i;
+
+ /* Enable APIO and Memory Win */
+ val = ccsr_readl(pcie, PAB_AXI_PIO_CTRL(0));
+ val |= APIO_EN | MEM_WIN_EN;
+ ccsr_writel(pcie, PAB_AXI_PIO_CTRL(0), val);
+
+ sriov = ccsr_readl(pcie, PCIE_SRIOV_CAPABILITY);
+ if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV)
+ pcie->sriov_support = 1;
+
+ pf = pcie->sriov_support ? PCIE_PF_NUM : 1;
+
+ for (i = 0; i < pf; i++) {
+ ls_pcie_g4_ep_setup_bars(pcie, i);
+ ls_pcie_g4_ep_setup_wins(pcie, i);
+ if (pcie->sriov_support)
+ ls_pcie_g4_set_sriov(pcie, i);
+ }
+
+ ls_pcie_g4_ep_enable_cfg(pcie);
+ ls_pcie_g4_dump_wins(pcie, pf);
+}
+
+static int ls_pcie_g4_probe(struct udevice *dev)
+{
+ struct ls_pcie_g4 *pcie = dev_get_priv(dev);
+ const void *fdt = gd->fdt_blob;
+ int node = dev_of_offset(dev);
+ u32 link_ctrl_sta;
+ u32 val;
+ int ret;
+ fdt_size_t cfg_size;
+
+ pcie->bus = dev;
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "ccsr", &pcie->ccsr_res);
+ if (ret) {
+ printf("ls-pcie-g4: resource \"ccsr\" not found\n");
+ return ret;
+ }
+
+ pcie->idx = (pcie->ccsr_res.start - PCIE_SYS_BASE_ADDR) /
+ PCIE_CCSR_SIZE;
+
+ list_add(&pcie->list, &ls_pcie_g4_list);
+
+ pcie->enabled = is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx));
+ if (!pcie->enabled) {
+ printf("PCIe%d: %s disabled\n", PCIE_SRDS_PRTCL(pcie->idx),
+ dev->name);
+ return 0;
+ }
+
+ pcie->ccsr = map_physmem(pcie->ccsr_res.start,
+ fdt_resource_size(&pcie->ccsr_res),
+ MAP_NOCACHE);
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "config", &pcie->cfg_res);
+ if (ret) {
+ printf("%s: resource \"config\" not found\n", dev->name);
+ return ret;
+ }
+
+ cfg_size = fdt_resource_size(&pcie->cfg_res);
+ if (cfg_size < SZ_4K) {
+ printf("PCIe%d: %s Invalid size(0x%llx) for resource \"config\",expected minimum 0x%x\n",
+ PCIE_SRDS_PRTCL(pcie->idx), dev->name, cfg_size, SZ_4K);
+ return 0;
+ }
+
+ pcie->cfg = map_physmem(pcie->cfg_res.start,
+ fdt_resource_size(&pcie->cfg_res),
+ MAP_NOCACHE);
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "lut", &pcie->lut_res);
+ if (ret) {
+ printf("ls-pcie-g4: resource \"lut\" not found\n");
+ return ret;
+ }
+
+ pcie->lut = map_physmem(pcie->lut_res.start,
+ fdt_resource_size(&pcie->lut_res),
+ MAP_NOCACHE);
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "pf_ctrl", &pcie->pf_ctrl_res);
+ if (ret) {
+ printf("ls-pcie-g4: resource \"pf_ctrl\" not found\n");
+ return ret;
+ }
+
+ pcie->pf_ctrl = map_physmem(pcie->pf_ctrl_res.start,
+ fdt_resource_size(&pcie->pf_ctrl_res),
+ MAP_NOCACHE);
+
+ pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian");
+
+ debug("%s ccsr:%lx, cfg:0x%lx, big-endian:%d\n",
+ dev->name, (unsigned long)pcie->ccsr, (unsigned long)pcie->cfg,
+ pcie->big_endian);
+
+ pcie->mode = readb(pcie->ccsr + PCI_HEADER_TYPE) & 0x7f;
+
+ if (pcie->mode == PCI_HEADER_TYPE_NORMAL) {
+ printf("PCIe%u: %s %s", PCIE_SRDS_PRTCL(pcie->idx), dev->name,
+ "Endpoint");
+ ls_pcie_g4_setup_ep(pcie);
+ } else {
+ printf("PCIe%u: %s %s", PCIE_SRDS_PRTCL(pcie->idx), dev->name,
+ "Root Complex");
+ ls_pcie_g4_setup_ctrl(pcie);
+ }
+
+ /* Enable Amba & PEX PIO */
+ val = ccsr_readl(pcie, PAB_CTRL);
+ val |= PAB_CTRL_APIO_EN | PAB_CTRL_PPIO_EN;
+ ccsr_writel(pcie, PAB_CTRL, val);
+
+ val = ccsr_readl(pcie, PAB_PEX_PIO_CTRL(0));
+ val |= PPIO_EN;
+ ccsr_writel(pcie, PAB_PEX_PIO_CTRL(0), val);
+
+ if (!ls_pcie_g4_link_up(pcie)) {
+ /* Let the user know there's no PCIe link */
+ printf(": no link\n");
+ return 0;
+ }
+
+ /* Print the negotiated PCIe link width */
+ link_ctrl_sta = ccsr_readl(pcie, PCIE_LINK_CTRL_STA);
+ printf(": x%d gen%d\n",
+ (link_ctrl_sta >> PCIE_LINK_WIDTH_SHIFT & PCIE_LINK_WIDTH_MASK),
+ (link_ctrl_sta >> PCIE_LINK_SPEED_SHIFT) & PCIE_LINK_SPEED_MASK);
+
+ return 0;
+}
+
+static const struct dm_pci_ops ls_pcie_g4_ops = {
+ .read_config = ls_pcie_g4_read_config,
+ .write_config = ls_pcie_g4_write_config,
+};
+
+static const struct udevice_id ls_pcie_g4_ids[] = {
+ { .compatible = "fsl,lx2160a-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_layerscape_gen4) = {
+ .name = "pcie_layerscape_gen4",
+ .id = UCLASS_PCI,
+ .of_match = ls_pcie_g4_ids,
+ .ops = &ls_pcie_g4_ops,
+ .probe = ls_pcie_g4_probe,
+ .priv_auto = sizeof(struct ls_pcie_g4),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_layerscape_gen4.h b/roms/u-boot/drivers/pci/pcie_layerscape_gen4.h
new file mode 100644
index 000000000..483eb538b
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_layerscape_gen4.h
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018-2019 NXP
+ *
+ * PCIe Gen4 driver for NXP Layerscape SoCs
+ * Author: Hou Zhiqiang <Minder.Hou@gmail.com>
+ */
+
+#ifndef _PCIE_LAYERSCAPE_GEN4_H_
+#define _PCIE_LAYERSCAPE_GEN4_H_
+#include <pci.h>
+#include <linux/bitops.h>
+
+#ifndef CONFIG_SYS_PCI_MEMORY_SIZE
+#define CONFIG_SYS_PCI_MEMORY_SIZE (4 * 1024 * 1024 * 1024ULL)
+#endif
+
+#ifndef CONFIG_SYS_PCI_EP_MEMORY_BASE
+#define CONFIG_SYS_PCI_EP_MEMORY_BASE CONFIG_SYS_LOAD_ADDR
+#endif
+
+#define PCIE_PF_NUM 2
+#define PCIE_VF_NUM 32
+
+#define LS_G4_PF0 0
+#define LS_G4_PF1 1
+#define PF_BAR_NUM 4
+#define VF_BAR_NUM 4
+#define PCIE_BAR_SIZE (8 * 1024) /* 8K */
+#define PCIE_BAR0_SIZE PCIE_BAR_SIZE
+#define PCIE_BAR1_SIZE PCIE_BAR_SIZE
+#define PCIE_BAR2_SIZE PCIE_BAR_SIZE
+#define PCIE_BAR4_SIZE PCIE_BAR_SIZE
+#define SIZE_1T (1024 * 1024 * 1024 * 1024ULL)
+
+/* GPEX CSR */
+#define GPEX_CLASSCODE 0x474
+#define GPEX_CLASSCODE_SHIFT 16
+#define GPEX_CLASSCODE_MASK 0xffff
+
+#define GPEX_CFG_READY 0x4b0
+#define PCIE_CONFIG_READY BIT(0)
+
+#define GPEX_BAR_ENABLE 0x4d4
+#define GPEX_BAR_SIZE_LDW 0x4d8
+#define GPEX_BAR_SIZE_UDW 0x4dC
+#define GPEX_BAR_SELECT 0x4e0
+
+#define BAR_POS(bar, pf, vf_bar) \
+ ((bar) + (pf) * PF_BAR_NUM + (vf_bar) * PCIE_PF_NUM * PF_BAR_NUM)
+
+#define GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf) (0x644 + (pf) * 4)
+#define TTL_VF_MASK 0xffff
+#define TTL_VF_SHIFT 16
+#define INI_VF_MASK 0xffff
+#define INI_VF_SHIFT 0
+#define GPEX_SRIOV_VF_OFFSET_STRIDE(pf) (0x704 + (pf) * 4)
+
+/* PAB CSR */
+#define PAB_CTRL 0x808
+#define PAB_CTRL_APIO_EN BIT(0)
+#define PAB_CTRL_PPIO_EN BIT(1)
+#define PAB_CTRL_MAX_BRST_LEN_SHIFT 4
+#define PAB_CTRL_MAX_BRST_LEN_MASK 0x3
+#define PAB_CTRL_PAGE_SEL_SHIFT 13
+#define PAB_CTRL_PAGE_SEL_MASK 0x3f
+#define PAB_CTRL_FUNC_SEL_SHIFT 19
+#define PAB_CTRL_FUNC_SEL_MASK 0x1ff
+
+#define PAB_RST_CTRL 0x820
+#define PAB_BR_STAT 0x80c
+
+/* AXI PIO Engines */
+#define PAB_AXI_PIO_CTRL(idx) (0x840 + 0x10 * (idx))
+#define APIO_EN BIT(0)
+#define MEM_WIN_EN BIT(1)
+#define IO_WIN_EN BIT(2)
+#define CFG_WIN_EN BIT(3)
+#define PAB_AXI_PIO_STAT(idx) (0x844 + 0x10 * (idx))
+#define PAB_AXI_PIO_SL_CMD_STAT(idx) (0x848 + 0x10 * (idx))
+#define PAB_AXI_PIO_SL_ADDR_STAT(idx) (0x84c + 0x10 * (idx))
+#define PAB_AXI_PIO_SL_EXT_ADDR_STAT(idx) (0xb8a0 + 0x4 * (idx))
+
+/* PEX PIO Engines */
+#define PAB_PEX_PIO_CTRL(idx) (0x8c0 + 0x10 * (idx))
+#define PPIO_EN BIT(0)
+#define PAB_PEX_PIO_STAT(idx) (0x8c4 + 0x10 * (idx))
+#define PAB_PEX_PIO_MT_STAT(idx) (0x8c8 + 0x10 * (idx))
+
+#define INDIRECT_ADDR_BNDRY 0xc00
+#define PAGE_IDX_SHIFT 10
+#define PAGE_ADDR_MASK 0x3ff
+
+#define OFFSET_TO_PAGE_IDX(off) \
+ (((off) >> PAGE_IDX_SHIFT) & PAB_CTRL_PAGE_SEL_MASK)
+
+#define OFFSET_TO_PAGE_ADDR(off) \
+ (((off) & PAGE_ADDR_MASK) | INDIRECT_ADDR_BNDRY)
+
+/* APIO WINs */
+#define PAB_AXI_AMAP_CTRL(idx) (0xba0 + 0x10 * (idx))
+#define PAB_EXT_AXI_AMAP_SIZE(idx) (0xbaf0 + 0x4 * (idx))
+#define PAB_AXI_AMAP_AXI_WIN(idx) (0xba4 + 0x10 * (idx))
+#define PAB_EXT_AXI_AMAP_AXI_WIN(idx) (0x80a0 + 0x4 * (idx))
+#define PAB_AXI_AMAP_PEX_WIN_L(idx) (0xba8 + 0x10 * (idx))
+#define PAB_AXI_AMAP_PEX_WIN_H(idx) (0xbac + 0x10 * (idx))
+#define PAB_AXI_AMAP_PCI_HDR_PARAM(idx) (0x5ba0 + 0x4 * (idx))
+#define FUNC_NUM_PCIE_MASK GENMASK(7, 0)
+
+#define AXI_AMAP_CTRL_EN BIT(0)
+#define AXI_AMAP_CTRL_TYPE_SHIFT 1
+#define AXI_AMAP_CTRL_TYPE_MASK 0x3
+#define AXI_AMAP_CTRL_SIZE_SHIFT 10
+#define AXI_AMAP_CTRL_SIZE_MASK 0x3fffff
+
+#define PAB_TARGET_BUS(x) (((x) & 0xff) << 24)
+#define PAB_TARGET_DEV(x) (((x) & 0x1f) << 19)
+#define PAB_TARGET_FUNC(x) (((x) & 0x7) << 16)
+
+#define PAB_AXI_TYPE_CFG 0x00
+#define PAB_AXI_TYPE_IO 0x01
+#define PAB_AXI_TYPE_MEM 0x02
+#define PAB_AXI_TYPE_ATOM 0x03
+
+#define PAB_WINS_NUM 256
+
+/* PPIO WINs RC mode */
+#define PAB_PEX_AMAP_CTRL(idx) (0x4ba0 + 0x10 * (idx))
+#define PAB_EXT_PEX_AMAP_SIZE(idx) (0xbef0 + 0x04 * (idx))
+#define PAB_PEX_AMAP_AXI_WIN(idx) (0x4ba4 + 0x10 * (idx))
+#define PAB_EXT_PEX_AMAP_AXI_WIN(idx) (0xb4a0 + 0x04 * (idx))
+#define PAB_PEX_AMAP_PEX_WIN_L(idx) (0x4ba8 + 0x10 * (idx))
+#define PAB_PEX_AMAP_PEX_WIN_H(idx) (0x4bac + 0x10 * (idx))
+
+#define IB_TYPE_MEM_F 0x2
+#define IB_TYPE_MEM_NF 0x3
+
+#define PEX_AMAP_CTRL_TYPE_SHIFT 0x1
+#define PEX_AMAP_CTRL_EN_SHIFT 0x0
+#define PEX_AMAP_CTRL_TYPE_MASK 0x3
+#define PEX_AMAP_CTRL_EN_MASK 0x1
+
+/* PPIO WINs EP mode */
+#define PAB_PEX_BAR_AMAP(pf, bar) \
+ (0x1ba0 + 0x20 * (pf) + 4 * (bar))
+#define BAR_AMAP_EN BIT(0)
+#define PAB_EXT_PEX_BAR_AMAP(pf, bar) \
+ (0x84a0 + 0x20 * (pf) + 4 * (bar))
+
+/* CCSR registers */
+#define PCIE_LINK_CTRL_STA 0x5c
+#define PCIE_LINK_SPEED_SHIFT 16
+#define PCIE_LINK_SPEED_MASK 0x0f
+#define PCIE_LINK_WIDTH_SHIFT 20
+#define PCIE_LINK_WIDTH_MASK 0x3f
+#define PCIE_SRIOV_CAPABILITY 0x2a0
+#define PCIE_SRIOV_VF_OFFSET_STRIDE 0x2b4
+
+/* LUT registers */
+#define PCIE_LUT_UDR(n) (0x800 + (n) * 8)
+#define PCIE_LUT_LDR(n) (0x804 + (n) * 8)
+#define PCIE_LUT_ENABLE BIT(31)
+#define PCIE_LUT_ENTRY_COUNT 32
+
+/* PF control registers */
+#define PCIE_LTSSM_STA 0x7fc
+#define LTSSM_STATE_MASK 0x7f
+#define LTSSM_PCIE_L0 0x2d /* L0 state */
+
+#define PCIE_SRDS_PRTCL(idx) (PCIE1 + (idx))
+#define PCIE_SYS_BASE_ADDR 0x3400000
+#define PCIE_CCSR_SIZE 0x0100000
+
+struct ls_pcie_g4 {
+ int idx;
+ struct list_head list;
+ struct udevice *bus;
+ struct fdt_resource ccsr_res;
+ struct fdt_resource cfg_res;
+ struct fdt_resource lut_res;
+ struct fdt_resource pf_ctrl_res;
+ void __iomem *ccsr;
+ void __iomem *cfg;
+ void __iomem *lut;
+ void __iomem *pf_ctrl;
+ bool big_endian;
+ bool enabled;
+ int next_lut_index;
+ struct pci_controller hose;
+ int stream_id_cur;
+ int mode;
+ int sriov_support;
+};
+
+extern struct list_head ls_pcie_g4_list;
+
+static inline void lut_writel(struct ls_pcie_g4 *pcie, unsigned int value,
+ unsigned int offset)
+{
+ if (pcie->big_endian)
+ out_be32(pcie->lut + offset, value);
+ else
+ out_le32(pcie->lut + offset, value);
+}
+
+static inline u32 lut_readl(struct ls_pcie_g4 *pcie, unsigned int offset)
+{
+ if (pcie->big_endian)
+ return in_be32(pcie->lut + offset);
+ else
+ return in_le32(pcie->lut + offset);
+}
+
+static inline void ccsr_set_page(struct ls_pcie_g4 *pcie, u8 pg_idx)
+{
+ u32 val;
+
+ val = in_le32(pcie->ccsr + PAB_CTRL);
+ val &= ~(PAB_CTRL_PAGE_SEL_MASK << PAB_CTRL_PAGE_SEL_SHIFT);
+ val |= (pg_idx & PAB_CTRL_PAGE_SEL_MASK) << PAB_CTRL_PAGE_SEL_SHIFT;
+
+ out_le32(pcie->ccsr + PAB_CTRL, val);
+}
+
+static inline unsigned int ccsr_readl(struct ls_pcie_g4 *pcie, u32 offset)
+{
+ if (offset < INDIRECT_ADDR_BNDRY) {
+ ccsr_set_page(pcie, 0);
+ return in_le32(pcie->ccsr + offset);
+ }
+
+ ccsr_set_page(pcie, OFFSET_TO_PAGE_IDX(offset));
+ return in_le32(pcie->ccsr + OFFSET_TO_PAGE_ADDR(offset));
+}
+
+static inline void ccsr_writel(struct ls_pcie_g4 *pcie, u32 offset, u32 value)
+{
+ if (offset < INDIRECT_ADDR_BNDRY) {
+ ccsr_set_page(pcie, 0);
+ out_le32(pcie->ccsr + offset, value);
+ } else {
+ ccsr_set_page(pcie, OFFSET_TO_PAGE_IDX(offset));
+ out_le32(pcie->ccsr + OFFSET_TO_PAGE_ADDR(offset), value);
+ }
+}
+
+static inline unsigned int pf_ctrl_readl(struct ls_pcie_g4 *pcie, u32 offset)
+{
+ if (pcie->big_endian)
+ return in_be32(pcie->pf_ctrl + offset);
+ else
+ return in_le32(pcie->pf_ctrl + offset);
+}
+
+static inline void pf_ctrl_writel(struct ls_pcie_g4 *pcie, u32 offset,
+ u32 value)
+{
+ if (pcie->big_endian)
+ out_be32(pcie->pf_ctrl + offset, value);
+ else
+ out_le32(pcie->pf_ctrl + offset, value);
+}
+
+#endif /* _PCIE_LAYERSCAPE_GEN4_H_ */
diff --git a/roms/u-boot/drivers/pci/pcie_layerscape_gen4_fixup.c b/roms/u-boot/drivers/pci/pcie_layerscape_gen4_fixup.c
new file mode 100644
index 000000000..e9ee15558
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_layerscape_gen4_fixup.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0+ OR X11
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * PCIe Gen4 driver for NXP Layerscape SoCs
+ * Author: Hou Zhiqiang <Minder.Hou@gmail.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <asm/arch/fsl_serdes.h>
+#include <asm/io.h>
+#include <errno.h>
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <linux/libfdt.h>
+#include <fdt_support.h>
+#ifdef CONFIG_ARM
+#include <asm/arch/clock.h>
+#endif
+#include "pcie_layerscape_gen4.h"
+#include "pcie_layerscape_fixup_common.h"
+
+#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
+/*
+ * Return next available LUT index.
+ */
+static int ls_pcie_g4_next_lut_index(struct ls_pcie_g4 *pcie)
+{
+ if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT)
+ return pcie->next_lut_index++;
+
+ return -ENOSPC; /* LUT is full */
+}
+
+/*
+ * Program a single LUT entry
+ */
+static void ls_pcie_g4_lut_set_mapping(struct ls_pcie_g4 *pcie, int index,
+ u32 devid, u32 streamid)
+{
+ /* leave mask as all zeroes, want to match all bits */
+ lut_writel(pcie, devid << 16, PCIE_LUT_UDR(index));
+ lut_writel(pcie, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index));
+}
+
+/*
+ * An msi-map is a property to be added to the pci controller
+ * node. It is a table, where each entry consists of 4 fields
+ * e.g.:
+ *
+ * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count]
+ * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>;
+ */
+static void fdt_pcie_set_msi_map_entry_ls_gen4(void *blob,
+ struct ls_pcie_g4 *pcie,
+ u32 devid, u32 streamid)
+{
+ u32 *prop;
+ u32 phandle;
+ int nodeoff;
+
+#ifdef CONFIG_FSL_PCIE_COMPAT
+ nodeoff = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT,
+ pcie->ccsr_res.start);
+#else
+#error "No CONFIG_FSL_PCIE_COMPAT defined"
+#endif
+ if (nodeoff < 0) {
+ debug("%s: ERROR: failed to find pcie compatiable\n", __func__);
+ return;
+ }
+
+ /* get phandle to MSI controller */
+ prop = (u32 *)fdt_getprop(blob, nodeoff, "msi-parent", 0);
+ if (!prop) {
+ debug("\n%s: ERROR: missing msi-parent: PCIe%d\n",
+ __func__, pcie->idx);
+ return;
+ }
+ phandle = fdt32_to_cpu(*prop);
+
+ /* set one msi-map row */
+ fdt_appendprop_u32(blob, nodeoff, "msi-map", devid);
+ fdt_appendprop_u32(blob, nodeoff, "msi-map", phandle);
+ fdt_appendprop_u32(blob, nodeoff, "msi-map", streamid);
+ fdt_appendprop_u32(blob, nodeoff, "msi-map", 1);
+}
+
+/*
+ * An iommu-map is a property to be added to the pci controller
+ * node. It is a table, where each entry consists of 4 fields
+ * e.g.:
+ *
+ * iommu-map = <[devid] [phandle-to-iommu-ctrl] [stream-id] [count]
+ * [devid] [phandle-to-iommu-ctrl] [stream-id] [count]>;
+ */
+static void fdt_pcie_set_iommu_map_entry_ls_gen4(void *blob,
+ struct ls_pcie_g4 *pcie,
+ u32 devid, u32 streamid)
+{
+ u32 *prop;
+ u32 iommu_map[4];
+ int nodeoff;
+ int lenp;
+
+#ifdef CONFIG_FSL_PCIE_COMPAT
+ nodeoff = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT,
+ pcie->ccsr_res.start);
+#else
+#error "No CONFIG_FSL_PCIE_COMPAT defined"
+#endif
+ if (nodeoff < 0) {
+ debug("%s: ERROR: failed to find pcie compatiable\n", __func__);
+ return;
+ }
+
+ /* get phandle to iommu controller */
+ prop = fdt_getprop_w(blob, nodeoff, "iommu-map", &lenp);
+ if (!prop) {
+ debug("\n%s: ERROR: missing iommu-map: PCIe%d\n",
+ __func__, pcie->idx);
+ return;
+ }
+
+ /* set iommu-map row */
+ iommu_map[0] = cpu_to_fdt32(devid);
+ iommu_map[1] = *++prop;
+ iommu_map[2] = cpu_to_fdt32(streamid);
+ iommu_map[3] = cpu_to_fdt32(1);
+
+ if (devid == 0)
+ fdt_setprop_inplace(blob, nodeoff, "iommu-map", iommu_map, 16);
+ else
+ fdt_appendprop(blob, nodeoff, "iommu-map", iommu_map, 16);
+}
+
+static void fdt_fixup_pcie_ls_gen4(void *blob)
+{
+ struct udevice *dev, *bus;
+ struct ls_pcie_g4 *pcie;
+ int streamid;
+ int index;
+ pci_dev_t bdf;
+
+ /* Scan all known buses */
+ for (pci_find_first_device(&dev); dev; pci_find_next_device(&dev)) {
+ for (bus = dev; device_is_on_pci_bus(bus);)
+ bus = bus->parent;
+ pcie = dev_get_priv(bus);
+
+ streamid = pcie_next_streamid(pcie->stream_id_cur, pcie->idx);
+ if (streamid < 0) {
+ debug("ERROR: no stream ids free\n");
+ continue;
+ } else {
+ pcie->stream_id_cur++;
+ }
+
+ index = ls_pcie_g4_next_lut_index(pcie);
+ if (index < 0) {
+ debug("ERROR: no LUT indexes free\n");
+ continue;
+ }
+
+ /* the DT fixup must be relative to the hose first_busno */
+ bdf = dm_pci_get_bdf(dev) - PCI_BDF(dev_seq(bus), 0, 0);
+ /* map PCI b.d.f to streamID in LUT */
+ ls_pcie_g4_lut_set_mapping(pcie, index, bdf >> 8, streamid);
+ /* update msi-map in device tree */
+ fdt_pcie_set_msi_map_entry_ls_gen4(blob, pcie, bdf >> 8,
+ streamid);
+ /* update iommu-map in device tree */
+ fdt_pcie_set_iommu_map_entry_ls_gen4(blob, pcie, bdf >> 8,
+ streamid);
+ }
+}
+#endif
+
+static void ft_pcie_ep_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie)
+{
+ int off;
+
+ off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_EP_COMPAT,
+ pcie->ccsr_res.start);
+
+ if (off < 0) {
+ debug("%s: ERROR: failed to find pcie compatiable\n",
+ __func__);
+ return;
+ }
+
+ if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL)
+ fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+ else
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+}
+
+static void ft_pcie_rc_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie)
+{
+ int off;
+
+#ifdef CONFIG_FSL_PCIE_COMPAT
+ off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT,
+ pcie->ccsr_res.start);
+#else
+#error "No CONFIG_FSL_PCIE_COMPAT defined"
+#endif
+ if (off < 0) {
+ debug("%s: ERROR: failed to find pcie compatiable\n", __func__);
+ return;
+ }
+
+ if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE)
+ fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+ else
+ fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+}
+
+static void ft_pcie_layerscape_gen4_setup(void *blob, struct ls_pcie_g4 *pcie)
+{
+ ft_pcie_rc_layerscape_gen4_fix(blob, pcie);
+ ft_pcie_ep_layerscape_gen4_fix(blob, pcie);
+}
+
+/* Fixup Kernel DT for PCIe */
+void ft_pci_setup_ls_gen4(void *blob, struct bd_info *bd)
+{
+ struct ls_pcie_g4 *pcie;
+
+ list_for_each_entry(pcie, &ls_pcie_g4_list, list)
+ ft_pcie_layerscape_gen4_setup(blob, pcie);
+
+#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)
+ fdt_fixup_pcie_ls_gen4(blob);
+#endif
+}
+
+#else /* !CONFIG_OF_BOARD_SETUP */
+void ft_pci_setup_ls_gen4(void *blob, struct bd_info *bd)
+{
+}
+#endif
diff --git a/roms/u-boot/drivers/pci/pcie_layerscape_rc.c b/roms/u-boot/drivers/pci/pcie_layerscape_rc.c
new file mode 100644
index 000000000..bd2c19f7f
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_layerscape_rc.c
@@ -0,0 +1,388 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ * Layerscape PCIe driver
+ */
+
+#include <common.h>
+#include <asm/arch/fsl_serdes.h>
+#include <pci.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <malloc.h>
+#include <dm.h>
+#include <dm/devres.h>
+#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \
+ defined(CONFIG_ARM)
+#include <asm/arch/clock.h>
+#endif
+#include "pcie_layerscape.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void ls_pcie_cfg0_set_busdev(struct ls_pcie_rc *pcie_rc, u32 busdev)
+{
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_VIEWPORT);
+ dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET);
+}
+
+static void ls_pcie_cfg1_set_busdev(struct ls_pcie_rc *pcie_rc, u32 busdev)
+{
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_VIEWPORT);
+ dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET);
+}
+
+static void ls_pcie_setup_atu(struct ls_pcie_rc *pcie_rc)
+{
+ struct pci_region *io, *mem, *pref;
+ unsigned long long offset = 0;
+ struct ls_pcie *pcie = pcie_rc->pcie;
+ int idx = 0;
+ uint svr;
+
+ svr = get_svr();
+ if (((svr >> SVR_VAR_PER_SHIFT) & SVR_LS102XA_MASK) == SVR_LS102XA) {
+ offset = LS1021_PCIE_SPACE_OFFSET +
+ LS1021_PCIE_SPACE_SIZE * pcie->idx;
+ }
+
+ /* ATU 0 : OUTBOUND : CFG0 */
+ ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_CFG0,
+ pcie_rc->cfg_res.start + offset,
+ 0,
+ fdt_resource_size(&pcie_rc->cfg_res) / 2);
+ /* ATU 1 : OUTBOUND : CFG1 */
+ ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_CFG1,
+ pcie_rc->cfg_res.start + offset +
+ fdt_resource_size(&pcie_rc->cfg_res) / 2,
+ 0,
+ fdt_resource_size(&pcie_rc->cfg_res) / 2);
+
+ pci_get_regions(pcie_rc->bus, &io, &mem, &pref);
+ idx = PCIE_ATU_REGION_INDEX1 + 1;
+
+ /* Fix the pcie memory map for LS2088A series SoCs */
+ svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
+ if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
+ svr == SVR_LS2048A || svr == SVR_LS2044A ||
+ svr == SVR_LS2081A || svr == SVR_LS2041A) {
+ if (io)
+ io->phys_start = (io->phys_start &
+ (PCIE_PHYS_SIZE - 1)) +
+ LS2088A_PCIE1_PHYS_ADDR +
+ LS2088A_PCIE_PHYS_SIZE * pcie->idx;
+ if (mem)
+ mem->phys_start = (mem->phys_start &
+ (PCIE_PHYS_SIZE - 1)) +
+ LS2088A_PCIE1_PHYS_ADDR +
+ LS2088A_PCIE_PHYS_SIZE * pcie->idx;
+ if (pref)
+ pref->phys_start = (pref->phys_start &
+ (PCIE_PHYS_SIZE - 1)) +
+ LS2088A_PCIE1_PHYS_ADDR +
+ LS2088A_PCIE_PHYS_SIZE * pcie->idx;
+ }
+
+ if (io)
+ /* ATU : OUTBOUND : IO */
+ ls_pcie_atu_outbound_set(pcie, idx++,
+ PCIE_ATU_TYPE_IO,
+ io->phys_start + offset,
+ io->bus_start,
+ io->size);
+
+ if (mem)
+ /* ATU : OUTBOUND : MEM */
+ ls_pcie_atu_outbound_set(pcie, idx++,
+ PCIE_ATU_TYPE_MEM,
+ mem->phys_start + offset,
+ mem->bus_start,
+ mem->size);
+
+ if (pref)
+ /* ATU : OUTBOUND : pref */
+ ls_pcie_atu_outbound_set(pcie, idx++,
+ PCIE_ATU_TYPE_MEM,
+ pref->phys_start + offset,
+ pref->bus_start,
+ pref->size);
+
+ ls_pcie_dump_atu(pcie, PCIE_ATU_REGION_NUM, PCIE_ATU_REGION_OUTBOUND);
+}
+
+/* Return 0 if the address is valid, -errno if not valid */
+static int ls_pcie_addr_valid(struct ls_pcie_rc *pcie_rc, pci_dev_t bdf)
+{
+ struct udevice *bus = pcie_rc->bus;
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ if (pcie->mode == PCI_HEADER_TYPE_NORMAL)
+ return -ENODEV;
+
+ if (!pcie_rc->enabled)
+ return -ENXIO;
+
+ if (PCI_BUS(bdf) < dev_seq(bus))
+ return -EINVAL;
+
+ if ((PCI_BUS(bdf) > dev_seq(bus)) && (!ls_pcie_link_up(pcie)))
+ return -EINVAL;
+
+ if (PCI_BUS(bdf) <= (dev_seq(bus) + 1) && (PCI_DEV(bdf) > 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+int ls_pcie_conf_address(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, void **paddress)
+{
+ struct ls_pcie_rc *pcie_rc = dev_get_priv(bus);
+ struct ls_pcie *pcie = pcie_rc->pcie;
+ u32 busdev;
+
+ if (ls_pcie_addr_valid(pcie_rc, bdf))
+ return -EINVAL;
+
+ if (PCI_BUS(bdf) == dev_seq(bus)) {
+ *paddress = pcie->dbi + offset;
+ return 0;
+ }
+
+ busdev = PCIE_ATU_BUS(PCI_BUS(bdf) - dev_seq(bus)) |
+ PCIE_ATU_DEV(PCI_DEV(bdf)) |
+ PCIE_ATU_FUNC(PCI_FUNC(bdf));
+
+ if (PCI_BUS(bdf) == dev_seq(bus) + 1) {
+ ls_pcie_cfg0_set_busdev(pcie_rc, busdev);
+ *paddress = pcie_rc->cfg0 + offset;
+ } else {
+ ls_pcie_cfg1_set_busdev(pcie_rc, busdev);
+ *paddress = pcie_rc->cfg1 + offset;
+ }
+ return 0;
+}
+
+static int ls_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_read_config(bus, ls_pcie_conf_address,
+ bdf, offset, valuep, size);
+}
+
+static int ls_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_write_config(bus, ls_pcie_conf_address,
+ bdf, offset, value, size);
+}
+
+/* Clear multi-function bit */
+static void ls_pcie_clear_multifunction(struct ls_pcie_rc *pcie_rc)
+{
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ writeb(PCI_HEADER_TYPE_BRIDGE, pcie->dbi + PCI_HEADER_TYPE);
+}
+
+/* Fix class value */
+static void ls_pcie_fix_class(struct ls_pcie_rc *pcie_rc)
+{
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ writew(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE);
+}
+
+/* Drop MSG TLP except for Vendor MSG */
+static void ls_pcie_drop_msg_tlp(struct ls_pcie_rc *pcie_rc)
+{
+ struct ls_pcie *pcie = pcie_rc->pcie;
+ u32 val;
+
+ val = dbi_readl(pcie, PCIE_STRFMR1);
+ val &= 0xDFFFFFFF;
+ dbi_writel(pcie, val, PCIE_STRFMR1);
+}
+
+/* Disable all bars in RC mode */
+static void ls_pcie_disable_bars(struct ls_pcie_rc *pcie_rc)
+{
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_0);
+ dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_1);
+ dbi_writel(pcie, 0xfffffffe, PCIE_CS2_OFFSET + PCI_ROM_ADDRESS1);
+}
+
+static void ls_pcie_setup_ctrl(struct ls_pcie_rc *pcie_rc)
+{
+ struct ls_pcie *pcie = pcie_rc->pcie;
+
+ ls_pcie_setup_atu(pcie_rc);
+
+ ls_pcie_dbi_ro_wr_en(pcie);
+ ls_pcie_fix_class(pcie_rc);
+ ls_pcie_clear_multifunction(pcie_rc);
+ ls_pcie_drop_msg_tlp(pcie_rc);
+ ls_pcie_dbi_ro_wr_dis(pcie);
+
+ ls_pcie_disable_bars(pcie_rc);
+ pcie_rc->stream_id_cur = 0;
+}
+
+static int ls_pcie_probe(struct udevice *dev)
+{
+ struct ls_pcie_rc *pcie_rc = dev_get_priv(dev);
+ const void *fdt = gd->fdt_blob;
+ int node = dev_of_offset(dev);
+ struct ls_pcie *pcie;
+ u16 link_sta;
+ uint svr;
+ int ret;
+ fdt_size_t cfg_size;
+
+ pcie_rc->bus = dev;
+
+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ pcie_rc->pcie = pcie;
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "dbi", &pcie_rc->dbi_res);
+ if (ret) {
+ printf("ls-pcie: resource \"dbi\" not found\n");
+ return ret;
+ }
+
+ pcie->idx = (pcie_rc->dbi_res.start - PCIE_SYS_BASE_ADDR) /
+ PCIE_CCSR_SIZE;
+
+ list_add(&pcie_rc->list, &ls_pcie_list);
+
+ pcie_rc->enabled = is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx));
+ if (!pcie_rc->enabled) {
+ printf("PCIe%d: %s disabled\n", PCIE_SRDS_PRTCL(pcie->idx),
+ dev->name);
+ return 0;
+ }
+
+ pcie->dbi = map_physmem(pcie_rc->dbi_res.start,
+ fdt_resource_size(&pcie_rc->dbi_res),
+ MAP_NOCACHE);
+
+ pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f;
+ if (pcie->mode == PCI_HEADER_TYPE_NORMAL)
+ return 0;
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "lut", &pcie_rc->lut_res);
+ if (!ret)
+ pcie->lut = map_physmem(pcie_rc->lut_res.start,
+ fdt_resource_size(&pcie_rc->lut_res),
+ MAP_NOCACHE);
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "ctrl", &pcie_rc->ctrl_res);
+ if (!ret)
+ pcie->ctrl = map_physmem(pcie_rc->ctrl_res.start,
+ fdt_resource_size(&pcie_rc->ctrl_res),
+ MAP_NOCACHE);
+ if (!pcie->ctrl)
+ pcie->ctrl = pcie->lut;
+
+ if (!pcie->ctrl) {
+ printf("%s: NOT find CTRL\n", dev->name);
+ return -1;
+ }
+
+ ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+ "config", &pcie_rc->cfg_res);
+ if (ret) {
+ printf("%s: resource \"config\" not found\n", dev->name);
+ return ret;
+ }
+
+ cfg_size = fdt_resource_size(&pcie_rc->cfg_res);
+ if (cfg_size < SZ_8K) {
+ printf("PCIe%d: %s Invalid size(0x%llx) for resource \"config\",expected minimum 0x%x\n",
+ PCIE_SRDS_PRTCL(pcie->idx), dev->name, (u64)cfg_size, SZ_8K);
+ return 0;
+ }
+
+ /*
+ * Fix the pcie memory map address and PF control registers address
+ * for LS2088A series SoCs
+ */
+ svr = get_svr();
+ svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
+ if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
+ svr == SVR_LS2048A || svr == SVR_LS2044A ||
+ svr == SVR_LS2081A || svr == SVR_LS2041A) {
+ pcie_rc->cfg_res.start = LS2088A_PCIE1_PHYS_ADDR +
+ LS2088A_PCIE_PHYS_SIZE * pcie->idx;
+ pcie_rc->cfg_res.end = pcie_rc->cfg_res.start + cfg_size;
+ pcie->ctrl = pcie->lut + 0x40000;
+ }
+
+ pcie_rc->cfg0 = map_physmem(pcie_rc->cfg_res.start,
+ fdt_resource_size(&pcie_rc->cfg_res),
+ MAP_NOCACHE);
+ pcie_rc->cfg1 = pcie_rc->cfg0 +
+ fdt_resource_size(&pcie_rc->cfg_res) / 2;
+
+ pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian");
+
+ debug("%s dbi:%lx lut:%lx ctrl:0x%lx cfg0:0x%lx, big-endian:%d\n",
+ dev->name, (unsigned long)pcie->dbi, (unsigned long)pcie->lut,
+ (unsigned long)pcie->ctrl, (unsigned long)pcie_rc->cfg0,
+ pcie->big_endian);
+
+ printf("PCIe%u: %s %s", PCIE_SRDS_PRTCL(pcie->idx), dev->name,
+ "Root Complex");
+ ls_pcie_setup_ctrl(pcie_rc);
+
+ if (!ls_pcie_link_up(pcie)) {
+ /* Let the user know there's no PCIe link */
+ printf(": no link\n");
+ return 0;
+ }
+
+ /* Print the negotiated PCIe link width */
+ link_sta = readw(pcie->dbi + PCIE_LINK_STA);
+ printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4,
+ link_sta & PCIE_LINK_SPEED_MASK);
+
+ return 0;
+}
+
+static const struct dm_pci_ops ls_pcie_ops = {
+ .read_config = ls_pcie_read_config,
+ .write_config = ls_pcie_write_config,
+};
+
+static const struct udevice_id ls_pcie_ids[] = {
+ { .compatible = "fsl,ls-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_layerscape) = {
+ .name = "pci_layerscape",
+ .id = UCLASS_PCI,
+ .of_match = ls_pcie_ids,
+ .ops = &ls_pcie_ops,
+ .probe = ls_pcie_probe,
+ .priv_auto = sizeof(struct ls_pcie_rc),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_mediatek.c b/roms/u-boot/drivers/pci/pcie_mediatek.c
new file mode 100644
index 000000000..f55567138
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_mediatek.c
@@ -0,0 +1,746 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek PCIe host controller driver.
+ *
+ * Copyright (c) 2017-2019 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ * Honghui Zhang <honghui.zhang@mediatek.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <pci.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include "pci_internal.h"
+
+/* PCIe shared registers */
+#define PCIE_SYS_CFG 0x00
+#define PCIE_INT_ENABLE 0x0c
+#define PCIE_CFG_ADDR 0x20
+#define PCIE_CFG_DATA 0x24
+
+/* PCIe per port registers */
+#define PCIE_BAR0_SETUP 0x10
+#define PCIE_CLASS 0x34
+#define PCIE_LINK_STATUS 0x50
+
+#define PCIE_PORT_INT_EN(x) BIT(20 + (x))
+#define PCIE_PORT_PERST(x) BIT(1 + (x))
+#define PCIE_PORT_LINKUP BIT(0)
+#define PCIE_BAR_MAP_MAX GENMASK(31, 16)
+
+#define PCIE_BAR_ENABLE BIT(0)
+#define PCIE_REVISION_ID BIT(0)
+#define PCIE_CLASS_CODE (0x60400 << 8)
+#define PCIE_CONF_REG(regn) (((regn) & GENMASK(7, 2)) | \
+ ((((regn) >> 8) & GENMASK(3, 0)) << 24))
+#define PCIE_CONF_ADDR(regn, bdf) \
+ (PCIE_CONF_REG(regn) | (bdf))
+
+/* MediaTek specific configuration registers */
+#define PCIE_FTS_NUM 0x70c
+#define PCIE_FTS_NUM_MASK GENMASK(15, 8)
+#define PCIE_FTS_NUM_L0(x) ((x) & 0xff << 8)
+
+#define PCIE_FC_CREDIT 0x73c
+#define PCIE_FC_CREDIT_MASK (GENMASK(31, 31) | GENMASK(28, 16))
+#define PCIE_FC_CREDIT_VAL(x) ((x) << 16)
+
+/* PCIe V2 share registers */
+#define PCIE_SYS_CFG_V2 0x0
+#define PCIE_CSR_LTSSM_EN(x) BIT(0 + (x) * 8)
+#define PCIE_CSR_ASPM_L1_EN(x) BIT(1 + (x) * 8)
+
+/* PCIe V2 per-port registers */
+#define PCIE_CONF_VEND_ID 0x100
+#define PCIE_CONF_DEVICE_ID 0x102
+#define PCIE_CONF_CLASS_ID 0x106
+
+#define PCIE_AHB_TRANS_BASE0_L 0x438
+#define PCIE_AHB_TRANS_BASE0_H 0x43c
+#define AHB2PCIE_SIZE(x) ((x) & GENMASK(4, 0))
+#define PCIE_AXI_WINDOW0 0x448
+#define WIN_ENABLE BIT(7)
+
+/*
+ * Define PCIe to AHB window size as 2^33 to support max 8GB address space
+ * translate, support least 4GB DRAM size access from EP DMA(physical DRAM
+ * start from 0x40000000).
+ */
+#define PCIE2AHB_SIZE 0x21
+
+/* PCIe V2 configuration transaction header */
+#define PCIE_CFG_HEADER0 0x460
+#define PCIE_CFG_HEADER1 0x464
+#define PCIE_CFG_HEADER2 0x468
+#define PCIE_CFG_WDATA 0x470
+#define PCIE_APP_TLP_REQ 0x488
+#define PCIE_CFG_RDATA 0x48c
+#define APP_CFG_REQ BIT(0)
+#define APP_CPL_STATUS GENMASK(7, 5)
+
+#define CFG_WRRD_TYPE_0 4
+#define CFG_WR_FMT 2
+#define CFG_RD_FMT 0
+
+#define CFG_DW0_LENGTH(length) ((length) & GENMASK(9, 0))
+#define CFG_DW0_TYPE(type) (((type) << 24) & GENMASK(28, 24))
+#define CFG_DW0_FMT(fmt) (((fmt) << 29) & GENMASK(31, 29))
+#define CFG_DW2_REGN(regn) ((regn) & GENMASK(11, 2))
+#define CFG_DW2_FUN(fun) (((fun) << 16) & GENMASK(18, 16))
+#define CFG_DW2_DEV(dev) (((dev) << 19) & GENMASK(23, 19))
+#define CFG_DW2_BUS(bus) (((bus) << 24) & GENMASK(31, 24))
+#define CFG_HEADER_DW0(type, fmt) \
+ (CFG_DW0_LENGTH(1) | CFG_DW0_TYPE(type) | CFG_DW0_FMT(fmt))
+#define CFG_HEADER_DW1(where, size) \
+ (GENMASK(((size) - 1), 0) << ((where) & 0x3))
+#define CFG_HEADER_DW2(regn, fun, dev, bus) \
+ (CFG_DW2_REGN(regn) | CFG_DW2_FUN(fun) | \
+ CFG_DW2_DEV(dev) | CFG_DW2_BUS(bus))
+
+#define PCIE_RST_CTRL 0x510
+#define PCIE_PHY_RSTB BIT(0)
+#define PCIE_PIPE_SRSTB BIT(1)
+#define PCIE_MAC_SRSTB BIT(2)
+#define PCIE_CRSTB BIT(3)
+#define PCIE_PERSTB BIT(8)
+#define PCIE_LINKDOWN_RST_EN GENMASK(15, 13)
+#define PCIE_LINK_STATUS_V2 0x804
+#define PCIE_PORT_LINKUP_V2 BIT(11)
+
+#define PCI_VENDOR_ID_MEDIATEK 0x14c3
+
+enum MTK_PCIE_GEN {PCIE_V1, PCIE_V2, PCIE_V3};
+
+struct mtk_pcie_port {
+ void __iomem *base;
+ struct list_head list;
+ struct mtk_pcie *pcie;
+ struct reset_ctl reset;
+ struct clk sys_ck;
+ struct clk ahb_ck;
+ struct clk axi_ck;
+ struct clk aux_ck;
+ struct clk obff_ck;
+ struct clk pipe_ck;
+ struct phy phy;
+ u32 slot;
+};
+
+struct mtk_pcie {
+ void __iomem *base;
+ void *priv;
+ struct clk free_ck;
+ struct list_head ports;
+};
+
+static int mtk_pcie_config_address(const struct udevice *udev, pci_dev_t bdf,
+ uint offset, void **paddress)
+{
+ struct mtk_pcie *pcie = dev_get_priv(udev);
+
+ writel(PCIE_CONF_ADDR(offset, bdf), pcie->base + PCIE_CFG_ADDR);
+ *paddress = pcie->base + PCIE_CFG_DATA + (offset & 3);
+
+ return 0;
+}
+
+static int mtk_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_read_config(bus, mtk_pcie_config_address,
+ bdf, offset, valuep, size);
+}
+
+static int mtk_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_write_config(bus, mtk_pcie_config_address,
+ bdf, offset, value, size);
+}
+
+static const struct dm_pci_ops mtk_pcie_ops = {
+ .read_config = mtk_pcie_read_config,
+ .write_config = mtk_pcie_write_config,
+};
+
+static int mtk_pcie_check_cfg_cpld(struct mtk_pcie_port *port)
+{
+ u32 val;
+ int err;
+
+ err = readl_poll_timeout(port->base + PCIE_APP_TLP_REQ, val,
+ !(val & APP_CFG_REQ), 100 * 1000);
+ if (err)
+ return -1;
+
+ if (readl(port->base + PCIE_APP_TLP_REQ) & APP_CPL_STATUS)
+ return -1;
+
+ return 0;
+}
+
+static int mtk_pcie_hw_rd_cfg(struct mtk_pcie_port *port, u32 bus, pci_dev_t devfn,
+ int where, int size, ulong *val)
+{
+ u32 tmp;
+
+ writel(CFG_HEADER_DW0(CFG_WRRD_TYPE_0, CFG_RD_FMT),
+ port->base + PCIE_CFG_HEADER0);
+ writel(CFG_HEADER_DW1(where, size), port->base + PCIE_CFG_HEADER1);
+ writel(CFG_HEADER_DW2(where, PCI_FUNC(devfn), PCI_DEV(devfn), bus),
+ port->base + PCIE_CFG_HEADER2);
+
+ /* Trigger h/w to transmit Cfgrd TLP */
+ tmp = readl(port->base + PCIE_APP_TLP_REQ);
+ tmp |= APP_CFG_REQ;
+ writel(tmp, port->base + PCIE_APP_TLP_REQ);
+
+ /* Check completion status */
+ if (mtk_pcie_check_cfg_cpld(port))
+ return -1;
+
+ /* Read cpld payload of Cfgrd */
+ *val = readl(port->base + PCIE_CFG_RDATA);
+
+ if (size == 1)
+ *val = (*val >> (8 * (where & 3))) & 0xff;
+ else if (size == 2)
+ *val = (*val >> (8 * (where & 3))) & 0xffff;
+
+ return 0;
+}
+
+static int mtk_pcie_hw_wr_cfg(struct mtk_pcie_port *port, u32 bus, pci_dev_t devfn,
+ int where, int size, u32 val)
+{
+ /* Write PCIe configuration transaction header for Cfgwr */
+ writel(CFG_HEADER_DW0(CFG_WRRD_TYPE_0, CFG_WR_FMT),
+ port->base + PCIE_CFG_HEADER0);
+ writel(CFG_HEADER_DW1(where, size), port->base + PCIE_CFG_HEADER1);
+ writel(CFG_HEADER_DW2(where, PCI_FUNC(devfn), PCI_DEV(devfn), bus),
+ port->base + PCIE_CFG_HEADER2);
+
+ /* Write Cfgwr data */
+ val = val << 8 * (where & 3);
+ writel(val, port->base + PCIE_CFG_WDATA);
+
+ /* Trigger h/w to transmit Cfgwr TLP */
+ val = readl(port->base + PCIE_APP_TLP_REQ);
+ val |= APP_CFG_REQ;
+ writel(val, port->base + PCIE_APP_TLP_REQ);
+
+ /* Check completion status */
+ return mtk_pcie_check_cfg_cpld(port);
+}
+
+static struct mtk_pcie_port *mtk_pcie_find_port(const struct udevice *bus,
+ pci_dev_t bdf)
+{
+ struct mtk_pcie *pcie = dev_get_priv(bus);
+ struct mtk_pcie_port *port;
+ struct udevice *dev;
+ struct pci_child_plat *pplat = NULL;
+ int ret = 0;
+
+ if (PCI_BUS(bdf) != 0) {
+ ret = pci_get_bus(PCI_BUS(bdf), &dev);
+ if (ret) {
+ debug("No such device,ret = %d\n", ret);
+ return NULL;
+ }
+
+ while (dev_seq(dev->parent) != 0)
+ dev = dev->parent;
+
+ pplat = dev_get_parent_plat(dev);
+ }
+
+ list_for_each_entry(port, &pcie->ports, list) {
+ if ((PCI_BUS(bdf) == 0) && (PCI_DEV(bdf) == port->slot))
+ return port;
+
+ if (PCI_BUS(bdf) != 0 && PCI_DEV(bdf) == 0 &&
+ PCI_DEV(pplat->devfn) == port->slot)
+ return port;
+ }
+
+ return NULL;
+}
+
+static int mtk_pcie_config_read(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct mtk_pcie_port *port;
+ int ret;
+
+ port = mtk_pcie_find_port(bus, bdf);
+ if (!port) {
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ ret = mtk_pcie_hw_rd_cfg(port, PCI_BUS(bdf), bdf, offset, (1 << size), valuep);
+ if (ret)
+ *valuep = pci_get_ff(size);
+
+ return ret;
+}
+
+static int mtk_pcie_config_write(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct mtk_pcie_port *port;
+
+ port = mtk_pcie_find_port(bus, bdf);
+ if (!port)
+ return 0;
+
+ /* Do not modify RC bar 0/1. */
+ if (PCI_BUS(bdf) == 0 && (offset == 0x10 || offset == 0x14))
+ return 0;
+
+ return mtk_pcie_hw_wr_cfg(port, PCI_BUS(bdf), bdf, offset, (1 << size), value);
+}
+
+static const struct dm_pci_ops mtk_pcie_ops_v2 = {
+ .read_config = mtk_pcie_config_read,
+ .write_config = mtk_pcie_config_write,
+};
+
+static void mtk_pcie_port_free(struct mtk_pcie_port *port)
+{
+ list_del(&port->list);
+ free(port);
+}
+
+static int mtk_pcie_startup_port(struct mtk_pcie_port *port)
+{
+ struct mtk_pcie *pcie = port->pcie;
+ u32 slot = PCI_DEV(port->slot << 11);
+ u32 val;
+ int err;
+
+ /* assert port PERST_N */
+ setbits_le32(pcie->base + PCIE_SYS_CFG, PCIE_PORT_PERST(port->slot));
+ /* de-assert port PERST_N */
+ clrbits_le32(pcie->base + PCIE_SYS_CFG, PCIE_PORT_PERST(port->slot));
+
+ /* 100ms timeout value should be enough for Gen1/2 training */
+ err = readl_poll_timeout(port->base + PCIE_LINK_STATUS, val,
+ !!(val & PCIE_PORT_LINKUP), 100000);
+ if (err)
+ return -ETIMEDOUT;
+
+ /* disable interrupt */
+ clrbits_le32(pcie->base + PCIE_INT_ENABLE,
+ PCIE_PORT_INT_EN(port->slot));
+
+ /* map to all DDR region. We need to set it before cfg operation. */
+ writel(PCIE_BAR_MAP_MAX | PCIE_BAR_ENABLE,
+ port->base + PCIE_BAR0_SETUP);
+
+ /* configure class code and revision ID */
+ writel(PCIE_CLASS_CODE | PCIE_REVISION_ID, port->base + PCIE_CLASS);
+
+ /* configure FC credit */
+ writel(PCIE_CONF_ADDR(PCIE_FC_CREDIT, slot),
+ pcie->base + PCIE_CFG_ADDR);
+ clrsetbits_le32(pcie->base + PCIE_CFG_DATA, PCIE_FC_CREDIT_MASK,
+ PCIE_FC_CREDIT_VAL(0x806c));
+
+ /* configure RC FTS number to 250 when it leaves L0s */
+ writel(PCIE_CONF_ADDR(PCIE_FTS_NUM, slot), pcie->base + PCIE_CFG_ADDR);
+ clrsetbits_le32(pcie->base + PCIE_CFG_DATA, PCIE_FTS_NUM_MASK,
+ PCIE_FTS_NUM_L0(0x50));
+
+ return 0;
+}
+
+static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
+{
+ struct mtk_pcie *pcie = port->pcie;
+ struct udevice *dev = pcie->priv;
+ struct pci_region *pci_mem;
+ u32 val;
+ int err;
+
+ /* MT7622/MT7629 platforms need to enable LTSSM and ASPM from PCIe subsys */
+ if (pcie->base) {
+ val = readl(pcie->base + PCIE_SYS_CFG_V2);
+ val |= PCIE_CSR_LTSSM_EN(port->slot) |
+ PCIE_CSR_ASPM_L1_EN(port->slot);
+ writel(val, pcie->base + PCIE_SYS_CFG_V2);
+ }
+
+ /* Assert all reset signals */
+ writel(0, port->base + PCIE_RST_CTRL);
+
+ /*
+ * Enable PCIe link down reset, if link status changed from link up to
+ * link down, this will reset MAC control registers and configuration
+ * space.
+ */
+ writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+ udelay(500);
+
+ /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+ val = readl(port->base + PCIE_RST_CTRL);
+ val |= PCIE_PHY_RSTB | PCIE_PIPE_SRSTB | PCIE_MAC_SRSTB | PCIE_CRSTB;
+ writel(val, port->base + PCIE_RST_CTRL);
+
+ mdelay(100);
+ val |= PCIE_PERSTB;
+ writel(val, port->base + PCIE_RST_CTRL);
+
+ /* Set up vendor ID and class code */
+ val = PCI_VENDOR_ID_MEDIATEK;
+ writew(val, port->base + PCIE_CONF_VEND_ID);
+
+ val = PCI_CLASS_BRIDGE_PCI;
+ writew(val, port->base + PCIE_CONF_CLASS_ID);
+
+ /* 100ms timeout value should be enough for Gen1/2 training */
+ err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
+ !!(val & PCIE_PORT_LINKUP_V2),
+ 100 * 1000);
+ if (err)
+ return -ETIMEDOUT;
+
+ pci_get_regions(dev, NULL, &pci_mem, NULL);
+
+ /* Set AHB to PCIe translation windows */
+ val = lower_32_bits(pci_mem->bus_start) |
+ AHB2PCIE_SIZE(fls(pci_mem->size) - 1);
+ writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
+
+ val = upper_32_bits(pci_mem->bus_start);
+ writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
+
+ /* Set PCIe to AXI translation memory space.*/
+ val = PCIE2AHB_SIZE | WIN_ENABLE;
+ writel(val, port->base + PCIE_AXI_WINDOW0);
+
+ return 0;
+}
+
+static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
+{
+ int err;
+
+ err = clk_enable(&port->sys_ck);
+ if (err)
+ goto err_sys_clk;
+
+ err = reset_assert(&port->reset);
+ if (err)
+ goto err_reset;
+
+ err = reset_deassert(&port->reset);
+ if (err)
+ goto err_reset;
+
+ err = generic_phy_init(&port->phy);
+ if (err)
+ goto err_phy_init;
+
+ err = generic_phy_power_on(&port->phy);
+ if (err)
+ goto err_phy_on;
+
+ if (!mtk_pcie_startup_port(port))
+ return;
+
+ pr_err("Port%d link down\n", port->slot);
+
+ generic_phy_power_off(&port->phy);
+err_phy_on:
+ generic_phy_exit(&port->phy);
+err_phy_init:
+err_reset:
+ clk_disable(&port->sys_ck);
+err_sys_clk:
+ mtk_pcie_port_free(port);
+}
+
+static void mtk_pcie_enable_port_v2(struct mtk_pcie_port *port)
+{
+ int err = 0;
+
+ err = clk_enable(&port->sys_ck);
+ if (err) {
+ debug("clk_enable(sys_ck) failed: %d\n", err);
+ goto exit;
+ }
+
+ err = clk_enable(&port->ahb_ck);
+ if (err) {
+ debug("clk_enable(ahb_ck) failed: %d\n", err);
+ goto exit;
+ }
+
+ err = clk_enable(&port->aux_ck);
+ if (err) {
+ debug("clk_enable(aux_ck) failed: %d\n", err);
+ goto exit;
+ }
+
+ err = clk_enable(&port->axi_ck);
+ if (err) {
+ debug("clk_enable(axi_ck) failed: %d\n", err);
+ goto exit;
+ }
+
+ err = clk_enable(&port->obff_ck);
+ if (err) {
+ debug("clk_enable(obff_ck) failed: %d\n", err);
+ goto exit;
+ }
+
+ err = clk_enable(&port->pipe_ck);
+ if (err) {
+ debug("clk_enable(pipe_ck) failed: %d\n", err);
+ goto exit;
+ }
+
+ err = mtk_pcie_startup_port_v2(port);
+ if (!err)
+ return;
+
+ pr_err("Port%d link down\n", port->slot);
+exit:
+ mtk_pcie_port_free(port);
+}
+
+static int mtk_pcie_parse_port(struct udevice *dev, u32 slot)
+{
+ struct mtk_pcie *pcie = dev_get_priv(dev);
+ struct mtk_pcie_port *port;
+ char name[10];
+ int err;
+
+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ snprintf(name, sizeof(name), "port%d", slot);
+ port->base = dev_remap_addr_name(dev, name);
+ if (!port->base)
+ return -ENOENT;
+
+ snprintf(name, sizeof(name), "sys_ck%d", slot);
+ err = clk_get_by_name(dev, name, &port->sys_ck);
+ if (err)
+ return err;
+
+ err = reset_get_by_index(dev, slot, &port->reset);
+ if (err)
+ return err;
+
+ err = generic_phy_get_by_index(dev, slot, &port->phy);
+ if (err)
+ return err;
+
+ port->slot = slot;
+ port->pcie = pcie;
+
+ INIT_LIST_HEAD(&port->list);
+ list_add_tail(&port->list, &pcie->ports);
+
+ return 0;
+}
+
+static int mtk_pcie_parse_port_v2(struct udevice *dev, u32 slot)
+{
+ struct mtk_pcie *pcie = dev_get_priv(dev);
+ struct mtk_pcie_port *port;
+ char name[10];
+ int err;
+
+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ snprintf(name, sizeof(name), "port%d", slot);
+ port->base = dev_remap_addr_name(dev, name);
+ if (!port->base) {
+ debug("failed to map port%d base\n", slot);
+ return -ENOENT;
+ }
+
+ snprintf(name, sizeof(name), "sys_ck%d", slot);
+ err = clk_get_by_name(dev, name, &port->sys_ck);
+ if (err) {
+ debug("clk_get_by_name(sys_ck) failed: %d\n", err);
+ return err;
+ }
+
+ snprintf(name, sizeof(name), "ahb_ck%d", slot);
+ err = clk_get_by_name(dev, name, &port->ahb_ck);
+ if (err) {
+ debug("clk_get_by_name(ahb_ck) failed: %d\n", err);
+ return err;
+ }
+
+ snprintf(name, sizeof(name), "aux_ck%d", slot);
+ err = clk_get_by_name(dev, name, &port->aux_ck);
+ if (err) {
+ debug("clk_get_by_name(aux_ck) failed: %d\n", err);
+ return err;
+ }
+
+ snprintf(name, sizeof(name), "axi_ck%d", slot);
+ err = clk_get_by_name(dev, name, &port->axi_ck);
+ if (err) {
+ debug("clk_get_by_name(axi_ck) failed: %d\n", err);
+ return err;
+ }
+
+ snprintf(name, sizeof(name), "obff_ck%d", slot);
+ err = clk_get_by_name(dev, name, &port->obff_ck);
+ if (err) {
+ debug("clk_get_by_name(obff_ck) failed: %d\n", err);
+ return err;
+ }
+
+ snprintf(name, sizeof(name), "pipe_ck%d", slot);
+ err = clk_get_by_name(dev, name, &port->pipe_ck);
+ if (err) {
+ debug("clk_get_by_name(pipe_ck) failed: %d\n", err);
+ return err;
+ }
+
+ port->slot = slot;
+ port->pcie = pcie;
+
+ INIT_LIST_HEAD(&port->list);
+ list_add_tail(&port->list, &pcie->ports);
+
+ return 0;
+}
+
+static int mtk_pcie_probe(struct udevice *dev)
+{
+ struct mtk_pcie *pcie = dev_get_priv(dev);
+ struct mtk_pcie_port *port, *tmp;
+ ofnode subnode;
+ int err;
+
+ INIT_LIST_HEAD(&pcie->ports);
+
+ pcie->base = dev_remap_addr_name(dev, "subsys");
+ if (!pcie->base)
+ return -ENOENT;
+
+ err = clk_get_by_name(dev, "free_ck", &pcie->free_ck);
+ if (err)
+ return err;
+
+ /* enable top level clock */
+ err = clk_enable(&pcie->free_ck);
+ if (err)
+ return err;
+
+ dev_for_each_subnode(subnode, dev) {
+ struct fdt_pci_addr addr;
+ u32 slot = 0;
+
+ if (!ofnode_is_available(subnode))
+ continue;
+
+ err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
+ if (err)
+ return err;
+
+ slot = PCI_DEV(addr.phys_hi);
+
+ err = mtk_pcie_parse_port(dev, slot);
+ if (err)
+ return err;
+ }
+
+ /* enable each port, and then check link status */
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+ mtk_pcie_enable_port(port);
+
+ return 0;
+}
+
+static int mtk_pcie_probe_v2(struct udevice *dev)
+{
+ struct mtk_pcie *pcie = dev_get_priv(dev);
+ struct mtk_pcie_port *port, *tmp;
+ struct fdt_pci_addr addr;
+ ofnode subnode;
+ unsigned int slot;
+ int err;
+
+ INIT_LIST_HEAD(&pcie->ports);
+
+ pcie->base = dev_remap_addr_name(dev, "subsys");
+ if (!pcie->base)
+ return -ENOENT;
+
+ pcie->priv = dev;
+
+ dev_for_each_subnode(subnode, dev) {
+ if (!ofnode_is_available(subnode))
+ continue;
+
+ err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
+ if (err)
+ return err;
+
+ slot = PCI_DEV(addr.phys_hi);
+ err = mtk_pcie_parse_port_v2(dev, slot);
+ if (err)
+ return err;
+ }
+
+ /* enable each port, and then check link status */
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+ mtk_pcie_enable_port_v2(port);
+
+ return 0;
+}
+
+static const struct udevice_id mtk_pcie_ids[] = {
+ { .compatible = "mediatek,mt7623-pcie", PCIE_V1},
+ { }
+};
+
+U_BOOT_DRIVER(pcie_mediatek_v1) = {
+ .name = "pcie_mediatek_v1",
+ .id = UCLASS_PCI,
+ .of_match = mtk_pcie_ids,
+ .ops = &mtk_pcie_ops,
+ .probe = mtk_pcie_probe,
+ .priv_auto = sizeof(struct mtk_pcie),
+};
+
+static const struct udevice_id mtk_pcie_ids_v2[] = {
+ { .compatible = "mediatek,mt7622-pcie", PCIE_V2},
+ { }
+};
+
+U_BOOT_DRIVER(pcie_mediatek_v2) = {
+ .name = "pcie_mediatek_v2",
+ .id = UCLASS_PCI,
+ .of_match = mtk_pcie_ids_v2,
+ .ops = &mtk_pcie_ops_v2,
+ .probe = mtk_pcie_probe_v2,
+ .priv_auto = sizeof(struct mtk_pcie),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_octeon.c b/roms/u-boot/drivers/pci/pcie_octeon.c
new file mode 100644
index 000000000..3b28bd814
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_octeon.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Stefan Roese <sr@denx.de>
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <pci.h>
+#include <linux/delay.h>
+
+#include <mach/octeon-model.h>
+#include <mach/octeon_pci.h>
+#include <mach/cvmx-regs.h>
+#include <mach/cvmx-pcie.h>
+#include <mach/cvmx-pemx-defs.h>
+
+struct octeon_pcie {
+ void *base;
+ int first_busno;
+ u32 port;
+ struct udevice *dev;
+ int pcie_port;
+};
+
+static bool octeon_bdf_invalid(pci_dev_t bdf, int first_busno)
+{
+ /*
+ * In PCIe only a single device (0) can exist on the local bus.
+ * Beyound the local bus, there might be a switch and everything
+ * is possible.
+ */
+ if ((PCI_BUS(bdf) == first_busno) && (PCI_DEV(bdf) > 0))
+ return true;
+
+ return false;
+}
+
+static int pcie_octeon_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct octeon_pcie *pcie = dev_get_priv(bus);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ int busno;
+ int port;
+
+ debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ debug("(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", offset, size, value);
+
+ port = pcie->pcie_port;
+ busno = PCI_BUS(bdf) - hose->first_busno + 1;
+
+ switch (size) {
+ case PCI_SIZE_8:
+ cvmx_pcie_config_write8(port, busno, PCI_DEV(bdf),
+ PCI_FUNC(bdf), offset, value);
+ break;
+ case PCI_SIZE_16:
+ cvmx_pcie_config_write16(port, busno, PCI_DEV(bdf),
+ PCI_FUNC(bdf), offset, value);
+ break;
+ case PCI_SIZE_32:
+ cvmx_pcie_config_write32(port, busno, PCI_DEV(bdf),
+ PCI_FUNC(bdf), offset, value);
+ break;
+ default:
+ printf("Invalid size\n");
+ };
+
+ return 0;
+}
+
+static int pcie_octeon_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct octeon_pcie *pcie = dev_get_priv(bus);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ int busno;
+ int port;
+
+ port = pcie->pcie_port;
+ busno = PCI_BUS(bdf) - hose->first_busno + 1;
+ if (octeon_bdf_invalid(bdf, pcie->first_busno)) {
+ *valuep = pci_get_ff(size);
+ return 0;
+ }
+
+ switch (size) {
+ case PCI_SIZE_8:
+ *valuep = cvmx_pcie_config_read8(port, busno, PCI_DEV(bdf),
+ PCI_FUNC(bdf), offset);
+ break;
+ case PCI_SIZE_16:
+ *valuep = cvmx_pcie_config_read16(port, busno, PCI_DEV(bdf),
+ PCI_FUNC(bdf), offset);
+ break;
+ case PCI_SIZE_32:
+ *valuep = cvmx_pcie_config_read32(port, busno, PCI_DEV(bdf),
+ PCI_FUNC(bdf), offset);
+ break;
+ default:
+ printf("Invalid size\n");
+ };
+
+ debug("%02x.%02x.%02x: u%d %x -> %lx\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, *valuep);
+
+ return 0;
+}
+
+static int pcie_octeon_probe(struct udevice *dev)
+{
+ struct octeon_pcie *pcie = dev_get_priv(dev);
+ int node = cvmx_get_node_num();
+ int pcie_port;
+ int ret = 0;
+
+ /* Get port number, lane number and memory target / attr */
+ if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port",
+ &pcie->port)) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ pcie->first_busno = dev_seq(dev);
+ pcie_port = ((node << 4) | pcie->port);
+ ret = cvmx_pcie_rc_initialize(pcie_port);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+
+err:
+ return ret;
+}
+
+static const struct dm_pci_ops pcie_octeon_ops = {
+ .read_config = pcie_octeon_read_config,
+ .write_config = pcie_octeon_write_config,
+};
+
+static const struct udevice_id pcie_octeon_ids[] = {
+ { .compatible = "marvell,pcie-host-octeon" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_octeon) = {
+ .name = "pcie_octeon",
+ .id = UCLASS_PCI,
+ .of_match = pcie_octeon_ids,
+ .ops = &pcie_octeon_ops,
+ .probe = pcie_octeon_probe,
+ .priv_auto = sizeof(struct octeon_pcie),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/roms/u-boot/drivers/pci/pcie_phytium.c b/roms/u-boot/drivers/pci/pcie_phytium.c
new file mode 100644
index 000000000..752e17032
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_phytium.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Phytium PCIE host driver
+ *
+ * Heavily based on drivers/pci/pcie_xilinx.c
+ *
+ * Copyright (C) 2019
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+
+/**
+ * struct phytium_pcie - phytium PCIe controller state
+ * @cfg_base: The base address of memory mapped configuration space
+ */
+struct phytium_pcie {
+ void *cfg_base;
+};
+
+/*
+ * phytium_pci_skip_dev()
+ * @parent: Identifies the PCIe device to access
+ *
+ * Checks whether the parent of the PCIe device is bridge
+ *
+ * Return: true if it is bridge, else false.
+ */
+static int phytium_pci_skip_dev(pci_dev_t parent)
+{
+ unsigned char pos, id;
+ unsigned long addr = 0x40000000;
+ unsigned short capreg;
+ unsigned char port_type;
+
+ addr += PCI_BUS(parent) << 20;
+ addr += PCI_DEV(parent) << 15;
+ addr += PCI_FUNC(parent) << 12;
+
+ pos = 0x34;
+ while (1) {
+ pos = readb(addr + pos);
+ if (pos < 0x40)
+ break;
+ pos &= ~3;
+ id = readb(addr + pos);
+ if (id == 0xff)
+ break;
+ if (id == 0x10) {
+ capreg = readw(addr + pos + 2);
+ port_type = (capreg >> 4) & 0xf;
+ if (port_type == 0x6 || port_type == 0x4)
+ return 1;
+ else
+ return 0;
+ }
+ pos += 1;
+ }
+ return 0;
+}
+
+/**
+ * pci_phytium_conf_address() - Calculate the address of a config access
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @paddress: Pointer to the pointer to write the calculates address to
+ *
+ * Calculates the address that should be accessed to perform a PCIe
+ * configuration space access for a given device identified by the PCIe
+ * controller device @pcie and the bus, device & function numbers in @bdf. If
+ * access to the device is not valid then the function will return an error
+ * code. Otherwise the address to access will be written to the pointer pointed
+ * to by @paddress.
+ */
+static int pci_phytium_conf_address(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, void **paddress)
+{
+ struct phytium_pcie *pcie = dev_get_priv(bus);
+ void *addr;
+ pci_dev_t bdf_parent;
+
+ unsigned int bus_no = PCI_BUS(bdf);
+ unsigned int dev_no = PCI_DEV(bdf);
+
+ bdf_parent = PCI_BDF((bus_no - 1), 0, 0);
+
+ addr = pcie->cfg_base;
+ addr += PCI_BUS(bdf) << 20;
+ addr += PCI_DEV(bdf) << 15;
+ addr += PCI_FUNC(bdf) << 12;
+
+ if (bus_no > 0 && dev_no > 0) {
+ if ((readb(addr + PCI_HEADER_TYPE) & 0x7f) !=
+ PCI_HEADER_TYPE_BRIDGE)
+ return -ENODEV;
+ if (phytium_pci_skip_dev(bdf_parent))
+ return -ENODEV;
+ }
+
+ addr += offset;
+ *paddress = addr;
+
+ return 0;
+}
+
+/**
+ * pci_phytium_read_config() - Read from configuration space
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ */
+static int pci_phytium_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_read_config(bus, pci_phytium_conf_address,
+ bdf, offset, valuep, size);
+}
+
+/**
+ * pci_phytium_write_config() - Write to configuration space
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ */
+static int pci_phytium_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_write_config(bus, pci_phytium_conf_address,
+ bdf, offset, value, size);
+}
+
+/**
+ * pci_phytium_of_to_plat() - Translate from DT to device state
+ * @dev: A pointer to the device being operated on
+ *
+ * Translate relevant data from the device tree pertaining to device @dev into
+ * state that the driver will later make use of. This state is stored in the
+ * device's private data structure.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+static int pci_phytium_of_to_plat(struct udevice *dev)
+{
+ struct phytium_pcie *pcie = dev_get_priv(dev);
+ struct fdt_resource reg_res;
+
+ DECLARE_GLOBAL_DATA_PTR;
+
+ int err;
+
+ err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg",
+ 0, &reg_res);
+ if (err < 0) {
+ pr_err("\"reg\" resource not found\n");
+ return err;
+ }
+
+ pcie->cfg_base = map_physmem(reg_res.start,
+ fdt_resource_size(&reg_res),
+ MAP_NOCACHE);
+
+ return 0;
+}
+
+static const struct dm_pci_ops pci_phytium_ops = {
+ .read_config = pci_phytium_read_config,
+ .write_config = pci_phytium_write_config,
+};
+
+static const struct udevice_id pci_phytium_ids[] = {
+ { .compatible = "phytium,pcie-host-1.0" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_phytium) = {
+ .name = "pci_phytium",
+ .id = UCLASS_PCI,
+ .of_match = pci_phytium_ids,
+ .ops = &pci_phytium_ops,
+ .of_to_plat = pci_phytium_of_to_plat,
+ .priv_auto = sizeof(struct phytium_pcie),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_rockchip.c b/roms/u-boot/drivers/pci/pcie_rockchip.c
new file mode 100644
index 000000000..b0c91c0f4
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_rockchip.c
@@ -0,0 +1,570 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Rockchip AXI PCIe host controller driver
+ *
+ * Copyright (c) 2016 Rockchip, Inc.
+ * Copyright (c) 2020 Amarula Solutions(India)
+ * Copyright (c) 2020 Jagan Teki <jagan@amarulasolutions.com>
+ * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se>
+ * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Bits taken from Linux Rockchip PCIe host controller.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/global_data.h>
+#include <dm/device_compat.h>
+#include <generic-phy.h>
+#include <pci.h>
+#include <power-domain.h>
+#include <power/regulator.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <asm/arch-rockchip/clock.h>
+#include <linux/iopoll.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val))
+#define HIWORD_UPDATE_BIT(val) HIWORD_UPDATE(val, val)
+
+#define ENCODE_LANES(x) ((((x) >> 1) & 3) << 4)
+#define PCIE_CLIENT_BASE 0x0
+#define PCIE_CLIENT_CONFIG (PCIE_CLIENT_BASE + 0x00)
+#define PCIE_CLIENT_CONF_ENABLE HIWORD_UPDATE_BIT(0x0001)
+#define PCIE_CLIENT_LINK_TRAIN_ENABLE HIWORD_UPDATE_BIT(0x0002)
+#define PCIE_CLIENT_MODE_RC HIWORD_UPDATE_BIT(0x0040)
+#define PCIE_CLIENT_GEN_SEL_1 HIWORD_UPDATE(0x0080, 0)
+#define PCIE_CLIENT_BASIC_STATUS1 0x0048
+#define PCIE_CLIENT_LINK_STATUS_UP GENMASK(21, 20)
+#define PCIE_CLIENT_LINK_STATUS_MASK GENMASK(21, 20)
+#define PCIE_LINK_UP(x) \
+ (((x) & PCIE_CLIENT_LINK_STATUS_MASK) == PCIE_CLIENT_LINK_STATUS_UP)
+#define PCIE_RC_NORMAL_BASE 0x800000
+#define PCIE_LM_BASE 0x900000
+#define PCIE_LM_VENDOR_ID (PCIE_LM_BASE + 0x44)
+#define PCIE_LM_VENDOR_ROCKCHIP 0x1d87
+#define PCIE_LM_RCBAR (PCIE_LM_BASE + 0x300)
+#define PCIE_LM_RCBARPIE BIT(19)
+#define PCIE_LM_RCBARPIS BIT(20)
+#define PCIE_RC_BASE 0xa00000
+#define PCIE_RC_CONFIG_DCR (PCIE_RC_BASE + 0x0c4)
+#define PCIE_RC_CONFIG_DCR_CSPL_SHIFT 18
+#define PCIE_RC_CONFIG_DCR_CPLS_SHIFT 26
+#define PCIE_RC_PCIE_LCAP (PCIE_RC_BASE + 0x0cc)
+#define PCIE_RC_PCIE_LCAP_APMS_L0S BIT(10)
+#define PCIE_ATR_BASE 0xc00000
+#define PCIE_ATR_OB_ADDR0(i) (PCIE_ATR_BASE + 0x000 + (i) * 0x20)
+#define PCIE_ATR_OB_ADDR1(i) (PCIE_ATR_BASE + 0x004 + (i) * 0x20)
+#define PCIE_ATR_OB_DESC0(i) (PCIE_ATR_BASE + 0x008 + (i) * 0x20)
+#define PCIE_ATR_OB_DESC1(i) (PCIE_ATR_BASE + 0x00c + (i) * 0x20)
+#define PCIE_ATR_IB_ADDR0(i) (PCIE_ATR_BASE + 0x800 + (i) * 0x8)
+#define PCIE_ATR_IB_ADDR1(i) (PCIE_ATR_BASE + 0x804 + (i) * 0x8)
+#define PCIE_ATR_HDR_MEM 0x2
+#define PCIE_ATR_HDR_IO 0x6
+#define PCIE_ATR_HDR_CFG_TYPE0 0xa
+#define PCIE_ATR_HDR_CFG_TYPE1 0xb
+#define PCIE_ATR_HDR_RID BIT(23)
+
+#define PCIE_ATR_OB_REGION0_SIZE (32 * 1024 * 1024)
+#define PCIE_ATR_OB_REGION_SIZE (1 * 1024 * 1024)
+
+struct rockchip_pcie {
+ fdt_addr_t axi_base;
+ fdt_addr_t apb_base;
+ int first_busno;
+ struct udevice *dev;
+
+ /* resets */
+ struct reset_ctl core_rst;
+ struct reset_ctl mgmt_rst;
+ struct reset_ctl mgmt_sticky_rst;
+ struct reset_ctl pipe_rst;
+ struct reset_ctl pm_rst;
+ struct reset_ctl pclk_rst;
+ struct reset_ctl aclk_rst;
+
+ /* gpio */
+ struct gpio_desc ep_gpio;
+
+ /* vpcie regulators */
+ struct udevice *vpcie12v;
+ struct udevice *vpcie3v3;
+ struct udevice *vpcie1v8;
+ struct udevice *vpcie0v9;
+
+ /* phy */
+ struct phy pcie_phy;
+};
+
+static int rockchip_pcie_off_conf(pci_dev_t bdf, uint offset)
+{
+ unsigned int bus = PCI_BUS(bdf);
+ unsigned int dev = PCI_DEV(bdf);
+ unsigned int func = PCI_FUNC(bdf);
+
+ return (bus << 20) | (dev << 15) | (func << 12) | (offset & ~0x3);
+}
+
+static int rockchip_pcie_rd_conf(const struct udevice *udev, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct rockchip_pcie *priv = dev_get_priv(udev);
+ unsigned int bus = PCI_BUS(bdf);
+ unsigned int dev = PCI_DEV(bdf);
+ int where = rockchip_pcie_off_conf(bdf, offset);
+ ulong value;
+
+ if (bus == priv->first_busno && dev == 0) {
+ value = readl(priv->apb_base + PCIE_RC_NORMAL_BASE + where);
+ *valuep = pci_conv_32_to_size(value, offset, size);
+ return 0;
+ }
+
+ if ((bus == priv->first_busno + 1) && dev == 0) {
+ value = readl(priv->axi_base + where);
+ *valuep = pci_conv_32_to_size(value, offset, size);
+ return 0;
+ }
+
+ *valuep = pci_get_ff(size);
+
+ return 0;
+}
+
+static int rockchip_pcie_wr_conf(struct udevice *udev, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct rockchip_pcie *priv = dev_get_priv(udev);
+ unsigned int bus = PCI_BUS(bdf);
+ unsigned int dev = PCI_DEV(bdf);
+ int where = rockchip_pcie_off_conf(bdf, offset);
+ ulong old;
+
+ if (bus == priv->first_busno && dev == 0) {
+ old = readl(priv->apb_base + PCIE_RC_NORMAL_BASE + where);
+ value = pci_conv_size_to_32(old, value, offset, size);
+ writel(value, priv->apb_base + PCIE_RC_NORMAL_BASE + where);
+ return 0;
+ }
+
+ if ((bus == priv->first_busno + 1) && dev == 0) {
+ old = readl(priv->axi_base + where);
+ value = pci_conv_size_to_32(old, value, offset, size);
+ writel(value, priv->axi_base + where);
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rockchip_pcie_atr_init(struct rockchip_pcie *priv)
+{
+ struct udevice *ctlr = pci_get_controller(priv->dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ u64 addr, size, offset;
+ u32 type;
+ int i, region;
+
+ /* Use region 0 to map PCI configuration space. */
+ writel(25 - 1, priv->apb_base + PCIE_ATR_OB_ADDR0(0));
+ writel(0, priv->apb_base + PCIE_ATR_OB_ADDR1(0));
+ writel(PCIE_ATR_HDR_CFG_TYPE0 | PCIE_ATR_HDR_RID,
+ priv->apb_base + PCIE_ATR_OB_DESC0(0));
+ writel(0, priv->apb_base + PCIE_ATR_OB_DESC1(0));
+
+ for (i = 0; i < hose->region_count; i++) {
+ if (hose->regions[i].flags == PCI_REGION_SYS_MEMORY)
+ continue;
+
+ if (hose->regions[i].flags == PCI_REGION_IO)
+ type = PCIE_ATR_HDR_IO;
+ else
+ type = PCIE_ATR_HDR_MEM;
+
+ /* Only support identity mappings. */
+ if (hose->regions[i].bus_start !=
+ hose->regions[i].phys_start)
+ return -EINVAL;
+
+ /* Only support mappings aligned on a region boundary. */
+ addr = hose->regions[i].bus_start;
+ if (addr & (PCIE_ATR_OB_REGION_SIZE - 1))
+ return -EINVAL;
+
+ /* Mappings should lie between AXI and APB regions. */
+ size = hose->regions[i].size;
+ if (addr < (u64)priv->axi_base + PCIE_ATR_OB_REGION0_SIZE)
+ return -EINVAL;
+ if (addr + size > (u64)priv->apb_base)
+ return -EINVAL;
+
+ offset = addr - (u64)priv->axi_base - PCIE_ATR_OB_REGION0_SIZE;
+ region = 1 + (offset / PCIE_ATR_OB_REGION_SIZE);
+ while (size > 0) {
+ writel(32 - 1,
+ priv->apb_base + PCIE_ATR_OB_ADDR0(region));
+ writel(0, priv->apb_base + PCIE_ATR_OB_ADDR1(region));
+ writel(type | PCIE_ATR_HDR_RID,
+ priv->apb_base + PCIE_ATR_OB_DESC0(region));
+ writel(0, priv->apb_base + PCIE_ATR_OB_DESC1(region));
+
+ addr += PCIE_ATR_OB_REGION_SIZE;
+ size -= PCIE_ATR_OB_REGION_SIZE;
+ region++;
+ }
+ }
+
+ /* Passthrough inbound translations unmodified. */
+ writel(32 - 1, priv->apb_base + PCIE_ATR_IB_ADDR0(2));
+ writel(0, priv->apb_base + PCIE_ATR_IB_ADDR1(2));
+
+ return 0;
+}
+
+static int rockchip_pcie_init_port(struct udevice *dev)
+{
+ struct rockchip_pcie *priv = dev_get_priv(dev);
+ u32 cr, val, status;
+ int ret;
+
+ if (dm_gpio_is_valid(&priv->ep_gpio))
+ dm_gpio_set_value(&priv->ep_gpio, 0);
+
+ ret = reset_assert(&priv->aclk_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert aclk reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_assert(&priv->pclk_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert pclk reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_assert(&priv->pm_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert pm reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_init(&priv->pcie_phy);
+ if (ret) {
+ dev_err(dev, "failed to init phy (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ ret = reset_assert(&priv->core_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert core reset (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ ret = reset_assert(&priv->mgmt_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert mgmt reset (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ ret = reset_assert(&priv->mgmt_sticky_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert mgmt-sticky reset (ret=%d)\n",
+ ret);
+ goto err_exit_phy;
+ }
+
+ ret = reset_assert(&priv->pipe_rst);
+ if (ret) {
+ dev_err(dev, "failed to assert pipe reset (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ udelay(10);
+
+ ret = reset_deassert(&priv->pm_rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert pm reset (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ ret = reset_deassert(&priv->aclk_rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert aclk reset (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ ret = reset_deassert(&priv->pclk_rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert pclk reset (ret=%d)\n", ret);
+ goto err_exit_phy;
+ }
+
+ /* Select GEN1 for now */
+ cr = PCIE_CLIENT_GEN_SEL_1;
+ /* Set Root complex mode */
+ cr |= PCIE_CLIENT_CONF_ENABLE | PCIE_CLIENT_MODE_RC;
+ writel(cr, priv->apb_base + PCIE_CLIENT_CONFIG);
+
+ ret = generic_phy_power_on(&priv->pcie_phy);
+ if (ret) {
+ dev_err(dev, "failed to power on phy (ret=%d)\n", ret);
+ goto err_power_off_phy;
+ }
+
+ ret = reset_deassert(&priv->mgmt_sticky_rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert mgmt-sticky reset (ret=%d)\n",
+ ret);
+ goto err_power_off_phy;
+ }
+
+ ret = reset_deassert(&priv->core_rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert core reset (ret=%d)\n", ret);
+ goto err_power_off_phy;
+ }
+
+ ret = reset_deassert(&priv->mgmt_rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert mgmt reset (ret=%d)\n", ret);
+ goto err_power_off_phy;
+ }
+
+ ret = reset_deassert(&priv->pipe_rst);
+ if (ret) {
+ dev_err(dev, "failed to deassert pipe reset (ret=%d)\n", ret);
+ goto err_power_off_phy;
+ }
+
+ /* Enable Gen1 training */
+ writel(PCIE_CLIENT_LINK_TRAIN_ENABLE,
+ priv->apb_base + PCIE_CLIENT_CONFIG);
+
+ if (dm_gpio_is_valid(&priv->ep_gpio))
+ dm_gpio_set_value(&priv->ep_gpio, 1);
+
+ ret = readl_poll_sleep_timeout
+ (priv->apb_base + PCIE_CLIENT_BASIC_STATUS1,
+ status, PCIE_LINK_UP(status), 20, 500 * 1000);
+ if (ret) {
+ dev_err(dev, "PCIe link training gen1 timeout!\n");
+ goto err_power_off_phy;
+ }
+
+ /* Initialize Root Complex registers. */
+ writel(PCIE_LM_VENDOR_ROCKCHIP, priv->apb_base + PCIE_LM_VENDOR_ID);
+ writel(PCI_CLASS_BRIDGE_PCI << 16,
+ priv->apb_base + PCIE_RC_BASE + PCI_CLASS_REVISION);
+ writel(PCIE_LM_RCBARPIE | PCIE_LM_RCBARPIS,
+ priv->apb_base + PCIE_LM_RCBAR);
+
+ if (dev_read_bool(dev, "aspm-no-l0s")) {
+ val = readl(priv->apb_base + PCIE_RC_PCIE_LCAP);
+ val &= ~PCIE_RC_PCIE_LCAP_APMS_L0S;
+ writel(val, priv->apb_base + PCIE_RC_PCIE_LCAP);
+ }
+
+ /* Configure Address Translation. */
+ ret = rockchip_pcie_atr_init(priv);
+ if (ret) {
+ dev_err(dev, "PCIE-%d: ATR init failed\n", dev_seq(dev));
+ goto err_power_off_phy;
+ }
+
+ return 0;
+
+err_power_off_phy:
+ generic_phy_power_off(&priv->pcie_phy);
+err_exit_phy:
+ generic_phy_exit(&priv->pcie_phy);
+ return ret;
+}
+
+static int rockchip_pcie_set_vpcie(struct udevice *dev)
+{
+ struct rockchip_pcie *priv = dev_get_priv(dev);
+ int ret;
+
+ if (priv->vpcie3v3) {
+ ret = regulator_set_enable(priv->vpcie3v3, true);
+ if (ret) {
+ dev_err(dev, "failed to enable vpcie3v3 (ret=%d)\n",
+ ret);
+ return ret;
+ }
+ }
+
+ if (priv->vpcie1v8) {
+ ret = regulator_set_enable(priv->vpcie1v8, true);
+ if (ret) {
+ dev_err(dev, "failed to enable vpcie1v8 (ret=%d)\n",
+ ret);
+ goto err_disable_3v3;
+ }
+ }
+
+ if (priv->vpcie0v9) {
+ ret = regulator_set_enable(priv->vpcie0v9, true);
+ if (ret) {
+ dev_err(dev, "failed to enable vpcie0v9 (ret=%d)\n",
+ ret);
+ goto err_disable_1v8;
+ }
+ }
+
+ return 0;
+
+err_disable_1v8:
+ if (priv->vpcie1v8)
+ regulator_set_enable(priv->vpcie1v8, false);
+err_disable_3v3:
+ if (priv->vpcie3v3)
+ regulator_set_enable(priv->vpcie3v3, false);
+ return ret;
+}
+
+static int rockchip_pcie_parse_dt(struct udevice *dev)
+{
+ struct rockchip_pcie *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->axi_base = dev_read_addr_name(dev, "axi-base");
+ if (!priv->axi_base)
+ return -ENODEV;
+
+ priv->apb_base = dev_read_addr_name(dev, "apb-base");
+ if (!priv->axi_base)
+ return -ENODEV;
+
+ ret = gpio_request_by_name(dev, "ep-gpios", 0,
+ &priv->ep_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ dev_err(dev, "failed to find ep-gpios property\n");
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "core", &priv->core_rst);
+ if (ret) {
+ dev_err(dev, "failed to get core reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "mgmt", &priv->mgmt_rst);
+ if (ret) {
+ dev_err(dev, "failed to get mgmt reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "mgmt-sticky", &priv->mgmt_sticky_rst);
+ if (ret) {
+ dev_err(dev, "failed to get mgmt-sticky reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "pipe", &priv->pipe_rst);
+ if (ret) {
+ dev_err(dev, "failed to get pipe reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "pm", &priv->pm_rst);
+ if (ret) {
+ dev_err(dev, "failed to get pm reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "pclk", &priv->pclk_rst);
+ if (ret) {
+ dev_err(dev, "failed to get pclk reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "aclk", &priv->aclk_rst);
+ if (ret) {
+ dev_err(dev, "failed to get aclk reset (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vpcie3v3-supply",
+ &priv->vpcie3v3);
+ if (ret && ret != -ENOENT) {
+ dev_err(dev, "failed to get vpcie3v3 supply (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vpcie1v8-supply",
+ &priv->vpcie1v8);
+ if (ret && ret != -ENOENT) {
+ dev_err(dev, "failed to get vpcie1v8 supply (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vpcie0v9-supply",
+ &priv->vpcie0v9);
+ if (ret && ret != -ENOENT) {
+ dev_err(dev, "failed to get vpcie0v9 supply (ret=%d)\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_get_by_index(dev, 0, &priv->pcie_phy);
+ if (ret) {
+ dev_err(dev, "failed to get pcie-phy (ret=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rockchip_pcie_probe(struct udevice *dev)
+{
+ struct rockchip_pcie *priv = dev_get_priv(dev);
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ int ret;
+
+ priv->first_busno = dev_seq(dev);
+ priv->dev = dev;
+
+ ret = rockchip_pcie_parse_dt(dev);
+ if (ret)
+ return ret;
+
+ ret = rockchip_pcie_set_vpcie(dev);
+ if (ret)
+ return ret;
+
+ ret = rockchip_pcie_init_port(dev);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "PCIE-%d: Link up (Bus%d)\n",
+ dev_seq(dev), hose->first_busno);
+
+ return 0;
+}
+
+static const struct dm_pci_ops rockchip_pcie_ops = {
+ .read_config = rockchip_pcie_rd_conf,
+ .write_config = rockchip_pcie_wr_conf,
+};
+
+static const struct udevice_id rockchip_pcie_ids[] = {
+ { .compatible = "rockchip,rk3399-pcie" },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_pcie) = {
+ .name = "rockchip_pcie",
+ .id = UCLASS_PCI,
+ .of_match = rockchip_pcie_ids,
+ .ops = &rockchip_pcie_ops,
+ .probe = rockchip_pcie_probe,
+ .priv_auto = sizeof(struct rockchip_pcie),
+};
diff --git a/roms/u-boot/drivers/pci/pcie_xilinx.c b/roms/u-boot/drivers/pci/pcie_xilinx.c
new file mode 100644
index 000000000..ae9a65b0a
--- /dev/null
+++ b/roms/u-boot/drivers/pci/pcie_xilinx.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx AXI Bridge for PCI Express Driver
+ *
+ * Copyright (C) 2016 Imagination Technologies
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/global_data.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+
+/**
+ * struct xilinx_pcie - Xilinx PCIe controller state
+ * @cfg_base: The base address of memory mapped configuration space
+ */
+struct xilinx_pcie {
+ void *cfg_base;
+};
+
+/* Register definitions */
+#define XILINX_PCIE_REG_PSCR 0x144
+#define XILINX_PCIE_REG_PSCR_LNKUP BIT(11)
+
+/**
+ * pcie_xilinx_link_up() - Check whether the PCIe link is up
+ * @pcie: Pointer to the PCI controller state
+ *
+ * Checks whether the PCIe link for the given device is up or down.
+ *
+ * Return: true if the link is up, else false
+ */
+static bool pcie_xilinx_link_up(struct xilinx_pcie *pcie)
+{
+ uint32_t pscr = __raw_readl(pcie->cfg_base + XILINX_PCIE_REG_PSCR);
+
+ return pscr & XILINX_PCIE_REG_PSCR_LNKUP;
+}
+
+/**
+ * pcie_xilinx_config_address() - Calculate the address of a config access
+ * @udev: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @paddress: Pointer to the pointer to write the calculates address to
+ *
+ * Calculates the address that should be accessed to perform a PCIe
+ * configuration space access for a given device identified by the PCIe
+ * controller device @pcie and the bus, device & function numbers in @bdf. If
+ * access to the device is not valid then the function will return an error
+ * code. Otherwise the address to access will be written to the pointer pointed
+ * to by @paddress.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int pcie_xilinx_config_address(const struct udevice *udev, pci_dev_t bdf,
+ uint offset, void **paddress)
+{
+ struct xilinx_pcie *pcie = dev_get_priv(udev);
+ unsigned int bus = PCI_BUS(bdf);
+ unsigned int dev = PCI_DEV(bdf);
+ unsigned int func = PCI_FUNC(bdf);
+ void *addr;
+
+ if ((bus > 0) && !pcie_xilinx_link_up(pcie))
+ return -ENODEV;
+
+ /*
+ * Busses 0 (host-PCIe bridge) & 1 (its immediate child) are
+ * limited to a single device each.
+ */
+ if ((bus < 2) && (dev > 0))
+ return -ENODEV;
+
+ addr = pcie->cfg_base;
+ addr += bus << 20;
+ addr += dev << 15;
+ addr += func << 12;
+ addr += offset;
+ *paddress = addr;
+
+ return 0;
+}
+
+/**
+ * pcie_xilinx_read_config() - Read from configuration space
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @valuep: A pointer at which to store the read value
+ * @size: Indicates the size of access to perform
+ *
+ * Read a value of size @size from offset @offset within the configuration
+ * space of the device identified by the bus, device & function numbers in @bdf
+ * on the PCI bus @bus.
+ *
+ * Return: 0 on success, else -ENODEV or -EINVAL
+ */
+static int pcie_xilinx_read_config(const struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_read_config(bus, pcie_xilinx_config_address,
+ bdf, offset, valuep, size);
+}
+
+/**
+ * pcie_xilinx_write_config() - Write to configuration space
+ * @bus: Pointer to the PCI bus
+ * @bdf: Identifies the PCIe device to access
+ * @offset: The offset into the device's configuration space
+ * @value: The value to write
+ * @size: Indicates the size of access to perform
+ *
+ * Write the value @value of size @size from offset @offset within the
+ * configuration space of the device identified by the bus, device & function
+ * numbers in @bdf on the PCI bus @bus.
+ *
+ * Return: 0 on success, else -ENODEV or -EINVAL
+ */
+static int pcie_xilinx_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ return pci_generic_mmap_write_config(bus, pcie_xilinx_config_address,
+ bdf, offset, value, size);
+}
+
+/**
+ * pcie_xilinx_of_to_plat() - Translate from DT to device state
+ * @dev: A pointer to the device being operated on
+ *
+ * Translate relevant data from the device tree pertaining to device @dev into
+ * state that the driver will later make use of. This state is stored in the
+ * device's private data structure.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+static int pcie_xilinx_of_to_plat(struct udevice *dev)
+{
+ struct xilinx_pcie *pcie = dev_get_priv(dev);
+ struct fdt_resource reg_res;
+ DECLARE_GLOBAL_DATA_PTR;
+ int err;
+
+ err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg",
+ 0, &reg_res);
+ if (err < 0) {
+ pr_err("\"reg\" resource not found\n");
+ return err;
+ }
+
+ pcie->cfg_base = map_physmem(reg_res.start,
+ fdt_resource_size(&reg_res),
+ MAP_NOCACHE);
+
+ return 0;
+}
+
+static const struct dm_pci_ops pcie_xilinx_ops = {
+ .read_config = pcie_xilinx_read_config,
+ .write_config = pcie_xilinx_write_config,
+};
+
+static const struct udevice_id pcie_xilinx_ids[] = {
+ { .compatible = "xlnx,axi-pcie-host-1.00.a" },
+ { }
+};
+
+U_BOOT_DRIVER(pcie_xilinx) = {
+ .name = "pcie_xilinx",
+ .id = UCLASS_PCI,
+ .of_match = pcie_xilinx_ids,
+ .ops = &pcie_xilinx_ops,
+ .of_to_plat = pcie_xilinx_of_to_plat,
+ .priv_auto = sizeof(struct xilinx_pcie),
+};