summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ddr/marvell/a38x/ddr3_training_centralization.c26
-rw-r--r--drivers/ddr/marvell/a38x/mv_ddr_plat.c19
-rw-r--r--drivers/mtd/nand/raw/pxa3xx_nand.c4
-rw-r--r--drivers/pci/Kconfig1
-rw-r--r--drivers/pci/pci_mvebu.c275
5 files changed, 251 insertions, 74 deletions
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c
index 648b37ef6f7..42308b6965d 100644
--- a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c
+++ b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c
@@ -55,6 +55,7 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode)
enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM];
u32 if_id, pattern_id, bit_id;
u8 bus_id;
+ u8 current_byte_status;
u8 cur_start_win[BUS_WIDTH_IN_BITS];
u8 centralization_result[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS];
u8 cur_end_win[BUS_WIDTH_IN_BITS];
@@ -166,6 +167,10 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode)
result[search_dir_id][7]));
}
+ current_byte_status =
+ mv_ddr_tip_sub_phy_byte_status_get(if_id,
+ bus_id);
+
for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS;
bit_id++) {
/* check if this code is valid for 2 edge, probably not :( */
@@ -174,11 +179,32 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode)
[HWS_LOW2HIGH]
[bit_id],
EDGE_1);
+ if (current_byte_status &
+ BYTE_SPLIT_OUT_MIX) {
+ if (cur_start_win[bit_id] >= 64)
+ cur_start_win[bit_id] -= 64;
+ else
+ cur_start_win[bit_id] = 0;
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("pattern %d IF %d pup %d bit %d subtract 64 adll from start\n",
+ pattern_id, if_id, bus_id, bit_id));
+ }
cur_end_win[bit_id] =
GET_TAP_RESULT(result
[HWS_HIGH2LOW]
[bit_id],
EDGE_1);
+ if (cur_end_win[bit_id] >= 64 &&
+ (current_byte_status &
+ BYTE_SPLIT_OUT_MIX)) {
+ cur_end_win[bit_id] -= 64;
+ DEBUG_CENTRALIZATION_ENGINE
+ (DEBUG_LEVEL_INFO,
+ ("pattern %d IF %d pup %d bit %d subtract 64 adll from end\n",
+ pattern_id, if_id, bus_id, bit_id));
+ }
+
/* window length */
current_window[bit_id] =
cur_end_win[bit_id] -
diff --git a/drivers/ddr/marvell/a38x/mv_ddr_plat.c b/drivers/ddr/marvell/a38x/mv_ddr_plat.c
index faafc86ea26..7c7bce73a35 100644
--- a/drivers/ddr/marvell/a38x/mv_ddr_plat.c
+++ b/drivers/ddr/marvell/a38x/mv_ddr_plat.c
@@ -167,8 +167,6 @@ static u16 a38x_vco_freq_per_sar_ref_clk_40_mhz[] = {
};
-static u32 async_mode_at_tf;
-
static u32 dq_bit_map_2_phy_pin[] = {
1, 0, 2, 6, 9, 8, 3, 7, /* 0 */
8, 9, 1, 7, 2, 6, 3, 0, /* 1 */
@@ -734,7 +732,8 @@ static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id,
u32 divider = 0;
u32 sar_val, ref_clk_satr;
u32 async_val;
- u32 freq = mv_ddr_freq_get(frequency);
+ u32 cpu_freq;
+ u32 ddr_freq = mv_ddr_freq_get(frequency);
if (if_id != 0) {
DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR,
@@ -751,11 +750,14 @@ static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id,
ref_clk_satr = reg_read(DEVICE_SAMPLE_AT_RESET2_REG);
if (((ref_clk_satr >> DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_OFFSET) & 0x1) ==
DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_25MHZ)
- divider = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val] / freq;
+ cpu_freq = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val];
else
- divider = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val] / freq;
+ cpu_freq = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val];
+
+ divider = cpu_freq / ddr_freq;
- if ((async_mode_at_tf == 1) && (freq > 400)) {
+ if (((cpu_freq % ddr_freq != 0) || (divider != 2 && divider != 3)) &&
+ (ddr_freq > 400)) {
/* Set async mode */
dunit_write(0x20220, 0x1000, 0x1000);
dunit_write(0xe42f4, 0x200, 0x200);
@@ -869,8 +871,6 @@ int ddr3_tip_ext_write(u32 dev_num, u32 if_id, u32 reg_addr,
int mv_ddr_early_init(void)
{
- struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
-
/* FIXME: change this configuration per ddr type
* configure a380 and a390 to work with receiver odt timing
* the odt_config is defined:
@@ -882,9 +882,6 @@ int mv_ddr_early_init(void)
mv_ddr_sw_db_init(0, 0);
- if (tm->interface_params[0].memory_freq != MV_DDR_FREQ_SAR)
- async_mode_at_tf = 1;
-
return MV_OK;
}
diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
index 8ff58a70387..3a9c9ca508d 100644
--- a/drivers/mtd/nand/raw/pxa3xx_nand.c
+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
@@ -1862,10 +1862,10 @@ static int pxa3xx_nand_probe_dt(struct udevice *dev, struct pxa3xx_nand_info *in
return -EINVAL;
}
- if (dev_read_bool(dev, "nand-enable-arbiter"))
+ if (dev_read_bool(dev, "marvell,nand-enable-arbiter"))
pdata->enable_arbiter = 1;
- if (dev_read_bool(dev, "nand-keep-config"))
+ if (dev_read_bool(dev, "marvell,nand-keep-config"))
pdata->keep_config = 1;
/*
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 18f79d249c7..b3ea034a284 100644
--- a/drivers/pci/pci_mvebu.c
+++ b/drivers/pci/pci_mvebu.c
@@ -18,13 +18,16 @@
#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>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/mbus.h>
+#include <linux/sizes.h>
/* PCIe unit register offsets */
#define SELECT(x, n) ((x >> n) & 1UL)
@@ -59,6 +62,9 @@
#define PCIE_DEBUG_CTRL 0x1a60
#define PCIE_DEBUG_SOFT_RESET BIT(20)
+#define LINK_WAIT_RETRIES 100
+#define LINK_WAIT_TIMEOUT 1000
+
struct mvebu_pcie {
struct pci_controller hose;
void __iomem *base;
@@ -66,8 +72,10 @@ struct mvebu_pcie {
struct resource mem;
void __iomem *iobase;
struct resource io;
+ u32 intregs;
u32 port;
u32 lane;
+ bool is_x4;
int devfn;
u32 lane_mask;
int first_busno;
@@ -80,14 +88,6 @@ struct mvebu_pcie {
u32 cfgcache[(0x3c - 0x10) / 4];
};
-/*
- * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
- * into SoCs address space. Each controller will map 128M of MEM
- * and 64K of I/O space when registered.
- */
-static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE;
-static void __iomem *mvebu_pcie_iobase = (void __iomem *)MBUS_PCI_IO_BASE;
-
static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
{
u32 val;
@@ -95,6 +95,23 @@ static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
return !(val & PCIE_STAT_LINK_DOWN);
}
+static void mvebu_pcie_wait_for_link(struct mvebu_pcie *pcie)
+{
+ int retries;
+
+ /* check if the link is up or not */
+ for (retries = 0; retries < LINK_WAIT_RETRIES; retries++) {
+ if (mvebu_pcie_link_up(pcie)) {
+ printf("%s: Link up\n", pcie->name);
+ return;
+ }
+
+ udelay(LINK_WAIT_TIMEOUT);
+ }
+
+ printf("%s: Link down\n", pcie->name);
+}
+
static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno)
{
u32 stat;
@@ -357,15 +374,43 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
pcie->base + PCIE_BAR_CTRL_OFF(1));
/* Setup BAR[0] to internal registers. */
- writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0));
+ writel(pcie->intregs, pcie->base + PCIE_BAR_LO_OFF(0));
writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
}
-static int mvebu_pcie_probe(struct udevice *dev)
+/* Only enable PCIe link, do not setup it */
+static int mvebu_pcie_enable_link(struct mvebu_pcie *pcie, ofnode node)
+{
+ 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;
+}
+
+/* Setup PCIe link but do not enable it */
+static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie)
{
- struct mvebu_pcie *pcie = dev_get_plat(dev);
- struct udevice *ctlr = pci_get_controller(dev);
- struct pci_controller *hose = dev_get_uclass_priv(ctlr);
u32 reg;
/* Setup PCIe controller to Root Complex mode */
@@ -374,6 +419,26 @@ static int mvebu_pcie_probe(struct udevice *dev)
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)
+{
+ struct mvebu_pcie *pcie = dev_get_plat(dev);
+ struct udevice *ctlr = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ u32 reg;
+
+ /*
* Change Class Code of PCI Bridge device to PCI Bridge (0x600400)
* because default value is Memory controller (0x508000) which
* U-Boot cannot recognize as P2P Bridge.
@@ -433,26 +498,26 @@ static int mvebu_pcie_probe(struct udevice *dev)
mvebu_pcie_set_local_bus_nr(pcie, 0);
mvebu_pcie_set_local_dev_nr(pcie, 1);
- pcie->mem.start = (u32)mvebu_pcie_membase;
- pcie->mem.end = pcie->mem.start + MBUS_PCI_MEM_SIZE - 1;
- mvebu_pcie_membase += MBUS_PCI_MEM_SIZE;
-
- if (mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
+ if (resource_size(&pcie->mem) &&
+ mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
(phys_addr_t)pcie->mem.start,
resource_size(&pcie->mem))) {
- printf("PCIe unable to add mbus window for mem at %08x+%08x\n",
+ printf("%s: unable to add mbus window for mem at %08x+%08x\n",
+ pcie->name,
(u32)pcie->mem.start, (unsigned)resource_size(&pcie->mem));
+ pcie->mem.start = 0;
+ pcie->mem.end = -1;
}
- pcie->io.start = (u32)mvebu_pcie_iobase;
- pcie->io.end = pcie->io.start + MBUS_PCI_IO_SIZE - 1;
- mvebu_pcie_iobase += MBUS_PCI_IO_SIZE;
-
- if (mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
+ if (resource_size(&pcie->io) &&
+ mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
(phys_addr_t)pcie->io.start,
resource_size(&pcie->io))) {
- printf("PCIe unable to add mbus window for IO at %08x+%08x\n",
+ printf("%s: unable to add mbus window for IO at %08x+%08x\n",
+ pcie->name,
(u32)pcie->io.start, (unsigned)resource_size(&pcie->io));
+ pcie->io.start = 0;
+ pcie->io.end = -1;
}
/* Setup windows and configure host bridge */
@@ -461,13 +526,23 @@ static int mvebu_pcie_probe(struct udevice *dev)
/* PCI memory space */
pci_set_region(hose->regions + 0, pcie->mem.start,
pcie->mem.start, resource_size(&pcie->mem), PCI_REGION_MEM);
- pci_set_region(hose->regions + 1,
- 0, 0,
- gd->ram_size,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
- pci_set_region(hose->regions + 2, pcie->io.start,
- pcie->io.start, resource_size(&pcie->io), PCI_REGION_IO);
- hose->region_count = 3;
+ hose->region_count = 1;
+
+ if (resource_size(&pcie->mem)) {
+ pci_set_region(hose->regions + hose->region_count,
+ pcie->mem.start, pcie->mem.start,
+ resource_size(&pcie->mem),
+ PCI_REGION_MEM);
+ hose->region_count++;
+ }
+
+ if (resource_size(&pcie->io)) {
+ pci_set_region(hose->regions + hose->region_count,
+ pcie->io.start, pcie->io.start,
+ resource_size(&pcie->io),
+ PCI_REGION_IO);
+ hose->region_count++;
+ }
/* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */
pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] =
@@ -475,21 +550,7 @@ static int mvebu_pcie_probe(struct udevice *dev)
pcie->cfgcache[(PCI_PREF_MEMORY_BASE - 0x10) / 4] =
PCI_PREF_RANGE_TYPE_64 | (PCI_PREF_RANGE_TYPE_64 << 16);
- return 0;
-}
-
-static int mvebu_pcie_port_parse_dt(ofnode node, struct mvebu_pcie *pcie)
-{
- const u32 *addr;
- int len;
-
- addr = ofnode_get_property(node, "assigned-addresses", &len);
- if (!addr) {
- pr_err("property \"assigned-addresses\" not found");
- return -FDT_ERR_NOTFOUND;
- }
-
- pcie->base = (void *)(fdt32_to_cpu(addr[2]) + SOC_REGS_PHY_BASE);
+ mvebu_pcie_wait_for_link(pcie);
return 0;
}
@@ -554,31 +615,38 @@ static int mvebu_get_tgt_attr(ofnode node, int devfn,
return -ENOENT;
}
-static int mvebu_pcie_of_to_plat(struct udevice *dev)
+static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pcie *pcie)
{
- struct mvebu_pcie *pcie = dev_get_plat(dev);
+ struct fdt_pci_addr pci_addr;
+ const u32 *addr;
+ u32 num_lanes;
int ret = 0;
+ int len;
/* Get port number, lane number and memory target / attr */
- if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port",
+ if (ofnode_read_u32(node, "marvell,pcie-port",
&pcie->port)) {
ret = -ENODEV;
goto err;
}
- if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-lane", &pcie->lane))
+ if (ofnode_read_u32(node, "marvell,pcie-lane", &pcie->lane))
pcie->lane = 0;
sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane);
- /* pci_get_devfn() returns devfn in bits 15..8, see PCI_DEV usage */
- pcie->devfn = pci_get_devfn(dev);
- if (pcie->devfn < 0) {
- ret = -ENODEV;
+ 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) {
+ printf("%s: property \"reg\" is invalid\n", pcie->name);
goto err;
}
+ pcie->devfn = pci_addr.phys_hi & 0xff00;
- ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn,
+ ret = mvebu_get_tgt_attr(parent, pcie->devfn,
IORESOURCE_MEM,
&pcie->mem_target, &pcie->mem_attr);
if (ret < 0) {
@@ -586,7 +654,7 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev)
goto err;
}
- ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn,
+ ret = mvebu_get_tgt_attr(parent, pcie->devfn,
IORESOURCE_IO,
&pcie->io_target, &pcie->io_attr);
if (ret < 0) {
@@ -595,9 +663,15 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev)
}
/* Parse PCIe controller register base from DT */
- ret = mvebu_pcie_port_parse_dt(dev_ofnode(dev), pcie);
- if (ret < 0)
+ addr = ofnode_get_property(node, "assigned-addresses", &len);
+ if (!addr) {
+ printf("%s: property \"assigned-addresses\" not found\n", pcie->name);
+ ret = -FDT_ERR_NOTFOUND;
goto err;
+ }
+
+ pcie->base = (void *)(u32)ofnode_translate_address(node, addr);
+ pcie->intregs = (u32)pcie->base - fdt32_to_cpu(addr[2]);
return 0;
@@ -615,7 +689,6 @@ static struct driver pcie_mvebu_drv = {
.id = UCLASS_PCI,
.ops = &mvebu_pcie_ops,
.probe = mvebu_pcie_probe,
- .of_to_plat = mvebu_pcie_of_to_plat,
.plat_auto = sizeof(struct mvebu_pcie),
};
@@ -625,9 +698,14 @@ static struct driver pcie_mvebu_drv = {
*/
static int mvebu_pcie_bind(struct udevice *parent)
{
+ struct mvebu_pcie **ports_pcie;
struct mvebu_pcie *pcie;
struct uclass_driver *drv;
struct udevice *dev;
+ struct resource mem;
+ struct resource io;
+ int ports_count, i;
+ ofnode *ports_nodes;
ofnode subnode;
/* Lookup pci driver */
@@ -637,19 +715,94 @@ static int mvebu_pcie_bind(struct udevice *parent)
return -ENOENT;
}
+ ports_count = ofnode_get_child_count(dev_ofnode(parent));
+ ports_pcie = calloc(ports_count, sizeof(*ports_pcie));
+ ports_nodes = calloc(ports_count, sizeof(*ports_nodes));
+ if (!ports_pcie || !ports_nodes) {
+ free(ports_pcie);
+ free(ports_nodes);
+ return -ENOMEM;
+ }
+ ports_count = 0;
+
+ mem.start = MBUS_PCI_MEM_BASE;
+ mem.end = MBUS_PCI_MEM_BASE + MBUS_PCI_MEM_SIZE - 1;
+ io.start = MBUS_PCI_IO_BASE;
+ io.end = MBUS_PCI_IO_BASE + MBUS_PCI_IO_SIZE - 1;
+
+ /* First phase: Fill mvebu_pcie struct for each port */
ofnode_for_each_subnode(subnode, dev_ofnode(parent)) {
if (!ofnode_is_available(subnode))
continue;
pcie = calloc(1, sizeof(*pcie));
if (!pcie)
- return -ENOMEM;
+ continue;
+
+ if (mvebu_pcie_port_parse_dt(subnode, dev_ofnode(parent), pcie) < 0) {
+ free(pcie);
+ continue;
+ }
+
+ /*
+ * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
+ * into SoCs address space. Each controller will map 128M of MEM
+ * and 64K of I/O space when registered.
+ */
+
+ if (resource_size(&mem) >= SZ_128M) {
+ pcie->mem.start = mem.start;
+ pcie->mem.end = mem.start + SZ_128M - 1;
+ mem.start += SZ_128M;
+ } else {
+ printf("%s: unable to assign mbus window for mem\n", pcie->name);
+ pcie->mem.start = 0;
+ pcie->mem.end = -1;
+ }
+
+ if (resource_size(&io) >= SZ_64K) {
+ pcie->io.start = io.start;
+ pcie->io.end = io.start + SZ_64K - 1;
+ io.start += SZ_64K;
+ } else {
+ printf("%s: unable to assign mbus window for io\n", pcie->name);
+ pcie->io.start = 0;
+ pcie->io.end = -1;
+ }
+
+ ports_pcie[ports_count] = pcie;
+ ports_nodes[ports_count] = subnode;
+ ports_count++;
+ }
+
+ /* Second phase: Setup all PCIe links (do not enable them yet) */
+ for (i = 0; i < ports_count; i++)
+ mvebu_pcie_setup_link(ports_pcie[i]);
+
+ /* Third phase: Enable all PCIe links and create for each UCLASS_PCI device */
+ for (i = 0; i < ports_count; i++) {
+ pcie = ports_pcie[i];
+ subnode = ports_nodes[i];
+
+ /*
+ * PCIe link can be enabled only after all PCIe links were
+ * properly configured. This is because more PCIe links shares
+ * one enable bit and some PCIe links cannot be enabled
+ * individually.
+ */
+ if (mvebu_pcie_enable_link(pcie, subnode) < 0) {
+ free(pcie);
+ continue;
+ }
/* Create child device UCLASS_PCI and bind it */
device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode,
&dev);
}
+ free(ports_pcie);
+ free(ports_nodes);
+
return 0;
}