diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-22 12:41:00 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-22 12:41:00 -0700 | 
| commit | 00937f36b09e89c74e4a059dbb8acbf4b971d5eb (patch) | |
| tree | ff2e5f5fa6736460437f57680405a20124d1e969 /drivers/pci/controller/dwc/pcie-designware.c | |
| parent | 96485e4462604744d66bf4301557d996d80b85eb (diff) | |
| parent | 28e34e751f6c50098d9bcecb30c97634b6126730 (diff) | |
Merge tag 'pci-v5.10-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas:
 "Enumeration:
   - Print IRQ number used by PCIe Link Bandwidth Notification (Dongdong
     Liu)
   - Add schedule point in pci_read_config() to reduce max latency
     (Jiang Biao)
   - Add Kconfig options for MPS/MRRS strategy (Jim Quinlan)
  Resource management:
   - Fix pci_iounmap() memory leak when !CONFIG_GENERIC_IOMAP (Lorenzo
     Pieralisi)
  PCIe native device hotplug:
   - Reduce noisiness on hot removal (Lukas Wunner)
  Power management:
   - Revert "PCI/PM: Apply D2 delay as milliseconds, not microseconds"
     that was done on the basis of spec typo (Bjorn Helgaas)
   - Rename pci_dev.d3_delay to d3hot_delay to remove D3hot/D3cold
     ambiguity (Krzysztof Wilczyński)
   - Remove unused pcibios_pm_ops (Vaibhav Gupta)
  IOMMU:
   - Enable Translation Blocking for external devices to harden against
     DMA attacks (Rajat Jain)
  Error handling:
   - Add an ACPI APEI notifier chain for vendor CPER records to enable
     device-specific error handling (Shiju Jose)
  ASPM:
   - Remove struct aspm_register_info to simplify code (Saheed O.
     Bolarinwa)
  Amlogic Meson PCIe controller driver:
   - Build as module by default (Kevin Hilman)
  Ampere Altra PCIe controller driver:
   - Add MCFG quirk to work around non-standard ECAM implementation
     (Tuan Phan)
  Broadcom iProc PCIe controller driver:
   - Set affinity mask on MSI interrupts (Mark Tomlinson)
  Broadcom STB PCIe controller driver:
   - Make PCIE_BRCMSTB depend on ARCH_BRCMSTB (Jim Quinlan)
   - Add DT bindings for more Brcmstb chips (Jim Quinlan)
   - Add bcm7278 register info (Jim Quinlan)
   - Add bcm7278 PERST# support (Jim Quinlan)
   - Add suspend and resume pm_ops (Jim Quinlan)
   - Add control of rescal reset (Jim Quinlan)
   - Set additional internal memory DMA viewport sizes (Jim Quinlan)
   - Accommodate MSI for older chips (Jim Quinlan)
   - Set bus max burst size by chip type (Jim Quinlan)
   - Add support for bcm7211, bcm7216, bcm7445, bcm7278 (Jim Quinlan)
  Freescale i.MX6 PCIe controller driver:
   - Use dev_err_probe() to reduce redundant messages (Anson Huang)
  Freescale Layerscape PCIe controller driver:
   - Enforce 4K DMA buffer alignment in endpoint test (Hou Zhiqiang)
   - Add DT compatible strings for ls1088a, ls2088a (Xiaowei Bao)
   - Add endpoint support for ls1088a, ls2088a (Xiaowei Bao)
   - Add endpoint test support for lS1088a (Xiaowei Bao)
   - Add MSI-X support for ls1088a (Xiaowei Bao)
  HiSilicon HIP PCIe controller driver:
   - Handle HIP-specific errors via ACPI APEI (Yicong Yang)
  HiSilicon Kirin PCIe controller driver:
   - Return -EPROBE_DEFER if the GPIO isn't ready (Bean Huo)
  Intel VMD host bridge driver:
   - Factor out physical offset, bus offset, IRQ domain, IRQ allocation
     (Jon Derrick)
   - Use generic PCI PM correctly (Jon Derrick)
  Marvell Aardvark PCIe controller driver:
   - Fix compilation on s390 (Pali Rohár)
   - Implement driver 'remove' function and allow to build it as module
     (Pali Rohár)
   - Move PCIe reset card code to advk_pcie_train_link() (Pali Rohár)
   - Convert mvebu a3700 internal SMCC firmware return codes to errno
     (Pali Rohár)
   - Fix initialization with old Marvell's Arm Trusted Firmware (Pali
     Rohár)
  Microsoft Hyper-V host bridge driver:
   - Fix hibernation in case interrupts are not re-created (Dexuan Cui)
  NVIDIA Tegra PCIe controller driver:
   - Stop checking return value of debugfs_create() functions (Greg
     Kroah-Hartman)
   - Convert to use DEFINE_SEQ_ATTRIBUTE macro (Liu Shixin)
  Qualcomm PCIe controller driver:
   - Reset PCIe to work around Qsdk U-Boot issue (Ansuel Smith)
  Renesas R-Car PCIe controller driver:
   - Add DT documentation for r8a774a1, r8a774b1, r8a774e1 endpoints
     (Lad Prabhakar)
   - Add RZ/G2M, RZ/G2N, RZ/G2H IDs to endpoint test (Lad Prabhakar)
   - Add DT support for r8a7742 (Lad Prabhakar)
  Socionext UniPhier Pro5 controller driver:
   - Add DT descriptions of iATU register (host and endpoint) (Kunihiko
     Hayashi)
  Synopsys DesignWare PCIe controller driver:
   - Add link up check in dw_child_pcie_ops.map_bus() (racy, but seems
     unavoidable) (Hou Zhiqiang)
   - Fix endpoint Header Type check so multi-function devices work (Hou
     Zhiqiang)
   - Skip PCIE_MSI_INTR0* programming if MSI is disabled (Jisheng Zhang)
   - Stop leaking MSI page in suspend/resume (Jisheng Zhang)
   - Add common iATU register support instead of keystone-specific code
     (Kunihiko Hayashi)
   - Major config space access and other cleanups in dwc core and
     drivers that use it (al, exynos, histb, imx6, intel-gw, keystone,
     kirin, meson, qcom, tegra) (Rob Herring)
   - Add multiple PFs support for endpoint (Xiaowei Bao)
   - Add MSI-X doorbell mode in endpoint mode (Xiaowei Bao)
  Miscellaneous:
   - Use fallthrough pseudo-keyword (Gustavo A. R. Silva)
   - Fix "0 used as NULL pointer" warnings (Gustavo Pimentel)
   - Fix "cast truncates bits from constant value" warnings (Gustavo
     Pimentel)
   - Remove redundant zeroing for sg_init_table() (Julia Lawall)
   - Use scnprintf(), not snprintf(), in sysfs "show" functions
     (Krzysztof Wilczyński)
   - Remove unused assignments (Krzysztof Wilczyński)
   - Fix "0 used as NULL pointer" warning (Krzysztof Wilczyński)
   - Simplify bool comparisons (Krzysztof Wilczyński)
   - Use for_each_child_of_node() and for_each_node_by_name() (Qinglang
     Miao)
   - Simplify return expressions (Qinglang Miao)"
