[U-Boot] [PATCH] Powerpc: Make pcie link state judge more specific

Bao Xiaowei xiaowei.bao at nxp.com
Mon Sep 25 03:27:16 UTC 2017


For some special reset times for longer pcie devices, in this case, the
pcie device may on polling compliance state, the RC considers the pcie
device is link up, but the pcie device is not link up, only the L0 state
is link up state. So add the link up status judgement mechanisms.

Signed-off-by: Bao Xiaowei <xiaowei.bao at nxp.com>
---
v2:
 - Detailed function module
 - Adjust the code structure

 arch/powerpc/include/asm/fsl_pci.h |   3 +
 drivers/pci/fsl_pci_init.c         | 151 ++++++++++++++++++++-----------------
 2 files changed, 86 insertions(+), 68 deletions(-)

diff --git a/arch/powerpc/include/asm/fsl_pci.h b/arch/powerpc/include/asm/fsl_pci.h
index cad341e..9dfbf19 100644
--- a/arch/powerpc/include/asm/fsl_pci.h
+++ b/arch/powerpc/include/asm/fsl_pci.h
@@ -24,6 +24,9 @@
 
 #define PCI_LTSSM	0x404   /* PCIe Link Training, Status State Machine */
 #define  PCI_LTSSM_L0	0x16    /* L0 state */
+#define PCIE_GEN3_LTSSM_L0     0x11    /* L0 state */
+#define LTSSM_PCIE_DETECT_QUIET                0x00 /* Detect state */
+#define LTSSM_PCIE_DETECT_ACTIVE       0x01 /* Detect state */
 
 int fsl_setup_hose(struct pci_controller *hose, unsigned long addr);
 int fsl_is_pci_agent(struct pci_controller *hose);
diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c
index af20cf0..5d697bc 100644
--- a/drivers/pci/fsl_pci_init.c
+++ b/drivers/pci/fsl_pci_init.c
@@ -39,6 +39,8 @@ DECLARE_GLOBAL_DATA_PTR;
 #if defined(CONFIG_SYS_PCI_64BIT) && !defined(CONFIG_SYS_PCI64_MEMORY_BUS)
 #define CONFIG_SYS_PCI64_MEMORY_BUS (64ull*1024*1024*1024)
 #endif
