arm: mvebu: a38x: serdes: Move non-serdes PCIe code to pci_mvebu.c

As explained in commit 3bedbcc3aa18 ("arm: mvebu: a38x: serdes: Don't
overwrite read-only SAR PCIe registers") it is required to set Maximum Link
Width bits of PCIe Root Port Link Capabilities Register depending of number
of used serdes lanes. As this register is part of PCIe address space and
not serdes address space, move it into pci_mvebu.c driver.

Read number of PCIe lanes from DT property "num-lanes" which is used also
by other PCIe controller drivers in Linux kernel. If this property is
absent then it defaults to 1. This property needs to be set to 4 for every
mvebu board which use PEX_ROOT_COMPLEX_X4 or PEX_BUS_MODE_X4.

Enabling of PCIe port needs to be done afer all registers in PCIe address
space are properly configure. For this purpose use new mvebu-reset driver
(part of system-controller) and remove this code from serdes code.

Because some PCIe ports cannot be enabled individually, it is required to
first setup all PCIe ports and then enable them.

This change contains also all required "num-lanes" and "resets" DTS
properties, to make pci_mvebu.c driver work correctly.

Signed-off-by: Pali Rohár <pali@kernel.org>
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 42f8cb6..630d6e6 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -265,6 +265,7 @@
 	bool "Enable Armada XP/38x PCIe driver"
 	depends on ARCH_MVEBU
 	select MISC
+	select DM_RESET
 	help
 	  Say Y here if you want to enable PCIe controller support on
 	  Armada XP/38x SoCs.
diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
index 55cde2d..b3ea034 100644
--- a/drivers/pci/pci_mvebu.c
+++ b/drivers/pci/pci_mvebu.c
@@ -18,6 +18,7 @@
 #include <dm/lists.h>
 #include <dm/of_access.h>
 #include <pci.h>
+#include <reset.h>
 #include <asm/io.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/soc.h>
@@ -74,6 +75,7 @@
 	u32 intregs;
 	u32 port;
 	u32 lane;
+	bool is_x4;
 	int devfn;
 	u32 lane_mask;
 	int first_busno;
@@ -379,7 +381,30 @@
 /* Only enable PCIe link, do not setup it */
 static int mvebu_pcie_enable_link(struct mvebu_pcie *pcie, ofnode node)
 {
-	/* PCIe link is currently automatically enabled in SerDes code */
+	struct reset_ctl rst;
+	int ret;
+
+	ret = reset_get_by_index_nodev(node, 0, &rst);
+	if (ret == -ENOENT) {
+		return 0;
+	} else if (ret < 0) {
+		printf("%s: cannot get reset controller: %d\n", pcie->name, ret);
+		return ret;
+	}
+
+	ret = reset_request(&rst);
+	if (ret) {
+		printf("%s: cannot request reset controller: %d\n", pcie->name, ret);
+		return ret;
+	}
+
+	ret = reset_deassert(&rst);
+	reset_free(&rst);
+	if (ret) {
+		printf("%s: cannot enable PCIe port: %d\n", pcie->name, ret);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -392,6 +417,18 @@
 	reg = readl(pcie->base + PCIE_CTRL_OFF);
 	reg |= PCIE_CTRL_RC_MODE;
 	writel(reg, pcie->base + PCIE_CTRL_OFF);
+
+	/*
+	 * Set Maximum Link Width to X1 or X4 in Root Port's PCIe Link
+	 * Capability register. This register is defined by PCIe specification
+	 * as read-only but this mvebu controller has it as read-write and must
+	 * be set to number of SerDes PCIe lanes (1 or 4). If this register is
+	 * not set correctly then link with endpoint card is not established.
+	 */
+	reg = readl(pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP);
+	reg &= ~PCI_EXP_LNKCAP_MLW;
+	reg |= (pcie->is_x4 ? 4 : 1) << 4;
+	writel(reg, pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP);
 }
 
 static int mvebu_pcie_probe(struct udevice *dev)
@@ -582,6 +619,7 @@
 {
 	struct fdt_pci_addr pci_addr;
 	const u32 *addr;
+	u32 num_lanes;
 	int ret = 0;
 	int len;
 
@@ -597,6 +635,9 @@
 
 	sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane);
 
+	if (!ofnode_read_u32(node, "num-lanes", &num_lanes) && num_lanes == 4)
+		pcie->is_x4 = true;
+
 	/* devfn is in bits [15:8], see PCI_DEV usage */
 	ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr);
 	if (ret < 0) {