* tag 'pci-v5.10-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (147 commits)
  PCI: vmd: Update VMD PM to correctly use generic PCI PM
  PCI: vmd: Create IRQ allocation helper
  PCI: vmd: Create IRQ Domain configuration helper
  PCI: vmd: Create bus offset configuration helper
  PCI: vmd: Create physical offset helper
  PCI: v3-semi: Remove unneeded break
  PCI: dwc: Add link up check in dw_child_pcie_ops.map_bus()
  PCI/ASPM: Remove struct pcie_link_state.l1ss
  PCI/ASPM: Remove struct aspm_register_info.l1ss_cap
  PCI/ASPM: Pass L1SS Capabilities value, not struct aspm_register_info
  PCI/ASPM: Remove struct aspm_register_info.l1ss_ctl1
  PCI/ASPM: Remove struct aspm_register_info.l1ss_ctl2 (unused)
  PCI/ASPM: Remove struct aspm_register_info.l1ss_cap_ptr
  PCI/ASPM: Remove struct aspm_register_info.latency_encoding
  PCI/ASPM: Remove struct aspm_register_info.enabled
  PCI/ASPM: Remove struct aspm_register_info.support
  PCI/ASPM: Use 'parent' and 'child' for readability
  PCI/ASPM: Move LTR path check to where it's used
  PCI/ASPM: Move pci_clear_and_set_dword() earlier
  PCI: dwc: Fix MSI page leakage in suspend/resume
  ...
