mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
Merge branch 'pci/controller/dwc-tegra194'
- Poll less aggressively and non-atomically for PME_TO_Ack during transition to L2 (Vidya Sagar) - Increase LTSSM poll time on surprise link down (Manikanta Maddireddy) - Disable LTSSM after transition to Detect on surprise link down to stop toggling between Polling and Detect (Manikanta Maddireddy) - Don't force the device into the D0 state before L2 when suspending or shutting down the controller (Vidya Sagar) - Disable PERST# IRQ only in Endpoint mode because it's not registered in Root Port mode (Manikanta Maddireddy) - Handle 'nvidia,refclk-select' as optional (Vidya Sagar) - Disable direct speed change in Endpoint mode so link speed change is controlled by the host (Vidya Sagar) - Set LTR values before link up to avoid bogus LTR messages with 0 latency (Vidya Sagar) - Allow system suspend when the Endpoint link is down (Vidya Sagar) - During remove, free resources allocated during Endpoint .probe() (Vidya Sagar) - Use DWC IP core version, not Tegra custom values, to avoid DWC core version check warnings (Manikanta Maddireddy) - Apply ECRC workaround to devices based on DesignWare 5.00a as well as 4.90a (Manikanta Maddireddy) - Disable PM Substate L1.2 in Endpoint mode to work around Tegra234 erratum (Vidya Sagar) - Delay post-PERST# cleanup until core is powered on to avoid CBB timeout (Manikanta Maddireddy) - Assert CLKREQ# so switches that forward it to their downstream side can bring up those links successfully (Vidya Sagar) - Calibrate pipe to UPHY for Endpoint mode to reset stale PLL state from any previous bad link state (Vidya Sagar) - Remove IRQF_ONESHOT flag from Endpoint interrupt registration so DMA driver and Endpoint controller driver can share the interrupt line (Vidya Sagar) - Enable DMA interrupt to support DMA in both Root Port and Endpoint modes (Vidya Sagar) - Enable hardware link retraining after link goes down in Endpoint mode (Vidya Sagar) - Add DT binding and driver support for core clock monitoring (Vidya Sagar) * pci/controller/dwc-tegra194: PCI: tegra194: Add core monitor clock support dt-bindings: PCI: tegra194: Add monitor clock support PCI: tegra194: Enable hardware hot reset mode in Endpoint mode PCI: tegra194: Enable DMA interrupt PCI: tegra194: Remove IRQF_ONESHOT flag during Endpoint interrupt registration PCI: tegra194: Calibrate pipe to UPHY for Endpoint mode PCI: tegra194: Assert CLKREQ# explicitly by default PCI: tegra194: Fix CBB timeout caused by DBI access before core power-on PCI: tegra194: Disable L1.2 capability of Tegra234 EP PCI: dwc: Apply ECRC workaround to DesignWare 5.00a as well PCI: tegra194: Use DWC IP core version PCI: tegra194: Free up Endpoint resources during remove() PCI: tegra194: Allow system suspend when the Endpoint link is not up PCI: tegra194: Set LTR message request before PCIe link up in Endpoint mode PCI: tegra194: Disable direct speed change for Endpoint mode PCI: tegra194: Use devm_gpiod_get_optional() to parse "nvidia,refclk-select" PCI: tegra194: Disable PERST# IRQ only in Endpoint mode PCI: tegra194: Don't force the device into the D0 state before L2 PCI: tegra194: Disable LTSSM after transition to Detect on surprise link down PCI: tegra194: Increase LTSSM poll time on surprise link down PCI: tegra194: Fix polling delay for L2 state
This commit is contained in:
commit
b43cdb32ee
|
|
@ -55,12 +55,16 @@ properties:
|
|||
- const: intr
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: module clock
|
||||
- description: core clock
|
||||
- description: monitor clock
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: core
|
||||
- const: core_m
|
||||
|
||||
resets:
|
||||
items:
|
||||
|
|
|
|||
|
|
@ -58,12 +58,16 @@ properties:
|
|||
- const: msi
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: module clock
|
||||
- description: core clock
|
||||
- description: monitor clock
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: core
|
||||
- const: core_m
|
||||
|
||||
resets:
|
||||
items:
|
||||
|
|
|
|||
|
|
@ -487,13 +487,13 @@ static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 index, u32 reg
|
|||
static inline u32 dw_pcie_enable_ecrc(u32 val)
|
||||
{
|
||||
/*
|
||||
* DesignWare core version 4.90A has a design issue where the 'TD'
|
||||
* bit in the Control register-1 of the ATU outbound region acts
|
||||
* like an override for the ECRC setting, i.e., the presence of TLP
|
||||
* Digest (ECRC) in the outgoing TLPs is solely determined by this
|
||||
* bit. This is contrary to the PCIe spec which says that the
|
||||
* enablement of the ECRC is solely determined by the AER
|
||||
* registers.
|
||||
* DWC versions 0x3530302a and 0x3536322a have a design issue where
|
||||
* the 'TD' bit in the Control register-1 of the ATU outbound
|
||||
* region acts like an override for the ECRC setting, i.e., the
|
||||
* presence of TLP Digest (ECRC) in the outgoing TLPs is solely
|
||||
* determined by this bit. This is contrary to the PCIe spec which
|
||||
* says that the enablement of the ECRC is solely determined by the
|
||||
* AER registers.
|
||||
*
|
||||
* Because of this, even when the ECRC is enabled through AER
|
||||
* registers, the transactions going through ATU won't have TLP
|
||||
|
|
@ -563,7 +563,7 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
|
|||
if (upper_32_bits(limit_addr) > upper_32_bits(parent_bus_addr) &&
|
||||
dw_pcie_ver_is_ge(pci, 460A))
|
||||
val |= PCIE_ATU_INCREASE_REGION_SIZE;
|
||||
if (dw_pcie_ver_is(pci, 490A))
|
||||
if (dw_pcie_ver_is(pci, 490A) || dw_pcie_ver_is(pci, 500A))
|
||||
val = dw_pcie_enable_ecrc(val);
|
||||
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL1, val);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,8 +34,10 @@
|
|||
#define DW_PCIE_VER_470A 0x3437302a
|
||||
#define DW_PCIE_VER_480A 0x3438302a
|
||||
#define DW_PCIE_VER_490A 0x3439302a
|
||||
#define DW_PCIE_VER_500A 0x3530302a
|
||||
#define DW_PCIE_VER_520A 0x3532302a
|
||||
#define DW_PCIE_VER_540A 0x3534302a
|
||||
#define DW_PCIE_VER_562A 0x3536322a
|
||||
|
||||
#define __dw_pcie_ver_cmp(_pci, _ver, _op) \
|
||||
((_pci)->version _op DW_PCIE_VER_ ## _ver)
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@
|
|||
#include <soc/tegra/bpmp-abi.h>
|
||||
#include "../../pci.h"
|
||||
|
||||
#define TEGRA194_DWC_IP_VER 0x490A
|
||||
#define TEGRA234_DWC_IP_VER 0x562A
|
||||
#define TEGRA194_DWC_IP_VER DW_PCIE_VER_500A
|
||||
#define TEGRA234_DWC_IP_VER DW_PCIE_VER_562A
|
||||
|
||||
#define APPL_PINMUX 0x0
|
||||
#define APPL_PINMUX_PEX_RST BIT(0)
|
||||
|
|
@ -44,6 +44,7 @@
|
|||
#define APPL_PINMUX_CLKREQ_OVERRIDE BIT(3)
|
||||
#define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN BIT(4)
|
||||
#define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE BIT(5)
|
||||
#define APPL_PINMUX_CLKREQ_DEFAULT_VALUE BIT(13)
|
||||
|
||||
#define APPL_CTRL 0x4
|
||||
#define APPL_CTRL_SYS_PRE_DET_STATE BIT(6)
|
||||
|
|
@ -90,6 +91,7 @@
|
|||
#define APPL_INTR_EN_L1_8_0 0x44
|
||||
#define APPL_INTR_EN_L1_8_BW_MGT_INT_EN BIT(2)
|
||||
#define APPL_INTR_EN_L1_8_AUTO_BW_INT_EN BIT(3)
|
||||
#define APPL_INTR_EN_L1_8_EDMA_INT_EN BIT(6)
|
||||
#define APPL_INTR_EN_L1_8_INTX_EN BIT(11)
|
||||
#define APPL_INTR_EN_L1_8_AER_INT_EN BIT(15)
|
||||
|
||||
|
|
@ -137,7 +139,11 @@
|
|||
#define APPL_DEBUG_PM_LINKST_IN_L0 0x11
|
||||
#define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3)
|
||||
#define APPL_DEBUG_LTSSM_STATE_SHIFT 3
|
||||
#define LTSSM_STATE_PRE_DETECT 5
|
||||
#define LTSSM_STATE_DETECT_QUIET 0x00
|
||||
#define LTSSM_STATE_DETECT_ACT 0x08
|
||||
#define LTSSM_STATE_PRE_DETECT_QUIET 0x28
|
||||
#define LTSSM_STATE_DETECT_WAIT 0x30
|
||||
#define LTSSM_STATE_L2_IDLE 0xa8
|
||||
|
||||
#define APPL_RADM_STATUS 0xE4
|
||||
#define APPL_PM_XMT_TURNOFF_STATE BIT(0)
|
||||
|
|
@ -198,9 +204,8 @@
|
|||
#define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8)
|
||||
#define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8
|
||||
|
||||
#define PME_ACK_TIMEOUT 10000
|
||||
|
||||
#define LTSSM_TIMEOUT 50000 /* 50ms */
|
||||
#define LTSSM_DELAY_US 10000 /* 10 ms */
|
||||
#define LTSSM_TIMEOUT_US 120000 /* 120 ms */
|
||||
|
||||
#define GEN3_GEN4_EQ_PRESET_INIT 5
|
||||
|
||||
|
|
@ -231,6 +236,7 @@ struct tegra_pcie_dw_of_data {
|
|||
bool has_sbr_reset_fix;
|
||||
bool has_l1ss_exit_fix;
|
||||
bool has_ltr_req_fix;
|
||||
bool disable_l1_2;
|
||||
u32 cdm_chk_int_en_bit;
|
||||
u32 gen4_preset_vec;
|
||||
u8 n_fts[2];
|
||||
|
|
@ -243,6 +249,7 @@ struct tegra_pcie_dw {
|
|||
struct resource *atu_dma_res;
|
||||
void __iomem *appl_base;
|
||||
struct clk *core_clk;
|
||||
struct clk *core_clk_m;
|
||||
struct reset_control *core_apb_rst;
|
||||
struct reset_control *core_rst;
|
||||
struct dw_pcie pci;
|
||||
|
|
@ -482,15 +489,6 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
|
|||
if (val & PCI_COMMAND_MASTER) {
|
||||
ktime_t timeout;
|
||||
|
||||
/* 110us for both snoop and no-snoop */
|
||||
val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) |
|
||||
FIELD_PREP(PCI_LTR_SCALE_MASK, 2) |
|
||||
LTR_MSG_REQ |
|
||||
FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) |
|
||||
FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) |
|
||||
LTR_NOSNOOP_MSG_REQ;
|
||||
appl_writel(pcie, val, APPL_LTR_MSG_1);
|
||||
|
||||
/* Send LTR upstream */
|
||||
val = appl_readl(pcie, APPL_LTR_MSG_2);
|
||||
val |= APPL_LTR_MSG_2_LTR_MSG_REQ_STATE;
|
||||
|
|
@ -548,6 +546,17 @@ static irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg)
|
|||
spurious = 0;
|
||||
}
|
||||
|
||||
if (status_l0 & APPL_INTR_STATUS_L0_INT_INT) {
|
||||
status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_8_0);
|
||||
|
||||
/*
|
||||
* Interrupt is handled by DMA driver; don't treat it as
|
||||
* spurious
|
||||
*/
|
||||
if (status_l1 & APPL_INTR_STATUS_L1_8_0_EDMA_INT_MASK)
|
||||
spurious = 0;
|
||||
}
|
||||
|
||||
if (spurious) {
|
||||
dev_warn(pcie->dev, "Random interrupt (STATUS = 0x%08X)\n",
|
||||
status_l0);
|
||||
|
|
@ -685,6 +694,23 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
|
|||
if (pcie->supports_clkreq)
|
||||
pci->l1ss_support = true;
|
||||
|
||||
/*
|
||||
* Disable L1.2 capability advertisement for Tegra234 Endpoint mode.
|
||||
* Tegra234 has a hardware bug where during L1.2 exit, the UPHY PLL is
|
||||
* powered up immediately without waiting for REFCLK to stabilize. This
|
||||
* causes the PLL to fail to lock to the correct frequency, resulting in
|
||||
* PCIe link loss. Since there is no hardware fix available, we prevent
|
||||
* the Endpoint from advertising L1.2 support by clearing the L1.2 bits
|
||||
* in the L1 PM Substates Capabilities register. This ensures the host
|
||||
* will not attempt to enter L1.2 state with this Endpoint.
|
||||
*/
|
||||
if (pcie->of_data->disable_l1_2 &&
|
||||
pcie->of_data->mode == DW_PCIE_EP_TYPE) {
|
||||
val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
|
||||
val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2);
|
||||
dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
|
||||
}
|
||||
|
||||
/* Program L0s and L1 entrance latencies */
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
|
||||
val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
|
||||
|
|
@ -767,6 +793,7 @@ static void tegra_pcie_enable_intx_interrupts(struct dw_pcie_rp *pp)
|
|||
val |= APPL_INTR_EN_L1_8_INTX_EN;
|
||||
val |= APPL_INTR_EN_L1_8_AUTO_BW_INT_EN;
|
||||
val |= APPL_INTR_EN_L1_8_BW_MGT_INT_EN;
|
||||
val |= APPL_INTR_EN_L1_8_EDMA_INT_EN;
|
||||
if (IS_ENABLED(CONFIG_PCIEAER))
|
||||
val |= APPL_INTR_EN_L1_8_AER_INT_EN;
|
||||
appl_writel(pcie, val, APPL_INTR_EN_L1_8_0);
|
||||
|
|
@ -924,6 +951,8 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
|
|||
}
|
||||
|
||||
clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
|
||||
if (clk_prepare_enable(pcie->core_clk_m))
|
||||
dev_err(pci->dev, "Failed to enable core monitor clock\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -996,6 +1025,12 @@ static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
|
|||
val &= ~PCI_DLF_EXCHANGE_ENABLE;
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_DLF_CAP, val);
|
||||
|
||||
/*
|
||||
* core_clk_m is enabled as part of host_init callback in
|
||||
* dw_pcie_host_init(). Disable the clock since below
|
||||
* tegra_pcie_dw_host_init() will enable it again.
|
||||
*/
|
||||
clk_disable_unprepare(pcie->core_clk_m);
|
||||
tegra_pcie_dw_host_init(pp);
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
|
|
@ -1022,7 +1057,8 @@ static void tegra_pcie_dw_stop_link(struct dw_pcie *pci)
|
|||
{
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
|
||||
disable_irq(pcie->pex_rst_irq);
|
||||
if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
|
||||
disable_irq(pcie->pex_rst_irq);
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops tegra_dw_pcie_ops = {
|
||||
|
|
@ -1058,6 +1094,9 @@ static int tegra_pcie_enable_phy(struct tegra_pcie_dw *pcie)
|
|||
ret = phy_power_on(pcie->phys[i]);
|
||||
if (ret < 0)
|
||||
goto phy_exit;
|
||||
|
||||
if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
|
||||
phy_calibrate(pcie->phys[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1163,9 +1202,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
|
|||
return err;
|
||||
}
|
||||
|
||||
pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev,
|
||||
"nvidia,refclk-select",
|
||||
GPIOD_OUT_HIGH);
|
||||
pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev,
|
||||
"nvidia,refclk-select",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(pcie->pex_refclk_sel_gpiod)) {
|
||||
int err = PTR_ERR(pcie->pex_refclk_sel_gpiod);
|
||||
const char *level = KERN_ERR;
|
||||
|
|
@ -1255,44 +1294,6 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
struct dw_pcie_rp *pp = &pcie->pci.pp;
|
||||
struct pci_bus *child, *root_port_bus = NULL;
|
||||
struct pci_dev *pdev;
|
||||
|
||||
/*
|
||||
* link doesn't go into L2 state with some of the endpoints with Tegra
|
||||
* if they are not in D0 state. So, need to make sure that immediate
|
||||
* downstream devices are in D0 state before sending PME_TurnOff to put
|
||||
* link into L2 state.
|
||||
* This is as per PCI Express Base r4.0 v1.0 September 27-2017,
|
||||
* 5.2 Link State Power Management (Page #428).
|
||||
*/
|
||||
|
||||
list_for_each_entry(child, &pp->bridge->bus->children, node) {
|
||||
if (child->parent == pp->bridge->bus) {
|
||||
root_port_bus = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!root_port_bus) {
|
||||
dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Bring downstream devices to D0 if they are not already in */
|
||||
list_for_each_entry(pdev, &root_port_bus->devices, bus_list) {
|
||||
if (PCI_SLOT(pdev->devfn) == 0) {
|
||||
if (pci_set_power_state(pdev, PCI_D0))
|
||||
dev_err(pcie->dev,
|
||||
"Failed to transition %s to D0 state\n",
|
||||
dev_name(&pdev->dev));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int tegra_pcie_get_slot_regulators(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
pcie->slot_ctl_3v3 = devm_regulator_get_optional(pcie->dev, "vpcie3v3");
|
||||
|
|
@ -1454,6 +1455,7 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
|
|||
val = appl_readl(pcie, APPL_PINMUX);
|
||||
val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN;
|
||||
val &= ~APPL_PINMUX_CLKREQ_OVERRIDE;
|
||||
val &= ~APPL_PINMUX_CLKREQ_DEFAULT_VALUE;
|
||||
appl_writel(pcie, val, APPL_PINMUX);
|
||||
}
|
||||
|
||||
|
|
@ -1553,9 +1555,10 @@ static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
|
|||
val |= APPL_PM_XMT_TURNOFF_STATE;
|
||||
appl_writel(pcie, val, APPL_RADM_STATUS);
|
||||
|
||||
return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val,
|
||||
val & APPL_DEBUG_PM_LINKST_IN_L2_LAT,
|
||||
1, PME_ACK_TIMEOUT);
|
||||
return readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val,
|
||||
val & APPL_DEBUG_PM_LINKST_IN_L2_LAT,
|
||||
PCIE_PME_TO_L2_TIMEOUT_US/10,
|
||||
PCIE_PME_TO_L2_TIMEOUT_US);
|
||||
}
|
||||
|
||||
static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
|
||||
|
|
@ -1590,23 +1593,22 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
|
|||
data &= ~APPL_PINMUX_PEX_RST;
|
||||
appl_writel(pcie, data, APPL_PINMUX);
|
||||
|
||||
err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data,
|
||||
((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) ||
|
||||
((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) ||
|
||||
((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) ||
|
||||
((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT),
|
||||
LTSSM_DELAY_US, LTSSM_TIMEOUT_US);
|
||||
if (err)
|
||||
dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err);
|
||||
|
||||
/*
|
||||
* Some cards do not go to detect state even after de-asserting
|
||||
* PERST#. So, de-assert LTSSM to bring link to detect state.
|
||||
* Deassert LTSSM state to stop the state toggling between
|
||||
* Polling and Detect.
|
||||
*/
|
||||
data = readl(pcie->appl_base + APPL_CTRL);
|
||||
data &= ~APPL_CTRL_LTSSM_EN;
|
||||
writel(data, pcie->appl_base + APPL_CTRL);
|
||||
|
||||
err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
|
||||
data,
|
||||
((data &
|
||||
APPL_DEBUG_LTSSM_STATE_MASK) >>
|
||||
APPL_DEBUG_LTSSM_STATE_SHIFT) ==
|
||||
LTSSM_STATE_PRE_DETECT,
|
||||
1, LTSSM_TIMEOUT);
|
||||
if (err)
|
||||
dev_info(pcie->dev, "Link didn't go to detect state\n");
|
||||
}
|
||||
/*
|
||||
* DBI registers may not be accessible after this as PLL-E would be
|
||||
|
|
@ -1622,7 +1624,7 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
|
|||
|
||||
static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
tegra_pcie_downstream_dev_to_D0(pcie);
|
||||
clk_disable_unprepare(pcie->core_clk_m);
|
||||
dw_pcie_host_deinit(&pcie->pci.pp);
|
||||
tegra_pcie_dw_pme_turnoff(pcie);
|
||||
tegra_pcie_unconfig_controller(pcie);
|
||||
|
|
@ -1680,19 +1682,24 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie)
|
|||
if (pcie->ep_state == EP_STATE_DISABLED)
|
||||
return;
|
||||
|
||||
/* Disable LTSSM */
|
||||
ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val,
|
||||
((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) ||
|
||||
((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) ||
|
||||
((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) ||
|
||||
((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT) ||
|
||||
((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_L2_IDLE),
|
||||
LTSSM_DELAY_US, LTSSM_TIMEOUT_US);
|
||||
if (ret)
|
||||
dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret);
|
||||
|
||||
/*
|
||||
* Deassert LTSSM state to stop the state toggling between
|
||||
* Polling and Detect.
|
||||
*/
|
||||
val = appl_readl(pcie, APPL_CTRL);
|
||||
val &= ~APPL_CTRL_LTSSM_EN;
|
||||
appl_writel(pcie, val, APPL_CTRL);
|
||||
|
||||
ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val,
|
||||
((val & APPL_DEBUG_LTSSM_STATE_MASK) >>
|
||||
APPL_DEBUG_LTSSM_STATE_SHIFT) ==
|
||||
LTSSM_STATE_PRE_DETECT,
|
||||
1, LTSSM_TIMEOUT);
|
||||
if (ret)
|
||||
dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret);
|
||||
|
||||
reset_control_assert(pcie->core_rst);
|
||||
|
||||
tegra_pcie_disable_phy(pcie);
|
||||
|
|
@ -1771,10 +1778,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
|
|||
goto fail_phy;
|
||||
}
|
||||
|
||||
/* Perform cleanup that requires refclk */
|
||||
pci_epc_deinit_notify(pcie->pci.ep.epc);
|
||||
dw_pcie_ep_cleanup(&pcie->pci.ep);
|
||||
|
||||
/* Clear any stale interrupt statuses */
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0);
|
||||
|
|
@ -1803,6 +1806,8 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
|
|||
val = appl_readl(pcie, APPL_CTRL);
|
||||
val |= APPL_CTRL_SYS_PRE_DET_STATE;
|
||||
val |= APPL_CTRL_HW_HOT_RST_EN;
|
||||
val &= ~(APPL_CTRL_HW_HOT_RST_MODE_MASK << APPL_CTRL_HW_HOT_RST_MODE_SHIFT);
|
||||
val |= (APPL_CTRL_HW_HOT_RST_MODE_IMDT_RST_LTSSM_EN << APPL_CTRL_HW_HOT_RST_MODE_SHIFT);
|
||||
appl_writel(pcie, val, APPL_CTRL);
|
||||
|
||||
val = appl_readl(pcie, APPL_CFG_MISC);
|
||||
|
|
@ -1826,6 +1831,7 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
|
|||
val |= APPL_INTR_EN_L0_0_SYS_INTR_EN;
|
||||
val |= APPL_INTR_EN_L0_0_LINK_STATE_INT_EN;
|
||||
val |= APPL_INTR_EN_L0_0_PCI_CMD_EN_INT_EN;
|
||||
val |= APPL_INTR_EN_L0_0_INT_INT_EN;
|
||||
appl_writel(pcie, val, APPL_INTR_EN_L0_0);
|
||||
|
||||
val = appl_readl(pcie, APPL_INTR_EN_L1_0_0);
|
||||
|
|
@ -1833,8 +1839,29 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
|
|||
val |= APPL_INTR_EN_L1_0_0_RDLH_LINK_UP_INT_EN;
|
||||
appl_writel(pcie, val, APPL_INTR_EN_L1_0_0);
|
||||
|
||||
val = appl_readl(pcie, APPL_INTR_EN_L1_8_0);
|
||||
val |= APPL_INTR_EN_L1_8_EDMA_INT_EN;
|
||||
appl_writel(pcie, val, APPL_INTR_EN_L1_8_0);
|
||||
|
||||
/* 110us for both snoop and no-snoop */
|
||||
val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) |
|
||||
FIELD_PREP(PCI_LTR_SCALE_MASK, 2) |
|
||||
LTR_MSG_REQ |
|
||||
FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) |
|
||||
FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) |
|
||||
LTR_NOSNOOP_MSG_REQ;
|
||||
appl_writel(pcie, val, APPL_LTR_MSG_1);
|
||||
|
||||
reset_control_deassert(pcie->core_rst);
|
||||
|
||||
/* Perform cleanup that requires refclk and core reset deasserted */
|
||||
pci_epc_deinit_notify(pcie->pci.ep.epc);
|
||||
dw_pcie_ep_cleanup(&pcie->pci.ep);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
|
||||
if (pcie->update_fc_fixup) {
|
||||
val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF);
|
||||
val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT;
|
||||
|
|
@ -2170,6 +2197,11 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(pcie->core_clk);
|
||||
}
|
||||
|
||||
pcie->core_clk_m = devm_clk_get_optional(dev, "core_m");
|
||||
if (IS_ERR(pcie->core_clk_m))
|
||||
return dev_err_probe(dev, PTR_ERR(pcie->core_clk_m),
|
||||
"Failed to get monitor clock\n");
|
||||
|
||||
pcie->appl_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"appl");
|
||||
if (!pcie->appl_res) {
|
||||
|
|
@ -2269,7 +2301,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
|||
ret = devm_request_threaded_irq(dev, pp->irq,
|
||||
tegra_pcie_ep_hard_irq,
|
||||
tegra_pcie_ep_irq_thread,
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
IRQF_SHARED,
|
||||
"tegra-pcie-ep-intr", pcie);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq,
|
||||
|
|
@ -2298,6 +2330,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
|||
static void tegra_pcie_dw_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev);
|
||||
struct dw_pcie_ep *ep = &pcie->pci.ep;
|
||||
|
||||
if (pcie->of_data->mode == DW_PCIE_RC_TYPE) {
|
||||
if (!pcie->link_state)
|
||||
|
|
@ -2309,6 +2342,7 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev)
|
|||
} else {
|
||||
disable_irq(pcie->pex_rst_irq);
|
||||
pex_ep_event_pex_rst_assert(pcie);
|
||||
dw_pcie_ep_deinit(ep);
|
||||
}
|
||||
|
||||
pm_runtime_disable(pcie->dev);
|
||||
|
|
@ -2317,16 +2351,28 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev)
|
|||
gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0);
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
|
||||
|
||||
if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
|
||||
if (pcie->ep_state == EP_STATE_ENABLED) {
|
||||
dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
disable_irq(pcie->pex_rst_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_suspend_late(struct device *dev)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
|
||||
u32 val;
|
||||
|
||||
if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
|
||||
dev_err(dev, "Failed to Suspend as Tegra PCIe is in EP mode\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (!pcie->link_state)
|
||||
return 0;
|
||||
|
||||
|
|
@ -2346,10 +2392,13 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
|
|||
{
|
||||
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
|
||||
|
||||
if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
|
||||
return 0;
|
||||
|
||||
if (!pcie->link_state)
|
||||
return 0;
|
||||
|
||||
tegra_pcie_downstream_dev_to_D0(pcie);
|
||||
clk_disable_unprepare(pcie->core_clk_m);
|
||||
tegra_pcie_dw_pme_turnoff(pcie);
|
||||
tegra_pcie_unconfig_controller(pcie);
|
||||
|
||||
|
|
@ -2361,6 +2410,9 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
|
|||
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
|
||||
return 0;
|
||||
|
||||
if (!pcie->link_state)
|
||||
return 0;
|
||||
|
||||
|
|
@ -2393,8 +2445,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev)
|
|||
u32 val;
|
||||
|
||||
if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
|
||||
dev_err(dev, "Suspend is not supported in EP mode");
|
||||
return -ENOTSUPP;
|
||||
enable_irq(pcie->pex_rst_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pcie->link_state)
|
||||
|
|
@ -2423,7 +2475,6 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev)
|
|||
return;
|
||||
|
||||
debugfs_remove_recursive(pcie->debugfs);
|
||||
tegra_pcie_downstream_dev_to_D0(pcie);
|
||||
|
||||
disable_irq(pcie->pci.pp.irq);
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
|
|
@ -2473,6 +2524,7 @@ static const struct tegra_pcie_dw_of_data tegra234_pcie_dw_ep_of_data = {
|
|||
.mode = DW_PCIE_EP_TYPE,
|
||||
.has_l1ss_exit_fix = true,
|
||||
.has_ltr_req_fix = true,
|
||||
.disable_l1_2 = true,
|
||||
.cdm_chk_int_en_bit = BIT(18),
|
||||
/* Gen4 - 6, 8 and 9 presets enabled */
|
||||
.gen4_preset_vec = 0x340,
|
||||
|
|
@ -2500,6 +2552,7 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = {
|
|||
};
|
||||
|
||||
static const struct dev_pm_ops tegra_pcie_dw_pm_ops = {
|
||||
.suspend = tegra_pcie_dw_suspend,
|
||||
.suspend_late = tegra_pcie_dw_suspend_late,
|
||||
.suspend_noirq = tegra_pcie_dw_suspend_noirq,
|
||||
.resume_noirq = tegra_pcie_dw_resume_noirq,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user