Patchwork [U-Boot] PCIe:Add a function to get the address of requested capability structure.

login
register
mail settings
Submitter Zhao Qiang
Date Aug. 19, 2013, 8:35 a.m.
Message ID <1376901350-3591-1-git-send-email-B45475@freescale.com>
Download mbox | patch
Permalink /patch/268245/
State Superseded
Delegated to: York Sun
Headers show

Comments

Zhao Qiang - Aug. 19, 2013, 8:35 a.m.
Add a function to get the address of requested capability structure in PCIe
configuration space by capability ID.
The step of this function:
	1. Read Status register in PCIe configuration space to confirm that
	   Capabilities List is valid.
	2. Find the address of Capabilities Pointer Register.
	3. Find the address of requested capability from the first capability.

Signed-off-by: Zhao Qiang <B45475@freescale.com>
---
 arch/powerpc/include/asm/fsl_pci.h | 13 +-------
 drivers/pci/fsl_pci_init.c         | 40 +++++++++++++++-------
 drivers/pci/pci.c                  | 68 ++++++++++++++++++++++++++++++++++++++
 include/pci.h                      |  7 ++++
 4 files changed, 104 insertions(+), 24 deletions(-)

Patch

diff --git a/arch/powerpc/include/asm/fsl_pci.h b/arch/powerpc/include/asm/fsl_pci.h
index 90b0a2f..6b12afa 100644
--- a/arch/powerpc/include/asm/fsl_pci.h
+++ b/arch/powerpc/include/asm/fsl_pci.h
@@ -32,22 +32,11 @@ 
 /* Freescale-specific PCI config registers */
 #define FSL_PCI_PBFR		0x44
 
-#ifdef CONFIG_SYS_FSL_PCI_VER_3_X
+#ifndef CONFIG_SYS_FSL_PCI_VER_3_X
 /* Currently only the PCIe capability is used, so hardcode the offset.
  * if more capabilities need to be justified, the capability link method
  * should be applied here
  */
-#define FSL_PCIE_CAP_ID		0x70
-#define PCI_DCR		0x78    /* PCIe Device Control Register */
-#define PCI_DSR		0x7a    /* PCIe Device Status Register */
-#define PCI_LSR		0x82    /* PCIe Link Status Register */
-#define PCI_LCR		0x80    /* PCIe Link Control Register */
-#else
-#define FSL_PCIE_CAP_ID		0x4c
-#define PCI_DCR		0x54    /* PCIe Device Control Register */
-#define PCI_DSR		0x56    /* PCIe Device Status Register */
-#define PCI_LSR		0x5e    /* PCIe Link Status Register */
-#define PCI_LCR		0x5c    /* PCIe Link Control Register */
 #define FSL_PCIE_CFG_RDY	0x4b0
 #endif
 #define FSL_PCI_CFG_READY	1 /* Endpoint: allow inbound configuration */
diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c
index 76337fe..5004fea 100644
--- a/drivers/pci/fsl_pci_init.c
+++ b/drivers/pci/fsl_pci_init.c
@@ -308,6 +308,11 @@  void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
 	int enabled, r, inbound = 0;
 	u16 ltssm;
 	u8 temp8, pcie_cap;
+	int pcie_cap_pos;
+	int pci_dcr;
+	int pci_dsr;
+	int pci_lsr;
+	int pci_lcr;
 	volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr;
 	struct pci_region *reg = hose->regions + hose->region_count;
 	pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
@@ -380,7 +385,13 @@  void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
 	hose->region_count++;
 
 	/* see if we are a PCIe or PCI controller */
-	pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);
+	pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+	pci_dcr = pcie_cap_pos + 0x08;
+	pci_dsr = pcie_cap_pos + 0x0a;
+	pci_lsr = pcie_cap_pos + 0x12;
+	pci_lcr = pcie_cap_pos + 0x10;
+
+	pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
 
 #ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
 	/* boot from PCIE --master */
@@ -419,15 +430,15 @@  void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
 					 * - Master PERR (pci)
 					 * - ICCA (PCIe)
 					 */
-	pci_hose_read_config_dword(hose, dev, PCI_DCR, &temp32);
+	pci_hose_read_config_dword(hose, dev, pci_dcr, &temp32);
 	temp32 |= 0xf000e;		/* set URR, FER, NFER (but not CER) */
-	pci_hose_write_config_dword(hose, dev, PCI_DCR, temp32);
+	pci_hose_write_config_dword(hose, dev, pci_dcr, temp32);
 
 #if defined(CONFIG_FSL_PCIE_DISABLE_ASPM)
 	temp32 = 0;
-	pci_hose_read_config_dword(hose, dev, PCI_LCR, &temp32);
+	pci_hose_read_config_dword(hose, dev, pci_lcr, &temp32);
 	temp32 &= ~0x03;		/* Disable ASPM  */
-	pci_hose_write_config_dword(hose, dev, PCI_LCR, temp32);
+	pci_hose_write_config_dword(hose, dev, pci_lcr, temp32);
 	udelay(1);
 #endif
 	if (pcie_cap == PCI_CAP_ID_EXP) {
@@ -507,7 +518,7 @@  void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
 		out_be32(&pci->pme_msg_int_en, 0xffffffff);
 
 		/* Print the negotiated PCIe link width */
-		pci_hose_read_config_word(hose, dev, PCI_LSR, &temp16);
+		pci_hose_read_config_word(hose, dev, pci_lsr, &temp16);
 		printf("x%d, regs @ 0x%lx\n", (temp16 & 0x3f0 ) >> 4,
 			pci_info->regs);
 
@@ -554,9 +565,9 @@  void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
 		out_be32(&pci->pme_msg_det, 0xffffffff);
 	out_be32(&pci->pedr, 0xffffffff);
 
-	pci_hose_read_config_word (hose, dev, PCI_DSR, &temp16);
+	pci_hose_read_config_word(hose, dev, pci_dsr, &temp16);
 	if (temp16) {
-		pci_hose_write_config_word(hose, dev, PCI_DSR, 0xffff);
+		pci_hose_write_config_word(hose, dev, pci_dsr, 0xffff);
 	}
 
 	pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16);
