lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAErSpo403JN+49WCTCSZ6rDtwTXbHb=R58p8pVvxx=6Ghg_ACg@mail.gmail.com>
Date:	Thu, 25 Jul 2013 12:00:08 -0600
From:	Bjorn Helgaas <bhelgaas@...gle.com>
To:	Thierry Reding <thierry.reding@...il.com>
Cc:	Stephen Warren <swarren@...dotorg.org>,
	Russell King <linux@....linux.org.uk>,
	Jason Cooper <jason@...edaemon.net>,
	Thomas Petazzoni <thomas.petazzoni@...e-electrons.com>,
	Jay Agarwal <jagarwal@...dia.com>,
	"linux-pci@...r.kernel.org" <linux-pci@...r.kernel.org>,
	"linux-tegra@...r.kernel.org" <linux-tegra@...r.kernel.org>,
	devicetree@...r.kernel.org,
	linux-arm <linux-arm-kernel@...ts.infradead.org>,
	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH v5 03/16] PCI: tegra: Move PCIe driver to drivers/pci/host

On Thu, Jul 25, 2013 at 11:53 AM, Thierry Reding
<thierry.reding@...il.com> wrote:
> From: Thierry Reding <thierry.reding@...onic-design.de>
>
> Move the PCIe driver from arch/arm/mach-tegra into the drivers/pci/host
> directory. The motivation is to collect various host controller drivers
> in the same location in order to facilitate refactoring.
>
> The Tegra PCIe driver has been largely rewritten, both in order to turn
> it into a proper platform driver and to add MSI (based on code by
> Krishna Kishore <kthota@...dia.com>) as well as device tree support.
>
> Signed-off-by: Thierry Reding <thierry.reding@...onic-design.de>
> Signed-off-by: Thierry Reding <treding@...dia.com>

Acked-by: Bjorn Helgaas <bhelgaas@...gle.com>

