From: John Jacques <john.jacq...@intel.com>

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

Signed-off-by: John Jacques <john.jacq...@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

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to