summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/pcie.c
diff options
context:
space:
mode:
authorJay Agarwal <jagarwal@nvidia.com>2011-12-05 14:13:01 +0530
committerVarun Wadekar <vwadekar@nvidia.com>2011-12-15 12:01:01 +0530
commite42fcdf86f423a0f8665ee4b2cdf40438ecd336c (patch)
tree27726e1c1a07aed0eed5c801e2b857369c372b9e /arch/arm/mach-tegra/pcie.c
parent0eaaee6304efd3281743d6db279fc8f9f39ee50f (diff)
arm: tegra: pcie: Adding tegra3 support for pcie
Added support for tegra3 to pcie driver Fixes bug: 637871 Reviewed-on: http://git-master/r/44989 (cherry picked from commit 9bbfb4189474ede7f16a20b564ac7da2a93f6750) Change-Id: Ic0bb5b8d3098030baee5d8db6ca043df71db5a8e Signed-off-by: Krishna Kishore <kthota@nvidia.com> Reviewed-on: http://git-master/r/62059 Reviewed-by: Lokesh Pathak <lpathak@nvidia.com> Tested-by: Lokesh Pathak <lpathak@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/pcie.c')
-rw-r--r--arch/arm/mach-tegra/pcie.c718
1 files changed, 515 insertions, 203 deletions
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index 6665a3d8ed34..7cab1f1ca067 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -1,13 +1,13 @@
/*
- * arch/arm/mach-tegra/pci.c
+ * arch/arm/mach-tegra/pcie.c
*
- * PCIe host controller driver for TEGRA(2) SOCs
+ * PCIe host controller driver for TEGRA SOCs
*
* Copyright (c) 2010, CompuLab, Ltd.
* Author: Mike Rapoport <mike@compulab.co.il>
*
* Based on NVIDIA PCIe driver
- * Copyright (c) 2008-2009, NVIDIA Corporation.
+ * Copyright (c) 2008-2011, NVIDIA Corporation.
*
* Bits taken from arch/arm/mach-dove/pcie.c
*
@@ -32,6 +32,9 @@
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/msi.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <asm/sizes.h>
#include <asm/mach/pci.h>
@@ -40,120 +43,172 @@
#include <mach/iomap.h>
#include <mach/clk.h>
#include <mach/powergate.h>
+#include <mach/pci.h>
-/* 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)
+#define MSELECT_CONFIG_0_ENABLE_PCIE_APERTURE 5
-/* PMC access is required for PCIE xclk (un)clamping */
-#define PMC_SCRATCH42 0x144
-#define PMC_SCRATCH42_PCX_CLAMP (1 << 0)
+#define PINMUX_AUX_PEX_L0_RST_N_0 0x33bc
+#define PINMUX_AUX_PEX_L0_RST_N_0_E_INPUT 5
+#define PINMUX_AUX_PEX_L0_RST_N_0_E_INPUT_ENABLE 1
-static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+#define PINMUX_AUX_PEX_L1_RST_N_0 0x33cc
+#define PINMUX_AUX_PEX_L1_RST_N_0_E_INPUT 5
+#define PINMUX_AUX_PEX_L1_RST_N_0_E_INPUT_ENABLE 1
-#define pmc_writel(value, reg) \
- __raw_writel(value, (u32)reg_pmc_base + (reg))
-#define pmc_readl(reg) \
- __raw_readl((u32)reg_pmc_base + (reg))
+#define PINMUX_AUX_PEX_L2_RST_N_0 0x33d8
+#define PINMUX_AUX_PEX_L2_RST_N_0_E_INPUT 5
+#define PINMUX_AUX_PEX_L2_RST_N_0_E_INPUT_ENABLE 1
+#define AFI_PEX0_CTRL_0_PEX0_CLKREQ_EN 1
+#define NV_PCIE2_PADS_REFCLK_CFG1 0x000000cc
+#define APBDEV_PMC_SCRATCH42_0_PCX_CLAMP_MASK 0x1
+
+
+#define AFI_MSI_VEC0_0 0x6c
+#define AFI_MSI_VEC1_0 0x70
+#define AFI_MSI_VEC2_0 0x74
+#define AFI_MSI_VEC3_0 0x78
+#define AFI_MSI_VEC4_0 0x7c
+#define AFI_MSI_VEC5_0 0x80
+#define AFI_MSI_VEC6_0 0x84
+#define AFI_MSI_VEC7_0 0x88
+
+#define AFI_MSI_EN_VEC0_0 0x8c
+#define AFI_MSI_EN_VEC1_0 0x90
+#define AFI_MSI_EN_VEC2_0 0x94
+#define AFI_MSI_EN_VEC3_0 0x98
+#define AFI_MSI_EN_VEC4_0 0x9c
+#define AFI_MSI_EN_VEC5_0 0xa0
+#define AFI_MSI_EN_VEC6_0 0xa4
+#define AFI_MSI_EN_VEC7_0 0xa8
+
+#define AFI_MSI_FPCI_BAR_ST_0 0x64
+#define AFI_MSI_BAR_SZ_0 0x60
+#define AFI_MSI_AXI_BAR_ST_0 0x68
+#define AFI_INTR_MASK_0 0xb4
+#define AFI_INTR_MASK_0_INT_MASK 0
+#define AFI_INTR_MASK_0_MSI_MASK 8
+
+
+#define AFI_PEXBIAS_CTRL_0 0x168
+
+
+/* register definitions */
+#define AFI_OFFSET 0x3800
+#define PADS_OFFSET 0x3000
+#define RP0_OFFSET 0x0000
+#define RP1_OFFSET 0x1000
+#define RP2_OFFSET 0x4000
+
+#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_INTR_EN_PRSNT_SENSE (1 << 8)
+
+#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_PCIEC2_DISABLE_DEVICE (1 << 3)
+#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_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20)
+
+#define AFI_FUSE 0x104
+#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2)
+
+#define AFI_PEX0_CTRL 0x110
+#define AFI_PEX1_CTRL 0x118
+#define AFI_PEX2_CTRL 0x128
+#define AFI_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)
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+#define PADS_PLL_CTL 0x000000B8
+#else
+#define PADS_PLL_CTL 0x000000B4
+#endif
+#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_BUF_EN (1 << 22)
+#define PADS_PLL_CTL_TXCLKREF_DIV10 (0 << 20)
+#define PADS_PLL_CTL_TXCLKREF_DIV5 (1 << 20)
+
+/* PMC access is required for PCIE xclk (un)clamping */
+#define PMC_SCRATCH42 0x144
+#define PMC_SCRATCH42_PCX_CLAMP (1 << 0)
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
/*
* Tegra2 defines 1GB in the AXI address map for PCIe.
*
@@ -184,14 +239,61 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
#define MEM_SIZE_0 SZ_128M
#define MEM_BASE_1 (MEM_BASE_0 + MEM_SIZE_0)
#define MEM_SIZE_1 SZ_128M
+#define MEM_SIZE (MEM_SIZE_0 + MEM_SIZE_1)
#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 PREFETCH_MEM_SIZE (PREFETCH_MEM_SIZE_0 + PREFETCH_MEM_SIZE_1)
+
+#else
-#define PCIE_CONF_BUS(b) ((b) << 16)
-#define PCIE_CONF_DEV(d) ((d) << 11)
-#define PCIE_CONF_FUNC(f) ((f) << 8)
+/*
+ * AXI address map for the PCIe aperture , defines 1GB in the AXI
+ * address map for PCIe.
+ *
+ * That address space is split into different regions, with sizes and
+ * offsets as follows. Exepct for the Register space, SW is free to slice the
+ * regions as it chooces.
+ *
+ * The split below seems to work fine for now.
+ *
+ * 0x0000_0000 to 0x00ff_ffff - Register space 16MB.
+ * 0x0100_0000 to 0x01ff_ffff - Config space 16MB.
+ * 0x0200_0000 to 0x02ff_ffff - Extended config space 16MB.
+ * 0x0300_0000 to 0x03ff_ffff - Downstream IO space
+ * ... Will be filled with other BARS like MSI/upstream IO etc.
+ * 0x1000_0000 to 0x1fff_ffff - non-prefetchable memory aperture
+ * 0x2000_0000 to 0x3fff_ffff - Prefetchable memory aperture
+ *
+ * Config and Extended config sizes are choosen to support
+ * maximum of 256 devices,
+ * which is good enough for all the current use cases.
+ *
+ */
+#define TEGRA_PCIE_BASE 0x00000000
+
+#define PCIE_REGS_SZ SZ_16M
+#define PCIE_CFG_OFF PCIE_REGS_SZ
+#define PCIE_CFG_SZ SZ_16M
+#define PCIE_EXT_CFG_OFF (PCIE_CFG_SZ + PCIE_CFG_OFF)
+#define PCIE_EXT_CFG_SZ SZ_16M
+/* During the boot only registers/config and extended config apertures are
+ * mapped. Rest are mapped on demand by the PCI device drivers.
+ */
+#define PCIE_IOMAP_SZ (PCIE_REGS_SZ + PCIE_CFG_SZ + PCIE_EXT_CFG_SZ)
+
+#define MMIO_BASE (TEGRA_PCIE_BASE + SZ_48M)
+#define MMIO_SIZE SZ_1M
+#define MEM_BASE_0 (TEGRA_PCIE_BASE + SZ_256M)
+#define MEM_SIZE SZ_256M
+#define PREFETCH_MEM_BASE_0 (MEM_BASE_0 + MEM_SIZE)
+#define PREFETCH_MEM_SIZE SZ_512M
+#endif
+
+#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))
@@ -212,15 +314,28 @@ struct tegra_pcie_info {
struct tegra_pcie_port port[2];
int num_ports;
+ void __iomem *reg_clk_base;
void __iomem *regs;
struct resource res_mmio;
+ int power_rails_enabled;
- struct clk *pex_clk;
- struct clk *afi_clk;
+ struct regulator *regulator_hvdd;
+ struct regulator *regulator_pexio;
+ struct regulator *regulator_avdd_plle;
struct clk *pcie_xclk;
struct clk *pll_e;
+ struct clk *clk_cml0;
+ struct clk *clk_tera_pcie_cml;
+ struct tegra_pci_platform_data *plat_data;
};
+#define pmc_writel(value, reg) \
+ __raw_writel(value, (u32)reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+ __raw_readl((u32)reg_pmc_base + (reg))
+
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
static struct tegra_pcie_info tegra_pcie = {
.res_mmio = {
.name = "PCI IO",
@@ -304,6 +419,19 @@ static int tegra_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
u32 mask;
u32 tmp;
+ /* pcie core is supposed to enable bus mastering and io/mem responses
+ * if its not setting then enable corresponding bits in pci_command
+ */
+ if (where == PCI_COMMAND) {
+ if (!(val & PCI_COMMAND_IO))
+ val |= PCI_COMMAND_IO;
+ if (!(val & PCI_COMMAND_MEMORY))
+ val |= PCI_COMMAND_MEMORY;
+ if (!(val & PCI_COMMAND_MASTER))
+ val |= PCI_COMMAND_MASTER;
+ if (!(val & PCI_COMMAND_SERR))
+ val |= PCI_COMMAND_SERR;
+ }
if (pp) {
if (devfn != 0)
@@ -359,8 +487,14 @@ static void __devinit tegra_pcie_fixup_class(struct pci_dev *dev)
{
dev->class = PCI_CLASS_BRIDGE_PCI << 8;
}
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
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);
+#else
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_fixup_class);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_fixup_class);
+#endif
/* Tegra PCIE requires relaxed ordering */
static void __devinit tegra_pcie_relax_enable(struct pci_dev *dev)
@@ -415,13 +549,8 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
"PCIe %d MEM", pp->index);
pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
pp->res[1].name = pp->mem_space_name;
- if (pp->index == 0) {
- pp->res[1].start = MEM_BASE_0;
- pp->res[1].end = pp->res[1].start + MEM_SIZE_0 - 1;
- } else {
- pp->res[1].start = MEM_BASE_1;
- pp->res[1].end = pp->res[1].start + MEM_SIZE_1 - 1;
- }
+ pp->res[1].start = MEM_BASE_0;
+ pp->res[1].end = pp->res[1].start + MEM_SIZE - 1;
pp->res[1].flags = IORESOURCE_MEM;
if (request_resource(&iomem_resource, &pp->res[1]))
panic("Request PCIe Memory resource failed\n");
@@ -434,18 +563,12 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
"PCIe %d PREFETCH MEM", pp->index);
pp->prefetch_space_name[sizeof(pp->prefetch_space_name) - 1] = 0;
pp->res[2].name = pp->prefetch_space_name;
- if (pp->index == 0) {
- pp->res[2].start = PREFETCH_MEM_BASE_0;
- pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_0 - 1;
- } else {
- pp->res[2].start = PREFETCH_MEM_BASE_1;
- pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_1 - 1;
- }
+ pp->res[2].start = PREFETCH_MEM_BASE_0;
+ pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE - 1;
pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
if (request_resource(&iomem_resource, &pp->res[2]))
panic("Request PCIe Prefetch Memory resource failed\n");
sys->resource[2] = &pp->res[2];
-
return 1;
}
@@ -469,7 +592,7 @@ static struct pci_bus __init *tegra_pcie_scan_bus(int nr,
}
static struct hw_pci tegra_pcie_hw __initdata = {
- .nr_controllers = 2,
+ .nr_controllers = MAX_PCIE_SUPPORTED_PORTS,
.setup = tegra_pcie_setup,
.scan = tegra_pcie_scan_bus,
.swizzle = pci_std_swizzle,
@@ -508,13 +631,17 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg)
* happen a lot during enumeration
*/
if (code == AFI_INTR_MASTER_ABORT)
- pr_debug("PCIE: %s, signature: %08x\n", err_msg[code], signature);
+ 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;
}
+/*
+ * PCIe support functions
+ */
static void tegra_pcie_setup_translations(void)
{
u32 fpci_bar;
@@ -547,7 +674,7 @@ static void tegra_pcie_setup_translations(void)
/* Bar 3: prefetchable memory BAR */
fpci_bar = (((PREFETCH_MEM_BASE_0 >> 12) & 0x0fffffff) << 4) | 0x1;
- size = PREFETCH_MEM_SIZE_0 + PREFETCH_MEM_SIZE_1;
+ size = PREFETCH_MEM_SIZE;
axi_address = PREFETCH_MEM_BASE_0;
afi_writel(axi_address, AFI_AXI_BAR3_START);
afi_writel(size >> 12, AFI_AXI_BAR3_SZ);
@@ -555,7 +682,7 @@ static void tegra_pcie_setup_translations(void)
/* Bar 4: non prefetchable memory BAR */
fpci_bar = (((MEM_BASE_0 >> 12) & 0x0FFFFFFF) << 4) | 0x1;
- size = MEM_SIZE_0 + MEM_SIZE_1;
+ size = MEM_SIZE;
axi_address = MEM_BASE_0;
afi_writel(axi_address, AFI_AXI_BAR4_START);
afi_writel(size >> 12, AFI_AXI_BAR4_SZ);
@@ -586,10 +713,21 @@ static void tegra_pcie_enable_controller(void)
{
u32 val, reg;
int i;
+ void __iomem *reg_apb_misc_base;
+ void __iomem *reg_mselect_base;
+ reg_apb_misc_base = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+ reg_mselect_base = IO_ADDRESS(TEGRA_MSELECT_BASE);
+
+ /* select the PCIE APERTURE in MSELECT config */
+ reg = readl(reg_mselect_base);
+ reg |= 1 << MSELECT_CONFIG_0_ENABLE_PCIE_APERTURE;
+ writel(reg, reg_mselect_base);
/* 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;
+ for (i = 0, reg = AFI_PEX0_CTRL; i < MAX_PCIE_SUPPORTED_PORTS;
+ i++, reg += (i*8)) {
+ val = afi_readl(reg) | AFI_PEX_CTRL_REFCLK_EN |
+ (1 << AFI_PEX0_CTRL_0_PEX0_CLKREQ_EN);
afi_writel(val, reg);
val &= ~AFI_PEX_CTRL_RST;
afi_writel(val, reg);
@@ -597,13 +735,19 @@ static void tegra_pcie_enable_controller(void)
val = afi_readl(reg) | AFI_PEX_CTRL_RST;
afi_writel(val, reg);
}
+ afi_writel(0, AFI_PEXBIAS_CTRL_0);
/* 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_PCIEC2_DISABLE_DEVICE |
AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
val |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
+#else
+ val |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411;
+#endif
afi_writel(val, AFI_PCIE_CONFIG);
val = afi_readl(AFI_FUSE) & ~AFI_FUSE_PCIE_T0_GEN2_DIS;
@@ -622,7 +766,12 @@ static void tegra_pcie_enable_controller(void)
*/
val = pads_readl(PADS_PLL_CTL);
val &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
val |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML | PADS_PLL_CTL_TXCLKREF_DIV10);
+#else
+ val |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML |
+ PADS_PLL_CTL_TXCLKREF_BUF_EN);
+#endif
pads_writel(val, PADS_PLL_CTL);
/* take PLL out of reset */
@@ -634,6 +783,7 @@ static void tegra_pcie_enable_controller(void)
* This doesn't exist in the documentation
*/
pads_writel(0xfa5cfa5c, 0xc8);
+ pads_writel(0x0000FA5C, NV_PCIE2_PADS_REFCLK_CFG1);
/* Wait for the PLL to lock */
do {
@@ -658,7 +808,8 @@ static void tegra_pcie_enable_controller(void)
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_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR |
+ AFI_INTR_EN_PRSNT_SENSE);
afi_writel(val, AFI_AFI_INTR_ENABLE);
afi_writel(0xffffffff, AFI_SM_INTR_ENABLE);
@@ -683,92 +834,192 @@ static void tegra_pcie_xclk_clamp(bool clamp)
pmc_writel(reg, PMC_SCRATCH42);
}
-static void tegra_pcie_power_off(void)
+static int tegra_pci_enable_regulators(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);
+ if (tegra_pcie.power_rails_enabled)
+ return 0;
+ if (tegra_pcie.regulator_hvdd == NULL) {
+ printk(KERN_INFO "PCIE.C: %s : regulator hvdd_pex\n",
+ __func__);
+ tegra_pcie.regulator_hvdd =
+ regulator_get(NULL, "hvdd_pex");
+ if (IS_ERR_OR_NULL(tegra_pcie.regulator_hvdd)) {
+ pr_err("%s: unable to get hvdd_pex regulator\n",
+ __func__);
+ tegra_pcie.regulator_hvdd = 0;
+ }
+ }
- tegra_powergate_partition(TEGRA_POWERGATE_PCIE);
- tegra_pcie_xclk_clamp(true);
+ if (tegra_pcie.regulator_pexio == NULL) {
+ printk(KERN_INFO "PCIE.C: %s : regulator pexio\n", __func__);
+ tegra_pcie.regulator_pexio =
+ regulator_get(NULL, "vdd_pexb");
+ if (IS_ERR_OR_NULL(tegra_pcie.regulator_pexio)) {
+ pr_err("%s: unable to get pexio regulator\n", __func__);
+ tegra_pcie.regulator_pexio = 0;
+ }
+ }
+
+ /*SATA and PCIE use same PLLE, In default configuration,
+ * and we set default AVDD_PLLE with SATA.
+ * So if use default board, you have to turn on (LDO2) AVDD_PLLE.
+ */
+ if (tegra_pcie.regulator_avdd_plle == NULL) {
+ printk(KERN_INFO "PCIE.C: %s : regulator avdd_plle\n",
+ __func__);
+ tegra_pcie.regulator_avdd_plle = regulator_get(NULL,
+ "avdd_plle");
+ if (IS_ERR_OR_NULL(tegra_pcie.regulator_avdd_plle)) {
+ pr_err("%s: unable to get avdd_plle regulator\n",
+ __func__);
+ tegra_pcie.regulator_avdd_plle = 0;
+ }
+ }
+ if (tegra_pcie.regulator_hvdd)
+ regulator_enable(tegra_pcie.regulator_hvdd);
+ if (tegra_pcie.regulator_pexio)
+ regulator_enable(tegra_pcie.regulator_pexio);
+ if (tegra_pcie.regulator_avdd_plle)
+ regulator_enable(tegra_pcie.regulator_avdd_plle);
+
+ tegra_pcie.power_rails_enabled = 1;
+
+ return 0;
}
-static int tegra_pcie_power_regate(void)
+static int tegra_pci_disable_regulators(void)
{
- int err;
+ int err = 0;
+ if (tegra_pcie.power_rails_enabled == 0)
+ goto err_exit;
+ if (tegra_pcie.regulator_hvdd)
+ err = regulator_disable(tegra_pcie.regulator_hvdd);
+ if (err)
+ goto err_exit;
+ if (tegra_pcie.regulator_pexio)
+ err = regulator_disable(tegra_pcie.regulator_pexio);
+ if (err)
+ goto err_exit;
+ if (tegra_pcie.regulator_avdd_plle)
+ err = regulator_disable(tegra_pcie.regulator_avdd_plle);
+ tegra_pcie.power_rails_enabled = 0;
+err_exit:
+ return err;
+}
- tegra_pcie_power_off();
+static int tegra_pcie_power_on(void)
+{
+ int err = 0;
+ err = tegra_pci_enable_regulators();
+ if (err)
+ goto err_exit;
+ err = tegra_unpowergate_partition_with_clk_on(TEGRA_POWERGATE_PCIE);
+ if (err)
+ goto err_exit;
+ if (tegra_pcie.clk_cml0)
+ clk_enable(tegra_pcie.clk_cml0);
+ if (tegra_pcie.clk_tera_pcie_cml)
+ clk_enable(tegra_pcie.clk_tera_pcie_cml);
+ if (tegra_pcie.pll_e)
+ clk_enable(tegra_pcie.pll_e);
+err_exit:
+ return err;
+}
+static int tegra_pcie_power_off(void)
+{
+ int err = 0;
+ err = tegra_powergate_partition_with_clk_off(TEGRA_POWERGATE_PCIE);
+ if (err)
+ goto err_exit;
tegra_pcie_xclk_clamp(true);
+ if (tegra_pcie.clk_cml0)
+ clk_disable(tegra_pcie.clk_cml0);
+ if (tegra_pcie.clk_tera_pcie_cml)
+ clk_disable(tegra_pcie.clk_tera_pcie_cml);
+ if (tegra_pcie.pll_e)
+ clk_disable(tegra_pcie.pll_e);
+ err = tegra_pci_disable_regulators();
+err_exit:
+ return err;
+}
- tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
- tegra_periph_reset_assert(tegra_pcie.afi_clk);
-
- err = tegra_unpowergate_partition(TEGRA_POWERGATE_PCIE);
+static int tegra_pcie_power_regate(void)
+{
+ int err;
+ err = tegra_unpowergate_partition_with_clk_on(TEGRA_POWERGATE_PCIE);
if (err) {
pr_err("PCIE: powerup sequence failed: %d\n", err);
return err;
}
-
- tegra_periph_reset_deassert(tegra_pcie.afi_clk);
-
- tegra_pcie_xclk_clamp(false);
-
- clk_enable(tegra_pcie.afi_clk);
- clk_enable(tegra_pcie.pex_clk);
+ tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
return clk_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;
+ /* reset the PCIEXCLK */
+ tegra_pcie.pcie_xclk = clk_get(NULL, "pciex");
+ if (IS_ERR_OR_NULL(tegra_pcie.pcie_xclk)) {
+ pr_err("%s: unable to get PCIE Xclock\n", __func__);
+ goto error_exit;
+ }
+ tegra_pcie.pll_e = clk_get_sys(NULL, "pll_e");
+ if (IS_ERR_OR_NULL(tegra_pcie.pll_e)) {
+ pr_err("%s: unable to get PLLE\n", __func__);
+ goto error_exit;
}
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- 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.clk_cml0 = clk_get_sys(NULL, "cml0");
+ if (IS_ERR_OR_NULL(tegra_pcie.clk_cml0)) {
+ pr_err("%s: unable to get cml0\n", __func__);
+ goto error_exit;
}
- 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;
+ tegra_pcie.clk_tera_pcie_cml = clk_get_sys("tegra_pcie", "cml");
+ if (IS_ERR_OR_NULL(tegra_pcie.clk_tera_pcie_cml)) {
+ pr_err("%s: unable to get cml0\n", __func__);
+ goto error_exit;
}
+ clk_enable(tegra_pcie.clk_cml0);
+ clk_enable(tegra_pcie.clk_tera_pcie_cml);
+#endif
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;
+error_exit:
+ if (tegra_pcie.clk_cml0)
+ clk_put(tegra_pcie.clk_cml0);
+ if (tegra_pcie.clk_tera_pcie_cml)
+ clk_put(tegra_pcie.clk_tera_pcie_cml);
+ if (tegra_pcie.pcie_xclk)
+ clk_put(tegra_pcie.pcie_xclk);
+ if (tegra_pcie.pll_e)
+ clk_put(tegra_pcie.pll_e);
+ return -EINVAL;
}
static void tegra_pcie_clocks_put(void)
{
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ clk_put(tegra_pcie.clk_cml0);
+ clk_put(tegra_pcie.clk_tera_pcie_cml);
+#endif
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)
{
- struct resource *res_mmio = &tegra_pcie.res_mmio;
+ struct resource *res_mmio = 0;
int err;
+ tegra_pcie.power_rails_enabled = 0;
+ tegra_unpowergate_partition(TEGRA_POWERGATE_PCIE);
+ err = tegra_pci_enable_regulators();
+ if (err) {
+ pr_err("PCIE: failed to enable power rails %d\n", err);
+ goto err_pwr_on_rail;
+ }
err = tegra_pcie_clocks_get();
if (err) {
@@ -788,7 +1039,8 @@ static int __init tegra_pcie_get_resources(void)
err = -ENOMEM;
goto err_map_reg;
}
-
+ res_mmio = &tegra_pcie.res_mmio;
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
err = request_resource(&iomem_resource, res_mmio);
if (err) {
pr_err("PCIE: Failed to request resources: %d\n", err);
@@ -802,7 +1054,7 @@ static int __init tegra_pcie_get_resources(void)
err = -ENOMEM;
goto err_map_io;
}
-
+#endif
err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
IRQF_SHARED, "PCIE", &tegra_pcie);
if (err) {
@@ -814,16 +1066,19 @@ static int __init tegra_pcie_get_resources(void)
return 0;
err_irq:
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
iounmap(tegra_pcie_io_base);
err_map_io:
release_resource(&tegra_pcie.res_mmio);
err_req_io:
+#endif
iounmap(tegra_pcie.regs);
err_map_reg:
tegra_pcie_power_off();
err_pwr_on:
tegra_pcie_clocks_put();
-
+err_pwr_on_rail:
+ tegra_pci_disable_regulators();
return err;
}
@@ -904,31 +1159,88 @@ static void __init tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
memset(pp->res, 0, sizeof(pp->res));
}
-int __init tegra_pcie_init(bool init_port0, bool init_port1)
+static int tegra_pcie_init(void)
{
- int err;
-
- if (!(init_port0 || init_port1))
- return -ENODEV;
+ int err = 0;
+ int port;
+ int rp_offset = 0;
+ int ctrl_offset = AFI_PEX0_CTRL;
pcibios_min_mem = 0;
err = tegra_pcie_get_resources();
if (err)
return err;
-
tegra_pcie_enable_controller();
/* setup the AFI address translations */
tegra_pcie_setup_translations();
+ for (port = 0; port < MAX_PCIE_SUPPORTED_PORTS; port++) {
+ ctrl_offset += (port * 8);
+ rp_offset = (rp_offset + 0x1000) * port;
+ if (tegra_pcie.plat_data->port_status[port])
+ tegra_pcie_add_port(port, rp_offset, ctrl_offset);
+ }
+
+ if (tegra_pcie.num_ports)
+ pci_common_init(&tegra_pcie_hw);
+ else
+ err = tegra_pcie_power_off();
- if (init_port0)
- tegra_pcie_add_port(0, RP0_OFFSET, AFI_PEX0_CTRL);
+ return err;
+}
- if (init_port1)
- tegra_pcie_add_port(1, RP1_OFFSET, AFI_PEX1_CTRL);
+static int tegra_pci_probe(struct platform_device *pdev)
+{
+ tegra_pcie.plat_data = pdev->dev.platform_data;
+ dev_dbg(&pdev->dev, "PCIE.C: %s : _port_status[0] %d\n",
+ __func__, tegra_pcie.plat_data->port_status[0]);
+ dev_dbg(&pdev->dev, "PCIE.C: %s : _port_status[1] %d\n",
+ __func__, tegra_pcie.plat_data->port_status[1]);
+ dev_dbg(&pdev->dev, "PCIE.C: %s : _port_status[2] %d\n",
+ __func__, tegra_pcie.plat_data->port_status[2]);
+
+ return tegra_pcie_init();
+}
- pci_common_init(&tegra_pcie_hw);
+static int tegra_pci_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return tegra_pcie_power_off();
+}
+
+static int tegra_pci_resume(struct platform_device *pdev)
+{
+ return tegra_pcie_power_on();
+}
+
+static int tegra_pci_remove(struct platform_device *pdev)
+{
return 0;
}
+
+static struct platform_driver tegra_pci_driver = {
+ .probe = tegra_pci_probe,
+ .remove = tegra_pci_remove,
+#ifdef CONFIG_PM
+ .suspend = tegra_pci_suspend,
+ .resume = tegra_pci_resume,
+#endif
+ .driver = {
+ .name = "tegra-pcie",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init tegra_pci_init_driver(void)
+{
+ return platform_driver_register(&tegra_pci_driver);
+}
+
+static void __exit tegra_pci_exit_driver(void)
+{
+ platform_driver_unregister(&tegra_pci_driver);
+}
+
+module_init(tegra_pci_init_driver);
+module_exit(tegra_pci_exit_driver);