lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID:
 <CY1PR12MB9697F67210064132883611A8B762A@CY1PR12MB9697.namprd12.prod.outlook.com>
Date: Tue, 10 Feb 2026 16:04:50 +0000
From: "Pandey, Radhey Shyam" <radhey.shyam.pandey@....com>
To: Sean Anderson <sean.anderson@...ux.dev>, Laurent Pinchart
	<laurent.pinchart@...asonboard.com>, Vinod Koul <vkoul@...nel.org>,
	"linux-phy@...ts.infradead.org" <linux-phy@...ts.infradead.org>
CC: Krzysztof Wilczyński <kwilczynski@...nel.org>, Lorenzo
 Pieralisi <lpieralisi@...nel.org>, "linux-kernel@...r.kernel.org"
	<linux-kernel@...r.kernel.org>, "Simek, Michal" <michal.simek@....com>,
	"linux-arm-kernel@...ts.infradead.org"
	<linux-arm-kernel@...ts.infradead.org>, "linux-pci@...r.kernel.org"
	<linux-pci@...r.kernel.org>, Neil Armstrong <neil.armstrong@...aro.org>, Rob
 Herring <robh@...nel.org>, "Havalige, Thippeswamy"
	<thippeswamy.havalige@....com>, Manivannan Sadhasivam <mani@...nel.org>,
	Bjorn Helgaas <bhelgaas@...gle.com>
Subject: RE: [PATCH 4/8] phy: zynqmp: Calibrate ILL if necessary

[Public]

> -----Original Message-----
> From: Sean Anderson <sean.anderson@...ux.dev>
> Sent: Tuesday, February 3, 2026 5:51 AM
> To: Laurent Pinchart <laurent.pinchart@...asonboard.com>; Vinod Koul
> <vkoul@...nel.org>; linux-phy@...ts.infradead.org
> Cc: Krzysztof Wilczyński <kwilczynski@...nel.org>; Lorenzo Pieralisi
> <lpieralisi@...nel.org>; Pandey, Radhey Shyam
> <radhey.shyam.pandey@....com>; linux-kernel@...r.kernel.org; Simek, Michal
> <michal.simek@....com>; linux-arm-kernel@...ts.infradead.org; linux-
> pci@...r.kernel.org; Neil Armstrong <neil.armstrong@...aro.org>; Rob Herring
> <robh@...nel.org>; Havalige, Thippeswamy <thippeswamy.havalige@....com>;
> Manivannan Sadhasivam <mani@...nel.org>; Bjorn Helgaas
> <bhelgaas@...gle.com>; Sean Anderson <sean.anderson@...ux.dev>
> Subject: [PATCH 4/8] phy: zynqmp: Calibrate ILL if necessary
>
> init_serdes in psu_init_gpl is supposed to calibrate the ILL. However, this
> may fail if the reference clock is not running, such as if the clock needs
> to be configured on boot. To work around this, add support for ILL
> calibration in U-Boot. If the ILL is already calibrated (any non-zero
> value) we skip calibration.
>
> The algorithm is substantially the same as serdes_illcalib [1], but it has
> been updated for readability (and to remove all the "if (lane0_active)"
> conditions). Due to the amount of register fields, many of which are
> undocumented (especially the chicken bits), I have mostly used defines only
> for the register names. There are certainly areas where register writes are
> superfluous, but I have left these in order to minimize deviation from the
> procedure in serdes_illcalib.

Please consider splitting the patch in introducing calibrate ILL functions
and then subsequently using them.

How did you validate the changes? functional testing is one part
but I think better to match register configuration done in psu_init vs
this series? Have we tried running on multiple designs having
different GT lane and protocol combinations .

There are multiple magic numbers. Consider renaming it to
meaningful defines.

