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