/* * Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit * entries, one entry per PCIe port. These field definitions and desired * values aren't in the TRM, but do come from NVIDIA.
*/ #define PADS_REFCLK_CFG_TERM_SHIFT 2 /* 6:2 */ #define PADS_REFCLK_CFG_E_TERM_SHIFT 7 #define PADS_REFCLK_CFG_PREDI_SHIFT 8 /* 11:8 */ #define PADS_REFCLK_CFG_DRVI_SHIFT 12 /* 15:12 */
#define PME_ACK_TIMEOUT 10000 #define LINK_RETRAIN_TIMEOUT 100000 /* in usec */
/* * The configuration space mapping on Tegra is somewhat similar to the ECAM * defined by PCIe. However it deviates a bit in how the 4 bits for extended * register accesses are mapped: * * [27:24] extended register number * [23:16] bus number * [15:11] device number * [10: 8] function number * [ 7: 0] register number * * Mapping the whole extended configuration space would require 256 MiB of * virtual address space, only a small part of which will actually be used. * * To work around this, a 4 KiB region is used to generate the required * configuration transaction with relevant B:D:F and register offset values. * This is achieved by dynamically programming base address and size of * AFI_AXI_BAR used for end point config space mapping to make sure that the * address (access to which generates correct config transaction) falls in * this 4 KiB region.
*/ staticunsignedint tegra_pcie_conf_offset(u8 bus, unsignedint devfn, unsignedint where)
{ return ((where & 0xf00) << 16) | (bus << 16) | (PCI_SLOT(devfn) << 11) |
(PCI_FUNC(devfn) << 8) | (where & 0xff);
}
/* 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;
}
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);
}
/* * 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);
}
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);
}
/* assert port reset */
value = afi_readl(port->pcie, ctrl);
value &= ~AFI_PEX_CTRL_RST;
afi_writel(port->pcie, value, ctrl);
/* disable reference clock */
value = afi_readl(port->pcie, ctrl);
if (soc->has_pex_clkreq_en)
value &= ~AFI_PEX_CTRL_CLKREQ_EN;
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);
}
/* * do not pollute kernel log with master abort reports since they * happen a lot during enumeration
*/ 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);
if (res->flags & IORESOURCE_PREFETCH) { /* Bar 2: prefetchable memory BAR */
afi_writel(pcie, axi_address, AFI_AXI_BAR2_START);
afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ);
afi_writel(pcie, fpci_bar, AFI_FPCI_BAR2);
} else { /* Bar 3: non prefetchable memory BAR */
afi_writel(pcie, axi_address, AFI_AXI_BAR3_START);
afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ);
afi_writel(pcie, fpci_bar, AFI_FPCI_BAR3);
} break;
}
}
/* NULL out the remaining BARs as they are not used */
afi_writel(pcie, 0, AFI_AXI_BAR4_START);
afi_writel(pcie, 0, AFI_AXI_BAR4_SZ);
afi_writel(pcie, 0, AFI_FPCI_BAR4);
/* initialize internal PHY, enable up to 16 PCIE lanes */
pads_writel(pcie, 0x0, PADS_CTL_SEL);
/* override IDDQ to 1 on all 4 lanes */
value = pads_readl(pcie, PADS_CTL);
value |= PADS_CTL_IDDQ_1L;
pads_writel(pcie, value, PADS_CTL);
/* * Set up PHY PLL inputs select PLLE output as refclock, * set TX ref sel to div10 (not div5).
*/
value = pads_readl(pcie, soc->pads_pll_ctl);
value &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel;
pads_writel(pcie, value, soc->pads_pll_ctl);
/* reset PLL */
value = pads_readl(pcie, soc->pads_pll_ctl);
value &= ~PADS_PLL_CTL_RST_B4SM;
pads_writel(pcie, value, soc->pads_pll_ctl);
usleep_range(20, 100);
/* take PLL out of reset */
value = pads_readl(pcie, soc->pads_pll_ctl);
value |= PADS_PLL_CTL_RST_B4SM;
pads_writel(pcie, value, soc->pads_pll_ctl);
/* wait for the PLL to lock */
err = tegra_pcie_pll_wait(pcie, 500); if (err < 0) {
dev_err(dev, "PLL failed to lock: %d\n", err); return err;
}
/* turn off IDDQ override */
value = pads_readl(pcie, PADS_CTL);
value &= ~PADS_CTL_IDDQ_1L;
pads_writel(pcie, value, PADS_CTL);
/* enable TX/RX data */
value = pads_readl(pcie, PADS_CTL);
value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L;
pads_writel(pcie, value, PADS_CTL);
for (i = 0; i < port->lanes; i++) {
err = phy_power_on(port->phys[i]); if (err < 0) {
dev_err(dev, "failed to power on PHY#%u: %d\n", i, err); return err;
}
}
for (i = 0; i < port->lanes; i++) {
err = phy_power_off(port->phys[i]); if (err < 0) {
dev_err(dev, "failed to power off PHY#%u: %d\n", i,
err); return err;
}
}
/* enable PLL power down */ if (pcie->phy) {
value = afi_readl(pcie, AFI_PLLE_CONTROL);
value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
afi_writel(pcie, value, AFI_PLLE_CONTROL);
}
/* power down PCIe slot clock bias pad */ if (soc->has_pex_bias_ctrl)
afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
/* configure mode and disable all ports */
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) {
value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
value &= ~AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index);
}
afi_writel(pcie, value, AFI_PCIE_CONFIG);
if (soc->has_gen2) {
value = afi_readl(pcie, AFI_FUSE);
value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
afi_writel(pcie, value, AFI_FUSE);
} else {
value = afi_readl(pcie, AFI_FUSE);
value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
afi_writel(pcie, value, AFI_FUSE);
}
/* 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);
port->phys = devm_kcalloc(dev, port->lanes, sizeof(phy), GFP_KERNEL); if (!port->phys) return -ENOMEM;
for (i = 0; i < port->lanes; i++) {
phy = devm_of_phy_optional_get_index(dev, port->np, "pcie", i); if (IS_ERR(phy)) {
dev_err(dev, "failed to get PHY#%u: %ld\n", i,
PTR_ERR(phy)); return PTR_ERR(phy);
}
err = phy_init(phy); if (err < 0) {
dev_err(dev, "failed to initialize PHY#%u: %d\n", i,
err); return err;
}
val = afi_readl(pcie, AFI_PCIE_PME);
val |= (0x1 << soc->ports[port->index].pme.turnoff_bit);
afi_writel(pcie, val, AFI_PCIE_PME);
ack_bit = soc->ports[port->index].pme.ack_bit;
err = readl_poll_timeout(pcie->afi + AFI_PCIE_PME, val,
val & (0x1 << ack_bit), 1, PME_ACK_TIMEOUT); if (err)
dev_err(pcie->dev, "PME Ack is not received on port: %d\n",
port->index);
usleep_range(10000, 11000);
val = afi_readl(pcie, AFI_PCIE_PME);
val &= ~(0x1 << soc->ports[port->index].pme.turnoff_bit);
afi_writel(pcie, val, AFI_PCIE_PME);
}
for (i = 0; i < nr_irqs; i++)
irq_domain_set_info(domain, virq + i, hwirq + i,
&tegra_msi_bottom_chip, domain->host_data,
handle_edge_irq, NULL, NULL);
/* Though the PCIe controller can address >32-bit address space, to * facilitate endpoints that support only 32-bit MSI target address, * the mask is set to 32-bit to make sure that MSI target address is * always a 32-bit address
*/
err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); if (err < 0) {
dev_err(dev, "failed to set DMA coherent mask: %d\n", err); goto free_irq;
}
msi->virt = dma_alloc_attrs(dev, PAGE_SIZE, &msi->phys, GFP_KERNEL,
DMA_ATTR_NO_KERNEL_MAPPING); if (!msi->virt) {
dev_err(dev, "failed to allocate DMA memory for MSI\n");
err = -ENOMEM; goto free_irq;
}
return 0;
free_irq:
irq_set_chained_handler_and_data(msi->irq, NULL, NULL);
free_irq_domain: if (IS_ENABLED(CONFIG_PCI_MSI))
tegra_free_domains(msi);
afi_writel(pcie, msi->phys >> soc->msi_base_shift, AFI_MSI_FPCI_BAR_ST);
afi_writel(pcie, msi->phys, AFI_MSI_AXI_BAR_ST); /* this register is in 4K increments */
afi_writel(pcie, 1, AFI_MSI_BAR_SZ);
/* Restore the MSI allocation state */
bitmap_to_arr32(msi_state, msi->used, INT_PCI_MSI_NR); for (i = 0; i < ARRAY_SIZE(msi_state); i++)
afi_writel(pcie, msi_state[i], AFI_MSI_EN_VEC(i));
/* and unmask the MSI interrupt */
reg = afi_readl(pcie, AFI_INTR_MASK);
reg |= AFI_INTR_MASK_MSI_MASK;
afi_writel(pcie, reg, AFI_INTR_MASK);
}
/* * Check whether a given set of supplies is available in a device tree node. * This is used to check whether the new or the legacy device tree bindings * should be used.
*/ staticbool of_regulator_bulk_available(struct device_node *np, struct regulator_bulk_data *supplies, unsignedint num_supplies)
{ char property[32]; unsignedint i;
for (i = 0; i < num_supplies; i++) {
snprintf(property, 32, "%s-supply", supplies[i].supply);
if (!of_property_present(np, property)) returnfalse;
}
returntrue;
}
/* * Old versions of the device tree binding for this device used a set of power * supplies that didn't match the hardware inputs. This happened to work for a * number of cases but is not future proof. However to preserve backwards- * compatibility with old device trees, this function will try to use the old * set of supplies.
*/ staticint tegra_pcie_get_legacy_regulators(struct tegra_pcie *pcie)
{ struct device *dev = pcie->dev; struct device_node *np = dev->of_node;
/* * Obtains the list of regulators required for a particular generation of the * IP block. * * This would've been nice to do simply by providing static tables for use * with the regulator_bulk_*() API, but unfortunately Tegra30 is a bit quirky * in that it has two pairs or AVDD_PEX and VDD_PEX supplies (PEXA and PEXB) * and either seems to be optional depending on which ports are being used.
*/ staticint tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
{ struct device *dev = pcie->dev; struct device_node *np = dev->of_node; unsignedint i = 0;
if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
pcie->num_supplies = 4;
pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, sizeof(*pcie->supplies),
GFP_KERNEL); if (!pcie->supplies) return -ENOMEM;
if (of_regulator_bulk_available(dev->of_node, pcie->supplies,
pcie->num_supplies)) return devm_regulator_bulk_get(dev, pcie->num_supplies,
pcie->supplies);
/* * If not all regulators are available for this new scheme, assume * that the device tree complies with an older version of the device * tree binding.
*/
dev_info(dev, "using legacy DT binding for power supplies\n");
rp->base = devm_pci_remap_cfg_resource(dev, &rp->regs); if (IS_ERR(rp->base)) return PTR_ERR(rp->base);
label = devm_kasprintf(dev, GFP_KERNEL, "pex-reset-%u", index); if (!label) 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_fwnode_gpiod_get(dev,
of_fwnode_handle(port), "reset",
GPIOD_OUT_LOW,
label); if (IS_ERR(rp->reset_gpio)) { if (PTR_ERR(rp->reset_gpio) == -ENOENT)
rp->reset_gpio = NULL; else return dev_err_probe(dev, PTR_ERR(rp->reset_gpio), "failed to get reset GPIO\n");
}
list_add_tail(&rp->list, &pcie->ports);
}
err = tegra_pcie_get_xbar_config(pcie, lanes, &pcie->xbar_config); if (err < 0) return dev_err_probe(dev, err, "invalid lane configuration\n");
err = tegra_pcie_get_regulators(pcie, mask); if (err < 0) return err;
return 0;
}
/* * FIXME: If there are no PCIe cards attached, then calling this function * can result in the increase of the bootup time as there are big timeout * loops.
*/ #define TEGRA_PCIE_LINKUP_TIMEOUT 200 /* up to 1.2 seconds */ staticbool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
{ struct device *dev = port->pcie->dev; unsignedint retries = 3; unsignedlong value;
/* override presence detection */
value = readl(port->base + RP_PRIV_MISC);
value &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
value |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
writel(value, port->base + RP_PRIV_MISC);
do { unsignedint timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
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);
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.