>
> [1] Example implementation; xpsgtr_phy_illcalib coresponds to
>     serdes_illcalib_pcie_gen1:
> https://source.denx.de/u-boot/u-boot/-/blob/v2026.01/board/xilinx/zynqmp/zynqmp-
> zcu208-revA/psu_init_gpl.c?ref_type=tags#L710
>
> Signed-off-by: Sean Anderson <sean.anderson@...ux.dev>
> ---
>
>  drivers/phy/xilinx/phy-zynqmp.c | 421 +++++++++++++++++++++++++++++++-
>  1 file changed, 420 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c
> index 152af1702bbd..854b0ea04648 100644
> --- a/drivers/phy/xilinx/phy-zynqmp.c
> +++ b/drivers/phy/xilinx/phy-zynqmp.c
> @@ -12,6 +12,7 @@
>   * PCIe should also work but that is experimental as of now.
>   */
>
> +#include <linux/bitfield.h>
>  #include <linux/clk.h>
>  #include <linux/debugfs.h>
>  #include <linux/delay.h>
> @@ -31,6 +32,7 @@
>   */
>
>  /* TX De-emphasis parameters */
> +#define L0_TX_ANA_TM_3                       0x000c
>  #define L0_TX_ANA_TM_18                      0x0048
>  #define L0_TX_ANA_TM_118             0x01d8
>  #define L0_TX_ANA_TM_118_FORCE_17_0  BIT(0)
> @@ -50,16 +52,49 @@
>  #define L0_TXPMD_TM_45_ENABLE_DP_POST2       BIT(5)
>
>  /* PCS control parameters */
> +#define L0_TM_ANA_BYP_4                      0x1010
> +#define L0_TM_ANA_BYP_7                      0x1018
>  #define L0_TM_DIG_6                  0x106c
> +#define L0_TM_DIG_22                 0x10ac
>  #define L0_TM_DIS_DESCRAMBLE_DECODER 0x0f
>  #define L0_TX_DIG_61                 0x00f4
>  #define L0_TM_DISABLE_SCRAMBLE_ENCODER       0x0f
> +#define L0_TM_AUX_0                  0x10cc
> +#define L0_TM_MISC2                  0x189c
> +#define L0_TM_MISC2_ILL_CAL_BYPASS   BIT(7)
> +#define L0_TM_IQ_ILL1                        0x18f8
> +#define L0_TM_IQ_ILL2                        0x18fc

#define L0_TM_IQ_ILL3                   0x1900

IQ_ILL(n) = 0x18f8 + (n - 1) * 4 ?

Similarly for others  (when applicable)?

