Merge branch 'remotes/lorenzo/pci/tegra'

- Reorganize Tegra AFI/PHY/REFCLK/etc functions (Manikanta Maddireddy)

  - Mask Tegra AFI_INTR in runtime suspend (Manikanta Maddireddy)

  - Fix Tegra AFI/PCIe powerup sequence (Manikanta Maddireddy)

  - Add Tegra124, Tegra132, Tegra210, and Tegra186 support for Gen2 link
    speed (Manikanta Maddireddy)

  - Advertise Tegra AER support (Manikanta Maddireddy)

  - Program Tegra210 UPHY settings (Manikanta Maddireddy)

  - Enable Tegra opportunistic UpdateFC and ACK (Manikanta Maddireddy)

  - Disable Tegra AFI dynamic clock gating (Manikanta Maddireddy)

  - Process Tegra pending DLL transactions before entering L1 or L2 to
    prevent receiver errors (Manikanta Maddireddy)

  - Enable Tegra xclk clock clamping in L1 (Manikanta Maddireddy)

  - Increase Tegra deskew retry time (Manikanta Maddireddy)

  - Work around Tegra hardware RAW erratum (Manikanta Maddireddy)

  - Update Tegra210 flow control timer frequency (Manikanta Maddireddy)

  - Work around Tegra Gen1/Gen2 link number negotiation issue (Manikanta
    Maddireddy)

  - Work around Tegra PLLE power down issue (Manikanta Maddireddy)

  - Program Tegra20 to support cacheable upstream transactions (Manikanta
    Maddireddy)

  - Log Tegra PRSNT_SENSE_IRQ as debug, not err (Manikanta Maddireddy)

  - Add register offset for third Root Port on Tegra186 and Tegra30
    (Manikanta Maddireddy)

  - Document Tegra PCIe DPD pinctrl property (Manikanta Maddireddy)

  - Put Tegra PEX CLK & BIAS pads in DPD mode to reduce power usage when
    powergated (Manikanta Maddireddy)

  - Add generic DT binding for "reset-gpios" property (Manikanta
    Maddireddy)

  - Add Tegra support for GPIO-based PERST# (Manikanta Maddireddy)

  - Enable Relaxed Ordering only for Tegra20 & Tegra30 (Vidya Sagar)

* remotes/lorenzo/pci/tegra:
  PCI: tegra: Enable Relaxed Ordering only for Tegra20 & Tegra30
  PCI: tegra: Change link retry log level to debug
  PCI: tegra: Add support for GPIO based PERST#
  PCI: Add DT binding for "reset-gpios" property
  PCI: tegra: Put PEX CLK & BIAS pads in DPD mode
  dt-bindings: pci: tegra: Document PCIe DPD pinctrl optional prop
  PCI: tegra: Add AFI_PEX2_CTRL reg offset as part of SoC struct
  PCI: tegra: Change PRSNT_SENSE IRQ log to debug
  PCI: tegra: Program AFI_CACHE_BAR_{0,1}_{ST,SZ} registers only for Tegra20
  PCI: tegra: Fix PLLE power down issue due to CLKREQ# signal
  PCI: tegra: Set target speed as Gen1 before starting LTSSM
  PCI: tegra: Update flow control timer frequency in Tegra210
  PCI: tegra: Add SW fixup for RAW violations
  PCI: tegra: Increase the deskew retry time
  PCI: tegra: Enable PCIe xclk clock clamping
  PCI: tegra: Process pending DLL transactions before entering L1 or L2
  PCI: tegra: Disable AFI dynamic clock gating
  PCI: tegra: Enable opportunistic UpdateFC and ACK
  PCI: tegra: Program UPHY electrical settings for Tegra210
  PCI: tegra: Advertise PCIe Advanced Error Reporting (AER) capability
  PCI: tegra: Add PCIe Gen2 link speed support
  PCI: tegra: Fix PCIe host power up sequence
  PCI: tegra: Mask AFI_INTR in runtime suspend
  PCI: tegra: Rearrange Tegra PCIe driver functions
  PCI: tegra: Handle failure cases in tegra_pcie_power_on()
  soc/tegra: pmc: Export tegra_powergate_power_on()
This commit is contained in:
Bjorn Helgaas
2019-07-12 17:08:37 -05:00
4 changed files with 519 additions and 82 deletions

View File