+#define PEX_CSR0_LTSSM_MASK	0xFC
+#define PEX_CSR0_LTSSM_SHIFT	2
 
 /* Setup one inbound ATMU window.
  *
@@ -290,6 +292,81 @@ static void fsl_pcie_boot_master_release_slave(int port)
 }
 #endif
 
+static int is_pcie_gen3(struct fsl_pci_info *pci_info)
+{
+	u32 cfg_addr = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_addr;
+	volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr;
+	u32 block_rev;
+
+	block_rev = in_be32(&pci->block_rev1);
+	if (block_rev >= PEX_IP_BLK_REV_3_0)
+		return 1;
+	else
+		return 0;
+}
+
+static int get_ltssm_val(struct pci_controller *hose,
+			 struct fsl_pci_info *pci_info)
+{
+	u16 ltssm = 0;
+	pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
+	u32 cfg_addr = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_addr;
+	volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr;
+
+	if (is_pcie_gen3(pci_info))
+		ltssm = (in_be32(&pci->pex_csr0)
+			& PEX_CSR0_LTSSM_MASK) >> PEX_CSR0_LTSSM_SHIFT;
+	else
+		pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
+
+	return ltssm;
+}
+
+static int pci_link_up(struct pci_controller *hose,
+			struct fsl_pci_info *pci_info)
+{
+	int enabled = 0;
+	u16 ltssm;
+	int i, pcie_ltssm_l0;
+
+	if (is_pcie_gen3(pci_info))
+		pcie_ltssm_l0 = PCIE_GEN3_LTSSM_L0;
+	else
+		pcie_ltssm_l0 = PCI_LTSSM_L0;
+
+	ltssm = get_ltssm_val(hose, pci_info);
+	if (ltssm == LTSSM_PCIE_DETECT_QUIET ||
+		ltssm == LTSSM_PCIE_DETECT_ACTIVE)
+		enabled = 0;
+	else if (ltssm == PCIE_GEN3_LTSSM_L0)
+		enabled = 1;
+	else {
+		for (i = 0; i < 100 && ltssm != pcie_ltssm_l0; i++) {
+			ltssm = get_ltssm_val(hose, pci_info);
+			udelay(1000);
+		}
+		enabled = (ltssm == pcie_ltssm_l0) ? 1 : 0;
+	}
+	return enabled;
+}
+
+#if defined(CONFIG_FSL_PCIE_RESET) || \
+	defined(CONFIG_SYS_P4080_ERRATUM_PCIE_A003)
+static void do_pcie_reset(struct fsl_pci_info *pci_info)
+{
+	u32 cfg_addr = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_addr;
+	volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr;
+
+	/* assert PCIe reset */
+	setbits_be32(&pci->pdb_stat, 0x08000000);
+	(void) in_be32(&pci->pdb_stat);
+	udelay(1000);
+	/* clear PCIe reset */
+	clrbits_be32(&pci->pdb_stat, 0x08000000);
+	asm("sync;isync");
+}
+#endif
+
 void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
 {
 	u32 cfg_addr = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_addr;
@@ -298,7 +375,6 @@ void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
 	u32 temp32;
 	u32 block_rev;
 	int enabled, r, inbound = 0;
-	u16 ltssm;
 	u8 temp8, pcie_cap;
 	int pcie_cap_pos;
 	int pci_dcr;
@@ -438,63 +514,12 @@ void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
 	udelay(1);
 #endif
 	if (pcie_cap == PCI_CAP_ID_EXP) {
-		if (block_rev >= PEX_IP_BLK_REV_3_0) {
-#define PEX_CSR0_LTSSM_MASK	0xFC
-#define PEX_CSR0_LTSSM_SHIFT	2
-			ltssm = (in_be32(&pci->pex_csr0)
-				& PEX_CSR0_LTSSM_MASK) >> PEX_CSR0_LTSSM_SHIFT;
-			enabled = (ltssm == 0x11) ? 1 : 0;
 #ifdef CONFIG_FSL_PCIE_RESET
-			int i;
-			/* assert PCIe reset */
-			setbits_be32(&pci->pdb_stat, 0x08000000);
-			(void) in_be32(&pci->pdb_stat);
-			udelay(1000);
-			/* clear PCIe reset */
-			clrbits_be32(&pci->pdb_stat, 0x08000000);
-			asm("sync;isync");
-			for (i = 0; i < 100 && ltssm < PCI_LTSSM_L0; i++) {
-				pci_hose_read_config_word(hose, dev, PCI_LTSSM,
-							  &ltssm);
-				udelay(1000);
-			}
+		do_pcie_reset(pci_info);
+		pci_hose_write_config_dword(hose, dev,
+						PCI_BASE_ADDRESS_0, pcicsrbar);
 #endif
-		} else {
-		/* pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm); */
-		/* enabled = ltssm >= PCI_LTSSM_L0; */
-		pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
-		enabled = ltssm >= PCI_LTSSM_L0;
-
-#ifdef CONFIG_FSL_PCIE_RESET
-		if (ltssm == 1) {
-			int i;
-			debug("....PCIe link error. " "LTSSM=0x%02x.", ltssm);
-			/* assert PCIe reset */
-			setbits_be32(&pci->pdb_stat, 0x08000000);
-			(void) in_be32(&pci->pdb_stat);
-			udelay(100);
-			debug("  Asserting PCIe reset @%p = %x\n",
-			      &pci->pdb_stat, in_be32(&pci->pdb_stat));
-			/* clear PCIe reset */
-			clrbits_be32(&pci->pdb_stat, 0x08000000);
-			asm("sync;isync");
-			for (i=0; i<100 && ltssm < PCI_LTSSM_L0; i++) {
-				pci_hose_read_config_word(hose, dev, PCI_LTSSM,
-							&ltssm);
-				udelay(1000);
-				debug("....PCIe link error. "
-				      "LTSSM=0x%02x.\n", ltssm);
-			}
-			enabled = ltssm >= PCI_LTSSM_L0;
-
-			/* we need to re-write the bar0 since a reset will
-			 * clear it
-			 */
-			pci_hose_write_config_dword(hose, dev,
-					PCI_BASE_ADDRESS_0, pcicsrbar);
-		}
-#endif
-	}
+		enabled = pci_link_up(hose, pci_info);
 
 #ifdef CONFIG_SYS_P4080_ERRATUM_PCIE_A003
 		if (enabled == 0) {
@@ -502,19 +527,9 @@ void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
 			temp32 = in_be32(&srds_regs->srdspccr0);
 
 			if ((temp32 >> 28) == 3) {
-				int i;
-
 				out_be32(&srds_regs->srdspccr0, 2 << 28);
-				setbits_be32(&pci->pdb_stat, 0x08000000);
-				in_be32(&pci->pdb_stat);
-				udelay(100);
-				clrbits_be32(&pci->pdb_stat, 0x08000000);
-				asm("sync;isync");
-				for (i=0; i < 100 && ltssm < PCI_LTSSM_L0; i++) {
-					pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
-					udelay(1000);
-				}
-				enabled = ltssm >= PCI_LTSSM_L0;
+				do_pcie_reset(pci_info);
+				enabled = pci_link_up(hose, pci_info);
 			}
 		}
 #endif
-- 
2.7.4



More information about the U-Boot mailing list