> +#define L0_TM_ILL11                  0x198c
> +#define L0_TM_ILL12                  0x1990
> +#define L0_TM_E_ILL1                 0x1924
> +#define L0_TM_E_ILL2                 0x1928
> +#define L0_TM_IQ_ILL3                        0x1900
> +#define L0_TM_E_ILL3                 0x192c
> +#define L0_TM_IQ_ILL7                        0x1910
> +#define L0_TM_E_ILL7                 0x193c
> +#define L0_TM_ILL8                   0x1980
> +#define L0_TM_IQ_ILL8                        0x1914
> +#define L0_TM_IQ_ILL9                        0x1918
> +#define L0_TM_EQ0                    0x194c
> +#define L0_TM_EQ0_EQ_STG2_CTRL_BYP   BIT(5)
> +#define L0_TM_EQ1                    0x1950
> +#define L0_TM_EQ1_EQ_STG2_RL_PROG    GENMASK(1, 0)
> +#define L0_TM_EQ1_EQ_STG2_PREAMP_MODE_VAL    BIT(2)
> +#define L0_TM_E_ILL8                 0x1940
> +#define L0_TM_E_ILL9                 0x1944
> +#define L0_TM_ILL13                  0x1994
> +#define L0_TM_CDR5                   0x1c14
> +#define L0_TM_CDR5_FPHL_FSM_ACC_CYCLES       GENMASK(7, 5)
> +#define L0_TM_CDR5_FFL_PH0_INT_GAIN  GENMASK(4, 0)
> +#define L0_TM_CDR16                  0x1c40
>
>  /* PLL Test Mode register parameters */
> +#define L0_TM_PLL_DIG_33             0x2084
>  #define L0_TM_PLL_DIG_37             0x2094
>  #define L0_TM_COARSE_CODE_LIMIT              0x10
>
>  /* PLL SSC step size offsets */
> +#define L0_PLL_FBDIV_FRAC_3_MSB              0x2360
>  #define L0_PLL_SS_STEPS_0_LSB                0x2368
>  #define L0_PLL_SS_STEPS_1_MSB                0x236c
>  #define L0_PLL_SS_STEP_SIZE_0_LSB    0x2370
> @@ -69,6 +104,7 @@
>  #define L0_PLL_STATUS_READ_1         0x23e4
>
>  /* SSC step size parameters */
> +#define TM_FORCE_EN_FRAC             BIT(6)
>  #define STEP_SIZE_0_MASK             0xff
>  #define STEP_SIZE_1_MASK             0xff
>  #define STEP_SIZE_2_MASK             0xff
> @@ -76,6 +112,7 @@
>  #define STEP_SIZE_SHIFT                      8
>  #define FORCE_STEP_SIZE                      0x10
>  #define FORCE_STEPS                  0x20
> +#define TM_FORCE_EN                  BIT(7)
>  #define STEPS_0_MASK                 0xff
>  #define STEPS_1_MASK                 0x07
>
> @@ -84,6 +121,32 @@
>  #define L0_REF_CLK_LCL_SEL           BIT(7)
>  #define L0_REF_CLK_SEL_MASK          0x9f
>
> +/* Built-in self-test parameters */
> +#define L0_BIST_CTRL_1                       0x3004
> +#define L0_BIST_CTRL_2                       0x3008
> +#define L0_BIST_RUN_LEN_L            0x300c
> +#define L0_BIST_ERR_INJ_POINT_L              0x3010
> +#define L0_BIST_RUNLEN_ERR_INJ_H     0x3014
> +#define L0_BIST_IDLE_TIME            0x3018
> +#define L0_BIST_MARKER_L             0x301c
> +#define L0_BIST_IDLE_CHAR_L          0x3020
> +#define L0_BIST_MARKER_IDLE_H                0x3024
> +#define L0_BIST_LOW_PULSE_TIME               0x3028
> +#define L0_BIST_TOTAL_PULSE_TIME     0x302c
> +#define L0_BIST_TEST_PAT_1           0x3030
> +#define L0_BIST_TEST_PAT_2           0x3034
> +#define L0_BIST_TEST_PAT_3           0x3038
> +#define L0_BIST_TEST_PAT_4           0x303c
> +#define L0_BIST_TEST_PAT_MSBS                0x3040
> +#define L0_BIST_PKT_NUM                      0x3044
> +#define L0_BIST_FRM_IDLE_TIME                0x3048
> +#define L0_BIST_PKT_CTR_L            0x304c
> +#define L0_BIST_PKT_CTR_H            0x3050
> +#define L0_BIST_ERR_CTR_L            0x3054
> +#define L0_BIST_ERR_CTR_H            0x3058
> +#define L0_BIST_FILLER_OUT           0x3068
> +#define L0_BIST_FORCE_MK_RST         0x306c
> +
>  /* Calibration digital logic parameters */
>  #define L3_TM_CALIB_DIG19            0xec4c
>  #define L3_CALIB_DONE_STATUS         0xef14
> @@ -139,6 +202,9 @@ static const char *const xpsgtr_icm_str[] = {
>  #define TM_CMN_RST_SET                       0x2
>  #define TM_CMN_RST_MASK                      0x3
>
> +#define LPBK_CTRL0                   0x10038
> +#define LPBK_CTRL1                   0x1003c
> +
>  /* Bus width parameters */
>  #define TX_PROT_BUS_WIDTH            0x10040
>  #define RX_PROT_BUS_WIDTH            0x10044
> @@ -148,9 +214,13 @@ static const char *const xpsgtr_icm_str[] = {
>  #define PROT_BUS_WIDTH_SHIFT(n)              ((n) * 2)
>  #define PROT_BUS_WIDTH_MASK(n)               GENMASK((n) * 2 + 1, (n) * 2)
>
> +#define UPHY_SPARE0                  0X10098
> +
>  /* Number of GT lanes */
>  #define NUM_LANES                    4
>
> +#define SIOU_ECO_0                   0x1c
> +
>  /* SIOU SATA control register */
>  #define SATA_CONTROL_OFFSET          0x0100
>
> @@ -338,6 +408,33 @@ static void xpsgtr_restore_lane_regs(struct xpsgtr_dev
> *gtr_dev)
>                            gtr_dev->saved_regs[i]);
>  }
>
> +static inline void xpsgtr_write_lanes(struct xpsgtr_dev *gtr_dev,
> +                                  unsigned long *lanes, u32 reg, u32 value)
> +{
> +     unsigned long lane;
> +
> +     for_each_set_bit(lane, lanes, NUM_LANES) {
> +             void __iomem *addr = gtr_dev->serdes + lane * PHY_REG_OFFSET
> +                                  + reg;
> +
> +             writel(value, addr);
> +     }
> +}
> +
> +static inline void xpsgtr_clr_set_lanes(struct xpsgtr_dev *gtr_dev,
> +                                    unsigned long *lanes, u32 reg, u32 clr,
> +                                    u32 set)
> +{
> +     unsigned long lane;
> +
> +     for_each_set_bit(lane, lanes, NUM_LANES) {
> +             void __iomem *addr = gtr_dev->serdes + lane * PHY_REG_OFFSET
> +                                  + reg;
> +
> +             writel((readl(addr) & ~clr) | set, addr);
> +     }
> +}
> +
>  /*
>   * Hardware Configuration
>   */
> @@ -351,7 +448,7 @@ static int xpsgtr_wait_pll_lock(struct phy *phy)
>       u8 protocol = gtr_phy->protocol;
>       int ret;
>
> -     dev_dbg(gtr_dev->dev, "Waiting for PLL lock\n");
> +     dev_vdbg(gtr_dev->dev, "Waiting for PLL lock\n");

