summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pcie_layerscape.c47
1 files changed, 33 insertions, 14 deletions
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c
index 1b0b814..402c519 100644
--- a/drivers/pci/pcie_layerscape.c
+++ b/drivers/pci/pcie_layerscape.c
@@ -49,11 +49,20 @@
#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
#define PCIE_ATU_UPPER_TARGET 0x91C
+/* LUT registers */
+#define PCIE_LUT_BASE 0x80000
+#define PCIE_LUT_DBG 0x7FC
+
+#define PCIE_DBI_RO_WR_EN 0x8bc
+
#define PCIE_LINK_CAP 0x7c
#define PCIE_LINK_SPEED_MASK 0xf
#define PCIE_LINK_STA 0x82
-#define PCIE_DBI_SIZE (4 * 1024) /* 4K */
+#define LTSSM_STATE_MASK 0x3f
+#define LTSSM_PCIE_L0 0x11 /* L0 state */
+
+#define PCIE_DBI_SIZE 0x100000 /* 1M */
struct ls_pcie {
int idx;
@@ -103,8 +112,6 @@ struct ls_pcie_info {
/* PEX1/2 Misc Ports Status Register */
#define LTSSM_STATE_SHIFT 20
-#define LTSSM_STATE_MASK 0x3f
-#define LTSSM_PCIE_L0 0x11 /* L0 state */
static int ls_pcie_link_state(struct ls_pcie *pcie)
{
@@ -121,18 +128,18 @@ static int ls_pcie_link_state(struct ls_pcie *pcie)
return 1;
}
#else
-#define PCIE_LDBG 0x7FC
-
static int ls_pcie_link_state(struct ls_pcie *pcie)
{
u32 state;
- state = readl(pcie->dbi + PCIE_LDBG);
- if (state)
- return 1;
+ state = readl(pcie->dbi + PCIE_LUT_BASE + PCIE_LUT_DBG) &
+ LTSSM_STATE_MASK;
+ if (state < LTSSM_PCIE_L0) {
+ debug("....PCIe link error. LTSSM=0x%02x.\n", state);
+ return 0;
+ }
- debug("....PCIe link error.\n");
- return 0;
+ return 1;
}
#endif
@@ -148,7 +155,11 @@ static int ls_pcie_link_up(struct ls_pcie *pcie)
/* Try to download speed to gen1 */
cap = readl(pcie->dbi + PCIE_LINK_CAP);
writel((cap & (~PCIE_LINK_SPEED_MASK)) | 1, pcie->dbi + PCIE_LINK_CAP);
- udelay(2000);
+ /*
+ * Notice: the following delay has critical impact on link training
+ * if too short (<30ms) the link doesn't get up.
+ */
+ mdelay(100);
state = ls_pcie_link_state(pcie);
if (state)
return state;
@@ -250,6 +261,10 @@ static int ls_pcie_addr_valid(struct pci_controller *hose, pci_dev_t d)
if (PCI_DEV(d) > 0)
return -EINVAL;
+ /* Controller does not support multi-function in RC mode */
+ if ((PCI_BUS(d) == hose->first_busno) && (PCI_FUNC(d) > 0))
+ return -EINVAL;
+
return 0;
}
@@ -326,8 +341,12 @@ static void ls_pcie_setup_ctrl(struct ls_pcie *pcie,
pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0);
/* program correct class for RC */
+ writel(1, pcie->dbi + PCIE_DBI_RO_WR_EN);
pci_hose_write_config_word(hose, dev, PCI_CLASS_DEVICE,
PCI_CLASS_BRIDGE_PCI);
+#ifndef CONFIG_LS102XA
+ writel(0, pcie->dbi + PCIE_DBI_RO_WR_EN);
+#endif
}
int ls_pcie_init_ctrl(int busno, enum srds_prtcl dev, struct ls_pcie_info *info)
@@ -416,9 +435,9 @@ int ls_pcie_init_ctrl(int busno, enum srds_prtcl dev, struct ls_pcie_info *info)
}
/* Print the negotiated PCIe link width */
- pci_hose_read_config_word(hose, dev, PCIE_LINK_STA, &temp16);
- printf("x%d gen%d, regs @ 0x%lx\n", (temp16 & 0x3f0) >> 4,
- (temp16 & 0xf), info->regs);
+ pci_hose_read_config_word(hose, pdev, PCIE_LINK_STA, &temp16);
+ printf("x%d gen%d, regs @ 0x%lx\n", (temp16 & 0x3f0) >> 4,
+ (temp16 & 0xf), info->regs);
if (ep_mode)
return busno;