diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/pci/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/pci/pci_mvebu.c | 43 |
2 files changed, 43 insertions, 1 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 42f8cb6be0d..630d6e6cc5e 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -265,6 +265,7 @@ config PCI_MVEBU 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 55cde2dd83e..b3ea034a284 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 @@ struct mvebu_pcie { u32 intregs; u32 port; u32 lane; + bool is_x4; int devfn; u32 lane_mask; int first_busno; @@ -379,7 +381,30 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) /* 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 @@ static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie) 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 @@ static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pci { struct fdt_pci_addr pci_addr; const u32 *addr; + u32 num_lanes; int ret = 0; int len; @@ -597,6 +635,9 @@ static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pci 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) { |