Unrelated change.

>
>       /*
>        * For DP and PCIe, only the instance 0 PLL is used. Switch to that phy
> @@ -520,6 +617,231 @@ static void xpsgtr_bypass_scrambler_8b10b(struct
> xpsgtr_phy *gtr_phy)
>       xpsgtr_write_phy(gtr_phy, L0_TX_DIG_61,
> L0_TM_DISABLE_SCRAMBLE_ENCODER);
>  }
>
> +/* Enable or disable loopback */
> +static void xpsgtr_phy_set_loopback(struct xpsgtr_phy *gtr_phy, bool enabled)
> +{
> +     struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
> +     u32 reg = gtr_phy->lane >= 2 ? LPBK_CTRL1 : LPBK_CTRL0;
> +     u32 shift = gtr_phy->lane & 1 ? 4 : 0;
> +
> +     xpsgtr_clr_set(gtr_dev, reg, 7 << shift, (u32)enabled << shift);
> +}
> +
> +static void xpsgtr_phy_set_ill(struct xpsgtr_phy *gtr_phy, u32 ill, bool gen2)
> +{
> +     u32 val = 4 + ill * 8;
> +
> +     if (gen2) {
> +             xpsgtr_write_phy(gtr_phy, L0_TM_E_ILL2, val & 0xff);
> +             xpsgtr_clr_set_phy(gtr_phy, L0_TM_ILL12, 0x0f,
> +                                1 << (val >> 8));
> +     } else {
> +             xpsgtr_write_phy(gtr_phy, L0_TM_E_ILL1, val & 0xff);
> +             xpsgtr_clr_set_phy(gtr_phy, L0_TM_ILL12, 0xf0,
> +                                (val >> 4) & 0x10);
> +     }
> +}
> +
> +static bool xpsgtr_ill_calibrated(struct xpsgtr_phy *gtr_phy)
> +{
> +     u32 ill1 = xpsgtr_read_phy(gtr_phy, L0_TM_E_ILL1);
> +     u32 ill2 = xpsgtr_read_phy(gtr_phy, L0_TM_E_ILL2);
> +     u32 ill12 = xpsgtr_read_phy(gtr_phy, L0_TM_ILL12);
> +
> +     dev_dbg(gtr_phy->dev->dev, "lane %u gen1 ILL was %u gen2 ILL was
> %u\n",
> +             gtr_phy->lane, ill1 / 8 + (ill12 & 0x10 ? 32 : 0),
> +             ill2 / 8 + (ill12 & 0x02 ? 32 : 0));
> +     return ill1 || ill2 || ill12;
> +}
> +
> +static void xpsgtr_init_ill(struct xpsgtr_phy *gtr_phy)
> +{
> +     struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
> +     struct clk *clk = gtr_dev->clk[gtr_phy->refclk];
> +     u32 ill123 = DIV_ROUND_CLOSEST(clk_get_rate(clk), 1000000);
> +
> +     xpsgtr_clr_set_phy(gtr_phy, L0_TM_MISC2, 0,
> L0_TM_MISC2_ILL_CAL_BYPASS);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_IQ_ILL1, ill123);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_IQ_ILL2, ill123);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_IQ_ILL3, ill123);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_IQ_ILL7, 0xf3);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_E_ILL7, 0xf3);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_ILL8, 0xff);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_IQ_ILL8, 0xf3);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_E_ILL8, 0xf3);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_IQ_ILL9, 1);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_E_ILL9, 1);
> +     xpsgtr_clr_set(gtr_dev, UPHY_SPARE0, BIT(5), 0);
> +}
> +
> +static void xpsgtr_phy_illcalib(struct xpsgtr_dev *gtr_dev,
> +                                  unsigned long *lanes, bool gen2)
> +{
> +     bool last_ok[NUM_LANES] = { 0 };
> +     int pass[NUM_LANES] = { 0 }, altpass[NUM_LANES] = { 0 };
> +     int best[NUM_LANES] = { 0 }, altbest[NUM_LANES] = { 0 };
> +     unsigned long lane;
> +     int i;
> +
> +     /* Initialize the BIST */
> +     xpsgtr_clr_set_lanes(gtr_dev, lanes, L0_BIST_CTRL_1, 0xe0, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_FILLER_OUT, 1);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_FORCE_MK_RST, 1);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_TM_DIG_22, 0x20);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_CTRL_2, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_RUN_LEN_L, 0xf4);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_ERR_INJ_POINT_L, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_RUNLEN_ERR_INJ_H, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_IDLE_TIME, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_MARKER_L, 0xfb);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_IDLE_CHAR_L, 0xff);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_MARKER_IDLE_H, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_LOW_PULSE_TIME, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TOTAL_PULSE_TIME, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TEST_PAT_1, 0x4a);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TEST_PAT_2, 0x4a);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TEST_PAT_3, 0x4a);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TEST_PAT_4, 0x4a);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TEST_PAT_MSBS, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_PKT_NUM, 0x14);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_FRM_IDLE_TIME, 2);
> +     xpsgtr_clr_set_lanes(gtr_dev, lanes, L0_BIST_CTRL_1, 0xe0, 0);
> +
> +     for (i = 0; i < 64; i++) {
> +             bool ok[NUM_LANES];
> +
> +             for_each_set_bit(lane, lanes, NUM_LANES)
> +                     xpsgtr_phy_set_ill(&gtr_dev->phys[lane], i, gen2);
> +
> +             /* Reset lanes */
> +             xpsgtr_clr_set_lanes(gtr_dev, lanes, L0_TM_ANA_BYP_7, 0x20,
> +                                  0x10);
> +             xpsgtr_write(gtr_dev, UPHY_SPARE0, 0x00);
> +             xpsgtr_write_lanes(gtr_dev, lanes, L0_TM_ANA_BYP_4, 0x40);
> +             xpsgtr_write_lanes(gtr_dev, lanes, L0_TM_PLL_DIG_33, 0x80);
> +             xpsgtr_write(gtr_dev, UPHY_SPARE0, 0x04);
> +             udelay(50);
> +             if (gen2)
> +                     xpsgtr_write(gtr_dev, UPHY_SPARE0, 0x0e);
> +             xpsgtr_write(gtr_dev, UPHY_SPARE0, 0x06);
> +             if (gen2) {
> +                     xpsgtr_write_lanes(gtr_dev, lanes, L0_TX_ANA_TM_3, 0x04);
> +                     xpsgtr_write(gtr_dev, UPHY_SPARE0, 0x07);
> +                     udelay(400);
> +                     xpsgtr_write_lanes(gtr_dev, lanes, L0_TX_ANA_TM_3, 0x0c);
> +                     udelay(15);
> +                     xpsgtr_write(gtr_dev, UPHY_SPARE0, 0x0f);
> +                     udelay(100);
> +             }
> +
> +             if (xpsgtr_wait_pll_lock(gtr_dev->phys[0].phy)) {
> +                     memset(last_ok, 0, sizeof(last_ok));
> +                     continue;
> +             }
> +
> +             udelay(50);
> +             xpsgtr_write_lanes(gtr_dev, lanes, L0_TM_ANA_BYP_4, 0xc0);
> +             xpsgtr_write_lanes(gtr_dev, lanes, L0_TM_ANA_BYP_4, 0x80);
> +             xpsgtr_write_lanes(gtr_dev, lanes, L0_TM_PLL_DIG_33, 0xc0);
> +             udelay(50);
> +             xpsgtr_write_lanes(gtr_dev, lanes, L0_TM_PLL_DIG_33, 0x80);
> +             udelay(50);
> +             xpsgtr_write_lanes(gtr_dev, lanes, L0_TM_ANA_BYP_4, 0);
> +             xpsgtr_write_lanes(gtr_dev, lanes, L0_TM_PLL_DIG_33, 0);
> +             udelay(500);
> +
> +             /* Do the BIST */
> +             for_each_set_bit(lane, lanes, NUM_LANES) {
> +                     struct xpsgtr_phy *gtr_phy = &gtr_dev->phys[lane];
> +                     u32 packets, errors;
> +
> +                     xpsgtr_phy_init_bus_width(gtr_phy, PROT_BUS_WIDTH_10);
> +                     xpsgtr_phy_set_loopback(gtr_phy, true);
> +                     xpsgtr_write_phy(gtr_phy, L0_TM_DIG_22, 0x20);
> +                     xpsgtr_clr_set_phy(gtr_phy, L0_BIST_CTRL_1, 0, 1);
> +
> +                     udelay(200);
> +                     xpsgtr_write_phy(gtr_phy, L0_BIST_CTRL_1, 0);
> +                     packets = xpsgtr_read_phy(gtr_phy, L0_BIST_PKT_CTR_L);
> +                     packets |= xpsgtr_read_phy(gtr_phy, L0_BIST_PKT_CTR_H)
> << 8;
> +                     errors = xpsgtr_read_phy(gtr_phy, L0_BIST_ERR_CTR_L);
> +                     errors |= xpsgtr_read_phy(gtr_phy, L0_BIST_ERR_CTR_H)
> << 8;
> +                     ok[lane] = packets && !errors;
> +
> +                     dev_dbg(gtr_dev->dev,
> +                             "lane %lu ILL %d packets %10u errors %10u\n",
> +                             lane, i, packets, errors);
> +             }
> +
> +             xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_CTRL_1, 0);
> +             xpsgtr_write(gtr_dev, UPHY_SPARE0, 0x00);
> +             xpsgtr_write(gtr_dev, UPHY_SPARE0, 0x02);
> +
> +             for_each_set_bit(lane, lanes, NUM_LANES) {
> +                     pass[lane] += ok[lane] && last_ok[lane];
> +                     if (pass[lane] < 4) {
> +                             if (!ok[lane] && i > 2) {
> +                                     if (altpass[lane] < pass[lane]) {
> +                                             altpass[lane] = pass[lane];
> +                                             altbest[lane] =
> +                                                     (i - 1) - (pass[lane] + 1) / 2;
> +                                     }
> +                                     pass[lane] = 0;
> +                             }
> +                     } else if (!best[lane] && (!ok[lane] || i == 63) &&
> +                                last_ok[lane]) {
> +                             best[lane] = (i - 1) - (pass[lane] + 1) / 2;
> +                     }
> +             }
> +
> +             memcpy(last_ok, ok, sizeof(ok));
> +     }
> +
> +     for_each_set_bit(lane, lanes, NUM_LANES) {
> +             dev_dbg(gtr_dev->dev, "lane %lu ILL best %d alt best %d\n",
> +                     lane, best[lane], altbest[lane]);
> +
> +             xpsgtr_phy_set_ill(&gtr_dev->phys[lane],
> +                                best[lane] ?: altbest[lane], gen2);
> +     }
> +
> +     /* Clean up */
> +     xpsgtr_clr_set_lanes(gtr_dev, lanes, L0_TM_ANA_BYP_7, 0x30, 0);
> +     xpsgtr_write(gtr_dev, UPHY_SPARE0, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_CTRL_1, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_CTRL_2, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_RUN_LEN_L, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_ERR_INJ_POINT_L, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_RUNLEN_ERR_INJ_H, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_IDLE_TIME, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_MARKER_L, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_IDLE_CHAR_L, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_MARKER_IDLE_H, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_LOW_PULSE_TIME, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TOTAL_PULSE_TIME, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TEST_PAT_1, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TEST_PAT_2, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TEST_PAT_3, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TEST_PAT_4, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_TEST_PAT_MSBS, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_PKT_NUM, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_FRM_IDLE_TIME, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_PKT_CTR_L, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_PKT_CTR_H, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_ERR_CTR_L, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_ERR_CTR_H, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_FILLER_OUT, 1);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_BIST_FORCE_MK_RST, 0);
> +     xpsgtr_write_lanes(gtr_dev, lanes, L0_TM_DIG_22, 0);
> +
> +     for_each_set_bit(lane, lanes, NUM_LANES) {
> +             struct xpsgtr_phy *gtr_phy = &gtr_dev->phys[lane];
> +
> +             xpsgtr_phy_init_bus_width(gtr_phy, PROT_BUS_WIDTH_20);
> +             xpsgtr_phy_set_loopback(gtr_phy, false);
> +     }
> +}
> +
>  static int xpsgtr_common_init(struct xpsgtr_phy *gtr_phy)
>  {
>       int ret;
> @@ -553,6 +875,37 @@ static void xpsgtr_phy_init_sata(struct xpsgtr_phy
> *gtr_phy)
>  {
>       struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
>
> +     if (!xpsgtr_ill_calibrated(gtr_phy)) {
> +             DECLARE_BITMAP(lanes, NUM_LANES) = { 0 };
> +
> +             xpsgtr_init_ill(gtr_phy);
> +             xpsgtr_write_phy(gtr_phy, L0_TM_E_ILL3, 100);
> +             xpsgtr_clr_set_phy(gtr_phy, L0_TM_ILL11, 0xf0, 0x20);
> +
> +             __set_bit(gtr_phy->lane, lanes);
> +             xpsgtr_phy_illcalib(gtr_dev, lanes, false);
> +             xpsgtr_phy_set_ill(gtr_phy, 7, true);
> +     }
> +
> +     /* Disable SSC */
> +     xpsgtr_write_phy(gtr_phy, L0_PLL_FBDIV_FRAC_3_MSB,
> TM_FORCE_EN_FRAC);
> +     xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_3_MSB, 0,
> TM_FORCE_EN);
> +
> +     /* Disable Tx deemphasis */
> +     xpsgtr_write_phy(gtr_phy, L0_TM_CDR5,
> +                      FIELD_PREP(L0_TM_CDR5_FPHL_FSM_ACC_CYCLES,
> 7) |
> +                      FIELD_PREP(L0_TM_CDR5_FFL_PH0_INT_GAIN, 6));
> +     xpsgtr_write_phy(gtr_phy, L0_TM_CDR16, 12);
> +
> +     /* Configure equalization */
> +     xpsgtr_write_phy(gtr_phy, L0_TX_ANA_TM_118,
> +                      L0_TX_ANA_TM_118_FORCE_17_0);
> +     xpsgtr_clr_set_phy(gtr_phy, L0_TM_EQ0, 0,
> L0_TM_EQ0_EQ_STG2_CTRL_BYP);
> +     xpsgtr_clr_set_phy(gtr_phy, L0_TM_EQ1,
> L0_TM_EQ1_EQ_STG2_RL_PROG,
> +                        FIELD_PREP(L0_TM_EQ1_EQ_STG2_RL_PROG, 2) |
> +                        L0_TM_EQ1_EQ_STG2_PREAMP_MODE_VAL);
> +     xpsgtr_write_phy(gtr_phy, L0_TX_ANA_TM_18, 2); /* -3.5 dB deemphasis */
> +
>       xpsgtr_bypass_scrambler_8b10b(gtr_phy);
>
>       writel(gtr_phy->lane, gtr_dev->siou + SATA_CONTROL_OFFSET);
> @@ -565,6 +918,64 @@ static void xpsgtr_phy_init_sgmii(struct xpsgtr_phy
> *gtr_phy)
>       xpsgtr_bypass_scrambler_8b10b(gtr_phy);
>  }
>
> +/* PCIe-specific initialization. */
> +static int xpsgtr_phy_init_pcie(struct xpsgtr_phy *gtr_phy)
> +{
> +     struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
> +     DECLARE_BITMAP(lanes, NUM_LANES) = { 0 };
> +     unsigned long lane;
> +     bool calibrated = false;
> +
> +     xpsgtr_clr_set_phy(gtr_phy, L0_TM_AUX_0, 0, 0x20);
> +
> +     for (lane = 0; lane < NUM_LANES; lane++) {
> +             struct xpsgtr_phy *gtr_phy = &gtr_dev->phys[lane];
> +
> +             if (gtr_phy->protocol != ICM_PROTOCOL_PCIE)
> +                     continue;
> +
> +             __set_bit(lane, lanes);
> +             calibrated = calibrated || xpsgtr_ill_calibrated(gtr_phy);
> +     }
> +
> +     if (calibrated)
> +             return 0;
> +
> +     /* Write default ILL config */
> +     for_each_set_bit(lane, lanes, NUM_LANES) {
> +             struct xpsgtr_phy *p = &gtr_dev->phys[lane];
> +
> +             if (lane != gtr_phy->lane) {
> +                     int ret = xpsgtr_common_init(p);
> +
> +                     if (ret)
> +                             return ret;
> +             }
> +
> +             xpsgtr_init_ill(p);
> +             xpsgtr_write_phy(p, L0_TM_E_ILL3, 0);
> +             xpsgtr_clr_set_phy(p, L0_TM_MISC2, 0,
> +                                L0_TM_MISC2_ILL_CAL_BYPASS);
> +     }
> +
> +     /* Perform the ILL calibration procedure */
> +     xpsgtr_phy_illcalib(gtr_dev, lanes, false);
> +     xpsgtr_phy_illcalib(gtr_dev, lanes, true);
> +
> +     /* Disable PCIe ECO */
> +     writel(1, gtr_dev->siou + SIOU_ECO_0);
> +     return 0;
> +}
> +
> +/* USB-specific initialization. */
> +static void xpsgtr_phy_init_usb(struct xpsgtr_phy *gtr_phy)
> +{
> +     xpsgtr_clr_set_phy(gtr_phy, L0_TM_AUX_0, 0, 0x20);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_IQ_ILL8, 0xf3);
> +     xpsgtr_write_phy(gtr_phy, L0_TM_E_ILL8, 0xf3);
> +     xpsgtr_phy_set_ill(gtr_phy, 7, false);
> +}
> +
>  /* Configure TX de-emphasis and margining for DP. */
>  static void xpsgtr_phy_configure_dp(struct xpsgtr_phy *gtr_phy, unsigned int pre,
>                                   unsigned int voltage)
> @@ -710,6 +1121,10 @@ static int xpsgtr_phy_init(struct phy *phy)
>               xpsgtr_phy_init_dp(gtr_phy);
>               break;
>
> +     case ICM_PROTOCOL_PCIE:
> +             ret = xpsgtr_phy_init_pcie(gtr_phy);
> +             break;
> +
>       case ICM_PROTOCOL_SATA:
>               xpsgtr_phy_init_sata(gtr_phy);
>               break;
> @@ -717,6 +1132,10 @@ static int xpsgtr_phy_init(struct phy *phy)
>       case ICM_PROTOCOL_SGMII:
>               xpsgtr_phy_init_sgmii(gtr_phy);
>               break;
> +
> +     case ICM_PROTOCOL_USB:
> +             xpsgtr_phy_init_usb(gtr_phy);
> +             break;
>       }
>
>  out:
> --
> 2.35.1.1320.gc452695387.dirty


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