Skip to content

Commit

Permalink
iio: jesd204: axi_adxcvr_eyescan: Fix UltraScale+ GTH Eye Scan
Browse files Browse the repository at this point in the history
Implement Realignment sequence AR#70872:

The aim of the Realignment sequence is to get a correct sync between
the Eye Scan clock and the data clock. In case of bad synchronization,
the error counter will saturate and the Eye Scan will show a closed eye.
The sequence should be executed at the end of the Eye Scan measurement,
if the eye appears completely closed, even if there are no data errors.

https://www.xilinx.com/support/answers/70872.html

Signed-off-by: Michael Hennerich <[email protected]>
  • Loading branch information
mhennerich authored and commodo committed Nov 14, 2018
1 parent e4b746b commit 22ad113
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
41 changes: 41 additions & 0 deletions drivers/iio/jesd204/axi_adxcvr_eyescan.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,24 @@ static int adxcvr_get_eyescan_es_hsize(struct adxcvr_state *st, u32 *hsize)
return 0;
}

static void adxcvr_eyescan_es_realignment(struct adxcvr_state *st, u32 lane)
{
/*
* AR# 70872: Manual Eye Scan with UltraScale+ GTH
*/
if (st->xcvr.type == XILINX_XCVR_TYPE_US_GTH4) {
dev_dbg(st->dev, "Executing realignment sequence\n");

adxcvr_eyescan_write(st, ADXCVR_REG_ES_REQ, 0);
xilinx_xcvr_drp_update(&st->xcvr, ADXCVR_DRP_PORT_CHANNEL(lane),
ES_DRP_HOFFSET_ADDR, 0xFFF0, 0x8800);
adxcvr_eyescan_write(st, ADXCVR_REG_ES_RESET, 1 << lane);
xilinx_xcvr_drp_update(&st->xcvr, ADXCVR_DRP_PORT_CHANNEL(lane),
ES_DRP_HOFFSET_ADDR, 0xFFF0, 0x8000);
adxcvr_eyescan_write(st, ADXCVR_REG_ES_RESET, 0);
}
}

static int adxcvr_eyescan_es(struct adxcvr_state *st, u32 lane)
{
u32 stat, hsize;
Expand Down Expand Up @@ -105,6 +123,24 @@ static int adxcvr_eyescan_es(struct adxcvr_state *st, u32 lane)

} while (stat & ADXCVR_ES_REQ);

if (st->xcvr.type == XILINX_XCVR_TYPE_US_GTH4) {
u32 midpoint = ((ES_VSIZE + 1) / 2) * hsize + hsize / 2;
u64 errors;

if (st->lpm_enable) {
u32 *buf32 = st->eye->buf_virt;

errors = buf32[midpoint] & 0xFFFF;
} else {
u64 *buf64 = st->eye->buf_virt;

errors = buf64[midpoint] & 0xFFFF0000FFFF;
}

if (errors)
return -EAGAIN;
}

return 0;
}

Expand All @@ -115,6 +151,11 @@ static void adxcvr_eyescan_work_func(struct work_struct *work)
int ret;

ret = adxcvr_eyescan_es(eye->st, eye->lane);
if (ret == -EAGAIN) {
adxcvr_eyescan_es_realignment(eye->st, eye->lane);
ret = adxcvr_eyescan_es(eye->st, eye->lane);
}

if (ret)
dev_warn(eye->st->dev, "Eye Scan failed (%d)\n", ret);

Expand Down
27 changes: 27 additions & 0 deletions drivers/iio/jesd204/axi_adxcvr_eyescan.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@
#ifndef AXI_ADXCVR_EYESCAN_H_
#define AXI_ADXCVR_EYESCAN_H_

/* GTH4 DRP Registers */
#define ES_DRP_CONTROL_ADDR 0x3c
#define ES_DRP_HOFFSET_ADDR 0x4f
#define ES_DRP_VOFFSET_ADDR 0x97
#define ES_DRP_STATUS_ADDR 0x253
#define ES_DRP_SCNT_ADDR 0x252
#define ES_DRP_ECNT_ADDR 0x251

#define ES_DRP_QUAL_MASK0 0x44
#define ES_DRP_QUAL_MASK1 0x45
#define ES_DRP_QUAL_MASK2 0x46
#define ES_DRP_QUAL_MASK3 0x47
#define ES_DRP_QUAL_MASK4 0x48

#define ES_DRP_QUALIFIER0 0x3f
#define ES_DRP_QUALIFIER1 0x40
#define ES_DRP_QUALIFIER2 0x41
#define ES_DRP_QUALIFIER3 0x42
#define ES_DRP_QUALIFIER4 0x43

#define ES_DRP_SDATA_MASK0 0x49
#define ES_DRP_SDATA_MASK1 0x4a
#define ES_DRP_SDATA_MASK2 0x4b
#define ES_DRP_SDATA_MASK3 0x4c
#define ES_DRP_SDATA_MASK4 0x4d

/* XCVR Eye Scan Registers */
#define ADXCVR_REG_ES_SEL 0x0080
#define ADXCVR_REG_ES_REQ 0x00A0
Expand All @@ -20,6 +46,7 @@
#define ADXCVR_REG_ES_CONTROL_4 0x00B0
#define ADXCVR_REG_ES_CONTROL_5 0x00B4
#define ADXCVR_REG_ES_STATUS 0x00B8
#define ADXCVR_REG_ES_RESET 0x00BC

/* XCVR Eye Scan Masks */
#define ADXCVR_ES_SEL(x) ((x) & 0xFF)
Expand Down
3 changes: 2 additions & 1 deletion drivers/iio/jesd204/xilinx_transceiver.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ static int xilinx_xcvr_drp_write(struct xilinx_xcvr *xcvr,
return 0;
}

static int xilinx_xcvr_drp_update(struct xilinx_xcvr *xcvr,
int xilinx_xcvr_drp_update(struct xilinx_xcvr *xcvr,
unsigned int drp_port, unsigned int reg, unsigned int mask,
unsigned int val)
{
Expand All @@ -123,6 +123,7 @@ static int xilinx_xcvr_drp_update(struct xilinx_xcvr *xcvr,

return xilinx_xcvr_drp_write(xcvr, drp_port, reg, val);
}
EXPORT_SYMBOL_GPL(xilinx_xcvr_drp_update);

static int xilinx_xcvr_gth3_configure_cdr(struct xilinx_xcvr *xcvr,
unsigned int drp_port, unsigned int out_div)
Expand Down
4 changes: 4 additions & 0 deletions drivers/iio/jesd204/xilinx_transceiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,8 @@ int xilinx_xcvr_write_rx_clk25_div(struct xilinx_xcvr *xcvr,
int xilinx_xcvr_write_tx_clk25_div(struct xilinx_xcvr *xcvr,
unsigned int drp_port, unsigned int div);

int xilinx_xcvr_drp_update(struct xilinx_xcvr *xcvr,
unsigned int drp_port, unsigned int reg, unsigned int mask,
unsigned int val);

#endif

0 comments on commit 22ad113

Please sign in to comment.