[linux-yocto] [PATCH 01/17] drivers/pci: Support the Updated Axxia PCIe/sRIO Coefficients

Daniel Dragomir daniel.dragomir at windriver.com
Tue May 16 11:38:53 PDT 2017


From: John Jacques <john.jacques at intel.com>

Get the updated PCIe/sRIO parameters from the device tree and
update the appropriate SerDes registers.

Signed-off-by: John Jacques <john.jacques at intel.com>
---
 drivers/misc/axxia-pei.c      | 287 +++++++++++++++++++++++++++++++++++++++++-
 drivers/pci/host/pcie-axxia.c |   5 +-
 include/linux/axxia-pei.h     |   2 +-
 3 files changed, 290 insertions(+), 4 deletions(-)

diff --git a/drivers/misc/axxia-pei.c b/drivers/misc/axxia-pei.c
index c65b98e..7a5b255 100644
--- a/drivers/misc/axxia-pei.c
+++ b/drivers/misc/axxia-pei.c
@@ -39,6 +39,26 @@ static int is_6700;
 static void __iomem *pcie_gpreg0;
 static void __iomem *pcie_rc;
 
+static int is_pei_control_available;
+static int is_pei_control_v2;
+
+struct pei_coefficients {
+	unsigned version;
+	unsigned control;
+	unsigned primary_input_clock;
+	unsigned input_ref_clock_range;
+	unsigned lane_0_eq_main;
+	unsigned lane_0_eq_pre;
+	unsigned lane_0_eq_post;
+	unsigned lane_0_vboost;
+	unsigned lane_1_eq_main;
+	unsigned lane_1_eq_pre;
+	unsigned lane_1_eq_post;
+	unsigned lane_1_vboost;
+};
+
+static struct pei_coefficients coefficients;
+
 enum SataMode {
 	SATA0,
 	SATA1
@@ -751,12 +771,148 @@ enable_lane(u32 phy, u32 lane, enum Dir dir)
 
 /*
   ------------------------------------------------------------------------------
+  update_settings
+*/
+
+static void
+update_settings(void)
+{
+	int i;
+	unsigned int region;
+
+	/*
+	  Make sure the parameters are version 2...
+	*/
+
+	if (!is_pei_control_v2)
+		return;
+
+	region = NCP_REGION_ID(0x115, 0);
+
+	/*
+	  Set per serdes values.
+	*/
+
+	for (i = 0; i < 4; ++i) {
+		unsigned int offset;
+		unsigned int pic;
+		unsigned int ref_range;
+		unsigned int value;
+
+		offset = (0xf8 + (i * 0x18));
+
+		if (0 != (coefficients.primary_input_clock & (0xff << (i * 8))))
+			pic = 2;
+		else
+			pic = 0;
+
+		ref_range = (coefficients.input_ref_clock_range &
+			     (0xff << (i * 8))) >> (i * 8);
+
+		ncr_read32(region, offset, &value);
+		pr_debug("0x%x.0x%x.0x%x : 0x%x => ",
+		      NCP_NODE_ID(region), NCP_TARGET_ID(region), offset,
+		      value);
+		value &= ~0x72;
+		value |= pic;
+		value |= ref_range << 4;
+		pr_debug("0x%x\n", value);
+		ncr_write32(region, offset, value);
+	}
+
+	/*
+	  Set per lane values.
+	*/
+
+	for (i = 0; i < 8; ++i) {
+		unsigned int offset;
+		unsigned int eq_main;
+		unsigned int pre;
+		unsigned int post;
+		unsigned int boost;
+		unsigned int value;
+
+		if (4 > i) {
+			eq_main = coefficients.lane_0_eq_main;
+			pre = coefficients.lane_0_eq_pre;
+			post = coefficients.lane_0_eq_post;
+			boost = coefficients.lane_0_vboost;
+		} else {
+			eq_main = coefficients.lane_1_eq_main;
+			pre = coefficients.lane_1_eq_pre;
+			post = coefficients.lane_1_eq_post;
+			boost = coefficients.lane_1_vboost;
+		}
+
+		switch (i % 4) {
+		case 0:
+			eq_main &= 0x3f;
+			pre &= 0x3f;
+			post &= 0x3f;
+			boost &= 0x3f;
+			break;
+		case 1:
+			eq_main = (eq_main & 0x3f00) >> 8;
+			pre = (pre & 0x3f00) >> 8;
+			post = (post & 0x3f00) >> 8;
+			boost = (boost & 0x3f00) >> 8;
+			break;
+		case 2:
+			eq_main = (eq_main & 0x3f0000) >> 16;
+			pre = (pre & 0x3f0000) >> 16;
+			post = (post & 0x3f0000) >> 16;
+			boost = (boost & 0x3f0000) >> 16;
+			break;
+		case 3:
+			eq_main = (eq_main & 0x3f000000) >> 24;
+			pre = (pre & 0x3f000000) >> 24;
+			post = (post & 0x3f000000) >> 24;
+			boost = (boost & 0x3f000000) >> 24;
+			break;
+		default:
+			pr_err("Error setting coefficients!\n");
+			break;
+		}
+
+		offset = 0x18 + (i * 0x1c);
+
+		ncr_read32(region, offset, &value);
+		pr_debug("0x%x.0x%x.0x%x : 0x%x => ",
+		      NCP_NODE_ID(region), NCP_TARGET_ID(region), offset,
+		      value);
+		value &= ~(1 << 11);
+
+		if (0 != boost)
+			value |= (1 << 11);
+
+		pr_debug("0x%x\n", value);
+		ncr_write32(region, offset, value);
+
+		offset += 0x8;
+
+		ncr_read32(region, offset, &value);
+		pr_debug("0x%x.0x%x.0x%x : 0x%x => ",
+		      NCP_NODE_ID(region), NCP_TARGET_ID(region), offset,
+		      value);
+		value &= ~0x3f3f3f;
+		value |= ((post << 16) | (pre << 8) | eq_main);
+		pr_debug("0x%x\n", value);
+		ncr_write32(region, offset, value);
+	}
+
+	return;
+}
+
+
+/*
+  ------------------------------------------------------------------------------
   pei_setup
 */
 
 int
-pei_setup(unsigned int control)
+pei_setup(void)
 {
+	unsigned int control;
 	unsigned int pci_srio_sata_mode;
 	unsigned int val;
 	unsigned int rc_mode;
@@ -776,6 +932,14 @@ pei_setup(unsigned int control)
 	enum PLLMode pll;
 	int phy, lane;
 
+	if (!is_pei_control_available) {
+		pr_err("Control value is NOT available!\n");
+
+		return 1;
+	}
+
+	control = coefficients.control;
+
 	pci_srio_sata_mode = (control & 0x03c00000) >> 22;
 	sata0_mode = (control & 0x20) >> 5;
 	sata1_mode = (control & 0x40) >> 6;
@@ -1527,6 +1691,8 @@ pei_setup(unsigned int control)
 		break;
 	}
 
+	update_settings();
+
 	return 0;
 }
 
