/* * NOTE:- Since this scenario is uncommon and link as such is not * stable anyway, not waiting to confirm if link is really * transitioning to Gen-2 speed
*/
val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA); if (val & PCI_EXP_LNKSTA_LBMS) {
current_link_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val); if (pcie->init_link_width > current_link_width) {
dev_warn(pci->dev, "PCIe link is bad, width reduced\n");
val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
PCI_EXP_LNKCTL2);
val &= ~PCI_EXP_LNKCTL2_TLS;
val |= PCI_EXP_LNKCTL2_TLS_2_5GT;
dw_pcie_writew_dbi(pci, pcie->pcie_cap_base +
PCI_EXP_LNKCTL2, val);
val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
PCI_EXP_LNKCTL);
val |= PCI_EXP_LNKCTL_RL;
dw_pcie_writew_dbi(pci, pcie->pcie_cap_base +
PCI_EXP_LNKCTL, val);
}
}
}
if (test_and_clear_bit(0, &pcie->link_status))
dw_pcie_ep_linkup(ep);
tegra_pcie_icc_set(pcie);
if (pcie->of_data->has_ltr_req_fix) return IRQ_HANDLED;
/* If EP doesn't advertise L1SS, just return */
val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub); if (!(val & (PCI_L1SS_CAP_ASPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_2))) return IRQ_HANDLED;
/* Check if BME is set to '1' */
val = dw_pcie_readl_dbi(pci, PCI_COMMAND); 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;
appl_writel(pcie, val, APPL_LTR_MSG_2);
timeout = ktime_add_us(ktime_get(), LTR_MSG_TIMEOUT); for (;;) {
val = appl_readl(pcie, APPL_LTR_MSG_2); if (!(val & APPL_LTR_MSG_2_LTR_MSG_REQ_STATE)) break; if (ktime_after(ktime_get(), timeout)) break;
usleep_range(1000, 1100);
} if (val & APPL_LTR_MSG_2_LTR_MSG_REQ_STATE)
dev_err(pcie->dev, "Failed to send LTR message\n");
}
/* * This is an endpoint mode specific register happen to appear even * when controller is operating in root port mode and system hangs * when it is accessed with link being in ASPM-L1 state. * So skip accessing it altogether
*/ if (!pcie->of_data->has_msix_doorbell_access_fix &&
!PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL) {
*val = 0x00000000; return PCIBIOS_SUCCESSFUL;
}
/* * This is an endpoint mode specific register happen to appear even * when controller is operating in root port mode and system hangs * when it is accessed with link being in ASPM-L1 state. * So skip accessing it altogether
*/ if (!pcie->of_data->has_msix_doorbell_access_fix &&
!PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL) return PCIBIOS_SUCCESSFUL;
/* Enable ASPM counters */
val = EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT;
val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT;
dw_pcie_writel_dbi(pci, pcie->ras_des_cap +
PCIE_RAS_DES_EVENT_COUNTER_CONTROL, val);
/* Program T_cmrt and T_pwr_on values */
val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
val &= ~(PCI_L1SS_CAP_CM_RESTORE_TIME | PCI_L1SS_CAP_P_PWR_ON_VALUE);
val |= (pcie->aspm_cmrt << 8);
val |= (pcie->aspm_pwr_on_t << 19);
dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
/* Program L0s and L1 entrance latencies */
val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
val |= (pcie->aspm_l0s_enter_lat << PORT_AFR_L0S_ENTRANCE_LAT_SHIFT);
val |= PORT_AFR_ENTER_ASPM;
dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
}
val = appl_readl(pcie, APPL_INTR_EN_L0_0);
val |= APPL_INTR_EN_L0_0_LINK_STATE_INT_EN;
appl_writel(pcie, val, APPL_INTR_EN_L0_0);
if (!pcie->of_data->has_sbr_reset_fix) {
val = appl_readl(pcie, APPL_INTR_EN_L1_0_0);
val |= APPL_INTR_EN_L1_0_0_LINK_REQ_RST_NOT_INT_EN;
appl_writel(pcie, val, APPL_INTR_EN_L1_0_0);
}
if (pcie->enable_cdm_check) {
val = appl_readl(pcie, APPL_INTR_EN_L0_0);
val |= pcie->of_data->cdm_chk_int_en_bit;
appl_writel(pcie, val, APPL_INTR_EN_L0_0);
val = appl_readl(pcie, APPL_INTR_EN_L1_18);
val |= APPL_INTR_EN_L1_18_CDM_REG_CHK_CMP_ERR;
val |= APPL_INTR_EN_L1_18_CDM_REG_CHK_LOGIC_ERR;
appl_writel(pcie, val, APPL_INTR_EN_L1_18);
}
/* Enable INTX interrupt generation */
val = appl_readl(pcie, APPL_INTR_EN_L0_0);
val |= APPL_INTR_EN_L0_0_SYS_INTR_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_8_0);
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; if (IS_ENABLED(CONFIG_PCIEAER))
val |= APPL_INTR_EN_L1_8_AER_INT_EN;
appl_writel(pcie, val, APPL_INTR_EN_L1_8_0);
}
/* Program init preset */ for (i = 0; i < pcie->num_lanes; i++) {
val = dw_pcie_readw_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2));
val &= ~CAP_SPCIE_CAP_OFF_DSP_TX_PRESET0_MASK;
val |= GEN3_GEN4_EQ_PRESET_INIT;
val &= ~CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK;
val |= (GEN3_GEN4_EQ_PRESET_INIT <<
CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT);
dw_pcie_writew_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2), val);
offset = dw_pcie_find_ext_capability(pci,
PCI_EXT_CAP_ID_PL_16GT) +
PCI_PL_16GT_LE_CTRL;
val = dw_pcie_readb_dbi(pci, offset + i);
val &= ~PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK;
val |= GEN3_GEN4_EQ_PRESET_INIT;
val &= ~PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK;
val |= (GEN3_GEN4_EQ_PRESET_INIT <<
PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT);
dw_pcie_writeb_dbi(pci, offset + i, val);
}
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
val &= ~GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC;
val |= FIELD_PREP(GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC, 0x3ff);
val &= ~GEN3_EQ_CONTROL_OFF_FB_MODE;
dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
val |= (0x1 << GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT);
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
val &= ~GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC;
val |= FIELD_PREP(GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC,
pcie->of_data->gen4_preset_vec);
val &= ~GEN3_EQ_CONTROL_OFF_FB_MODE;
dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
}
if (!pcie->pcie_cap_base)
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
PCI_CAP_ID_EXP);
val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
val = dw_pcie_readl_dbi(pci, PCI_PREF_MEMORY_BASE);
val |= CFG_PREF_MEM_LIMIT_BASE_MEM_DECODE;
val |= CFG_PREF_MEM_LIMIT_BASE_MEM_LIMIT_DECODE;
dw_pcie_writel_dbi(pci, PCI_PREF_MEMORY_BASE, val);
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
/* Enable as 0xFFFF0001 response for RRS */
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT);
val &= ~(AMBA_ERROR_RESPONSE_RRS_MASK << AMBA_ERROR_RESPONSE_RRS_SHIFT);
val |= (AMBA_ERROR_RESPONSE_RRS_OKAY_FFFF0001 <<
AMBA_ERROR_RESPONSE_RRS_SHIFT);
dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val);
/* Clear Slot Clock Configuration bit if SRNS configuration */ if (pcie->enable_srns) {
val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
PCI_EXP_LNKSTA);
val_16 &= ~PCI_EXP_LNKSTA_SLC;
dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA,
val_16);
}
config_gen3_gen4_eq_presets(pcie);
init_host_aspm(pcie);
/* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */ if (!pcie->supports_clkreq) {
disable_aspm_l11(pcie);
disable_aspm_l12(pcie);
}
if (!pcie->of_data->has_l1ss_exit_fix) {
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, 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;
dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val);
}
if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
enable_irq(pcie->pex_rst_irq); return 0;
}
retry_link: /* Assert RST */
val = appl_readl(pcie, APPL_PINMUX);
val &= ~APPL_PINMUX_PEX_RST;
appl_writel(pcie, val, APPL_PINMUX);
usleep_range(100, 200);
/* Enable LTSSM */
val = appl_readl(pcie, APPL_CTRL);
val |= APPL_CTRL_LTSSM_EN;
appl_writel(pcie, val, APPL_CTRL);
/* De-assert RST */
val = appl_readl(pcie, APPL_PINMUX);
val |= APPL_PINMUX_PEX_RST;
appl_writel(pcie, val, APPL_PINMUX);
msleep(100);
if (dw_pcie_wait_for_link(pci)) { if (!retry) return 0; /* * There are some endpoints which can't get the link up if * root port has Data Link Feature (DLF) enabled. * Refer Spec rev 4.0 ver 1.0 sec 3.4.2 & 7.7.4 for more info * on Scaled Flow Control and DLF. * So, need to confirm that is indeed the case here and attempt * link up once again with DLF disabled.
*/
val = appl_readl(pcie, APPL_DEBUG);
val &= APPL_DEBUG_LTSSM_STATE_MASK;
val >>= APPL_DEBUG_LTSSM_STATE_SHIFT;
tmp = appl_readl(pcie, APPL_LINK_STATUS);
tmp &= APPL_LINK_STATUS_RDLH_LINK_UP; if (!(val == 0x11 && !tmp)) { /* Link is down for all good reasons */ return 0;
}
dev_info(pci->dev, "Link is down in DLL");
dev_info(pci->dev, "Trying again with DLFE disabled\n"); /* Disable LTSSM */
val = appl_readl(pcie, APPL_CTRL);
val &= ~APPL_CTRL_LTSSM_EN;
appl_writel(pcie, val, APPL_CTRL);
pcie->dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); if (!pcie->dbi_res) {
dev_err(pcie->dev, "Failed to find \"dbi\" region\n"); return -ENODEV;
}
ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", &pcie->aspm_cmrt); if (ret < 0) {
dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret); return ret;
}
ret = of_property_read_u32(np, "nvidia,aspm-pwr-on-t-us",
&pcie->aspm_pwr_on_t); if (ret < 0)
dev_info(pcie->dev, "Failed to read ASPM Power On time: %d\n",
ret);
ret = of_property_read_u32(np, "nvidia,aspm-l0s-entrance-latency-us",
&pcie->aspm_l0s_enter_lat); if (ret < 0)
dev_info(pcie->dev, "Failed to read ASPM L0s Entrance latency: %d\n", ret);
ret = of_property_read_u32(np, "num-lanes", &pcie->num_lanes); if (ret < 0) {
dev_err(pcie->dev, "Failed to read num-lanes: %d\n", ret); return ret;
}
ret = of_property_read_u32_index(np, "nvidia,bpmp", 1, &pcie->cid); if (ret) {
dev_err(pcie->dev, "Failed to read Controller-ID: %d\n", ret); return ret;
}
ret = of_property_count_strings(np, "phy-names"); if (ret < 0) {
dev_err(pcie->dev, "Failed to find PHY entries: %d\n",
ret); return ret;
}
pcie->phy_count = ret;
if (of_property_read_bool(np, "nvidia,update-fc-fixup"))
pcie->update_fc_fixup = true;
/* RP using an external REFCLK is supported only in Tegra234 */ if (pcie->of_data->version == TEGRA194_DWC_IP_VER) { if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
pcie->enable_ext_refclk = true;
} else {
pcie->enable_ext_refclk =
of_property_read_bool(pcie->dev->of_node, "nvidia,enable-ext-refclk");
}
/* * Controller-5 doesn't need to have its state set by BPMP-FW in * Tegra194
*/ if (pcie->of_data->version == TEGRA194_DWC_IP_VER && pcie->cid == 5) return 0;
/* * 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) { /* Bring downstream devices to D0 if they are not already in */ if (child->parent == pp->bridge->bus) {
root_bus = child; break;
}
}
if (!root_bus) {
dev_err(pcie->dev, "Failed to find downstream devices\n"); return;
}
list_for_each_entry(pdev, &root_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));
}
}
}
staticint tegra_pcie_get_slot_regulators(struct tegra_pcie_dw *pcie)
{
pcie->slot_ctl_3v3 = devm_regulator_get_optional(pcie->dev, "vpcie3v3"); if (IS_ERR(pcie->slot_ctl_3v3)) { if (PTR_ERR(pcie->slot_ctl_3v3) != -ENODEV) return PTR_ERR(pcie->slot_ctl_3v3);
pcie->slot_ctl_3v3 = NULL;
}
pcie->slot_ctl_12v = devm_regulator_get_optional(pcie->dev, "vpcie12v"); if (IS_ERR(pcie->slot_ctl_12v)) { if (PTR_ERR(pcie->slot_ctl_12v) != -ENODEV) return PTR_ERR(pcie->slot_ctl_12v);
pcie->slot_ctl_12v = NULL;
}
return 0;
}
staticint tegra_pcie_enable_slot_regulators(struct tegra_pcie_dw *pcie)
{ int ret;
if (pcie->slot_ctl_3v3) {
ret = regulator_enable(pcie->slot_ctl_3v3); if (ret < 0) {
dev_err(pcie->dev, "Failed to enable 3.3V slot supply: %d\n", ret); return ret;
}
}
if (pcie->slot_ctl_12v) {
ret = regulator_enable(pcie->slot_ctl_12v); if (ret < 0) {
dev_err(pcie->dev, "Failed to enable 12V slot supply: %d\n", ret); goto fail_12v_enable;
}
}
/* * According to PCI Express Card Electromechanical Specification * Revision 1.1, Table-2.4, T_PVPERL (Power stable to PERST# inactive) * should be a minimum of 100ms.
*/ if (pcie->slot_ctl_3v3 || pcie->slot_ctl_12v)
msleep(100);
return 0;
fail_12v_enable: if (pcie->slot_ctl_3v3)
regulator_disable(pcie->slot_ctl_3v3); return ret;
}
staticvoid tegra_pcie_disable_slot_regulators(struct tegra_pcie_dw *pcie)
{ if (pcie->slot_ctl_12v)
regulator_disable(pcie->slot_ctl_12v); if (pcie->slot_ctl_3v3)
regulator_disable(pcie->slot_ctl_3v3);
}
/* Configure this core for RP mode operation */
appl_writel(pcie, APPL_DM_TYPE_RP, APPL_DM_TYPE);
appl_writel(pcie, 0x0, APPL_CFG_SLCG_OVERRIDE);
val = appl_readl(pcie, APPL_CTRL);
appl_writel(pcie, val | APPL_CTRL_SYS_PRE_DET_STATE, APPL_CTRL);
val = appl_readl(pcie, APPL_CFG_MISC);
val |= (APPL_CFG_MISC_ARCACHE_VAL << APPL_CFG_MISC_ARCACHE_SHIFT);
appl_writel(pcie, val, APPL_CFG_MISC);
if (pcie->enable_srns || pcie->enable_ext_refclk) { /* * When Tegra PCIe RP is using external clock, it cannot supply * same clock to its downstream hierarchy. Hence, gate PCIe RP * REFCLK out pads when RP & EP are using separate clocks or RP * is using an external REFCLK.
*/
val = appl_readl(pcie, APPL_PINMUX);
val |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN;
val &= ~APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE;
appl_writel(pcie, val, APPL_PINMUX);
}
if (!pcie->supports_clkreq) {
val = appl_readl(pcie, APPL_PINMUX);
val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN;
val &= ~APPL_PINMUX_CLKREQ_OVERRIDE;
appl_writel(pcie, val, APPL_PINMUX);
}
staticvoid tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
{
u32 data; int err;
if (!tegra_pcie_dw_link_up(&pcie->pci)) {
dev_dbg(pcie->dev, "PCIe link is not up...!\n"); return;
}
/* * PCIe controller exits from L2 only if reset is applied, so * controller doesn't handle interrupts. But in cases where * L2 entry fails, PERST# is asserted which can trigger surprise * link down AER. However this function call happens in * suspend_noirq(), so AER interrupt will not be processed. * Disable all interrupts to avoid such a scenario.
*/
appl_writel(pcie, 0x0, APPL_INTR_EN_L0_0);
if (tegra_pcie_try_link_l2(pcie)) {
dev_info(pcie->dev, "Link didn't transition to L2 state\n"); /* * TX lane clock freq will reset to Gen1 only if link is in L2 * or detect state. * So apply pex_rst to end point to force RP to go into detect * state
*/
data = appl_readl(pcie, APPL_PINMUX);
data &= ~APPL_PINMUX_PEX_RST;
appl_writel(pcie, data, APPL_PINMUX);
/* * Some cards do not go to detect state even after de-asserting * PERST#. So, de-assert LTSSM to bring link to detect state.
*/
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 * down depending on how CLKREQ is pulled by end point
*/
data = appl_readl(pcie, APPL_PINMUX);
data |= (APPL_PINMUX_CLKREQ_OVERRIDE_EN | APPL_PINMUX_CLKREQ_OVERRIDE); /* Cut REFCLK to slot */
data |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN;
data &= ~APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE;
appl_writel(pcie, data, APPL_PINMUX);
}
ret = pm_runtime_resume_and_get(dev); if (ret < 0) {
dev_err(dev, "Failed to get runtime sync for PCIe dev: %d\n",
ret); return;
}
ret = tegra_pcie_bpmp_set_ctrl_state(pcie, true); if (ret) {
dev_err(pcie->dev, "Failed to enable controller %u: %d\n",
pcie->cid, ret); goto fail_set_ctrl_state;
}
if (pcie->enable_ext_refclk) {
ret = tegra_pcie_bpmp_set_pll_state(pcie, true); if (ret) {
dev_err(dev, "Failed to init UPHY for PCIe EP: %d\n",
ret); goto fail_pll_init;
}
}
ret = clk_prepare_enable(pcie->core_clk); if (ret) {
dev_err(dev, "Failed to enable core clock: %d\n", ret); goto fail_core_clk_enable;
}
ret = reset_control_deassert(pcie->core_apb_rst); if (ret) {
dev_err(dev, "Failed to deassert core APB reset: %d\n", ret); goto fail_core_apb_rst;
}
ret = tegra_pcie_enable_phy(pcie); if (ret) {
dev_err(dev, "Failed to enable PHY: %d\n", ret); goto fail_phy;
}
/* Perform cleanup that requires refclk */
pci_epc_deinit_notify(pcie->pci.ep.epc);
dw_pcie_ep_cleanup(&pcie->pci.ep);
/* configure this core for EP mode operation */
val = appl_readl(pcie, APPL_DM_TYPE);
val &= ~APPL_DM_TYPE_MASK;
val |= APPL_DM_TYPE_EP;
appl_writel(pcie, val, APPL_DM_TYPE);
appl_writel(pcie, 0x0, APPL_CFG_SLCG_OVERRIDE);
val = appl_readl(pcie, APPL_CTRL);
val |= APPL_CTRL_SYS_PRE_DET_STATE;
val |= APPL_CTRL_HW_HOT_RST_EN;
appl_writel(pcie, val, APPL_CTRL);
val = appl_readl(pcie, APPL_CFG_MISC);
val |= APPL_CFG_MISC_SLV_EP_MODE;
val |= (APPL_CFG_MISC_ARCACHE_VAL << APPL_CFG_MISC_ARCACHE_SHIFT);
appl_writel(pcie, val, APPL_CFG_MISC);
val = appl_readl(pcie, APPL_PINMUX);
val |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN;
val |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE;
appl_writel(pcie, val, APPL_PINMUX);
val = appl_readl(pcie, APPL_INTR_EN_L0_0);
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;
appl_writel(pcie, val, APPL_INTR_EN_L0_0);
val = appl_readl(pcie, APPL_INTR_EN_L1_0_0);
val |= APPL_INTR_EN_L1_0_0_HOT_RESET_DONE_INT_EN;
val |= APPL_INTR_EN_L1_0_0_RDLH_LINK_UP_INT_EN;
appl_writel(pcie, val, APPL_INTR_EN_L1_0_0);
reset_control_deassert(pcie->core_rst);
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;
dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val);
}
config_gen3_gen4_eq_presets(pcie);
init_host_aspm(pcie);
/* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */ if (!pcie->supports_clkreq) {
disable_aspm_l11(pcie);
disable_aspm_l12(pcie);
}
if (!pcie->of_data->has_l1ss_exit_fix) {
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
}
/* Clear Slot Clock Configuration bit if SRNS configuration */ if (pcie->enable_srns) {
val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
PCI_EXP_LNKSTA);
val_16 &= ~PCI_EXP_LNKSTA_SLC;
dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA,
val_16);
}
clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
val = (ep->msi_mem_phys & MSIX_ADDR_MATCH_LOW_OFF_MASK);
val |= MSIX_ADDR_MATCH_LOW_OFF_EN;
dw_pcie_writel_dbi(pci, MSIX_ADDR_MATCH_LOW_OFF, val);
val = (upper_32_bits(ep->msi_mem_phys) & MSIX_ADDR_MATCH_HIGH_OFF_MASK);
dw_pcie_writel_dbi(pci, MSIX_ADDR_MATCH_HIGH_OFF, val);
ret = dw_pcie_ep_init_registers(ep); if (ret) {
dev_err(dev, "Failed to complete initialization: %d\n", ret); goto fail_init_complete;
}
pci_epc_init_notify(ep->epc);
/* Program the private control to allow sending LTR upstream */ if (pcie->of_data->has_ltr_req_fix) {
val = appl_readl(pcie, APPL_LTR_MSG_2);
val |= APPL_LTR_MSG_2_LTR_MSG_REQ_STATE;
appl_writel(pcie, val, APPL_LTR_MSG_2);
}
/* Enable LTSSM */
val = appl_readl(pcie, APPL_CTRL);
val |= APPL_CTRL_LTSSM_EN;
appl_writel(pcie, val, APPL_CTRL);
pcie->ep_state = EP_STATE_ENABLED;
dev_dbg(dev, "Initialization of endpoint is completed\n");
ret = gpiod_set_debounce(pcie->pex_rst_gpiod, PERST_DEBOUNCE_TIME); if (ret < 0) {
dev_err(dev, "Failed to set PERST GPIO debounce time: %d\n",
ret); return ret;
}
ret = gpiod_to_irq(pcie->pex_rst_gpiod); if (ret < 0) {
dev_err(dev, "Failed to get IRQ for PERST GPIO: %d\n", ret); return ret;
}
pcie->pex_rst_irq = (unsignedint)ret;
name = devm_kasprintf(dev, GFP_KERNEL, "tegra_pcie_%u_pex_rst_irq",
pcie->cid); if (!name) {
dev_err(dev, "Failed to create PERST IRQ string\n"); return -ENOMEM;
}
ret = tegra_pcie_get_slot_regulators(pcie); if (ret < 0) { constchar *level = KERN_ERR;
if (ret == -EPROBE_DEFER)
level = KERN_DEBUG;
dev_printk(level, dev,
dev_fmt("Failed to get slot regulators: %d\n"),
ret); return ret;
}
if (pcie->pex_refclk_sel_gpiod)
gpiod_set_value(pcie->pex_refclk_sel_gpiod, 1);
pcie->pex_ctl_supply = devm_regulator_get(dev, "vddio-pex-ctl"); if (IS_ERR(pcie->pex_ctl_supply)) {
ret = PTR_ERR(pcie->pex_ctl_supply); if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get regulator: %ld\n",
PTR_ERR(pcie->pex_ctl_supply)); return ret;
}
pcie->core_clk = devm_clk_get(dev, "core"); if (IS_ERR(pcie->core_clk)) {
dev_err(dev, "Failed to get core clock: %ld\n",
PTR_ERR(pcie->core_clk)); return PTR_ERR(pcie->core_clk);
}
pcie->appl_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "appl"); if (!pcie->appl_res) {
dev_err(dev, "Failed to find \"appl\" region\n"); return -ENODEV;
}
pcie->appl_base = devm_ioremap_resource(dev, pcie->appl_res); if (IS_ERR(pcie->appl_base)) return PTR_ERR(pcie->appl_base);
pcie->core_apb_rst = devm_reset_control_get(dev, "apb"); if (IS_ERR(pcie->core_apb_rst)) {
dev_err(dev, "Failed to get APB reset: %ld\n",
PTR_ERR(pcie->core_apb_rst)); return PTR_ERR(pcie->core_apb_rst);
}
phys = devm_kcalloc(dev, pcie->phy_count, sizeof(*phys), GFP_KERNEL); if (!phys) return -ENOMEM;
for (i = 0; i < pcie->phy_count; i++) {
name = kasprintf(GFP_KERNEL, "p2u-%u", i); if (!name) {
dev_err(dev, "Failed to create P2U string\n"); return -ENOMEM;
}
phys[i] = devm_phy_get(dev, name);
kfree(name); if (IS_ERR(phys[i])) {
ret = PTR_ERR(phys[i]); if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get PHY: %d\n", ret); return ret;
}
}
pcie->phys = phys;
atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu_dma"); if (!atu_dma_res) {
dev_err(dev, "Failed to find \"atu_dma\" region\n"); return -ENODEV;
}
pcie->atu_dma_res = atu_dma_res;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.