@@ -567,10 +578,12 @@  void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
 
 int fsl_is_pci_agent(struct pci_controller *hose)
 {
+	int pcie_cap_pos;
 	u8 pcie_cap;
 	pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
 
-	pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);
+	pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+	pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
 	if (pcie_cap == PCI_CAP_ID_EXP) {
 		u8 header_type;
 
@@ -595,6 +608,7 @@  int fsl_pci_init_port(struct fsl_pci_info *pci_info,
 	volatile ccsr_fsl_pci_t *pci;
 	struct pci_region *r;
 	pci_dev_t dev = PCI_BDF(busno,0,0);
+	int pcie_cap_pos;
 	u8 pcie_cap;
 
 	pci = (ccsr_fsl_pci_t *) pci_info->regs;
@@ -644,7 +658,8 @@  int fsl_pci_init_port(struct fsl_pci_info *pci_info,
 #endif
 	}
 
-	pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);
+	pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+	pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
 	printf("PCI%s%x: Bus %02x - %02x\n", pcie_cap == PCI_CAP_ID_EXP ?
 		"e" : "", pci_info->pci_num,
 		hose->first_busno, hose->last_busno);
@@ -656,13 +671,14 @@  int fsl_pci_init_port(struct fsl_pci_info *pci_info,
 void fsl_pci_config_unlock(struct pci_controller *hose)
 {
 	pci_dev_t dev = PCI_BDF(hose->first_busno,0,0);
+	int pcie_cap_pos;
 	u8 pcie_cap;
 	u16 pbfr;
 
 	if (!fsl_is_pci_agent(hose))
 		return;
-
-	pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);
+	pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+	pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
 	if (pcie_cap != 0x0) {
 		/* PCIe - set CFG_READY bit of Configuration Ready Register */
 #ifdef CONFIG_SYS_FSL_PCI_VER_3_X
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d864f13..3d2bf77 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -35,6 +35,9 @@ 
 #include <asm/io.h>
 #include <pci.h>
 
+#define PCI_FIND_CAP_TTL 0x48
+#define CAP_START_POS 0x40
+
 #define PCI_HOSE_OP(rw, size, type)					\
 int pci_hose_##rw##_config_##size(struct pci_controller *hose,		\
 				  pci_dev_t dev,			\
@@ -738,3 +741,68 @@  void pci_init(void)
 	/* now call board specific pci_init()... */
 	pci_init_board();
 }
+
+/* Returns the address of the requested capability structure within the
+ * device's PCI configuration space or 0 in case the device does not
+ * support it.
+ * */
+int pci_hose_find_capability(struct pci_controller *hose, pci_dev_t dev,
+			     int cap)
+{
+	int pos;
+	u8 hdr_type;
+
+	pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &hdr_type);
+
+	pos = pci_hose_find_cap_start(hose, dev, hdr_type & 0x7F);
+
+	if (pos)
+		pos = pci_find_cap(hose, dev, pos, cap);
+
+	return pos;
+}
+
+/* Find the header pointer to the Capabilities*/
+int pci_hose_find_cap_start(struct pci_controller *hose, pci_dev_t dev,
+			    u8 hdr_type)
+{
+	u16 status;
+
+	pci_hose_read_config_word(hose, dev, PCI_STATUS, &status);
+
+	if (!(status & PCI_STATUS_CAP_LIST))
+		return 0;
+
+	switch (hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+	case PCI_HEADER_TYPE_BRIDGE:
+		return PCI_CAPABILITY_LIST;
+	case PCI_HEADER_TYPE_CARDBUS:
+		return PCI_CB_CAPABILITY_LIST;
+	default:
+		return 0;
+	}
+}
+
+int pci_find_cap(struct pci_controller *hose, pci_dev_t dev, int pos, int cap)
+{
+	int ttl = PCI_FIND_CAP_TTL;
+	u8 id;
+	u8 next_pos;
+
+	while (ttl--) {
+		pci_hose_read_config_byte(hose, dev, pos, &next_pos);
+		if (next_pos < CAP_START_POS)
+			break;
+		next_pos &= ~3;
+		pos = (int) next_pos;
+		pci_hose_read_config_byte(hose, dev,
+					  pos + PCI_CAP_LIST_ID, &id);
+		if (id == 0xff)
+			break;
+		if (id == cap)
+			return pos;
+		pos += PCI_CAP_LIST_NEXT;
+	}
+	return 0;
+}
diff --git a/include/pci.h b/include/pci.h
index 7e3b3b6..e59c3b5 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -663,6 +663,13 @@  extern int pci_hose_config_device(struct pci_controller *hose,
 				  pci_addr_t mem,
 				  unsigned long command);
 
+extern int pci_hose_find_capability(struct pci_controller *hose, pci_dev_t dev,
+				    int cap);
+extern int pci_hose_find_cap_start(struct pci_controller *hose, pci_dev_t dev,
+				   u8 hdr_type);
+extern int pci_find_cap(struct pci_controller *hose, pci_dev_t dev, int pos,
+			int cap);
+
 const char * pci_class_str(u8 class);
 int pci_last_busno(void);