@@ -1534,6 +1700,48 @@ EXPORT_SYMBOL(pei_setup);
 
 /*
   ------------------------------------------------------------------------------
+  get_v2_coefficients
+*/
+
+static int
+get_v2_coefficients(struct device_node *pei_control)
+{
+	int i;
+	unsigned *lvalue;
+	char *names[] = {
+		"primary_input_clock",
+		"input_ref_clock_range",
+		"lane_0_eq_main",
+		"lane_0_eq_pre",
+		"lane_0_eq_post",
+		"lane_0_vboost",
+		"lane_1_eq_main",
+		"lane_1_eq_pre",
+		"lane_1_eq_post",
+		"lane_1_vboost"
+	};
+
+	lvalue = &coefficients.primary_input_clock;
+
+	for (i = 0; i < sizeof(names) / sizeof(char *); ++i, ++lvalue) {
+		const unsigned int *value;
+
+		value = of_get_property(pei_control, names[i], NULL);
+
+		if (NULL == value) {
+			pr_warn("Failed reading %s\n.", names[i]);
+
+			return -1;
+		}
+
+		*lvalue = be32_to_cpu(*value);
+	}
+
+	return 0;
+}
+
+/*
+  ------------------------------------------------------------------------------
   pei_init
 */
 
@@ -1556,6 +1764,83 @@ pei_init(void)
 		return -1;
 	}
 
