[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