> ---
> Changes in v2:
> - remove Harmony and TrimSlice leftovers
> - use symbolic names for interrupt codes
> - fix root port reset sequence
> - depend on ARCH_TEGRA
> - only enable configured root ports
> - make regulators mandatory
> - fix build with !PCI_MSI
> - derive XBAR configuration from nvidia,num-lanes property
> - remap configuration space on a per-bus basis
>
> Changes in v3:
> - move Tegra30 specific bits into a follow-up patch
> - update DT binding to be more spec-conformant
> - update for recent OF ranges parser changes
> - use new MSI chip infrastructure
>
> Changes in v4:
> - update binding documentation as per Stephen's comments
>
> Changes in v5:
> - update for latest OF ranges parsing API
> - use pci_common_init_dev() instead of pci_common_init()
> - add hw_pci.add_bus implementation to attach MSI chip
> - fixup any remaining checkpatch warnings
> - use define for link active status bit
> - move msi_chip structure to the beginning of struct tegra_msi to maybe
>   save some bytes when upcasting
> - refactor common code from tegra_pcie_{read,write}_conf()
> - don't use potentially dangerous devm_request_irq()
> - return IRQ_NONE if the MSI handler doesn't detect any pending
>   interrupts
> - don't read AFI_MSI_AXI_BAR_ST when setting up MSI messages (the same
>   data is available in msi->pages)
> - request a single page (instead of 8) for the MSI BAR
> - return an error when detecting an invalid lane configuration
> - remove driver's .remove() function and set .suppress_bind_attrs to
>   prevent the driver from being unbound from the device via sysfs
> - add MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_LICENSE
> - export OF device table
> - use symbolic constants for interrupts and clocks
>
>  .../bindings/pci/nvidia,tegra20-pcie.txt           |  161 ++
>  arch/arm/boot/dts/tegra20.dtsi                     |   55 +
>  arch/arm/mach-tegra/Kconfig                        |    7 +-
>  arch/arm/mach-tegra/Makefile                       |    3 -
>  arch/arm/mach-tegra/board-harmony-pcie.c           |   89 --
>  arch/arm/mach-tegra/board.h                        |    8 -
>  arch/arm/mach-tegra/iomap.h                        |    3 -
>  arch/arm/mach-tegra/pcie.c                         |  864 -----------
>  arch/arm/mach-tegra/tegra.c                        |   24 -
>  drivers/pci/host/Kconfig                           |    4 +
>  drivers/pci/host/Makefile                          |    1 +
>  drivers/pci/host/pci-tegra.c                       | 1540 ++++++++++++++++++++
>  12 files changed, 1763 insertions(+), 996 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
>  delete mode 100644 arch/arm/mach-tegra/board-harmony-pcie.c
>  delete mode 100644 arch/arm/mach-tegra/pcie.c
>  create mode 100644 drivers/pci/host/pci-tegra.c
>
> diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
> new file mode 100644
> index 0000000..90c112f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
> @@ -0,0 +1,161 @@
> +NVIDIA Tegra PCIe controller
> +
> +Required properties:
> +- compatible: "nvidia,tegra20-pcie"
> +- device_type: Must be "pci"
> +- reg: A list of physical base address and length for each set of controller
> +  registers. Must contain an entry for each entry in the reg-names property.
> +- reg-names: Must include the following entries:
> +  "pads": PADS registers
> +  "afi": AFI registers
> +  "cs": configuration space region
> +- interrupts: A list of interrupt outputs of the controller. Must contain an
> +  entry for each entry in the interrupt-names property.
> +- interrupt-names: Must include the following entries:
> +  "intr": The Tegra interrupt that is asserted for controller interrupts
> +  "msi": The Tegra interrupt that is asserted when an MSI is received
> +- pex-clk-supply: Supply voltage for internal reference clock
> +- vdd-supply: Power supply for controller (1.05V)
> +- bus-range: Range of bus numbers associated with this controller
> +- #address-cells: Address representation for root ports (must be 3)
> +  - cell 0 specifies the bus and device numbers of the root port:
> +    [23:16]: bus number
> +    [15:11]: device number
> +  - cell 1 denotes the upper 32 address bits and should be 0
> +  - cell 2 contains the lower 32 address bits and is used to translate to the
> +    CPU address space
> +- #size-cells: Size representation for root ports (must be 2)
> +- ranges: Describes the translation of addresses for root ports and standard
> +  PCI regions. The entries must be 6 cells each, where the first three cells
> +  correspond to the address as described for the #address-cells property
> +  above, the fourth cell is the physical CPU address to translate to and the
> +  fifth and six cells are as described for the #size-cells property above.
> +  - The first two entries are expected to translate the addresses for the root
> +    port registers, which are referenced by the assigned-addresses property of
> +    the root port nodes (see below).
> +  - The remaining entries setup the mapping for the standard I/O, memory and
> +    prefetchable PCI regions. The first cell determines the type of region
> +    that is setup:
> +    - 0x81000000: I/O memory region
> +    - 0x82000000: non-prefetchable memory region
> +    - 0xc2000000: prefetchable memory region
> +  Please refer to the standard PCI bus binding document for a more detailed
> +  explanation.
> +- clocks: List of clock inputs of the controller. Must contain an entry for
> +  each entry in the clock-names property.
> +- clock-names: Must include the following entries:
> +  "pex": The Tegra clock of that name
> +  "afi": The Tegra clock of that name
> +  "pcie_xclk": The Tegra clock of that name
> +  "pll_e": The Tegra clock of that name
> +
> +Root ports are defined as subnodes of the PCIe controller node.
> +
> +Required properties:
> +- device_type: Must be "pci"
> +- assigned-addresses: Address and size of the port configuration registers
> +- reg: PCI bus address of the root port
> +- #address-cells: Must be 3
> +- #size-cells: Must be 2
> +- ranges: Sub-ranges distributed from the PCIe controller node. An empty
> +  property is sufficient.
> +- nvidia,num-lanes: Number of lanes to use for this port. Valid combinations
> +  are:
> +  - Root port 0 uses 4 lanes, root port 1 is unused.
> +  - Both root ports use 2 lanes.
> +
> +Example:
> +
> +SoC DTSI:
> +
> +       pcie-controller {
> +               compatible = "nvidia,tegra20-pcie";
> +               device_type = "pci";
> +               reg = <0x80003000 0x00000800   /* PADS registers */
> +                      0x80003800 0x00000200   /* AFI registers */
> +                      0x90000000 0x10000000>; /* configuration space */
> +               reg-names = "pads", "afi", "cs";
> +               interrupts = <0 98 0x04   /* controller interrupt */
> +                             0 99 0x04>; /* MSI interrupt */
> +               interrupt-names = "intr", "msi";
> +
> +               bus-range = <0x00 0xff>;
> +               #address-cells = <3>;
> +               #size-cells = <2>;
> +
> +               ranges = <0x82000000 0 0x80000000 0x80000000 0 0x00001000   /* port 0 registers */
> +                         0x82000000 0 0x80001000 0x80001000 0 0x00001000   /* port 1 registers */
> +                         0x81000000 0 0          0x82000000 0 0x00010000   /* downstream I/O */
> +                         0x82000000 0 0xa0000000 0xa0000000 0 0x10000000   /* non-prefetchable memory */
> +                         0xc2000000 0 0xb0000000 0xb0000000 0 0x10000000>; /* prefetchable memory */
> +
> +               clocks = <&tegra_car 70>, <&tegra_car 72>, <&tegra_car 74>,
> +                        <&tegra_car 118>;
> +               clock-names = "pex", "afi", "pcie_xclk", "pll_e";
> +               status = "disabled";
> +
> +               pci@1,0 {
> +                       device_type = "pci";
> +                       assigned-addresses = <0x82000800 0 0x80000000 0 0x1000>;
> +                       reg = <0x000800 0 0 0 0>;
> +                       status = "disabled";
> +
> +                       #address-cells = <3>;
> +                       #size-cells = <2>;
> +
> +                       ranges;
> +
> +                       nvidia,num-lanes = <2>;
> +               };
> +
> +               pci@2,0 {
> +                       device_type = "pci";
> +                       assigned-addresses = <0x82001000 0 0x80001000 0 0x1000>;
> +                       reg = <0x001000 0 0 0 0>;
> +                       status = "disabled";
> +
> +                       #address-cells = <3>;
> +                       #size-cells = <2>;
> +
> +                       ranges;
> +
> +                       nvidia,num-lanes = <2>;
> +               };
> +       };
> +
> +
> +Board DTS:
> +
> +       pcie-controller {
> +               status = "okay";
> +
> +               vdd-supply = <&pci_vdd_reg>;
> +               pex-clk-supply = <&pci_clk_reg>;
> +
> +               /* root port 00:01.0 */
> +               pci@1,0 {
> +                       status = "okay";
> +
> +                       /* bridge 01:00.0 (optional) */
> +                       pci@0,0 {
> +                               reg = <0x010000 0 0 0 0>;
> +
> +                               #address-cells = <3>;
> +                               #size-cells = <2>;
> +
> +                               device_type = "pci";
> +
> +                               /* endpoint 02:00.0 */
> +                               pci@0,0 {
> +                                       reg = <0x020000 0 0 0 0>;
> +                               };
> +                       };
> +               };
> +       };
> +
> +Note that devices on the PCI bus are dynamically discovered using PCI's bus
> +enumeration and therefore don't need corresponding device nodes in DT. However
> +if a device on the PCI bus provides a non-probeable bus such as I2C or SPI,
> +device nodes need to be added in order to allow the bus' children to be
> +instantiated at the proper location in the operating system's device tree (as
> +illustrated by the optional nodes in the example above).
> diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
> index 9653fd8..ecd016a 100644
> --- a/arch/arm/boot/dts/tegra20.dtsi
> +++ b/arch/arm/boot/dts/tegra20.dtsi
> @@ -455,6 +455,61 @@
>                 #size-cells = <0>;
>         };
>
> +       pcie-controller {
> +               compatible = "nvidia,tegra20-pcie";
> +               device_type = "pci";
> +               reg = <0x80003000 0x00000800   /* PADS registers */
> +                      0x80003800 0x00000200   /* AFI registers */
> +                      0x90000000 0x10000000>; /* configuration space */
> +               reg-names = "pads", "afi", "cs";
> +               interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH   /* controller interrupt */
> +                             GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */
> +               interrupt-names = "intr", "msi";
> +
> +               bus-range = <0x00 0xff>;
> +               #address-cells = <3>;
> +               #size-cells = <2>;
> +
> +               ranges = <0x82000000 0 0x80000000 0x80000000 0 0x00001000   /* port 0 registers */
> +                         0x82000000 0 0x80001000 0x80001000 0 0x00001000   /* port 1 registers */
> +                         0x81000000 0 0          0x82000000 0 0x00010000   /* downstream I/O */
> +                         0x82000000 0 0xa0000000 0xa0000000 0 0x10000000   /* non-prefetchable memory */
> +                         0xc2000000 0 0xb0000000 0xb0000000 0 0x10000000>; /* prefetchable memory */
> +
> +               clocks = <&tegra_car TEGRA20_CLK_PEX>,
> +                        <&tegra_car TEGRA20_CLK_AFI>,
> +                        <&tegra_car TEGRA20_CLK_PCIE_XCLK>,
> +                        <&tegra_car TEGRA20_CLK_PLL_E>;
> +               clock-names = "pex", "afi", "pcie_xclk", "pll_e";
> +               status = "disabled";
> +
> +               pci@1,0 {
> +                       device_type = "pci";
> +                       assigned-addresses = <0x82000800 0 0x80000000 0 0x1000>;
> +                       reg = <0x000800 0 0 0 0>;
> +                       status = "disabled";
> +
> +                       #address-cells = <3>;
> +                       #size-cells = <2>;
> +                       ranges;
> +
> +                       nvidia,num-lanes = <2>;
> +               };
> +
> +               pci@2,0 {
> +                       device_type = "pci";
> +                       assigned-addresses = <0x82001000 0 0x80001000 0 0x1000>;
> +                       reg = <0x001000 0 0 0 0>;
> +                       status = "disabled";
> +
> +                       #address-cells = <3>;
> +                       #size-cells = <2>;
> +                       ranges;
> +
> +                       nvidia,num-lanes = <2>;
> +               };
> +       };
> +
>         usb@...00000 {
>                 compatible = "nvidia,tegra20-ehci", "usb-ehci";
>                 reg = <0xc5000000 0x4000>;
> diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
> index 80d3b82..f3ba4c6 100644
> --- a/arch/arm/mach-tegra/Kconfig
> +++ b/arch/arm/mach-tegra/Kconfig
> @@ -15,6 +15,8 @@ config ARCH_TEGRA
>         select SOC_BUS
>         select SPARSE_IRQ
>         select USE_OF
> +       select MIGHT_HAVE_PCI
> +       select ARCH_SUPPORTS_MSI
>         help
>           This enables support for NVIDIA Tegra based systems.
>
> @@ -69,11 +71,6 @@ config ARCH_TEGRA_114_SOC
>           Support for NVIDIA Tegra T114 processor family, based on the
>           ARM CortexA15MP CPU
>
> -config TEGRA_PCI
> -       bool "PCI Express support"
> -       depends on ARCH_TEGRA_2x_SOC
> -       select PCI
> -
>  config TEGRA_AHB
>         bool "Enable AHB driver for NVIDIA Tegra SoCs"
>         default y
> diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
> index 98b184e..01a0e6f 100644
> --- a/arch/arm/mach-tegra/Makefile
> +++ b/arch/arm/mach-tegra/Makefile
> @@ -27,7 +27,6 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC)               += cpuidle-tegra30.o
>  endif
>  obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o
>  obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
> -obj-$(CONFIG_TEGRA_PCI)                        += pcie.o
>
>  obj-$(CONFIG_ARCH_TEGRA_114_SOC)       += tegra114_speedo.o
>  obj-$(CONFIG_ARCH_TEGRA_114_SOC)       += sleep-tegra30.o
> @@ -35,6 +34,4 @@ ifeq ($(CONFIG_CPU_IDLE),y)
>  obj-$(CONFIG_ARCH_TEGRA_114_SOC)       += cpuidle-tegra114.o
>  endif
>
> -obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += board-harmony-pcie.o
> -
>  obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += board-paz00.o
> diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c
> deleted file mode 100644
> index 035b240..0000000
> --- a/arch/arm/mach-tegra/board-harmony-pcie.c
> +++ /dev/null
> @@ -1,89 +0,0 @@
> -/*
> - * arch/arm/mach-tegra/board-harmony-pcie.c
> - *
> - * Copyright (C) 2010 CompuLab, Ltd.
> - * Mike Rapoport <mike@...pulab.co.il>
> - *
> - * This software is licensed under the terms of the GNU General Public
> - * License version 2, as published by the Free Software Foundation, and
> - * may be copied, distributed, and modified under those terms.
> - *
> - * 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.
> - *
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/gpio.h>
> -#include <linux/err.h>
> -#include <linux/of_gpio.h>
> -#include <linux/regulator/consumer.h>
> -
> -#include <asm/mach-types.h>
> -
> -#include "board.h"
> -
> -#ifdef CONFIG_TEGRA_PCI
> -
> -int __init harmony_pcie_init(void)
> -{
> -       struct device_node *np;
> -       int en_vdd_1v05;
> -       struct regulator *regulator = NULL;
> -       int err;
> -
> -       np = of_find_node_by_path("/regulators/regulator@3");
> -       if (!np) {
> -               pr_err("%s: of_find_node_by_path failed\n", __func__);
> -               return -ENODEV;
> -       }
> -
> -       en_vdd_1v05 = of_get_named_gpio(np, "gpio", 0);
> -       if (en_vdd_1v05 < 0) {
> -               pr_err("%s: of_get_named_gpio failed: %d\n", __func__,
> -                      en_vdd_1v05);
> -               return en_vdd_1v05;
> -       }
> -
> -       err = gpio_request(en_vdd_1v05, "EN_VDD_1V05");
> -       if (err) {
> -               pr_err("%s: gpio_request failed: %d\n", __func__, err);
> -               return err;
> -       }
> -
> -       gpio_direction_output(en_vdd_1v05, 1);
> -
> -       regulator = regulator_get(NULL, "vdd_ldo0,vddio_pex_clk");
> -       if (IS_ERR(regulator)) {
> -               err = PTR_ERR(regulator);
> -               pr_err("%s: regulator_get failed: %d\n", __func__, err);
> -               goto err_reg;
> -       }
> -
> -       err = regulator_enable(regulator);
> -       if (err) {
> -               pr_err("%s: regulator_enable failed: %d\n", __func__, err);
> -               goto err_en;
> -       }
> -
> -       err = tegra_pcie_init(true, true);
> -       if (err) {
> -               pr_err("%s: tegra_pcie_init failed: %d\n", __func__, err);
> -               goto err_pcie;
> -       }
> -
> -       return 0;
> -
> -err_pcie:
> -       regulator_disable(regulator);
> -err_en:
> -       regulator_put(regulator);
> -err_reg:
> -       gpio_free(en_vdd_1v05);
> -
> -       return err;
> -}
> -
> -#endif
> diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
> index 9a6659f..db6810d 100644
> --- a/arch/arm/mach-tegra/board.h
> +++ b/arch/arm/mach-tegra/board.h
> @@ -31,7 +31,6 @@ void __init tegra_init_early(void);
>  void __init tegra_map_common_io(void);
>  void __init tegra_init_irq(void);
>  void __init tegra_dt_init_irq(void);
> -int __init tegra_pcie_init(bool init_port0, bool init_port1);
>
>  void tegra_init_late(void);
>
> @@ -48,13 +47,6 @@ int __init tegra_powergate_debugfs_init(void);
>  static inline int tegra_powergate_debugfs_init(void) { return 0; }
>  #endif
>
> -int __init harmony_regulator_init(void);
> -#ifdef CONFIG_TEGRA_PCI
> -int __init harmony_pcie_init(void);
> -#else
> -static inline int harmony_pcie_init(void) { return 0; }
> -#endif
> -
>  void __init tegra_paz00_wifikill_init(void);
>
>  #endif
> diff --git a/arch/arm/mach-tegra/iomap.h b/arch/arm/mach-tegra/iomap.h
> index 399fbca..d228421 100644
> --- a/arch/arm/mach-tegra/iomap.h
> +++ b/arch/arm/mach-tegra/iomap.h
> @@ -278,9 +278,6 @@
>  #define IO_APB_VIRT    IOMEM(0xFE300000)
>  #define IO_APB_SIZE    SZ_1M
>
> -#define TEGRA_PCIE_BASE                0x80000000
> -#define TEGRA_PCIE_IO_BASE     (TEGRA_PCIE_BASE + SZ_4M)
> -
>  #define IO_TO_VIRT_BETWEEN(p, st, sz)  ((p) >= (st) && (p) < ((st) + (sz)))
>  #define IO_TO_VIRT_XLATE(p, pst, vst)  (((p) - (pst) + (vst)))
>
> diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
> deleted file mode 100644
> index 6c1989b..0000000
> --- a/arch/arm/mach-tegra/pcie.c
> +++ /dev/null
> @@ -1,864 +0,0 @@
> -/*
> - * arch/arm/mach-tegra/pci.c
> - *
> - * PCIe host controller driver for TEGRA(2) SOCs
> - *
> - * Copyright (c) 2010, CompuLab, Ltd.
> - * Author: Mike Rapoport <mike@...pulab.co.il>
> - *
> - * Based on NVIDIA PCIe driver
> - * Copyright (c) 2008-2009, NVIDIA Corporation.
> - *
> - * Bits taken from arch/arm/mach-dove/pcie.c
> - *
> - * 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
> - * (at your option) 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, write to the Free Software Foundation, Inc.,
> - * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/pci.h>
> -#include <linux/interrupt.h>
> -#include <linux/irq.h>
> -#include <linux/clk.h>
> -#include <linux/delay.h>
> -#include <linux/export.h>
> -#include <linux/clk/tegra.h>
> -#include <linux/tegra-powergate.h>
> -
> -#include <asm/sizes.h>
> -#include <asm/mach/pci.h>
> -
> -#include "board.h"
> -#include "iomap.h"
> -#include "pmc.h"
> -
> -/* Hack - need to parse this from DT */
> -#define INT_PCIE_INTR 130
> -
> -/* register definitions */
> -#define AFI_OFFSET     0x3800
> -#define PADS_OFFSET    0x3000
> -#define RP0_OFFSET     0x0000
> -#define RP1_OFFSET     0x1000
> -
> -#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_INTR_CODE          0xb8
> -#define  AFI_INTR_CODE_MASK    0xf
> -#define  AFI_INTR_MASTER_ABORT 4
> -#define  AFI_INTR_LEGACY       6
> -
> -#define AFI_INTR_SIGNATURE     0xbc
> -#define AFI_SM_INTR_ENABLE     0xc4
> -
> -#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_PCIE_CONFIG                                        0x0f8
> -#define  AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE         (1 << 1)
> -#define  AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE         (1 << 2)
> -#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_DUAL      (0x1 << 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_PEX_CTRL_RST              (1 << 0)
> -#define  AFI_PEX_CTRL_REFCLK_EN                (1 << 3)
> -
> -#define RP_VEND_XP     0x00000F00
> -#define  RP_VEND_XP_DL_UP      (1 << 30)
> -
> -#define RP_LINK_CONTROL_STATUS                 0x00000090
> -#define  RP_LINK_CONTROL_STATUS_LINKSTAT_MASK  0x3fff0000
> -
> -#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                           0x000000B8
> -#define  PADS_PLL_CTL_RST_B4SM                 (1 << 1)
> -#define  PADS_PLL_CTL_LOCKDET                  (1 << 8)
> -#define  PADS_PLL_CTL_REFCLK_MASK              (0x3 << 16)
> -#define  PADS_PLL_CTL_REFCLK_INTERNAL_CML      (0 << 16)
> -#define  PADS_PLL_CTL_REFCLK_INTERNAL_CMOS     (1 << 16)
> -#define  PADS_PLL_CTL_REFCLK_EXTERNAL          (2 << 16)
> -#define  PADS_PLL_CTL_TXCLKREF_MASK            (0x1 << 20)
> -#define  PADS_PLL_CTL_TXCLKREF_DIV10           (0 << 20)
> -#define  PADS_PLL_CTL_TXCLKREF_DIV5            (1 << 20)
> -
> -/*
> - * Tegra2 defines 1GB in the AXI address map for PCIe.
> - *
> - * That address space is split into different regions, with sizes and
> - * offsets as follows:
> - *
> - * 0x80000000 - 0x80003fff - PCI controller registers
> - * 0x80004000 - 0x80103fff - PCI configuration space
> - * 0x80104000 - 0x80203fff - PCI extended configuration space
> - * 0x80203fff - 0x803fffff - unused
> - * 0x80400000 - 0x8040ffff - downstream IO
> - * 0x80410000 - 0x8fffffff - unused
> - * 0x90000000 - 0x9fffffff - non-prefetchable memory
> - * 0xa0000000 - 0xbfffffff - prefetchable memory
> - */
> -#define PCIE_REGS_SZ           SZ_16K
> -#define PCIE_CFG_OFF           PCIE_REGS_SZ
> -#define PCIE_CFG_SZ            SZ_1M
> -#define PCIE_EXT_CFG_OFF       (PCIE_CFG_SZ + PCIE_CFG_OFF)
> -#define PCIE_EXT_CFG_SZ                SZ_1M
> -#define PCIE_IOMAP_SZ          (PCIE_REGS_SZ + PCIE_CFG_SZ + PCIE_EXT_CFG_SZ)
> -
> -#define MEM_BASE_0             (TEGRA_PCIE_BASE + SZ_256M)
> -#define MEM_SIZE_0             SZ_128M
> -#define MEM_BASE_1             (MEM_BASE_0 + MEM_SIZE_0)
> -#define MEM_SIZE_1             SZ_128M
> -#define PREFETCH_MEM_BASE_0    (MEM_BASE_1 + MEM_SIZE_1)
> -#define PREFETCH_MEM_SIZE_0    SZ_128M
> -#define PREFETCH_MEM_BASE_1    (PREFETCH_MEM_BASE_0 + PREFETCH_MEM_SIZE_0)
> -#define PREFETCH_MEM_SIZE_1    SZ_128M
> -
> -#define  PCIE_CONF_BUS(b)      ((b) << 16)
> -#define  PCIE_CONF_DEV(d)      ((d) << 11)
> -#define  PCIE_CONF_FUNC(f)     ((f) << 8)
> -#define  PCIE_CONF_REG(r)      \
> -       (((r) & ~0x3) | (((r) < 256) ? PCIE_CFG_OFF : PCIE_EXT_CFG_OFF))
> -
> -struct tegra_pcie_port {
> -       int                     index;
> -       u8                      root_bus_nr;
> -       void __iomem            *base;
> -
> -       bool                    link_up;
> -
> -       char                    mem_space_name[16];
> -       char                    prefetch_space_name[20];
> -       struct resource         res[2];
> -};
> -
> -struct tegra_pcie_info {
> -       struct tegra_pcie_port  port[2];
> -       int                     num_ports;
> -
> -       void __iomem            *regs;
> -       struct resource         res_mmio;
> -
> -       struct clk              *pex_clk;
> -       struct clk              *afi_clk;
> -       struct clk              *pcie_xclk;
> -       struct clk              *pll_e;
> -};
> -
> -static struct tegra_pcie_info tegra_pcie;
> -
> -static inline void afi_writel(u32 value, unsigned long offset)
> -{
> -       writel(value, offset + AFI_OFFSET + tegra_pcie.regs);
> -}
> -
> -static inline u32 afi_readl(unsigned long offset)
> -{
> -       return readl(offset + AFI_OFFSET + tegra_pcie.regs);
> -}
> -
> -static inline void pads_writel(u32 value, unsigned long offset)
> -{
> -       writel(value, offset + PADS_OFFSET + tegra_pcie.regs);
> -}
> -
> -static inline u32 pads_readl(unsigned long offset)
> -{
> -       return readl(offset + PADS_OFFSET + tegra_pcie.regs);
> -}
> -
> -static struct tegra_pcie_port *bus_to_port(int bus)
> -{
> -       int i;
> -
> -       for (i = tegra_pcie.num_ports - 1; i >= 0; i--) {
> -               int rbus = tegra_pcie.port[i].root_bus_nr;
> -               if (rbus != -1 && rbus == bus)
> -                       break;
> -       }
> -
> -       return i >= 0 ? tegra_pcie.port + i : NULL;
> -}
> -
> -static int tegra_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
> -                               int where, int size, u32 *val)
> -{
> -       struct tegra_pcie_port *pp = bus_to_port(bus->number);
> -       void __iomem *addr;
> -
> -       if (pp) {
> -               if (devfn != 0) {
> -                       *val = 0xffffffff;
> -                       return PCIBIOS_DEVICE_NOT_FOUND;
> -               }
> -
> -               addr = pp->base + (where & ~0x3);
> -       } else {
> -               addr = tegra_pcie.regs + (PCIE_CONF_BUS(bus->number) +
> -                                         PCIE_CONF_DEV(PCI_SLOT(devfn)) +
> -                                         PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
> -                                         PCIE_CONF_REG(where));
> -       }
> -
> -       *val = readl(addr);
> -
> -       if (size == 1)
> -               *val = (*val >> (8 * (where & 3))) & 0xff;
> -       else if (size == 2)
> -               *val = (*val >> (8 * (where & 3))) & 0xffff;
> -
> -       return PCIBIOS_SUCCESSFUL;
> -}
> -
> -static int tegra_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
> -                                int where, int size, u32 val)
> -{
> -       struct tegra_pcie_port *pp = bus_to_port(bus->number);
> -       void __iomem *addr;
> -
> -       u32 mask;
> -       u32 tmp;
> -
> -       if (pp) {
> -               if (devfn != 0)
> -                       return PCIBIOS_DEVICE_NOT_FOUND;
> -
> -               addr = pp->base + (where & ~0x3);
> -       } else {
> -               addr = tegra_pcie.regs + (PCIE_CONF_BUS(bus->number) +
> -                                         PCIE_CONF_DEV(PCI_SLOT(devfn)) +
> -                                         PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
> -                                         PCIE_CONF_REG(where));
> -       }
> -
> -       if (size == 4) {
> -               writel(val, addr);
> -               return PCIBIOS_SUCCESSFUL;
> -       }
> -
> -       if (size == 2)
> -               mask = ~(0xffff << ((where & 0x3) * 8));
> -       else if (size == 1)
> -               mask = ~(0xff << ((where & 0x3) * 8));
> -       else
> -               return PCIBIOS_BAD_REGISTER_NUMBER;
> -
> -       tmp = readl(addr) & mask;
> -       tmp |= val << ((where & 0x3) * 8);
> -       writel(tmp, addr);
> -
> -       return PCIBIOS_SUCCESSFUL;
> -}
> -
> -static struct pci_ops tegra_pcie_ops = {
> -       .read   = tegra_pcie_read_conf,
> -       .write  = tegra_pcie_write_conf,
> -};
> -
> -static void tegra_pcie_fixup_bridge(struct pci_dev *dev)
> -{
> -       u16 reg;
> -
> -       if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) {
> -               pci_read_config_word(dev, PCI_COMMAND, &reg);
> -               reg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
> -                       PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
> -               pci_write_config_word(dev, PCI_COMMAND, reg);
> -       }
> -}
> -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge);
> -
> -/* Tegra PCIE root complex wrongly reports device class */
> -static void tegra_pcie_fixup_class(struct pci_dev *dev)
> -{
> -       dev->class = PCI_CLASS_BRIDGE_PCI << 8;
> -}
> -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class);
> -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
> -
> -/* Tegra PCIE requires relaxed ordering */
> -static void tegra_pcie_relax_enable(struct pci_dev *dev)
> -{
> -       pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN);
> -}
> -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
> -
> -static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
> -{
> -       struct tegra_pcie_port *pp;
> -
> -       if (nr >= tegra_pcie.num_ports)
> -               return 0;
> -
> -       pp = tegra_pcie.port + nr;
> -       pp->root_bus_nr = sys->busnr;
> -
> -       pci_ioremap_io(nr * SZ_64K, TEGRA_PCIE_IO_BASE);
> -
> -       /*
> -        * IORESOURCE_MEM
> -        */
> -       snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
> -                "PCIe %d MEM", pp->index);
> -       pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
> -       pp->res[0].name = pp->mem_space_name;
> -       if (pp->index == 0) {
> -               pp->res[0].start = MEM_BASE_0;
> -               pp->res[0].end = pp->res[0].start + MEM_SIZE_0 - 1;
> -       } else {
> -               pp->res[0].start = MEM_BASE_1;
> -               pp->res[0].end = pp->res[0].start + MEM_SIZE_1 - 1;
> -       }
> -       pp->res[0].flags = IORESOURCE_MEM;
> -       if (request_resource(&iomem_resource, &pp->res[0]))
> -               panic("Request PCIe Memory resource failed\n");
> -       pci_add_resource_offset(&sys->resources, &pp->res[0], sys->mem_offset);
> -
> -       /*
> -        * IORESOURCE_MEM | IORESOURCE_PREFETCH
> -        */
> -       snprintf(pp->prefetch_space_name, sizeof(pp->prefetch_space_name),
> -                "PCIe %d PREFETCH MEM", pp->index);
> -       pp->prefetch_space_name[sizeof(pp->prefetch_space_name) - 1] = 0;
> -       pp->res[1].name = pp->prefetch_space_name;
> -       if (pp->index == 0) {
> -               pp->res[1].start = PREFETCH_MEM_BASE_0;
> -               pp->res[1].end = pp->res[1].start + PREFETCH_MEM_SIZE_0 - 1;
> -       } else {
> -               pp->res[1].start = PREFETCH_MEM_BASE_1;
> -               pp->res[1].end = pp->res[1].start + PREFETCH_MEM_SIZE_1 - 1;
> -       }
> -       pp->res[1].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
> -       if (request_resource(&iomem_resource, &pp->res[1]))
> -               panic("Request PCIe Prefetch Memory resource failed\n");
> -       pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
> -
> -       return 1;
> -}
> -
> -static int tegra_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> -{
> -       return INT_PCIE_INTR;
> -}
> -
> -static struct pci_bus __init *tegra_pcie_scan_bus(int nr,
> -                                                 struct pci_sys_data *sys)
> -{
> -       struct tegra_pcie_port *pp;
> -
> -       if (nr >= tegra_pcie.num_ports)
> -               return NULL;
> -
> -       pp = tegra_pcie.port + nr;
> -       pp->root_bus_nr = sys->busnr;
> -
> -       return pci_scan_root_bus(NULL, sys->busnr, &tegra_pcie_ops, sys,
> -                                &sys->resources);
> -}
> -
> -static struct hw_pci tegra_pcie_hw __initdata = {
> -       .nr_controllers = 2,
> -       .setup          = tegra_pcie_setup,
> -       .scan           = tegra_pcie_scan_bus,
> -       .map_irq        = tegra_pcie_map_irq,
> -};
> -
> -
> -static irqreturn_t tegra_pcie_isr(int irq, void *arg)
> -{
> -       const char *err_msg[] = {
> -               "Unknown",
> -               "AXI slave error",
> -               "AXI decode error",
> -               "Target abort",
> -               "Master abort",
> -               "Invalid write",
> -               "Response decoding error",
> -               "AXI response decoding error",
> -               "Transcation timeout",
> -       };
> -
> -       u32 code, signature;
> -
> -       code = afi_readl(AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
> -       signature = afi_readl(AFI_INTR_SIGNATURE);
> -       afi_writel(0, AFI_INTR_CODE);
> -
> -       if (code == AFI_INTR_LEGACY)
> -               return IRQ_NONE;
> -
> -       if (code >= ARRAY_SIZE(err_msg))
> -               code = 0;
> -
> -       /*
> -        * do not pollute kernel log with master abort reports since they
> -        * happen a lot during enumeration
> -        */
> -       if (code == AFI_INTR_MASTER_ABORT)
> -               pr_debug("PCIE: %s, signature: %08x\n", err_msg[code], signature);
> -       else
> -               pr_err("PCIE: %s, signature: %08x\n", err_msg[code], signature);
> -
> -       return IRQ_HANDLED;
> -}
> -
> -static void tegra_pcie_setup_translations(void)
> -{
> -       u32 fpci_bar;
> -       u32 size;
> -       u32 axi_address;
> -
> -       /* Bar 0: config Bar */
> -       fpci_bar = ((u32)0xfdff << 16);
> -       size = PCIE_CFG_SZ;
> -       axi_address = TEGRA_PCIE_BASE + PCIE_CFG_OFF;
> -       afi_writel(axi_address, AFI_AXI_BAR0_START);
> -       afi_writel(size >> 12, AFI_AXI_BAR0_SZ);
> -       afi_writel(fpci_bar, AFI_FPCI_BAR0);
> -
> -       /* Bar 1: extended config Bar */
> -       fpci_bar = ((u32)0xfe1 << 20);
> -       size = PCIE_EXT_CFG_SZ;
> -       axi_address = TEGRA_PCIE_BASE + PCIE_EXT_CFG_OFF;
> -       afi_writel(axi_address, AFI_AXI_BAR1_START);
> -       afi_writel(size >> 12, AFI_AXI_BAR1_SZ);
> -       afi_writel(fpci_bar, AFI_FPCI_BAR1);
> -
> -       /* Bar 2: downstream IO bar */
> -       fpci_bar = ((__u32)0xfdfc << 16);
> -       size = SZ_128K;
> -       axi_address = TEGRA_PCIE_IO_BASE;
> -       afi_writel(axi_address, AFI_AXI_BAR2_START);
> -       afi_writel(size >> 12, AFI_AXI_BAR2_SZ);
> -       afi_writel(fpci_bar, AFI_FPCI_BAR2);
> -
> -       /* Bar 3: prefetchable memory BAR */
> -       fpci_bar = (((PREFETCH_MEM_BASE_0 >> 12) & 0x0fffffff) << 4) | 0x1;
> -       size =  PREFETCH_MEM_SIZE_0 +  PREFETCH_MEM_SIZE_1;
> -       axi_address = PREFETCH_MEM_BASE_0;
> -       afi_writel(axi_address, AFI_AXI_BAR3_START);
> -       afi_writel(size >> 12, AFI_AXI_BAR3_SZ);
> -       afi_writel(fpci_bar, AFI_FPCI_BAR3);
> -
> -       /* Bar 4: non prefetchable memory BAR */
> -       fpci_bar = (((MEM_BASE_0 >> 12) & 0x0FFFFFFF) << 4) | 0x1;
> -       size = MEM_SIZE_0 + MEM_SIZE_1;
> -       axi_address = MEM_BASE_0;
> -       afi_writel(axi_address, AFI_AXI_BAR4_START);
> -       afi_writel(size >> 12, AFI_AXI_BAR4_SZ);
> -       afi_writel(fpci_bar, AFI_FPCI_BAR4);
> -
> -       /* Bar 5: NULL out the remaining BAR as it is not used */
> -       fpci_bar = 0;
> -       size = 0;
> -       axi_address = 0;
> -       afi_writel(axi_address, AFI_AXI_BAR5_START);
> -       afi_writel(size >> 12, AFI_AXI_BAR5_SZ);
> -       afi_writel(fpci_bar, AFI_FPCI_BAR5);
> -
> -       /* map all upstream transactions as uncached */
> -       afi_writel(PHYS_OFFSET, AFI_CACHE_BAR0_ST);
> -       afi_writel(0, AFI_CACHE_BAR0_SZ);
> -       afi_writel(0, AFI_CACHE_BAR1_ST);
> -       afi_writel(0, AFI_CACHE_BAR1_SZ);
> -
> -       /* No MSI */
> -       afi_writel(0, AFI_MSI_FPCI_BAR_ST);
> -       afi_writel(0, AFI_MSI_BAR_SZ);
> -       afi_writel(0, AFI_MSI_AXI_BAR_ST);
> -       afi_writel(0, AFI_MSI_BAR_SZ);
> -}
> -
> -static int tegra_pcie_enable_controller(void)
> -{
> -       u32 val, reg;
> -       int i, timeout;
> -
> -       /* Enable slot clock and pulse the reset signals */
> -       for (i = 0, reg = AFI_PEX0_CTRL; i < 2; i++, reg += 0x8) {
> -               val = afi_readl(reg) |  AFI_PEX_CTRL_REFCLK_EN;
> -               afi_writel(val, reg);
> -               val &= ~AFI_PEX_CTRL_RST;
> -               afi_writel(val, reg);
> -
> -               val = afi_readl(reg) | AFI_PEX_CTRL_RST;
> -               afi_writel(val, reg);
> -       }
> -
> -       /* Enable dual controller and both ports */
> -       val = afi_readl(AFI_PCIE_CONFIG);
> -       val &= ~(AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE |
> -                AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE |
> -                AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK);
> -       val |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
> -       afi_writel(val, AFI_PCIE_CONFIG);
> -
> -       val = afi_readl(AFI_FUSE) & ~AFI_FUSE_PCIE_T0_GEN2_DIS;
> -       afi_writel(val, AFI_FUSE);
> -
> -       /* Initialze internal PHY, enable up to 16 PCIE lanes */
> -       pads_writel(0x0, PADS_CTL_SEL);
> -
> -       /* override IDDQ to 1 on all 4 lanes */
> -       val = pads_readl(PADS_CTL) | PADS_CTL_IDDQ_1L;
> -       pads_writel(val, PADS_CTL);
> -
> -       /*
> -        * set up PHY PLL inputs select PLLE output as refclock,
> -        * set TX ref sel to div10 (not div5)
> -        */
> -       val = pads_readl(PADS_PLL_CTL);
> -       val &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
> -       val |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML | PADS_PLL_CTL_TXCLKREF_DIV10);
> -       pads_writel(val, PADS_PLL_CTL);
> -
> -       /* take PLL out of reset  */
> -       val = pads_readl(PADS_PLL_CTL) | PADS_PLL_CTL_RST_B4SM;
> -       pads_writel(val, PADS_PLL_CTL);
> -
> -       /*
> -        * Hack, set the clock voltage to the DEFAULT provided by hw folks.
> -        * This doesn't exist in the documentation
> -        */
> -       pads_writel(0xfa5cfa5c, 0xc8);
> -
> -       /* Wait for the PLL to lock */
> -       timeout = 300;
> -       do {
> -               val = pads_readl(PADS_PLL_CTL);
> -               usleep_range(1000, 1000);
> -               if (--timeout == 0) {
> -                       pr_err("Tegra PCIe error: timeout waiting for PLL\n");
> -                       return -EBUSY;
> -               }
> -       } while (!(val & PADS_PLL_CTL_LOCKDET));
> -
> -       /* turn off IDDQ override */
> -       val = pads_readl(PADS_CTL) & ~PADS_CTL_IDDQ_1L;
> -       pads_writel(val, PADS_CTL);
> -
> -       /* enable TX/RX data */
> -       val = pads_readl(PADS_CTL);
> -       val |= (PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L);
> -       pads_writel(val, PADS_CTL);
> -
> -       /* Take the PCIe interface module out of reset */
> -       tegra_periph_reset_deassert(tegra_pcie.pcie_xclk);
> -
> -       /* Finally enable PCIe */
> -       val = afi_readl(AFI_CONFIGURATION) | AFI_CONFIGURATION_EN_FPCI;
> -       afi_writel(val, AFI_CONFIGURATION);
> -
> -       val = (AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
> -              AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR |
> -              AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR);
> -       afi_writel(val, AFI_AFI_INTR_ENABLE);
> -       afi_writel(0xffffffff, AFI_SM_INTR_ENABLE);
> -
> -       /* FIXME: No MSI for now, only INT */
> -       afi_writel(AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK);
> -
> -       /* Disable all execptions */
> -       afi_writel(0, AFI_FPCI_ERROR_MASKS);
> -
> -       return 0;
> -}
> -
> -static void tegra_pcie_power_off(void)
> -{
> -       tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
> -       tegra_periph_reset_assert(tegra_pcie.afi_clk);
> -       tegra_periph_reset_assert(tegra_pcie.pex_clk);
> -
> -       tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
> -       tegra_pmc_pcie_xclk_clamp(true);
> -}
> -
> -static int tegra_pcie_power_regate(void)
> -{
> -       int err;
> -
> -       tegra_pcie_power_off();
> -
> -       tegra_pmc_pcie_xclk_clamp(true);
> -
> -       tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
> -       tegra_periph_reset_assert(tegra_pcie.afi_clk);
> -
> -       err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
> -                                               tegra_pcie.pex_clk);
> -       if (err) {
> -               pr_err("PCIE: powerup sequence failed: %d\n", err);
> -               return err;
> -       }
> -
> -       tegra_periph_reset_deassert(tegra_pcie.afi_clk);
> -
> -       tegra_pmc_pcie_xclk_clamp(false);
> -
> -       clk_prepare_enable(tegra_pcie.afi_clk);
> -       clk_prepare_enable(tegra_pcie.pex_clk);
> -       return clk_prepare_enable(tegra_pcie.pll_e);
> -}
> -
> -static int tegra_pcie_clocks_get(void)
> -{
> -       int err;
> -
> -       tegra_pcie.pex_clk = clk_get(NULL, "pex");
> -       if (IS_ERR(tegra_pcie.pex_clk))
> -               return PTR_ERR(tegra_pcie.pex_clk);
> -
> -       tegra_pcie.afi_clk = clk_get(NULL, "afi");
> -       if (IS_ERR(tegra_pcie.afi_clk)) {
> -               err = PTR_ERR(tegra_pcie.afi_clk);
> -               goto err_afi_clk;
> -       }
> -
> -       tegra_pcie.pcie_xclk = clk_get(NULL, "pcie_xclk");
> -       if (IS_ERR(tegra_pcie.pcie_xclk)) {
> -               err =  PTR_ERR(tegra_pcie.pcie_xclk);
> -               goto err_pcie_xclk;
> -       }
> -
> -       tegra_pcie.pll_e = clk_get_sys(NULL, "pll_e");
> -       if (IS_ERR(tegra_pcie.pll_e)) {
> -               err = PTR_ERR(tegra_pcie.pll_e);
> -               goto err_pll_e;
> -       }
> -
> -       return 0;
> -
> -err_pll_e:
> -       clk_put(tegra_pcie.pcie_xclk);
> -err_pcie_xclk:
> -       clk_put(tegra_pcie.afi_clk);
> -err_afi_clk:
> -       clk_put(tegra_pcie.pex_clk);
> -
> -       return err;
> -}
> -
> -static void tegra_pcie_clocks_put(void)
> -{
> -       clk_put(tegra_pcie.pll_e);
> -       clk_put(tegra_pcie.pcie_xclk);
> -       clk_put(tegra_pcie.afi_clk);
> -       clk_put(tegra_pcie.pex_clk);
> -}
> -
> -static int __init tegra_pcie_get_resources(void)
> -{
> -       int err;
> -
> -       err = tegra_pcie_clocks_get();
> -       if (err) {
> -               pr_err("PCIE: failed to get clocks: %d\n", err);
> -               return err;
> -       }
> -
> -       err = tegra_pcie_power_regate();
> -       if (err) {
> -               pr_err("PCIE: failed to power up: %d\n", err);
> -               goto err_pwr_on;
> -       }
> -
> -       tegra_pcie.regs = ioremap_nocache(TEGRA_PCIE_BASE, PCIE_IOMAP_SZ);
> -       if (tegra_pcie.regs == NULL) {
> -               pr_err("PCIE: Failed to map PCI/AFI registers\n");
> -               err = -ENOMEM;
> -               goto err_map_reg;
> -       }
> -
> -       err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
> -                         IRQF_SHARED, "PCIE", &tegra_pcie);
> -       if (err) {
> -               pr_err("PCIE: Failed to register IRQ: %d\n", err);
> -               goto err_req_io;
> -       }
> -       set_irq_flags(INT_PCIE_INTR, IRQF_VALID);
> -
> -       return 0;
> -
> -err_req_io:
> -       iounmap(tegra_pcie.regs);
> -err_map_reg:
> -       tegra_pcie_power_off();
> -err_pwr_on:
> -       tegra_pcie_clocks_put();
> -
> -       return err;
> -}
> -
> -/*
> - * FIXME: If there are no PCIe cards attached, then calling this function
> - * can result in the increase of the bootup time as there are big timeout
> - * loops.
> - */
> -#define TEGRA_PCIE_LINKUP_TIMEOUT      200     /* up to 1.2 seconds */
> -static bool tegra_pcie_check_link(struct tegra_pcie_port *pp, int idx,
> -                                 u32 reset_reg)
> -{
> -       u32 reg;
> -       int retries = 3;
> -       int timeout;
> -
> -       do {
> -               timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
> -               while (timeout) {
> -                       reg = readl(pp->base + RP_VEND_XP);
> -
> -                       if (reg & RP_VEND_XP_DL_UP)
> -                               break;
> -
> -                       mdelay(1);
> -                       timeout--;
> -               }
> -
> -               if (!timeout)  {
> -                       pr_err("PCIE: port %d: link down, retrying\n", idx);
> -                       goto retry;
> -               }
> -
> -               timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
> -               while (timeout) {
> -                       reg = readl(pp->base + RP_LINK_CONTROL_STATUS);
> -
> -                       if (reg & 0x20000000)
> -                               return true;
> -
> -                       mdelay(1);
> -                       timeout--;
> -               }
> -
> -retry:
> -               /* Pulse the PEX reset */
> -               reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;
> -               afi_writel(reg, reset_reg);
> -               mdelay(1);
> -               reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
> -               afi_writel(reg, reset_reg);
> -
> -               retries--;
> -       } while (retries);
> -
> -       return false;
> -}
> -
> -static void __init tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
> -{
> -       struct tegra_pcie_port *pp;
> -
> -       pp = tegra_pcie.port + tegra_pcie.num_ports;
> -
> -       pp->index = -1;
> -       pp->base = tegra_pcie.regs + offset;
> -       pp->link_up = tegra_pcie_check_link(pp, index, reset_reg);
> -
> -       if (!pp->link_up) {
> -               pp->base = NULL;
> -               printk(KERN_INFO "PCIE: port %d: link down, ignoring\n", index);
> -               return;
> -       }
> -
> -       tegra_pcie.num_ports++;
> -       pp->index = index;
> -       pp->root_bus_nr = -1;
> -       memset(pp->res, 0, sizeof(pp->res));
> -}
> -
> -int __init tegra_pcie_init(bool init_port0, bool init_port1)
> -{
> -       int err;
> -
> -       if (!(init_port0 || init_port1))
> -               return -ENODEV;
> -
> -       pcibios_min_mem = 0;
> -
> -       err = tegra_pcie_get_resources();
> -       if (err)
> -               return err;
> -
> -       err = tegra_pcie_enable_controller();
> -       if (err)
> -               return err;
> -
> -       /* setup the AFI address translations */
> -       tegra_pcie_setup_translations();
> -
> -       if (init_port0)
> -               tegra_pcie_add_port(0, RP0_OFFSET, AFI_PEX0_CTRL);
> -
> -       if (init_port1)
> -               tegra_pcie_add_port(1, RP1_OFFSET, AFI_PEX1_CTRL);
> -
> -       pci_common_init(&tegra_pcie_hw);
> -
> -       return 0;
> -}
> diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
> index 0d1e412..fe56fca 100644
> --- a/arch/arm/mach-tegra/tegra.c
> +++ b/arch/arm/mach-tegra/tegra.c
> @@ -116,28 +116,6 @@ out:
>                                 tegra20_auxdata_lookup, parent);
>  }
>
> -static void __init trimslice_init(void)
> -{
> -#ifdef CONFIG_TEGRA_PCI
> -       int ret;
> -
> -       ret = tegra_pcie_init(true, true);
> -       if (ret)
> -               pr_err("tegra_pci_init() failed: %d\n", ret);
> -#endif
> -}
> -
> -static void __init harmony_init(void)
> -{
> -#ifdef CONFIG_TEGRA_PCI
> -       int ret;
> -
> -       ret = harmony_pcie_init();
> -       if (ret)
> -               pr_err("harmony_pcie_init() failed: %d\n", ret);
> -#endif
> -}
> -
>  static void __init paz00_init(void)
>  {
>         if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
> @@ -148,8 +126,6 @@ static struct {
>         char *machine;
>         void (*init)(void);
>  } board_init_funcs[] = {
> -       { "compulab,trimslice", trimslice_init },
> -       { "nvidia,harmony", harmony_init },
>         { "compal,paz00", paz00_init },
>  };
>
> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
> index 1184ff6..5f33746 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -14,4 +14,8 @@ config PCI_EXYNOS
>         select PCIEPORTBUS
>         select PCIE_DW
>
> +config PCI_TEGRA
> +       bool "NVIDIA Tegra PCIe controller"
> +       depends on ARCH_TEGRA
> +
>  endmenu
> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> index 086d850..a733fb0 100644
> --- a/drivers/pci/host/Makefile
> +++ b/drivers/pci/host/Makefile
> @@ -1,2 +1,3 @@
>  obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
>  obj-$(CONFIG_PCIE_DW) += pcie-designware.o
> +obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
> diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
> new file mode 100644
> index 0000000..223069a
> --- /dev/null
> +++ b/drivers/pci/host/pci-tegra.c
> @@ -0,0 +1,1540 @@
> +/*
> + * PCIe host controller driver for TEGRA(2) SOCs
> + *
> + * Copyright (c) 2010, CompuLab, Ltd.
> + * Author: Mike Rapoport <mike@...pulab.co.il>
> + *
> + * Based on NVIDIA PCIe driver
> + * Copyright (c) 2008-2009, NVIDIA Corporation.
> + *
> + * Bits taken from arch/arm/mach-dove/pcie.c
> + *
> + * 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
> + * (at your option) 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, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk/tegra.h>
> +#include <linux/delay.h>
> +#include <linux/export.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/msi.h>
> +#include <linux/of_address.h>
> +#include <linux/of_pci.h>
> +#include <linux/of_platform.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/sizes.h>
> +#include <linux/slab.h>
> +#include <linux/tegra-pmc.h>
> +#include <linux/tegra-powergate.h>
> +#include <linux/vmalloc.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <asm/mach/irq.h>
> +#include <asm/mach/map.h>
> +#include <asm/mach/pci.h>
> +
> +#define INT_PCI_MSI_NR (8 * 32)
> +#define TEGRA_MAX_PORTS 2
> +
> +/* register definitions */
> +
> +#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_MSI_VEC0           0x6c
> +#define AFI_MSI_VEC1           0x70
> +#define AFI_MSI_VEC2           0x74
> +#define AFI_MSI_VEC3           0x78
> +#define AFI_MSI_VEC4           0x7c
> +#define AFI_MSI_VEC5           0x80
> +#define AFI_MSI_VEC6           0x84
> +#define AFI_MSI_VEC7           0x88
> +
> +#define AFI_MSI_EN_VEC0                0x8c
> +#define AFI_MSI_EN_VEC1                0x90
> +#define AFI_MSI_EN_VEC2                0x94
> +#define AFI_MSI_EN_VEC3                0x98
> +#define AFI_MSI_EN_VEC4                0x9c
> +#define AFI_MSI_EN_VEC5                0xa0
> +#define AFI_MSI_EN_VEC6                0xa4
> +#define AFI_MSI_EN_VEC7                0xa8
> +
> +#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_INTR_CODE                  0xb8
> +#define  AFI_INTR_CODE_MASK            0xf
> +#define  AFI_INTR_AXI_SLAVE_ERROR      1
> +#define  AFI_INTR_AXI_DECODE_ERROR     2
> +#define  AFI_INTR_TARGET_ABORT         3
> +#define  AFI_INTR_MASTER_ABORT         4
> +#define  AFI_INTR_INVALID_WRITE                5
> +#define  AFI_INTR_LEGACY               6
> +#define  AFI_INTR_FPCI_DECODE_ERROR    7
> +
> +#define AFI_INTR_SIGNATURE     0xbc
> +#define AFI_UPPER_FPCI_ADDRESS 0xc0
> +#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_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_DUAL      (0x1 << 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_PEX_CTRL_RST              (1 << 0)
> +#define  AFI_PEX_CTRL_REFCLK_EN                (1 << 3)
> +
> +#define RP_VEND_XP     0x00000F00
> +#define  RP_VEND_XP_DL_UP      (1 << 30)
> +
> +#define RP_LINK_CONTROL_STATUS                 0x00000090
> +#define  RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
> +#define  RP_LINK_CONTROL_STATUS_LINKSTAT_MASK  0x3fff0000
> +
> +#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                           0x000000B8
> +#define  PADS_PLL_CTL_RST_B4SM                 (1 << 1)
> +#define  PADS_PLL_CTL_LOCKDET                  (1 << 8)
> +#define  PADS_PLL_CTL_REFCLK_MASK              (0x3 << 16)
> +#define  PADS_PLL_CTL_REFCLK_INTERNAL_CML      (0 << 16)
> +#define  PADS_PLL_CTL_REFCLK_INTERNAL_CMOS     (1 << 16)
> +#define  PADS_PLL_CTL_REFCLK_EXTERNAL          (2 << 16)
> +#define  PADS_PLL_CTL_TXCLKREF_MASK            (0x1 << 20)
> +#define  PADS_PLL_CTL_TXCLKREF_DIV10           (0 << 20)
> +#define  PADS_PLL_CTL_TXCLKREF_DIV5            (1 << 20)
> +
> +struct tegra_msi {
> +       struct msi_chip chip;
> +       DECLARE_BITMAP(used, INT_PCI_MSI_NR);
> +       struct irq_domain *domain;
> +       unsigned long pages;
> +       struct mutex lock;
> +       int irq;
> +};
> +
> +static inline struct tegra_msi *to_tegra_msi(struct msi_chip *chip)
> +{
> +       return container_of(chip, struct tegra_msi, chip);
> +}
> +
> +struct tegra_pcie {
> +       struct device *dev;
> +
> +       void __iomem *pads;
> +       void __iomem *afi;
> +       int irq;
> +
> +       struct list_head busses;
> +       struct resource *cs;
> +
> +       struct resource io;
> +       struct resource mem;
> +       struct resource prefetch;
> +       struct resource busn;
> +
> +       struct clk *pex_clk;
> +       struct clk *afi_clk;
> +       struct clk *pcie_xclk;
> +       struct clk *pll_e;
> +
> +       struct tegra_msi msi;
> +
> +       struct list_head ports;
> +       unsigned int num_ports;
> +       u32 xbar_config;
> +
> +       struct regulator *pex_clk_supply;
> +       struct regulator *vdd_supply;
> +};
> +
> +struct tegra_pcie_port {
> +       struct tegra_pcie *pcie;
> +       struct list_head list;
> +       struct resource regs;
> +       void __iomem *base;
> +       unsigned int index;
> +       unsigned int lanes;
> +};
> +
> +struct tegra_pcie_bus {
> +       struct vm_struct *area;
> +       struct list_head list;
> +       unsigned int nr;
> +};
> +
> +static inline struct tegra_pcie *sys_to_pcie(struct pci_sys_data *sys)
> +{
> +       return sys->private_data;
> +}
> +
> +static inline void afi_writel(struct tegra_pcie *pcie, u32 value,
> +                             unsigned long offset)
> +{
> +       writel(value, pcie->afi + offset);
> +}
> +
> +static inline u32 afi_readl(struct tegra_pcie *pcie, unsigned long offset)
> +{
> +       return readl(pcie->afi + offset);
> +}
> +
> +static inline void pads_writel(struct tegra_pcie *pcie, u32 value,
> +                              unsigned long offset)
> +{
> +       writel(value, pcie->pads + offset);
> +}
> +
> +static inline u32 pads_readl(struct tegra_pcie *pcie, unsigned long offset)
> +{
> +       return readl(pcie->pads + offset);
> +}
> +
> +/*
> + * The configuration space mapping on Tegra is somewhat similar to the ECAM
> + * defined by PCIe. However it deviates a bit in how the 4 bits for extended
> + * register accesses are mapped:
> + *
> + *    [27:24] extended register number
> + *    [23:16] bus number
> + *    [15:11] device number
> + *    [10: 8] function number
> + *    [ 7: 0] register number
> + *
> + * Mapping the whole extended configuration space would require 256 MiB of
> + * virtual address space, only a small part of which will actually be used.
> + * To work around this, a 1 MiB of virtual addresses are allocated per bus
> + * when the bus is first accessed. When the physical range is mapped, the
> + * the bus number bits are hidden so that the extended register number bits
> + * appear as bits [19:16]. Therefore the virtual mapping looks like this:
> + *
> + *    [19:16] extended register number
> + *    [15:11] device number
> + *    [10: 8] function number
> + *    [ 7: 0] register number
> + *
> + * This is achieved by stitching together 16 chunks of 64 KiB of physical
> + * address space via the MMU.
> + */
> +static unsigned long tegra_pcie_conf_offset(unsigned int devfn, int where)
> +{
> +       return ((where & 0xf00) << 8) | (PCI_SLOT(devfn) << 11) |
> +              (PCI_FUNC(devfn) << 8) | (where & 0xfc);
> +}
> +
> +static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie,
> +                                                  unsigned int busnr)
> +{
> +       pgprot_t prot = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_XN |
> +                       L_PTE_MT_DEV_SHARED | L_PTE_SHARED;
> +       phys_addr_t cs = pcie->cs->start;
> +       struct tegra_pcie_bus *bus;
> +       unsigned int i;
> +       int err;
> +
> +       bus = kzalloc(sizeof(*bus), GFP_KERNEL);
> +       if (!bus)
> +               return ERR_PTR(-ENOMEM);
> +
> +       INIT_LIST_HEAD(&bus->list);
> +       bus->nr = busnr;
> +
> +       /* allocate 1 MiB of virtual addresses */
> +       bus->area = get_vm_area(SZ_1M, VM_IOREMAP);
> +       if (!bus->area) {
> +               err = -ENOMEM;
> +               goto free;
> +       }
> +
> +       /* map each of the 16 chunks of 64 KiB each */
> +       for (i = 0; i < 16; i++) {
> +               unsigned long virt = (unsigned long)bus->area->addr +
> +                                    i * SZ_64K;
> +               phys_addr_t phys = cs + i * SZ_1M + busnr * SZ_64K;
> +
> +               err = ioremap_page_range(virt, virt + SZ_64K, phys, prot);
> +               if (err < 0) {
> +                       dev_err(pcie->dev, "ioremap_page_range() failed: %d\n",
> +                               err);
> +                       goto unmap;
> +               }
> +       }
> +
> +       return bus;
> +
> +unmap:
> +       vunmap(bus->area->addr);
> +free:
> +       kfree(bus);
> +       return ERR_PTR(err);
> +}
> +
> +/*
> + * Look up a virtual address mapping for the specified bus number. If no such
> + * mapping existis, try to create one.
> + */
> +static void __iomem *tegra_pcie_bus_map(struct tegra_pcie *pcie,
> +                                       unsigned int busnr)
> +{
> +       struct tegra_pcie_bus *bus;
> +
> +       list_for_each_entry(bus, &pcie->busses, list)
> +               if (bus->nr == busnr)
> +                       return bus->area->addr;
> +
> +       bus = tegra_pcie_bus_alloc(pcie, busnr);
> +       if (IS_ERR(bus))
> +               return NULL;
> +
> +       list_add_tail(&bus->list, &pcie->busses);
> +
> +       return bus->area->addr;
> +}
> +
> +static void __iomem *tegra_pcie_conf_address(struct pci_bus *bus,
> +                                            unsigned int devfn,
> +                                            int where)
> +{
> +       struct tegra_pcie *pcie = sys_to_pcie(bus->sysdata);
> +       void __iomem *addr = NULL;
> +
> +       if (bus->number == 0) {
> +               unsigned int slot = PCI_SLOT(devfn);
> +               struct tegra_pcie_port *port;
> +
> +               list_for_each_entry(port, &pcie->ports, list) {
> +                       if (port->index + 1 == slot) {
> +                               addr = port->base + (where & ~3);
> +                               break;
> +                       }
> +               }
> +       } else {
> +               addr = tegra_pcie_bus_map(pcie, bus->number);
> +               if (!addr) {
> +                       dev_err(pcie->dev,
> +                               "failed to map cfg. space for bus %u\n",
> +                               bus->number);
> +                       return NULL;
> +               }
> +
> +               addr += tegra_pcie_conf_offset(devfn, where);
> +       }
> +
> +       return addr;
> +}
> +
> +static int tegra_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
> +                               int where, int size, u32 *value)
> +{
> +       void __iomem *addr;
> +
> +       addr = tegra_pcie_conf_address(bus, devfn, where);
> +       if (!addr) {
> +               *value = 0xffffffff;
> +               return PCIBIOS_DEVICE_NOT_FOUND;
> +       }
> +
> +       *value = readl(addr);
> +
> +       if (size == 1)
> +               *value = (*value >> (8 * (where & 3))) & 0xff;
> +       else if (size == 2)
> +               *value = (*value >> (8 * (where & 3))) & 0xffff;
> +
> +       return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static int tegra_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
> +                                int where, int size, u32 value)
> +{
> +       void __iomem *addr;
> +       u32 mask, tmp;
> +
> +       addr = tegra_pcie_conf_address(bus, devfn, where);
> +       if (!addr)
> +               return PCIBIOS_DEVICE_NOT_FOUND;
> +
> +       if (size == 4) {
> +               writel(value, addr);
> +               return PCIBIOS_SUCCESSFUL;
> +       }
> +
> +       if (size == 2)
> +               mask = ~(0xffff << ((where & 0x3) * 8));
> +       else if (size == 1)
> +               mask = ~(0xff << ((where & 0x3) * 8));
> +       else
> +               return PCIBIOS_BAD_REGISTER_NUMBER;
> +
> +       tmp = readl(addr) & mask;
> +       tmp |= value << ((where & 0x3) * 8);
> +       writel(tmp, addr);
> +
> +       return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static struct pci_ops tegra_pcie_ops = {
> +       .read = tegra_pcie_read_conf,
> +       .write = tegra_pcie_write_conf,
> +};
> +
> +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;
> +       }
> +
> +       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 signal */
> +       value = afi_readl(port->pcie, ctrl);
> +       value &= ~AFI_PEX_CTRL_RST;
> +       afi_writel(port->pcie, value, ctrl);
> +
> +       usleep_range(1000, 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)
> +{
> +       unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
> +       unsigned long value;
> +
> +       /* enable reference clock */
> +       value = afi_readl(port->pcie, ctrl);
> +       value |= AFI_PEX_CTRL_REFCLK_EN;
> +       afi_writel(port->pcie, value, ctrl);
> +
> +       tegra_pcie_port_reset(port);
> +}
> +
> +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)
> +{
> +       struct tegra_pcie *pcie = port->pcie;
> +
> +       devm_iounmap(pcie->dev, port->base);
> +       devm_release_mem_region(pcie->dev, port->regs.start,
> +                               resource_size(&port->regs));
> +       list_del(&port->list);
> +       devm_kfree(pcie->dev, port);
> +}
> +
> +static void tegra_pcie_fixup_bridge(struct pci_dev *dev)
> +{
> +       u16 reg;
> +
> +       if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) {
> +               pci_read_config_word(dev, PCI_COMMAND, &reg);
> +               reg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
> +                       PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
> +               pci_write_config_word(dev, PCI_COMMAND, reg);
> +       }
> +}
> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge);
> +
> +/* Tegra PCIE root complex wrongly reports device class */
> +static void tegra_pcie_fixup_class(struct pci_dev *dev)
> +{
> +       dev->class = PCI_CLASS_BRIDGE_PCI << 8;
> +}
> +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class);
> +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
> +
> +/* Tegra PCIE requires relaxed ordering */
> +static void tegra_pcie_relax_enable(struct pci_dev *dev)
> +{
> +       pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN);
> +}
> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
> +
> +static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
> +{
> +       struct tegra_pcie *pcie = sys_to_pcie(sys);
> +
> +       pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
> +       pci_add_resource_offset(&sys->resources, &pcie->prefetch,
> +                               sys->mem_offset);
> +       pci_add_resource(&sys->resources, &pcie->busn);
> +
> +       pci_ioremap_io(nr * SZ_64K, pcie->io.start);
> +
> +       return 1;
> +}
> +
> +static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
> +{
> +       struct tegra_pcie *pcie = sys_to_pcie(pdev->bus->sysdata);
> +
> +       return pcie->irq;
> +}
> +
> +static void tegra_pcie_add_bus(struct pci_bus *bus)
> +{
> +       if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +               struct tegra_pcie *pcie = sys_to_pcie(bus->sysdata);
> +
> +               bus->msi = &pcie->msi.chip;
> +       }
> +}
> +
> +static struct pci_bus *tegra_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> +{
> +       struct tegra_pcie *pcie = sys_to_pcie(sys);
> +       struct pci_bus *bus;
> +
> +       bus = pci_create_root_bus(pcie->dev, sys->busnr, &tegra_pcie_ops, sys,
> +                                 &sys->resources);
> +       if (!bus)
> +               return NULL;
> +
> +       pci_scan_child_bus(bus);
> +
> +       return bus;
> +}
> +
> +static irqreturn_t tegra_pcie_isr(int irq, void *arg)
> +{
> +       const char *err_msg[] = {
> +               "Unknown",
> +               "AXI slave error",
> +               "AXI decode error",
> +               "Target abort",
> +               "Master abort",
> +               "Invalid write",
> +               "Response decoding error",
> +               "AXI response decoding error",
> +               "Transaction timeout",
> +       };
> +       struct tegra_pcie *pcie = arg;
> +       u32 code, signature;
> +
> +       code = afi_readl(pcie, AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
> +       signature = afi_readl(pcie, AFI_INTR_SIGNATURE);
> +       afi_writel(pcie, 0, AFI_INTR_CODE);
> +
> +       if (code == AFI_INTR_LEGACY)
> +               return IRQ_NONE;
> +
> +       if (code >= ARRAY_SIZE(err_msg))
> +               code = 0;
> +
> +       /*
> +        * do not pollute kernel log with master abort reports since they
> +        * happen a lot during enumeration
> +        */
> +       if (code == AFI_INTR_MASTER_ABORT)
> +               dev_dbg(pcie->dev, "%s, signature: %08x\n", err_msg[code],
> +                       signature);
> +       else
> +               dev_err(pcie->dev, "%s, signature: %08x\n", err_msg[code],
> +                       signature);
> +
> +       if (code == AFI_INTR_TARGET_ABORT || code == AFI_INTR_MASTER_ABORT ||
> +           code == AFI_INTR_FPCI_DECODE_ERROR) {
> +               u32 fpci = afi_readl(pcie, AFI_UPPER_FPCI_ADDRESS) & 0xff;
> +               u64 address = (u64)fpci << 32 | (signature & 0xfffffffc);
> +
> +               if (code == AFI_INTR_MASTER_ABORT)
> +                       dev_dbg(pcie->dev, "  FPCI address: %10llx\n", address);
> +               else
> +                       dev_err(pcie->dev, "  FPCI address: %10llx\n", address);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
> +/*
> + * FPCI map is as follows:
> + * - 0xfdfc000000: I/O space
> + * - 0xfdfe000000: type 0 configuration space
> + * - 0xfdff000000: type 1 configuration space
> + * - 0xfe00000000: type 0 extended configuration space
> + * - 0xfe10000000: type 1 extended configuration space
> + */
> +static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
> +{
> +       u32 fpci_bar, size, axi_address;
> +
> +       /* Bar 0: type 1 extended configuration space */
> +       fpci_bar = 0xfe100000;
> +       size = resource_size(pcie->cs);
> +       axi_address = pcie->cs->start;
> +       afi_writel(pcie, axi_address, AFI_AXI_BAR0_START);
> +       afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ);
> +       afi_writel(pcie, fpci_bar, AFI_FPCI_BAR0);
> +
> +       /* Bar 1: downstream IO bar */
> +       fpci_bar = 0xfdfc0000;
> +       size = resource_size(&pcie->io);
> +       axi_address = pcie->io.start;
> +       afi_writel(pcie, axi_address, AFI_AXI_BAR1_START);
> +       afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
> +       afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1);
> +
> +       /* Bar 2: prefetchable memory BAR */
> +       fpci_bar = (((pcie->prefetch.start >> 12) & 0x0fffffff) << 4) | 0x1;
> +       size = resource_size(&pcie->prefetch);
> +       axi_address = pcie->prefetch.start;
> +       afi_writel(pcie, axi_address, AFI_AXI_BAR2_START);
> +       afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ);
> +       afi_writel(pcie, fpci_bar, AFI_FPCI_BAR2);
> +
> +       /* Bar 3: non prefetchable memory BAR */
> +       fpci_bar = (((pcie->mem.start >> 12) & 0x0fffffff) << 4) | 0x1;
> +       size = resource_size(&pcie->mem);
> +       axi_address = pcie->mem.start;
> +       afi_writel(pcie, axi_address, AFI_AXI_BAR3_START);
> +       afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ);
> +       afi_writel(pcie, fpci_bar, 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, PHYS_OFFSET, 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);
> +}
> +
> +static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
> +{
> +       struct tegra_pcie_port *port;
> +       unsigned int timeout;
> +       unsigned long value;
> +
> +       /* configure mode and disable all ports */
> +       value = afi_readl(pcie, AFI_PCIE_CONFIG);
> +       value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
> +       value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config;
> +
> +       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);
> +       value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
> +       afi_writel(pcie, value, AFI_FUSE);
> +
> +       /* initialze internal PHY, enable up to 16 PCIE lanes */
> +       pads_writel(pcie, 0x0, 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, PADS_PLL_CTL);
> +       value &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
> +       value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML |
> +                PADS_PLL_CTL_TXCLKREF_DIV10;
> +       pads_writel(pcie, value, PADS_PLL_CTL);
> +
> +       /* take PLL out of reset  */
> +       value = pads_readl(pcie, PADS_PLL_CTL);
> +       value |= PADS_PLL_CTL_RST_B4SM;
> +       pads_writel(pcie, value, PADS_PLL_CTL);
> +
> +       /*
> +        * Hack, set the clock voltage to the DEFAULT provided by hw folks.
> +        * This doesn't exist in the documentation.
> +        */
> +       pads_writel(pcie, 0xfa5cfa5c, 0xc8);
> +
> +       /* wait for the PLL to lock */
> +       timeout = 300;
> +       do {
> +               value = pads_readl(pcie, PADS_PLL_CTL);
> +               usleep_range(1000, 2000);
> +               if (--timeout == 0) {
> +                       pr_err("Tegra PCIe error: timeout waiting for PLL\n");
> +                       return -EBUSY;
> +               }
> +       } while (!(value & PADS_PLL_CTL_LOCKDET));
> +
> +       /* 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);
> +
> +       /* take the PCIe interface module out of reset */
> +       tegra_periph_reset_deassert(pcie->pcie_xclk);
> +
> +       /* finally enable PCIe */
> +       value = afi_readl(pcie, AFI_CONFIGURATION);
> +       value |= AFI_CONFIGURATION_EN_FPCI;
> +       afi_writel(pcie, value, AFI_CONFIGURATION);
> +
> +       value = AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
> +               AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR |
> +               AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR;
> +       afi_writel(pcie, value, AFI_AFI_INTR_ENABLE);
> +       afi_writel(pcie, 0xffffffff, AFI_SM_INTR_ENABLE);
> +
> +       /* don't enable MSI for now, only when needed */
> +       afi_writel(pcie, AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK);
> +
> +       /* disable all exceptions */
> +       afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS);
> +
> +       return 0;
> +}
> +
> +static void tegra_pcie_power_off(struct tegra_pcie *pcie)
> +{
> +       int err;
> +
> +       /* TODO: disable and unprepare clocks? */
> +
> +       tegra_periph_reset_assert(pcie->pcie_xclk);
> +       tegra_periph_reset_assert(pcie->afi_clk);
> +       tegra_periph_reset_assert(pcie->pex_clk);
> +
> +       tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
> +       tegra_pmc_pcie_xclk_clamp(true);
> +
> +       err = regulator_disable(pcie->pex_clk_supply);
> +       if (err < 0)
> +               dev_err(pcie->dev, "failed to disable pex-clk regulator: %d\n",
> +                       err);
> +
> +       err = regulator_disable(pcie->vdd_supply);
> +       if (err < 0)
> +               dev_err(pcie->dev, "failed to disable VDD regulator: %d\n",
> +                       err);
> +}
> +
> +static int tegra_pcie_power_on(struct tegra_pcie *pcie)
> +{
> +       int err;
> +
> +       tegra_periph_reset_assert(pcie->pcie_xclk);
> +       tegra_periph_reset_assert(pcie->afi_clk);
> +       tegra_periph_reset_assert(pcie->pex_clk);
> +
> +       tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
> +       tegra_pmc_pcie_xclk_clamp(true);
> +
> +       /* enable regulators */
> +       err = regulator_enable(pcie->vdd_supply);
> +       if (err < 0) {
> +               dev_err(pcie->dev, "failed to enable VDD regulator: %d\n", err);
> +               return err;
> +       }
> +
> +       err = regulator_enable(pcie->pex_clk_supply);
> +       if (err < 0) {
> +               dev_err(pcie->dev, "failed to enable pex-clk regulator: %d\n",
> +                       err);
> +               return err;
> +       }
> +
> +       err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
> +                                               pcie->pex_clk);
> +       if (err) {
> +               dev_err(pcie->dev, "powerup sequence failed: %d\n", err);
> +               return err;
> +       }
> +
> +       tegra_periph_reset_deassert(pcie->afi_clk);
> +
> +       tegra_pmc_pcie_xclk_clamp(false);
> +
> +       err = clk_prepare_enable(pcie->afi_clk);
> +       if (err < 0) {
> +               dev_err(pcie->dev, "failed to enable AFI clock: %d\n", err);
> +               return err;
> +       }
> +
> +       err = clk_prepare_enable(pcie->pll_e);
> +       if (err < 0) {
> +               dev_err(pcie->dev, "failed to enable PLLE clock: %d\n", err);
> +               return err;
> +       }
> +
> +       return 0;
> +}
> +
> +static int tegra_pcie_clocks_get(struct tegra_pcie *pcie)
> +{
> +       pcie->pex_clk = devm_clk_get(pcie->dev, "pex");
> +       if (IS_ERR(pcie->pex_clk))
> +               return PTR_ERR(pcie->pex_clk);
> +
> +       pcie->afi_clk = devm_clk_get(pcie->dev, "afi");
> +       if (IS_ERR(pcie->afi_clk))
> +               return PTR_ERR(pcie->afi_clk);
> +
> +       pcie->pcie_xclk = devm_clk_get(pcie->dev, "pcie_xclk");
> +       if (IS_ERR(pcie->pcie_xclk))
> +               return PTR_ERR(pcie->pcie_xclk);
> +
> +       pcie->pll_e = devm_clk_get(pcie->dev, "pll_e");
> +       if (IS_ERR(pcie->pll_e))
> +               return PTR_ERR(pcie->pll_e);
> +
> +       return 0;
> +}
> +
> +static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
> +{
> +       struct platform_device *pdev = to_platform_device(pcie->dev);
> +       struct resource *pads, *afi, *res;
> +       int err;
> +
> +       err = tegra_pcie_clocks_get(pcie);
> +       if (err) {
> +               dev_err(&pdev->dev, "failed to get clocks: %d\n", err);
> +               return err;
> +       }
> +
> +       err = tegra_pcie_power_on(pcie);
> +       if (err) {
> +               dev_err(&pdev->dev, "failed to power up: %d\n", err);
> +               return err;
> +       }
> +
> +       /* request and remap controller registers */
> +       pads = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pads");
> +       if (!pads) {
> +               err = -EADDRNOTAVAIL;
> +               goto poweroff;
> +       }
> +
> +       afi = platform_get_resource_byname(pdev, IORESOURCE_MEM, "afi");
> +       if (!afi) {
> +               err = -EADDRNOTAVAIL;
> +               goto poweroff;
> +       }
> +
> +       pcie->pads = devm_request_and_ioremap(&pdev->dev, pads);
> +       if (!pcie->pads) {
> +               err = -EADDRNOTAVAIL;
> +               goto poweroff;
> +       }
> +
> +       pcie->afi = devm_request_and_ioremap(&pdev->dev, afi);
> +       if (!pcie->afi) {
> +               err = -EADDRNOTAVAIL;
> +               goto poweroff;
> +       }
> +
> +       /* request and remap configuration space */
> +       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs");
> +       if (!res) {
> +               err = -EADDRNOTAVAIL;
> +               goto poweroff;
> +       }
> +
> +       pcie->cs = devm_request_mem_region(pcie->dev, res->start,
> +                                          resource_size(res), res->name);
> +       if (!pcie->cs) {
> +               err = -EADDRNOTAVAIL;
> +               goto poweroff;
> +       }
> +
> +       /* request interrupt */
> +       err = platform_get_irq_byname(pdev, "intr");
> +       if (err < 0) {
> +               dev_err(&pdev->dev, "failed to get IRQ: %d\n", err);
> +               goto poweroff;
> +       }
> +
> +       pcie->irq = err;
> +
> +       err = request_irq(pcie->irq, tegra_pcie_isr, IRQF_SHARED, "PCIE", pcie);
> +       if (err) {
> +               dev_err(&pdev->dev, "failed to register IRQ: %d\n", err);
> +               goto poweroff;
> +       }
> +
> +       return 0;
> +
> +poweroff:
> +       tegra_pcie_power_off(pcie);
> +       return err;
> +}
> +
> +static int tegra_pcie_put_resources(struct tegra_pcie *pcie)
> +{
> +       if (pcie->irq > 0)
> +               free_irq(pcie->irq, pcie);
> +
> +       tegra_pcie_power_off(pcie);
> +       return 0;
> +}
> +
> +static int tegra_msi_alloc(struct tegra_msi *chip)
> +{
> +       int msi;
> +
> +       mutex_lock(&chip->lock);
> +
> +       msi = find_first_zero_bit(chip->used, INT_PCI_MSI_NR);
> +       if (msi < INT_PCI_MSI_NR)
> +               set_bit(msi, chip->used);
> +       else
> +               msi = -ENOSPC;
> +
> +       mutex_unlock(&chip->lock);
> +
> +       return msi;
> +}
> +
> +static void tegra_msi_free(struct tegra_msi *chip, unsigned long irq)
> +{
> +       struct device *dev = chip->chip.dev;
> +
> +       mutex_lock(&chip->lock);
> +
> +       if (!test_bit(irq, chip->used))
> +               dev_err(dev, "trying to free unused MSI#%lu\n", irq);
> +       else
> +               clear_bit(irq, chip->used);
> +
> +       mutex_unlock(&chip->lock);
> +}
> +
> +static irqreturn_t tegra_pcie_msi_irq(int irq, void *data)
> +{
> +       struct tegra_pcie *pcie = data;
> +       struct tegra_msi *msi = &pcie->msi;
> +       unsigned int i, processed = 0;
> +
> +       for (i = 0; i < 8; i++) {
> +               unsigned long reg = afi_readl(pcie, AFI_MSI_VEC0 + i * 4);
> +
> +               while (reg) {
> +                       unsigned int offset = find_first_bit(&reg, 32);
> +                       unsigned int index = i * 32 + offset;
> +                       unsigned int irq;
> +
> +                       /* clear the interrupt */
> +                       afi_writel(pcie, 1 << offset, AFI_MSI_VEC0 + i * 4);
> +
> +                       irq = irq_find_mapping(msi->domain, index);
> +                       if (irq) {
> +                               if (test_bit(index, msi->used))
> +                                       generic_handle_irq(irq);
> +                               else
> +                                       dev_info(pcie->dev, "unhandled MSI\n");
> +                       } else {
> +                               /*
> +                                * that's weird who triggered this?
> +                                * just clear it
> +                                */
> +                               dev_info(pcie->dev, "unexpected MSI\n");
> +                       }
> +
> +                       /* see if there's any more pending in this vector */
> +                       reg = afi_readl(pcie, AFI_MSI_VEC0 + i * 4);
> +
> +                       processed++;
> +               }
> +       }
> +
> +       return processed > 0 ? IRQ_HANDLED : IRQ_NONE;
> +}
> +
> +static int tegra_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
> +                              struct msi_desc *desc)
> +{
> +       struct tegra_msi *msi = to_tegra_msi(chip);
> +       struct msi_msg msg;
> +       unsigned int irq;
> +       int hwirq;
> +
> +       hwirq = tegra_msi_alloc(msi);
> +       if (hwirq < 0)
> +               return hwirq;
> +
> +       irq = irq_create_mapping(msi->domain, hwirq);
> +       if (!irq)
> +               return -EINVAL;
> +
> +       irq_set_msi_desc(irq, desc);
> +
> +       msg.address_lo = virt_to_phys((void *)msi->pages);
> +       /* 32 bit address only */
> +       msg.address_hi = 0;
> +       msg.data = hwirq;
> +
> +       write_msi_msg(irq, &msg);
> +
> +       return 0;
> +}
> +
> +static void tegra_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
> +{
> +       struct tegra_msi *msi = to_tegra_msi(chip);
> +       struct irq_data *d = irq_get_irq_data(irq);
> +
> +       tegra_msi_free(msi, d->hwirq);
> +}
> +
> +static struct irq_chip tegra_msi_irq_chip = {
> +       .name = "Tegra PCIe MSI",
> +       .irq_enable = unmask_msi_irq,
> +       .irq_disable = mask_msi_irq,
> +       .irq_mask = mask_msi_irq,
> +       .irq_unmask = unmask_msi_irq,
> +};
> +
> +static int tegra_msi_map(struct irq_domain *domain, unsigned int irq,
> +                        irq_hw_number_t hwirq)
> +{
> +       irq_set_chip_and_handler(irq, &tegra_msi_irq_chip, handle_simple_irq);
> +       irq_set_chip_data(irq, domain->host_data);
> +       set_irq_flags(irq, IRQF_VALID);
> +
> +       return 0;
> +}
> +
> +static const struct irq_domain_ops msi_domain_ops = {
> +       .map = tegra_msi_map,
> +};
> +
> +static int tegra_pcie_enable_msi(struct tegra_pcie *pcie)
> +{
> +       struct platform_device *pdev = to_platform_device(pcie->dev);
> +       struct tegra_msi *msi = &pcie->msi;
> +       unsigned long base;
> +       int err;
> +       u32 reg;
> +
> +       mutex_init(&msi->lock);
> +
> +       msi->chip.dev = pcie->dev;
> +       msi->chip.setup_irq = tegra_msi_setup_irq;
> +       msi->chip.teardown_irq = tegra_msi_teardown_irq;
> +
> +       msi->domain = irq_domain_add_linear(pcie->dev->of_node, INT_PCI_MSI_NR,
> +                                           &msi_domain_ops, &msi->chip);
> +       if (!msi->domain) {
> +               dev_err(&pdev->dev, "failed to create IRQ domain\n");
> +               return -ENOMEM;
> +       }
> +
> +       err = platform_get_irq_byname(pdev, "msi");
> +       if (err < 0) {
> +               dev_err(&pdev->dev, "failed to get IRQ: %d\n", err);
> +               goto err;
> +       }
> +
> +       msi->irq = err;
> +
> +       err = request_irq(msi->irq, tegra_pcie_msi_irq, 0,
> +                         tegra_msi_irq_chip.name, pcie);
> +       if (err < 0) {
> +               dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
> +               goto err;
> +       }
> +
> +       /* setup AFI/FPCI range */
> +       msi->pages = __get_free_pages(GFP_KERNEL, 0);
> +       base = virt_to_phys((void *)msi->pages);
> +
> +       afi_writel(pcie, base, AFI_MSI_FPCI_BAR_ST);
> +       afi_writel(pcie, base, AFI_MSI_AXI_BAR_ST);
> +       /* this register is in 4K increments */
> +       afi_writel(pcie, 1, AFI_MSI_BAR_SZ);
> +
> +       /* enable all MSI vectors */
> +       afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC0);
> +       afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC1);
> +       afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC2);
> +       afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC3);
> +       afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC4);
> +       afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC5);
> +       afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC6);
> +       afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC7);
> +
> +       /* and unmask the MSI interrupt */
> +       reg = afi_readl(pcie, AFI_INTR_MASK);
> +       reg |= AFI_INTR_MASK_MSI_MASK;
> +       afi_writel(pcie, reg, AFI_INTR_MASK);
> +
> +       return 0;
> +
> +err:
> +       irq_domain_remove(msi->domain);
> +       return err;
> +}
> +
> +static int tegra_pcie_disable_msi(struct tegra_pcie *pcie)
> +{
> +       struct tegra_msi *msi = &pcie->msi;
> +       unsigned int i, irq;
> +       u32 value;
> +
> +       /* mask the MSI interrupt */
> +       value = afi_readl(pcie, AFI_INTR_MASK);
> +       value &= ~AFI_INTR_MASK_MSI_MASK;
> +       afi_writel(pcie, value, AFI_INTR_MASK);
> +
> +       /* disable all MSI vectors */
> +       afi_writel(pcie, 0, AFI_MSI_EN_VEC0);
> +       afi_writel(pcie, 0, AFI_MSI_EN_VEC1);
> +       afi_writel(pcie, 0, AFI_MSI_EN_VEC2);
> +       afi_writel(pcie, 0, AFI_MSI_EN_VEC3);
> +       afi_writel(pcie, 0, AFI_MSI_EN_VEC4);
> +       afi_writel(pcie, 0, AFI_MSI_EN_VEC5);
> +       afi_writel(pcie, 0, AFI_MSI_EN_VEC6);
> +       afi_writel(pcie, 0, AFI_MSI_EN_VEC7);
> +
> +       free_pages(msi->pages, 0);
> +
> +       if (msi->irq > 0)
> +               free_irq(msi->irq, pcie);
> +
> +       for (i = 0; i < INT_PCI_MSI_NR; i++) {
> +               irq = irq_find_mapping(msi->domain, i);
> +               if (irq > 0)
> +                       irq_dispose_mapping(irq);
> +       }
> +
> +       irq_domain_remove(msi->domain);
> +
> +       return 0;
> +}
> +
> +static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
> +                                     u32 *xbar)
> +{
> +       struct device_node *np = pcie->dev->of_node;
> +
> +       switch (lanes) {
> +       case 0x00000004:
> +               dev_info(pcie->dev, "single-mode configuration\n");
> +               *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE;
> +               return 0;
> +
> +       case 0x00000202:
> +               dev_info(pcie->dev, "dual-mode configuration\n");
> +               *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
> +               return 0;
> +       }
> +
> +       return -EINVAL;
> +}
> +
> +static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
> +{
> +       struct device_node *np = pcie->dev->of_node, *port;
> +       struct of_pci_range_parser parser;
> +       struct of_pci_range range;
> +       struct resource res;
> +       u32 lanes = 0;
> +       int err;
> +
> +       if (of_pci_range_parser_init(&parser, np)) {
> +               dev_err(pcie->dev, "missing \"ranges\" property\n");
> +               return -EINVAL;
> +       }
> +
> +       pcie->vdd_supply = devm_regulator_get(pcie->dev, "vdd");
> +       if (IS_ERR(pcie->vdd_supply))
> +               return PTR_ERR(pcie->vdd_supply);
> +
> +       pcie->pex_clk_supply = devm_regulator_get(pcie->dev, "pex-clk");
> +       if (IS_ERR(pcie->pex_clk_supply))
> +               return PTR_ERR(pcie->pex_clk_supply);
> +
> +       for_each_of_pci_range(&parser, &range) {
> +               of_pci_range_to_resource(&range, np, &res);
> +
> +               switch (res.flags & IORESOURCE_TYPE_BITS) {
> +               case IORESOURCE_IO:
> +                       memcpy(&pcie->io, &res, sizeof(res));
> +                       pcie->io.name = "I/O";
> +                       break;
> +
> +               case IORESOURCE_MEM:
> +                       if (res.flags & IORESOURCE_PREFETCH) {
> +                               memcpy(&pcie->prefetch, &res, sizeof(res));
> +                               pcie->prefetch.name = "PREFETCH";
> +                       } else {
> +                               memcpy(&pcie->mem, &res, sizeof(res));
> +                               pcie->mem.name = "MEM";
> +                       }
> +                       break;
> +               }
> +       }
> +
> +       err = of_pci_parse_bus_range(np, &pcie->busn);
> +       if (err < 0) {
> +               dev_err(pcie->dev, "failed to parse ranges property: %d\n",
> +                       err);
> +               pcie->busn.name = np->name;
> +               pcie->busn.start = 0;
> +               pcie->busn.end = 0xff;
> +               pcie->busn.flags = IORESOURCE_BUS;
> +       }
> +
> +       /* parse root ports */
> +       for_each_child_of_node(np, port) {
> +               struct tegra_pcie_port *rp;
> +               unsigned int index;
> +               u32 value;
> +
> +               err = of_pci_get_devfn(port);
> +               if (err < 0) {
> +                       dev_err(pcie->dev, "failed to parse address: %d\n",
> +                               err);
> +                       return err;
> +               }
> +
> +               index = PCI_SLOT(err);
> +
> +               if (index < 1 || index > TEGRA_MAX_PORTS) {
> +                       dev_err(pcie->dev, "invalid port number: %d\n", index);
> +                       return -EINVAL;
> +               }
> +
> +               index--;
> +
> +               err = of_property_read_u32(port, "nvidia,num-lanes", &value);
> +               if (err < 0) {
> +                       dev_err(pcie->dev, "failed to parse # of lanes: %d\n",
> +                               err);
> +                       return err;
> +               }
> +
> +               if (value > 16) {
> +                       dev_err(pcie->dev, "invalid # of lanes: %u\n", value);
> +                       return -EINVAL;
> +               }
> +
> +               lanes |= value << (index << 3);
> +
> +               if (!of_device_is_available(port))
> +                       continue;
> +
> +               rp = devm_kzalloc(pcie->dev, sizeof(*rp), GFP_KERNEL);
> +               if (!rp)
> +                       return -ENOMEM;
> +
> +               err = of_address_to_resource(port, 0, &rp->regs);
> +               if (err < 0) {
> +                       dev_err(pcie->dev, "failed to parse address: %d\n",
> +                               err);
> +                       return err;
> +               }
> +
> +               INIT_LIST_HEAD(&rp->list);
> +               rp->index = index;
> +               rp->lanes = value;
> +               rp->pcie = pcie;
> +
> +               rp->base = devm_request_and_ioremap(pcie->dev, &rp->regs);
> +               if (!rp->base)
> +                       return -EADDRNOTAVAIL;
> +
> +               list_add_tail(&rp->list, &pcie->ports);
> +       }
> +
> +       err = tegra_pcie_get_xbar_config(pcie, lanes, &pcie->xbar_config);
> +       if (err < 0) {
> +               dev_err(pcie->dev, "invalid lane configuration\n");
> +               return err;
> +       }
> +
> +       return 0;
> +}
> +
> +/*
> + * FIXME: If there are no PCIe cards attached, then calling this function
> + * can result in the increase of the bootup time as there are big timeout
> + * loops.
> + */
> +#define TEGRA_PCIE_LINKUP_TIMEOUT      200     /* up to 1.2 seconds */
> +static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
> +{
> +       unsigned int retries = 3;
> +       unsigned long value;
> +
> +       do {
> +               unsigned int timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
> +
> +               do {
> +                       value = readl(port->base + RP_VEND_XP);
> +
> +                       if (value & RP_VEND_XP_DL_UP)
> +                               break;
> +
> +                       usleep_range(1000, 2000);
> +               } while (--timeout);
> +
> +               if (!timeout) {
> +                       dev_err(port->pcie->dev, "link %u down, retrying\n",
> +                               port->index);
> +                       goto retry;
> +               }
> +
> +               timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
> +
> +               do {
> +                       value = readl(port->base + RP_LINK_CONTROL_STATUS);
> +
> +                       if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
> +                               return true;
> +
> +                       usleep_range(1000, 2000);
> +               } while (--timeout);
> +
> +retry:
> +               tegra_pcie_port_reset(port);
> +       } while (--retries);
> +
> +       return false;
> +}
> +
> +static int tegra_pcie_enable(struct tegra_pcie *pcie)
> +{
> +       struct tegra_pcie_port *port, *tmp;
> +       struct hw_pci hw;
> +
> +       list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
> +               dev_info(pcie->dev, "probing port %u, using %u lanes\n",
> +                        port->index, port->lanes);
> +
> +               tegra_pcie_port_enable(port);
> +
> +               if (tegra_pcie_port_check_link(port))
> +                       continue;
> +
> +               dev_info(pcie->dev, "link %u down, ignoring\n", port->index);
> +
> +               tegra_pcie_port_disable(port);
> +               tegra_pcie_port_free(port);
> +       }
> +
> +       memset(&hw, 0, sizeof(hw));
> +
> +       hw.nr_controllers = 1;
> +       hw.private_data = (void **)&pcie;
> +       hw.setup = tegra_pcie_setup;
> +       hw.map_irq = tegra_pcie_map_irq;
> +       hw.add_bus = tegra_pcie_add_bus;
> +       hw.scan = tegra_pcie_scan_bus;
> +       hw.ops = &tegra_pcie_ops;
> +
> +       pci_common_init_dev(pcie->dev, &hw);
> +
> +       return 0;
> +}
> +
> +static int tegra_pcie_probe(struct platform_device *pdev)
> +{
> +       struct tegra_pcie *pcie;
> +       int err;
> +
> +       pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
> +       if (!pcie)
> +               return -ENOMEM;
> +
> +       INIT_LIST_HEAD(&pcie->busses);
> +       INIT_LIST_HEAD(&pcie->ports);
> +       pcie->dev = &pdev->dev;
> +
> +       err = tegra_pcie_parse_dt(pcie);
> +       if (err < 0)
> +               return err;
> +
> +       pcibios_min_mem = 0;
> +
> +       err = tegra_pcie_get_resources(pcie);
> +       if (err < 0) {
> +               dev_err(&pdev->dev, "failed to request resources: %d\n", err);
> +               return err;
> +       }
> +
> +       err = tegra_pcie_enable_controller(pcie);
> +       if (err)
> +               goto put_resources;
> +
> +       /* setup the AFI address translations */
> +       tegra_pcie_setup_translations(pcie);
> +
> +       if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +               err = tegra_pcie_enable_msi(pcie);
> +               if (err < 0) {
> +                       dev_err(&pdev->dev,
> +                               "failed to enable MSI support: %d\n",
> +                               err);
> +                       goto put_resources;
> +               }
> +       }
> +
> +       err = tegra_pcie_enable(pcie);
> +       if (err < 0) {
> +               dev_err(&pdev->dev, "failed to enable PCIe ports: %d\n", err);
> +               goto disable_msi;
> +       }
> +
> +       platform_set_drvdata(pdev, pcie);
> +       return 0;
> +
> +disable_msi:
> +       if (IS_ENABLED(CONFIG_PCI_MSI))
> +               tegra_pcie_disable_msi(pcie);
> +put_resources:
> +       tegra_pcie_put_resources(pcie);
> +       return err;
> +}
> +
> +static const struct of_device_id tegra_pcie_of_match[] = {
> +       { .compatible = "nvidia,tegra20-pcie", },
> +       { },
> +};
> +MODULE_DEVICE_TABLE(of, tegra_pcie_of_match);
> +
> +static struct platform_driver tegra_pcie_driver = {
> +       .driver = {
> +               .name = "tegra-pcie",
> +               .owner = THIS_MODULE,
> +               .of_match_table = tegra_pcie_of_match,
> +               .suppress_bind_attrs = true,
> +       },
> +       .probe = tegra_pcie_probe,
> +};
> +module_platform_driver(tegra_pcie_driver);
> +
> +MODULE_AUTHOR("Thierry Reding <treding@...dia.com>");
> +MODULE_DESCRIPTION("NVIDIA Tegra PCIe driver");
> +MODULE_LICENSE("GPLv2");
> --
> 1.8.1.5
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