+	pr_debug("is_5500=%d is_5600=%d is_6700=%d\n",
+		 is_5500, is_5600, is_6700);
+
+	if ((1 == is_5600) || (1 == is_6700)) {
+		struct device_node *pei_control;
+		const unsigned int *value;
+
+		memset(&coefficients, 0, sizeof(struct pei_coefficients));
+		is_pei_control_available = 0;
+		is_pei_control_v2 = 0;
+
+		/* Get the extra parameters. */
+		pei_control = of_find_node_by_name(NULL, "pei_control");
+
+		if (!pei_control) {
+			pr_warn("No Parameters Available for PEI Setup!\n");
+
+			return 0;
+		}
+
+		value = of_get_property(pei_control, "control", NULL);
+
+		if (NULL == value) {
+			pr_warn("PEI Control Version is NOT set!\n");
+
+			return 0;
+		}
+
+		coefficients.control = be32_to_cpu(*value);
+		is_pei_control_available = 1;
+		pr_debug("coefficients.control = 0x%x\n",
+			 coefficients.control);
+
+		value = of_get_property(pei_control, "version", NULL);
+
+		if (NULL == value) {
+			pr_warn("PEI Control Version is NOT set!\n");
+
+			return 0;
+		}
+
+		coefficients.version = be32_to_cpu(*value);
+		pr_debug("coefficients.version = 0x%x\n",
+			 coefficients.version);
+
+		if (2 == coefficients.version) {
+			if (0 != get_v2_coefficients(pei_control)) {
+				pr_warn("Error reading PEI Coefficients!\n");
+
+				return 0;
+			}
+
+			is_pei_control_v2 = 1;
+
+			pr_debug("primary_input_clock=0x%x\n",
+				 coefficients.primary_input_clock);
+			pr_debug("input_ref_clock_range=0x%x\n",
+				 coefficients.input_ref_clock_range);
+			pr_debug("lane_0_eq_main=0x%x\n",
+				 coefficients.lane_0_eq_main);
+			pr_debug("lane_0_eq_pre=0x%x\n",
+				 coefficients.lane_0_eq_pre);
+			pr_debug("lane_0_eq_post=0x%x\n",
+				 coefficients.lane_0_eq_post);
+			pr_debug("lane_0_vboost=0x%x\n",
+				 coefficients.lane_0_vboost);
+			pr_debug("lane_1_eq_main=0x%x\n",
+				 coefficients.lane_1_eq_main);
+			pr_debug("lane_1_eq_pre=0x%x\n",
+				 coefficients.lane_1_eq_pre);
+			pr_debug("lane_1_eq_post=0x%x\n",
+				 coefficients.lane_1_eq_post);
+			pr_debug("lane_1_vboost=0x%x\n",
+				 coefficients.lane_1_vboost);
+		}
+	}
+
 	return 0;
 }
 
diff --git a/drivers/pci/host/pcie-axxia.c b/drivers/pci/host/pcie-axxia.c
index 52ccbd7..247838e 100644
--- a/drivers/pci/host/pcie-axxia.c
+++ b/drivers/pci/host/pcie-axxia.c
@@ -963,7 +963,7 @@ static int axxia_pcie_probe(struct platform_device *pdev)
 			axxia_pcie->initialized = be32_to_cpu(*initialized);
 
 		if (0 == axxia_pcie->initialized)
-			if (0 != pei_setup(axxia_pcie->control)) {
+			if (0 != pei_setup()) {
 				pr_err("pcie-axxia: PEI setup failed!\n");
 
 				return -EINVAL;
@@ -1015,7 +1015,7 @@ axxia_pcie_reset(void)
 		return -1;
 
 	/* Re-initialize the PEIs */
-	pei_setup(control_value);
+	pei_setup();
 
 	/* Re-configure the root complex */
 	axxia_pcie_setup_rc(_pp);
@@ -1059,6 +1059,7 @@ static int pcie2_init(void)
 	struct proc_dir_entry *pf = proc_create("driver/axxia_pcie_reset",
 						S_IWUSR, NULL,
 						&axxia_pcie_reset_proc_ops);
+
 	if (pf == NULL) {
 		pr_err("Could not create /proc/driver/axxia_pcie_reset!\n");
 		return -1;
diff --git a/include/linux/axxia-pei.h b/include/linux/axxia-pei.h
index cfd4dc2..abbe9d6 100644
--- a/include/linux/axxia-pei.h
+++ b/include/linux/axxia-pei.h
@@ -18,7 +18,7 @@
 #ifndef __AXXIA_PEI_H
 #define __AXXIA_PEI_H
 
-int pei_setup(unsigned int);
+int pei_setup(void);
 int axxia_pcie_reset(void);
 
 #endif	/* __AXXIA_PEI_H */
-- 
2.7.4



More information about the linux-yocto mailing list