@@ -17,6 +17,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/irq.h>
@@ -30,6 +31,7 @@
#include <linux/of_platform.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/sizes.h>
@@ -95,7 +97,8 @@
#define AFI_MSI_EN_VEC7 0xa8
#define AFI_CONFIGURATION 0xac
#define AFI_CONFIGURATION_EN_FPCI (1 << 0)
#define AFI_CONFIGURATION_EN_FPCI (1 << 0)
#define AFI_CONFIGURATION_CLKEN_OVERRIDE (1 << 31)
#define AFI_FPCI_ERROR_MASKS 0xb0
@@ -159,13 +162,14 @@
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211 (0x1 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111 (0x2 << 20)
#define AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(x) (1 << ((x) + 29))
#define AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO_ALL (0x7 << 29)
#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_CLKREQ_EN (1 << 1)
#define AFI_PEX_CTRL_REFCLK_EN (1 << 3)
@@ -177,20 +181,74 @@
#define AFI_PEXBIAS_CTRL_0 0x168
#define RP_PRIV_XP_DL 0x00000494
#define RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD (0x1ff << 1)
#define RP_RX_HDR_LIMIT 0x00000e00
#define RP_RX_HDR_LIMIT_PW_MASK (0xff << 8)
#define RP_RX_HDR_LIMIT_PW (0x0e << 8)
#define RP_ECTL_2_R1 0x00000e84
#define RP_ECTL_2_R1_RX_CTLE_1C_MASK 0xffff
#define RP_ECTL_4_R1 0x00000e8c
#define RP_ECTL_4_R1_RX_CDR_CTRL_1C_MASK (0xffff << 16)
#define RP_ECTL_4_R1_RX_CDR_CTRL_1C_SHIFT 16
#define RP_ECTL_5_R1 0x00000e90
#define RP_ECTL_5_R1_RX_EQ_CTRL_L_1C_MASK 0xffffffff
#define RP_ECTL_6_R1 0x00000e94
#define RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK 0xffffffff
#define RP_ECTL_2_R2 0x00000ea4
#define RP_ECTL_2_R2_RX_CTLE_1C_MASK 0xffff
#define RP_ECTL_4_R2 0x00000eac
#define RP_ECTL_4_R2_RX_CDR_CTRL_1C_MASK (0xffff << 16)
#define RP_ECTL_4_R2_RX_CDR_CTRL_1C_SHIFT 16
#define RP_ECTL_5_R2 0x00000eb0
#define RP_ECTL_5_R2_RX_EQ_CTRL_L_1C_MASK 0xffffffff
#define RP_ECTL_6_R2 0x00000eb4
#define RP_ECTL_6_R2_RX_EQ_CTRL_H_1C_MASK 0xffffffff
#define RP_VEND_XP 0x00000f00
#define RP_VEND_XP_DL_UP (1 << 30)
#define RP_VEND_XP_DL_UP (1 << 30)
#define RP_VEND_XP_OPPORTUNISTIC_ACK (1 << 27)
#define RP_VEND_XP_OPPORTUNISTIC_UPDATEFC (1 << 28)
#define RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK (0xff << 18)
#define RP_VEND_CTL0 0x00000f44
#define RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK (0xf << 12)
#define RP_VEND_CTL0_DSK_RST_PULSE_WIDTH (0x9 << 12)
#define RP_VEND_CTL1 0x00000f48
#define RP_VEND_CTL1_ERPT (1 << 13)
#define RP_VEND_XP_BIST 0x00000f4c
#define RP_VEND_XP_BIST_GOTO_L1_L2_AFTER_DLLP_DONE (1 << 28)
#define RP_VEND_CTL2 0x00000fa8
#define RP_VEND_CTL2_PCA_ENABLE (1 << 7)
#define RP_PRIV_MISC 0x00000fe0
#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xe << 0)
#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xf << 0)
#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xe << 0)
#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xf << 0)
#define RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD_MASK (0x7f << 16)
#define RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD (0xf << 16)
#define RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE (1 << 23)
#define RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD_MASK (0x7f << 24)
#define RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD (0xf << 24)
#define RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE (1 << 31)
#define RP_LINK_CONTROL_STATUS 0x00000090
#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
#define RP_LINK_CONTROL_STATUS_2 0x000000b0
#define PADS_CTL_SEL 0x0000009c
#define PADS_CTL 0x000000a0
@@ -226,6 +284,7 @@
#define PADS_REFCLK_CFG_DRVI_SHIFT 12 /* 15:12 */
#define PME_ACK_TIMEOUT 10000
#define LINK_RETRAIN_TIMEOUT 100000 /* in usec */
struct tegra_msi {
struct msi_controller chip;
@@ -249,10 +308,12 @@ struct tegra_pcie_soc {
unsigned int num_ports;
const struct tegra_pcie_port_soc *ports;
unsigned int msi_base_shift;
unsigned long afi_pex2_ctrl;
u32 pads_pll_ctl;
u32 tx_ref_sel;
u32 pads_refclk_cfg0;
u32 pads_refclk_cfg1;
u32 update_fc_threshold;
bool has_pex_clkreq_en;
bool has_pex_bias_ctrl;
bool has_intr_prsnt_sense;
@@ -260,6 +321,24 @@ struct tegra_pcie_soc {
bool has_gen2;
bool force_pca_enable;
bool program_uphy;
bool update_clamp_threshold;
bool program_deskew_time;
bool raw_violation_fixup;
bool update_fc_timer;
bool has_cache_bars;
struct {
struct {
u32 rp_ectl_2_r1;
u32 rp_ectl_4_r1;
u32 rp_ectl_5_r1;
u32 rp_ectl_6_r1;
u32 rp_ectl_2_r2;
u32 rp_ectl_4_r2;
u32 rp_ectl_5_r2;
u32 rp_ectl_6_r2;
} regs;
bool enable;
} ectl;
};
static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip)
@@ -321,6 +400,8 @@ struct tegra_pcie_port {
unsigned int lanes;
struct phy **phys;
struct gpio_desc *reset_gpio;
};
struct tegra_pcie_bus {
@@ -440,6 +521,7 @@ static struct pci_ops tegra_pcie_ops = {
static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
{
const struct tegra_pcie_soc *soc = port->pcie->soc;
unsigned long ret = 0;
switch (port->index) {
@@ -452,7 +534,7 @@ static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
break;
case 2:
ret = AFI_PEX2_CTRL;
ret = soc->afi_pex2_ctrl;
break;
}
@@ -465,15 +547,162 @@ static void tegra_pcie_port_reset(struct tegra_pcie_port *port)
unsigned long value;
/* pulse reset signal */
value = afi_readl(port->pcie, ctrl);
value &= ~AFI_PEX_CTRL_RST;
afi_writel(port->pcie, value, ctrl);
if (port->reset_gpio) {
gpiod_set_value(port->reset_gpio, 1);
} else {
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);
if (port->reset_gpio) {
gpiod_set_value(port->reset_gpio, 0);
} else {
value = afi_readl(port->pcie, ctrl);
value |= AFI_PEX_CTRL_RST;
afi_writel(port->pcie, value, ctrl);
}
}
static void tegra_pcie_enable_rp_features(struct tegra_pcie_port *port)
{
const struct tegra_pcie_soc *soc = port->pcie->soc;
u32 value;
/* Enable AER capability */
value = readl(port->base + RP_VEND_CTL1);
value |= RP_VEND_CTL1_ERPT;
writel(value, port->base + RP_VEND_CTL1);
/* Optimal settings to enhance bandwidth */
value = readl(port->base + RP_VEND_XP);
value |= RP_VEND_XP_OPPORTUNISTIC_ACK;
value |= RP_VEND_XP_OPPORTUNISTIC_UPDATEFC;
writel(value, port->base + RP_VEND_XP);
/*
* LTSSM will wait for DLLP to finish before entering L1 or L2,
* to avoid truncation of PM messages which results in receiver errors
*/
value = readl(port->base + RP_VEND_XP_BIST);
value |= RP_VEND_XP_BIST_GOTO_L1_L2_AFTER_DLLP_DONE;
writel(value, port->base + RP_VEND_XP_BIST);
value = readl(port->base + RP_PRIV_MISC);
value |= RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE;
value |= RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE;
if (soc->update_clamp_threshold) {
value &= ~(RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD_MASK |
RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD_MASK);
value |= RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD |
RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD;
}
writel(value, port->base + RP_PRIV_MISC);
}
static void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port)
{
const struct tegra_pcie_soc *soc = port->pcie->soc;
u32 value;
value = readl(port->base + RP_ECTL_2_R1);
value &= ~RP_ECTL_2_R1_RX_CTLE_1C_MASK;
value |= soc->ectl.regs.rp_ectl_2_r1;
writel(value, port->base + RP_ECTL_2_R1);
value = readl(port->base + RP_ECTL_4_R1);
value &= ~RP_ECTL_4_R1_RX_CDR_CTRL_1C_MASK;
value |= soc->ectl.regs.rp_ectl_4_r1 <<
RP_ECTL_4_R1_RX_CDR_CTRL_1C_SHIFT;
writel(value, port->base + RP_ECTL_4_R1);
value = readl(port->base + RP_ECTL_5_R1);
value &= ~RP_ECTL_5_R1_RX_EQ_CTRL_L_1C_MASK;
value |= soc->ectl.regs.rp_ectl_5_r1;
writel(value, port->base + RP_ECTL_5_R1);
value = readl(port->base + RP_ECTL_6_R1);
value &= ~RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK;
value |= soc->ectl.regs.rp_ectl_6_r1;
writel(value, port->base + RP_ECTL_6_R1);
value = readl(port->base + RP_ECTL_2_R2);
value &= ~RP_ECTL_2_R2_RX_CTLE_1C_MASK;
value |= soc->ectl.regs.rp_ectl_2_r2;
writel(value, port->base + RP_ECTL_2_R2);
value = readl(port->base + RP_ECTL_4_R2);
value &= ~RP_ECTL_4_R2_RX_CDR_CTRL_1C_MASK;
value |= soc->ectl.regs.rp_ectl_4_r2 <<
RP_ECTL_4_R2_RX_CDR_CTRL_1C_SHIFT;
writel(value, port->base + RP_ECTL_4_R2);
value = readl(port->base + RP_ECTL_5_R2);
value &= ~RP_ECTL_5_R2_RX_EQ_CTRL_L_1C_MASK;
value |= soc->ectl.regs.rp_ectl_5_r2;
writel(value, port->base + RP_ECTL_5_R2);
value = readl(port->base + RP_ECTL_6_R2);
value &= ~RP_ECTL_6_R2_RX_EQ_CTRL_H_1C_MASK;
value |= soc->ectl.regs.rp_ectl_6_r2;
writel(value, port->base + RP_ECTL_6_R2);
}
static void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port)
{
const struct tegra_pcie_soc *soc = port->pcie->soc;
u32 value;
/*
* Sometimes link speed change from Gen2 to Gen1 fails due to
* instability in deskew logic on lane-0. Increase the deskew
* retry time to resolve this issue.
*/
if (soc->program_deskew_time) {
value = readl(port->base + RP_VEND_CTL0);
value &= ~RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK;
value |= RP_VEND_CTL0_DSK_RST_PULSE_WIDTH;
writel(value, port->base + RP_VEND_CTL0);
}
/* Fixup for read after write violation. */
if (soc->raw_violation_fixup) {
value = readl(port->base + RP_RX_HDR_LIMIT);
value &= ~RP_RX_HDR_LIMIT_PW_MASK;
value |= RP_RX_HDR_LIMIT_PW;
writel(value, port->base + RP_RX_HDR_LIMIT);
value = readl(port->base + RP_PRIV_XP_DL);
value |= RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD;
writel(value, port->base + RP_PRIV_XP_DL);
value = readl(port->base + RP_VEND_XP);
value &= ~RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK;
value |= soc->update_fc_threshold;
writel(value, port->base + RP_VEND_XP);
}
if (soc->update_fc_timer) {
value = readl(port->base + RP_VEND_XP);
value &= ~RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK;
value |= soc->update_fc_threshold;
writel(value, port->base + RP_VEND_XP);
}
/*
* PCIe link doesn't come up with few legacy PCIe endpoints if
* root port advertises both Gen-1 and Gen-2 speeds in Tegra.
* Hence, the strategy followed here is to initially advertise
* only Gen-1 and after link is up, retrain link to Gen-2 speed
*/
value = readl(port->base + RP_LINK_CONTROL_STATUS_2);
value &= ~PCI_EXP_LNKSTA_CLS;
value |= PCI_EXP_LNKSTA_CLS_2_5GB;
writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
}
static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
@@ -500,6 +729,13 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
value |= RP_VEND_CTL2_PCA_ENABLE;
writel(value, port->base + RP_VEND_CTL2);
}
tegra_pcie_enable_rp_features(port);
if (soc->ectl.enable)
tegra_pcie_program_ectl_settings(port);
tegra_pcie_apply_sw_fixup(port);
}
static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
@@ -521,6 +757,12 @@ static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
value &= ~AFI_PEX_CTRL_REFCLK_EN;
afi_writel(port->pcie, value, ctrl);
/* disable PCIe port and set CLKREQ# as GPIO to allow PLLE power down */
value = afi_readl(port->pcie, AFI_PCIE_CONFIG);
value |= AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
value |= AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index);
afi_writel(port->pcie, value, AFI_PCIE_CONFIG);
}
static void tegra_pcie_port_free(struct tegra_pcie_port *port)
@@ -545,12 +787,15 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
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);
/* Tegra PCIE requires relaxed ordering */
/* Tegra20 and Tegra30 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);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_relax_enable);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_relax_enable);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_relax_enable);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_relax_enable);
static int tegra_pcie_request_resources(struct tegra_pcie *pcie)
{
@@ -635,7 +880,7 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg)
* do not pollute kernel log with master abort reports since they
* happen a lot during enumeration
*/
if (code == AFI_INTR_MASTER_ABORT)
if (code == AFI_INTR_MASTER_ABORT || code == AFI_INTR_PE_PRSNT_SENSE)
dev_dbg(dev, "%s, signature: %08x\n", err_msg[code], signature);
else
dev_err(dev, "%s, signature: %08x\n", err_msg[code], signature);
@@ -704,11 +949,13 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
afi_writel(pcie, 0, AFI_AXI_BAR5_SZ);
afi_writel(pcie, 0, AFI_FPCI_BAR5);
/* map all upstream transactions as uncached */
afi_writel(pcie, 0, 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);
if (pcie->soc->has_cache_bars) {
/* map all upstream transactions as uncached */
afi_writel(pcie, 0, 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);
@@ -852,7 +1099,6 @@ static int tegra_pcie_port_phy_power_off(struct tegra_pcie_port *port)
static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie)
{
struct device *dev = pcie->dev;
const struct tegra_pcie_soc *soc = pcie->soc;
struct tegra_pcie_port *port;
int err;
@@ -878,12 +1124,6 @@ static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie)
}
}
/* Configure the reference clock driver */
pads_writel(pcie, soc->pads_refclk_cfg0, PADS_REFCLK_CFG0);
if (soc->num_ports > 2)
pads_writel(pcie, soc->pads_refclk_cfg1, PADS_REFCLK_CFG1);
return 0;
}
@@ -918,13 +1158,11 @@ static int tegra_pcie_phy_power_off(struct tegra_pcie *pcie)
return 0;
}
static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
static void tegra_pcie_enable_controller(struct tegra_pcie *pcie)
{
struct device *dev = pcie->dev;
const struct tegra_pcie_soc *soc = pcie->soc;
struct tegra_pcie_port *port;
unsigned long value;
int err;
/* enable PLL power down */
if (pcie->phy) {
@@ -942,9 +1180,12 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
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;
value |= AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO_ALL;
list_for_each_entry(port, &pcie->ports, list)
list_for_each_entry(port, &pcie->ports, list) {
value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
value &= ~AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index);
}
afi_writel(pcie, value, AFI_PCIE_CONFIG);
@@ -958,20 +1199,10 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
afi_writel(pcie, value, AFI_FUSE);
}
if (soc->program_uphy) {
err = tegra_pcie_phy_power_on(pcie);
if (err < 0) {
dev_err(dev, "failed to power on PHY(s): %d\n", err);
return err;
}
}
/* take the PCIe interface module out of reset */
reset_control_deassert(pcie->pcie_xrst);
/* finally enable PCIe */
/* Disable AFI dynamic clock gating and enable PCIe */
value = afi_readl(pcie, AFI_CONFIGURATION);
value |= AFI_CONFIGURATION_EN_FPCI;
value |= AFI_CONFIGURATION_CLKEN_OVERRIDE;
afi_writel(pcie, value, AFI_CONFIGURATION);
value = AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
@@ -989,22 +1220,6 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
/* disable all exceptions */
afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS);
return 0;
}
static void tegra_pcie_disable_controller(struct tegra_pcie *pcie)
{
int err;
reset_control_assert(pcie->pcie_xrst);
if (pcie->soc->program_uphy) {
err = tegra_pcie_phy_power_off(pcie);
if (err < 0)
dev_err(pcie->dev, "failed to power off PHY(s): %d\n",
err);
}
}
static void tegra_pcie_power_off(struct tegra_pcie *pcie)
@@ -1014,13 +1229,11 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie)
int err;
reset_control_assert(pcie->afi_rst);
reset_control_assert(pcie->pex_rst);
clk_disable_unprepare(pcie->pll_e);
if (soc->has_cml_clk)
clk_disable_unprepare(pcie->cml_clk);
clk_disable_unprepare(pcie->afi_clk);
clk_disable_unprepare(pcie->pex_clk);
if (!dev->pm_domain)
tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
@@ -1048,46 +1261,66 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
if (err < 0)
dev_err(dev, "failed to enable regulators: %d\n", err);
if (dev->pm_domain) {
err = clk_prepare_enable(pcie->pex_clk);
if (!dev->pm_domain) {
err = tegra_powergate_power_on(TEGRA_POWERGATE_PCIE);
if (err) {
dev_err(dev, "failed to enable PEX clock: %d\n", err);
return err;
dev_err(dev, "failed to power ungate: %d\n", err);
goto regulator_disable;
}
reset_control_deassert(pcie->pex_rst);
} else {
err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
pcie->pex_clk,
pcie->pex_rst);
err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_PCIE);
if (err) {
dev_err(dev, "powerup sequence failed: %d\n", err);
return err;
dev_err(dev, "failed to remove clamp: %d\n", err);
goto powergate;
}
}
reset_control_deassert(pcie->afi_rst);
err = clk_prepare_enable(pcie->afi_clk);
if (err < 0) {
dev_err(dev, "failed to enable AFI clock: %d\n", err);
return err;
goto powergate;
}
if (soc->has_cml_clk) {
err = clk_prepare_enable(pcie->cml_clk);
if (err < 0) {
dev_err(dev, "failed to enable CML clock: %d\n", err);
return err;
goto disable_afi_clk;
}
}
err = clk_prepare_enable(pcie->pll_e);
if (err < 0) {
dev_err(dev, "failed to enable PLLE clock: %d\n", err);
return err;
goto disable_cml_clk;
}
reset_control_deassert(pcie->afi_rst);
return 0;
disable_cml_clk:
if (soc->has_cml_clk)
clk_disable_unprepare(pcie->cml_clk);
disable_afi_clk:
clk_disable_unprepare(pcie->afi_clk);
powergate:
if (!dev->pm_domain)
tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
regulator_disable:
regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
return err;
}
static void tegra_pcie_apply_pad_settings(struct tegra_pcie *pcie)
{
const struct tegra_pcie_soc *soc = pcie->soc;
/* Configure the reference clock driver */
pads_writel(pcie, soc->pads_refclk_cfg0, PADS_REFCLK_CFG0);
if (soc->num_ports > 2)
pads_writel(pcie, soc->pads_refclk_cfg1, PADS_REFCLK_CFG1);
}
static int tegra_pcie_clocks_get(struct tegra_pcie *pcie)
@@ -1647,6 +1880,15 @@ static int tegra_pcie_disable_msi(struct tegra_pcie *pcie)
return 0;
}
static void tegra_pcie_disable_interrupts(struct tegra_pcie *pcie)
{
u32 value;
value = afi_readl(pcie, AFI_INTR_MASK);
value &= ~AFI_INTR_MASK_INT_MASK;
afi_writel(pcie, value, AFI_INTR_MASK);
}
static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
u32 *xbar)
{
@@ -1990,6 +2232,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
struct tegra_pcie_port *rp;
unsigned int index;
u32 value;
char *label;
err = of_pci_get_devfn(port);
if (err < 0) {
@@ -2048,6 +2291,31 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
if (IS_ERR(rp->base))
return PTR_ERR(rp->base);
label = devm_kasprintf(dev, GFP_KERNEL, "pex-reset-%u", index);
if (!label) {
dev_err(dev, "failed to create reset GPIO label\n");
return -ENOMEM;
}
/*
* Returns -ENOENT if reset-gpios property is not populated
* and in this case fall back to using AFI per port register
* to toggle PERST# SFIO line.
*/
rp->reset_gpio = devm_gpiod_get_from_of_node(dev, port,
"reset-gpios", 0,
GPIOD_OUT_LOW,
label);
if (IS_ERR(rp->reset_gpio)) {
if (PTR_ERR(rp->reset_gpio) == -ENOENT) {
rp->reset_gpio = NULL;
} else {
dev_err(dev, "failed to get reset GPIO: %d\n",
err);
return PTR_ERR(rp->reset_gpio);
}
}
list_add_tail(&rp->list, &pcie->ports);
}
@@ -2095,7 +2363,7 @@ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
} while (--timeout);
if (!timeout) {
dev_err(dev, "link %u down, retrying\n", port->index);
dev_dbg(dev, "link %u down, retrying\n", port->index);
goto retry;
}
@@ -2117,6 +2385,64 @@ retry:
return false;
}
static void tegra_pcie_change_link_speed(struct tegra_pcie *pcie)
{
struct device *dev = pcie->dev;
struct tegra_pcie_port *port;
ktime_t deadline;
u32 value;
list_for_each_entry(port, &pcie->ports, list) {
/*
* "Supported Link Speeds Vector" in "Link Capabilities 2"
* is not supported by Tegra. tegra_pcie_change_link_speed()
* is called only for Tegra chips which support Gen2.
* So there no harm if supported link speed is not verified.
*/
value = readl(port->base + RP_LINK_CONTROL_STATUS_2);
value &= ~PCI_EXP_LNKSTA_CLS;
value |= PCI_EXP_LNKSTA_CLS_5_0GB;
writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
/*
* Poll until link comes back from recovery to avoid race
* condition.
*/
deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT);
while (ktime_before(ktime_get(), deadline)) {
value = readl(port->base + RP_LINK_CONTROL_STATUS);
if ((value & PCI_EXP_LNKSTA_LT) == 0)
break;
usleep_range(2000, 3000);
}
if (value & PCI_EXP_LNKSTA_LT)
dev_warn(dev, "PCIe port %u link is in recovery\n",
port->index);
/* Retrain the link */
value = readl(port->base + RP_LINK_CONTROL_STATUS);
value |= PCI_EXP_LNKCTL_RL;
writel(value, port->base + RP_LINK_CONTROL_STATUS);
deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT);
while (ktime_before(ktime_get(), deadline)) {
value = readl(port->base + RP_LINK_CONTROL_STATUS);
if ((value & PCI_EXP_LNKSTA_LT) == 0)
break;
usleep_range(2000, 3000);
}
if (value & PCI_EXP_LNKSTA_LT)
dev_err(dev, "failed to retrain link of port %u\n",
port->index);
}
}
static void tegra_pcie_enable_ports(struct tegra_pcie *pcie)
{
struct device *dev = pcie->dev;
@@ -2127,7 +2453,12 @@ static void tegra_pcie_enable_ports(struct tegra_pcie *pcie)
port->index, port->lanes);
tegra_pcie_port_enable(port);
}
/* Start LTSSM from Tegra side */
reset_control_deassert(pcie->pcie_xrst);
list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
if (tegra_pcie_port_check_link(port))
continue;
@@ -2136,12 +2467,17 @@ static void tegra_pcie_enable_ports(struct tegra_pcie *pcie)
tegra_pcie_port_disable(port);
tegra_pcie_port_free(port);
}
if (pcie->soc->has_gen2)
tegra_pcie_change_link_speed(pcie);
}
static void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
{
struct tegra_pcie_port *port, *tmp;
reset_control_assert(pcie->pcie_xrst);
list_for_each_entry_safe(port, tmp, &pcie->ports, list)
tegra_pcie_port_disable(port);
}
@@ -2155,6 +2491,7 @@ static const struct tegra_pcie_soc tegra20_pcie = {
.num_ports = 2,
.ports = tegra20_pcie_ports,
.msi_base_shift = 0,
.afi_pex2_ctrl = 0x128,
.pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
.pads_refclk_cfg0 = 0xfa5cfa5c,
@@ -2165,6 +2502,12 @@ static const struct tegra_pcie_soc tegra20_pcie = {
.has_gen2 = false,
.force_pca_enable = false,
.program_uphy = true,
.update_clamp_threshold = false,
.program_deskew_time = false,
.raw_violation_fixup = false,
.update_fc_timer = false,
.has_cache_bars = true,
.ectl.enable = false,
};
static const struct tegra_pcie_port_soc tegra30_pcie_ports[] = {
@@ -2188,6 +2531,12 @@ static const struct tegra_pcie_soc tegra30_pcie = {
.has_gen2 = false,
.force_pca_enable = false,
.program_uphy = true,
.update_clamp_threshold = false,
.program_deskew_time = false,
.raw_violation_fixup = false,
.update_fc_timer = false,
.has_cache_bars = false,
.ectl.enable = false,
};
static const struct tegra_pcie_soc tegra124_pcie = {
@@ -2197,6 +2546,8 @@ static const struct tegra_pcie_soc tegra124_pcie = {
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
.pads_refclk_cfg0 = 0x44ac44ac,
/* FC threshold is bit[25:18] */
.update_fc_threshold = 0x03fc0000,
.has_pex_clkreq_en = true,
.has_pex_bias_ctrl = true,
.has_intr_prsnt_sense = true,
@@ -2204,6 +2555,12 @@ static const struct tegra_pcie_soc tegra124_pcie = {
.has_gen2 = true,
.force_pca_enable = false,
.program_uphy = true,
.update_clamp_threshold = true,
.program_deskew_time = false,
.raw_violation_fixup = true,
.update_fc_timer = false,
.has_cache_bars = false,
.ectl.enable = false,
};
static const struct tegra_pcie_soc tegra210_pcie = {
@@ -2213,6 +2570,8 @@ static const struct tegra_pcie_soc tegra210_pcie = {
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
.pads_refclk_cfg0 = 0x90b890b8,
/* FC threshold is bit[25:18] */
.update_fc_threshold = 0x01800000,
.has_pex_clkreq_en = true,
.has_pex_bias_ctrl = true,
.has_intr_prsnt_sense = true,
@@ -2220,6 +2579,24 @@ static const struct tegra_pcie_soc tegra210_pcie = {
.has_gen2 = true,
.force_pca_enable = true,
.program_uphy = true,
.update_clamp_threshold = true,
.program_deskew_time = true,
.raw_violation_fixup = false,
.update_fc_timer = true,
.has_cache_bars = false,
.ectl = {
.regs = {
.rp_ectl_2_r1 = 0x0000000f,
.rp_ectl_4_r1 = 0x00000067,
.rp_ectl_5_r1 = 0x55010000,
.rp_ectl_6_r1 = 0x00000001,
.rp_ectl_2_r2 = 0x0000008f,
.rp_ectl_4_r2 = 0x000000c7,
.rp_ectl_5_r2 = 0x55010000,
.rp_ectl_6_r2 = 0x00000001,
},
.enable = true,
},
};
static const struct tegra_pcie_port_soc tegra186_pcie_ports[] = {
@@ -2232,6 +2609,7 @@ static const struct tegra_pcie_soc tegra186_pcie = {
.num_ports = 3,
.ports = tegra186_pcie_ports,
.msi_base_shift = 8,
.afi_pex2_ctrl = 0x19c,
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
.pads_refclk_cfg0 = 0x80b880b8,
@@ -2243,6 +2621,12 @@ static const struct tegra_pcie_soc tegra186_pcie = {
.has_gen2 = true,
.force_pca_enable = false,
.program_uphy = false,
.update_clamp_threshold = false,
.program_deskew_time = false,
.raw_violation_fixup = false,
.update_fc_timer = false,
.has_cache_bars = false,
.ectl.enable = false,
};
static const struct of_device_id tegra_pcie_of_match[] = {
@@ -2485,16 +2869,32 @@ static int __maybe_unused tegra_pcie_pm_suspend(struct device *dev)
{
struct tegra_pcie *pcie = dev_get_drvdata(dev);
struct tegra_pcie_port *port;
int err;
list_for_each_entry(port, &pcie->ports, list)
tegra_pcie_pme_turnoff(port);
tegra_pcie_disable_ports(pcie);
/*
* AFI_INTR is unmasked in tegra_pcie_enable_controller(), mask it to
* avoid unwanted interrupts raised by AFI after pex_rst is asserted.
*/
tegra_pcie_disable_interrupts(pcie);
if (pcie->soc->program_uphy) {
err = tegra_pcie_phy_power_off(pcie);
if (err < 0)
dev_err(dev, "failed to power off PHY(s): %d\n", err);
}
reset_control_assert(pcie->pex_rst);
clk_disable_unprepare(pcie->pex_clk);
if (IS_ENABLED(CONFIG_PCI_MSI))
tegra_pcie_disable_msi(pcie);
tegra_pcie_disable_controller(pcie);
pinctrl_pm_select_idle_state(dev);
tegra_pcie_power_off(pcie);
return 0;
@@ -2510,20 +2910,45 @@ static int __maybe_unused tegra_pcie_pm_resume(struct device *dev)
dev_err(dev, "tegra pcie power on fail: %d\n", err);
return err;
}
err = tegra_pcie_enable_controller(pcie);
if (err) {
dev_err(dev, "tegra pcie controller enable fail: %d\n", err);
err = pinctrl_pm_select_default_state(dev);
if (err < 0) {
dev_err(dev, "failed to disable PCIe IO DPD: %d\n", err);
goto poweroff;
}
tegra_pcie_enable_controller(pcie);
tegra_pcie_setup_translations(pcie);
if (IS_ENABLED(CONFIG_PCI_MSI))
tegra_pcie_enable_msi(pcie);
err = clk_prepare_enable(pcie->pex_clk);
if (err) {
dev_err(dev, "failed to enable PEX clock: %d\n", err);
goto pex_dpd_enable;
}
reset_control_deassert(pcie->pex_rst);
if (pcie->soc->program_uphy) {
err = tegra_pcie_phy_power_on(pcie);
if (err < 0) {
dev_err(dev, "failed to power on PHY(s): %d\n", err);
goto disable_pex_clk;
}
}
tegra_pcie_apply_pad_settings(pcie);
tegra_pcie_enable_ports(pcie);
return 0;
disable_pex_clk:
reset_control_assert(pcie->pex_rst);
clk_disable_unprepare(pcie->pex_clk);
pex_dpd_enable:
pinctrl_pm_select_idle_state(dev);
poweroff:
tegra_pcie_power_off(pcie);