| /* | 
|  * 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. | 
|  * | 
|  * SPDX-License-Identifier:    GPL-2.0 | 
|  */ | 
|   | 
| #define pr_fmt(fmt) "tegra-pcie: " fmt | 
|   | 
| #include <common.h> | 
| #include <clk.h> | 
| #include <dm.h> | 
| #include <errno.h> | 
| #include <malloc.h> | 
| #include <pci.h> | 
| #include <power-domain.h> | 
| #include <reset.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. | 
|  */ | 
|   | 
| DECLARE_GLOBAL_DATA_PTR; | 
|   | 
| #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 pci_controller hose; | 
|   | 
|     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(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; | 
| } | 
|   | 
| static 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); | 
| } | 
|   | 
| 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_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_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_ofdata_to_platdata(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, | 
|     .ofdata_to_platdata = pci_tegra_ofdata_to_platdata, | 
|     .probe    = pci_tegra_probe, | 
|     .priv_auto_alloc_size = sizeof(struct tegra_pcie), | 
| }; |