mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-28 03:40:04 +00:00
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:
commit
6bfc0c07cd
4 changed files with 519 additions and 82 deletions
|
@ -65,6 +65,14 @@ Required properties:
|
|||
- afi
|
||||
- pcie_x
|
||||
|
||||
Optional properties:
|
||||
- pinctrl-names: A list of pinctrl state names. Must contain the following
|
||||
entries:
|
||||
- "default": active state, puts PCIe I/O out of deep power down state
|
||||
- "idle": puts PCIe I/O into deep power down state
|
||||
- pinctrl-0: phandle for the default/active state of pin configurations.
|
||||
- pinctrl-1: phandle for the idle state of pin configurations.
|
||||
|
||||
Required properties on Tegra124 and later (deprecated):
|
||||
- phys: Must contain an entry for each entry in phy-names.
|
||||
- phy-names: Must include the following entries:
|
||||
|
|
|
@ -24,6 +24,9 @@ driver implementation may support the following properties:
|
|||
unsupported link speed, for instance, trying to do training for
|
||||
unsupported link speed, etc. Must be '4' for gen4, '3' for gen3, '2'
|
||||
for gen2, and '1' for gen1. Any other values are invalid.
|
||||
- reset-gpios:
|
||||
If present this property specifies PERST# GPIO. Host drivers can parse the
|
||||
GPIO and apply fundamental reset to endpoints.
|
||||
|
||||
PCI-PCI Bridge properties
|
||||
-------------------------
|
||||
|
|
|
@ -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 @@ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
|
|||
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);
|
||||
|
||||
|
|
|
@ -709,6 +709,7 @@ int tegra_powergate_power_on(unsigned int id)
|
|||
|
||||
return tegra_powergate_set(pmc, id, true);
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_powergate_power_on);
|
||||
|
||||
/**
|
||||
* tegra_powergate_power_off() - power off partition
|
||||
|
|
Loading…
Reference in a new issue