Diffstat (limited to 'drivers/pci/controller/dwc/pcie-designware.c')
| -rw-r--r-- | drivers/pci/controller/dwc/pcie-designware.c | 170 | 
1 files changed, 98 insertions, 72 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index b723e0cc41fb..c2dea8fc97c8 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -10,6 +10,7 @@  #include <linux/delay.h>  #include <linux/of.h> +#include <linux/of_platform.h>  #include <linux/types.h>  #include "../../pci.h" @@ -166,21 +167,6 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val)  }  EXPORT_SYMBOL_GPL(dw_pcie_write_dbi); -u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size) -{ -	int ret; -	u32 val; - -	if (pci->ops->read_dbi2) -		return pci->ops->read_dbi2(pci, pci->dbi_base2, reg, size); - -	ret = dw_pcie_read(pci->dbi_base2 + reg, size, &val); -	if (ret) -		dev_err(pci->dev, "read DBI address failed\n"); - -	return val; -} -  void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)  {  	int ret; @@ -195,31 +181,31 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)  		dev_err(pci->dev, "write DBI address failed\n");  } -u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size) +static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)  {  	int ret;  	u32 val;  	if (pci->ops->read_dbi) -		return pci->ops->read_dbi(pci, pci->atu_base, reg, size); +		return pci->ops->read_dbi(pci, pci->atu_base, reg, 4); -	ret = dw_pcie_read(pci->atu_base + reg, size, &val); +	ret = dw_pcie_read(pci->atu_base + reg, 4, &val);  	if (ret)  		dev_err(pci->dev, "Read ATU address failed\n");  	return val;  } -void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val) +static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)  {  	int ret;  	if (pci->ops->write_dbi) { -		pci->ops->write_dbi(pci, pci->atu_base, reg, size, val); +		pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val);  		return;  	} -	ret = dw_pcie_write(pci->atu_base + reg, size, val); +	ret = dw_pcie_write(pci->atu_base + reg, 4, val);  	if (ret)  		dev_err(pci->dev, "Write ATU address failed\n");  } @@ -239,9 +225,10 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,  	dw_pcie_writel_atu(pci, offset + reg, val);  } -static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index, -					     int type, u64 cpu_addr, -					     u64 pci_addr, u32 size) +static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, +					     int index, int type, +					     u64 cpu_addr, u64 pci_addr, +					     u32 size)  {  	u32 retries, val;  	u64 limit_addr = cpu_addr + size - 1; @@ -259,7 +246,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,  	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,  				 upper_32_bits(pci_addr));  	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, -				 type); +				 type | PCIE_ATU_FUNC_NUM(func_no));  	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,  				 PCIE_ATU_ENABLE); @@ -278,8 +265,9 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,  	dev_err(pci->dev, "Outbound iATU is not being enabled\n");  } -void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, -			       u64 cpu_addr, u64 pci_addr, u32 size) +static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, +					int index, int type, u64 cpu_addr, +					u64 pci_addr, u32 size)  {  	u32 retries, val; @@ -287,8 +275,8 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,  		cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);  	if (pci->iatu_unroll_enabled) { -		dw_pcie_prog_outbound_atu_unroll(pci, index, type, cpu_addr, -						 pci_addr, size); +		dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type, +						 cpu_addr, pci_addr, size);  		return;  	} @@ -304,7 +292,8 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,  			   lower_32_bits(pci_addr));  	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,  			   upper_32_bits(pci_addr)); -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type); +	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type | +			   PCIE_ATU_FUNC_NUM(func_no));  	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);  	/* @@ -321,6 +310,21 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,  	dev_err(pci->dev, "Outbound iATU is not being enabled\n");  } +void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, +			       u64 cpu_addr, u64 pci_addr, u32 size) +{ +	__dw_pcie_prog_outbound_atu(pci, 0, index, type, +				    cpu_addr, pci_addr, size); +} + +void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, +				  int type, u64 cpu_addr, u64 pci_addr, +				  u32 size) +{ +	__dw_pcie_prog_outbound_atu(pci, func_no, index, type, +				    cpu_addr, pci_addr, size); +} +  static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg)  {  	u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); @@ -336,8 +340,8 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,  	dw_pcie_writel_atu(pci, offset + reg, val);  } -static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index, -					   int bar, u64 cpu_addr, +static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no, +					   int index, int bar, u64 cpu_addr,  					   enum dw_pcie_as_type as_type)  {  	int type; @@ -359,8 +363,10 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,  		return -EINVAL;  	} -	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type); +	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type | +				 PCIE_ATU_FUNC_NUM(func_no));  	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, +				 PCIE_ATU_FUNC_NUM_MATCH_EN |  				 PCIE_ATU_ENABLE |  				 PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); @@ -381,14 +387,15 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,  	return -EBUSY;  } -int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar, -			     u64 cpu_addr, enum dw_pcie_as_type as_type) +int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, +			     int bar, u64 cpu_addr, +			     enum dw_pcie_as_type as_type)  {  	int type;  	u32 retries, val;  	if (pci->iatu_unroll_enabled) -		return dw_pcie_prog_inbound_atu_unroll(pci, index, bar, +		return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar,  						       cpu_addr, as_type);  	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | @@ -407,9 +414,11 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,  		return -EINVAL;  	} -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type); -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE -			   | PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); +	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type | +			   PCIE_ATU_FUNC_NUM(func_no)); +	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE | +			   PCIE_ATU_FUNC_NUM_MATCH_EN | +			   PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));  	/*  	 * Make sure ATU enable takes effect before any subsequent config @@ -444,7 +453,7 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, int index,  	}  	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index); -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, (u32)~PCIE_ATU_ENABLE); +	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(u32)PCIE_ATU_ENABLE);  }  int dw_pcie_wait_for_link(struct dw_pcie *pci) @@ -488,50 +497,41 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci)  }  EXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup); -void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen) +static void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)  { -	u32 reg, val; +	u32 cap, ctrl2, link_speed;  	u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); -	reg = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2); -	reg &= ~PCI_EXP_LNKCTL2_TLS; +	cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); +	ctrl2 = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2); +	ctrl2 &= ~PCI_EXP_LNKCTL2_TLS;  	switch (pcie_link_speed[link_gen]) {  	case PCIE_SPEED_2_5GT: -		reg |= PCI_EXP_LNKCTL2_TLS_2_5GT; +		link_speed = PCI_EXP_LNKCTL2_TLS_2_5GT;  		break;  	case PCIE_SPEED_5_0GT: -		reg |= PCI_EXP_LNKCTL2_TLS_5_0GT; +		link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT;  		break;  	case PCIE_SPEED_8_0GT: -		reg |= PCI_EXP_LNKCTL2_TLS_8_0GT; +		link_speed = PCI_EXP_LNKCTL2_TLS_8_0GT;  		break;  	case PCIE_SPEED_16_0GT: -		reg |= PCI_EXP_LNKCTL2_TLS_16_0GT; +		link_speed = PCI_EXP_LNKCTL2_TLS_16_0GT;  		break;  	default:  		/* Use hardware capability */ -		val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); -		val = FIELD_GET(PCI_EXP_LNKCAP_SLS, val); -		reg &= ~PCI_EXP_LNKCTL2_HASD; -		reg |= FIELD_PREP(PCI_EXP_LNKCTL2_TLS, val); +		link_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap); +		ctrl2 &= ~PCI_EXP_LNKCTL2_HASD;  		break;  	} -	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, reg); -} -EXPORT_SYMBOL_GPL(dw_pcie_link_set_max_speed); +	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, ctrl2 | link_speed); -void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts) -{ -	u32 val; +	cap &= ~((u32)PCI_EXP_LNKCAP_SLS); +	dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, cap | link_speed); -	val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); -	val &= ~PORT_LOGIC_N_FTS_MASK; -	val |= n_fts & PORT_LOGIC_N_FTS_MASK; -	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);  } -EXPORT_SYMBOL_GPL(dw_pcie_link_set_n_fts);  static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)  { @@ -546,32 +546,58 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)  void dw_pcie_setup(struct dw_pcie *pci)  { -	int ret;  	u32 val; -	u32 lanes;  	struct device *dev = pci->dev;  	struct device_node *np = dev->of_node; +	struct platform_device *pdev = to_platform_device(dev);  	if (pci->version >= 0x480A || (!pci->version &&  				       dw_pcie_iatu_unroll_enabled(pci))) {  		pci->iatu_unroll_enabled = true;  		if (!pci->atu_base) +			pci->atu_base = +			    devm_platform_ioremap_resource_byname(pdev, "atu"); +		if (IS_ERR(pci->atu_base))  			pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;  	}  	dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?  		"enabled" : "disabled"); +	if (pci->link_gen > 0) +		dw_pcie_link_set_max_speed(pci, pci->link_gen); -	ret = of_property_read_u32(np, "num-lanes", &lanes); -	if (ret) { -		dev_dbg(pci->dev, "property num-lanes isn't found\n"); +	/* Configure Gen1 N_FTS */ +	if (pci->n_fts[0]) { +		val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); +		val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK); +		val |= PORT_AFR_N_FTS(pci->n_fts[0]); +		val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]); +		dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val); +	} + +	/* Configure Gen2+ N_FTS */ +	if (pci->n_fts[1]) { +		val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); +		val &= ~PORT_LOGIC_N_FTS_MASK; +		val |= pci->n_fts[pci->link_gen - 1]; +		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); +	} + +	val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); +	val &= ~PORT_LINK_FAST_LINK_MODE; +	val |= PORT_LINK_DLL_LINK_EN; +	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); + +	of_property_read_u32(np, "num-lanes", &pci->num_lanes); +	if (!pci->num_lanes) { +		dev_dbg(pci->dev, "Using h/w default number of lanes\n");  		return;  	}  	/* Set the number of lanes */ -	val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); +	val &= ~PORT_LINK_FAST_LINK_MODE;  	val &= ~PORT_LINK_MODE_MASK; -	switch (lanes) { +	switch (pci->num_lanes) {  	case 1:  		val |= PORT_LINK_MODE_1_LANES;  		break; @@ -585,7 +611,7 @@ void dw_pcie_setup(struct dw_pcie *pci)  		val |= PORT_LINK_MODE_8_LANES;  		break;  	default: -		dev_err(pci->dev, "num-lanes %u: invalid value\n", lanes); +		dev_err(pci->dev, "num-lanes %u: invalid value\n", pci->num_lanes);  		return;  	}  	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); @@ -593,7 +619,7 @@ void dw_pcie_setup(struct dw_pcie *pci)  	/* Set link width speed control register */  	val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);  	val &= ~PORT_LOGIC_LINK_WIDTH_MASK; -	switch (lanes) { +	switch (pci->num_lanes) {  	case 1:  		val |= PORT_LOGIC_LINK_WIDTH_1_LANES;  		break;  | 
