forked from M-Labs/artiq-zynq
Compare commits
6 Commits
a6b1701de3
...
cc8ae30303
Author | SHA1 | Date |
---|---|---|
morgan | cc8ae30303 | |
morgan | f8a2920033 | |
morgan | 95493c2ea7 | |
morgan | 6922934897 | |
morgan | ecd2d6a790 | |
morgan | 870f4fdf96 |
|
@ -1,5 +1,5 @@
|
||||||
from migen import *
|
from migen import *
|
||||||
from migen.genlib.cdc import MultiReg, PulseSynchronizer
|
from migen.genlib.cdc import MultiReg
|
||||||
from migen.genlib.resetsync import AsyncResetSynchronizer
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
|
||||||
from misoc.cores.code_8b10b import Encoder, Decoder
|
from misoc.cores.code_8b10b import Encoder, Decoder
|
||||||
|
@ -32,12 +32,13 @@ class CXP_DownConn(Module, AutoCSR):
|
||||||
|
|
||||||
# single & master tx_mode can lock with rx in loopback
|
# single & master tx_mode can lock with rx in loopback
|
||||||
self.submodules.gtx = gtx = GTX(self.qpll, pads, sys_clk_freq, tx_mode="single", rx_mode="single")
|
self.submodules.gtx = gtx = GTX(self.qpll, pads, sys_clk_freq, tx_mode="single", rx_mode="single")
|
||||||
|
|
||||||
# TEST: txusrclk alignment
|
|
||||||
# 1) use GTREFCLK with TXSYSCLKSEL = 0b10 -> still inconsistant
|
|
||||||
# 2) tie qpllPDEN with ~qpll.reset, -> inconsistant
|
|
||||||
# 3) seems like tx_init gtxXreset fall too soon (cplllock hold hi too long) <--- this a cross clk domain issue :<
|
|
||||||
|
|
||||||
|
# NOTE: No need to connect cxp_gtx_tx, we don't use tx anyway (just for loopback)
|
||||||
|
|
||||||
|
# TODO: Connect slave cxp_gtx_rx clock tgt
|
||||||
|
# checkout channel interfaces & drtio_gtx
|
||||||
|
# checkout GTPTXPhaseAlignement for inspiration
|
||||||
|
|
||||||
self.sync += [
|
self.sync += [
|
||||||
# PLL
|
# PLL
|
||||||
qpll.reset.eq(self.qpll_reset.re),
|
qpll.reset.eq(self.qpll_reset.re),
|
||||||
|
@ -156,18 +157,18 @@ class CXP_DownConn(Module, AutoCSR):
|
||||||
|
|
||||||
# DEBUG: IO SMA & PMOD
|
# DEBUG: IO SMA & PMOD
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("OBUF", i_I=gtx.rxoutclk, o_O=debug_sma.p_tx),
|
Instance("OBUF", i_I=gtx.cd_cxp_gtx_rx.clk, o_O=debug_sma.p_tx),
|
||||||
Instance("OBUF", i_I=gtx.cd_cxp_gtx_tx.clk, o_O=debug_sma.n_rx),
|
Instance("OBUF", i_I=gtx.cd_cxp_gtx_tx.clk, o_O=debug_sma.n_rx),
|
||||||
|
|
||||||
# pmod 0-7 pin
|
# pmod 0-7 pin
|
||||||
Instance("OBUF", i_I=gtx.comma_det.word_aligned, o_O=pmod_pads[0]),
|
Instance("OBUF", i_I=gtx.comma_checker.comma_aligned, o_O=pmod_pads[0]),
|
||||||
Instance("OBUF", i_I=gtx.comma_det.restart, o_O=pmod_pads[1]),
|
Instance("OBUF", i_I=gtx.comma_checker.comma_det, o_O=pmod_pads[1]),
|
||||||
Instance("OBUF", i_I=gtx.comma_det.aligner_en_rxclk, o_O=pmod_pads[2]),
|
Instance("OBUF", i_I=gtx.comma_checker.restart_sys, o_O=pmod_pads[2]),
|
||||||
Instance("OBUF", i_I=gtx.comma_det.check_reset, o_O=pmod_pads[3]),
|
Instance("OBUF", i_I=gtx.comma_checker.aligner_en, o_O=pmod_pads[3]),
|
||||||
Instance("OBUF", i_I=gtx.comma_det.comma_aligned, o_O=pmod_pads[4]),
|
Instance("OBUF", i_I=gtx.comma_checker.check_reset, o_O=pmod_pads[4]),
|
||||||
Instance("OBUF", i_I=gtx.comma_det.comma_seen, o_O=pmod_pads[5]),
|
Instance("OBUF", i_I=gtx.comma_checker.has_comma, o_O=pmod_pads[5]),
|
||||||
Instance("OBUF", i_I=gtx.comma_det.has_error, o_O=pmod_pads[6]),
|
Instance("OBUF", i_I=gtx.comma_checker.has_error, o_O=pmod_pads[6]),
|
||||||
Instance("OBUF", i_I=gtx.comma_det.ready, o_O=pmod_pads[7]),
|
Instance("OBUF", i_I=gtx.comma_checker.ready_sys, o_O=pmod_pads[7]),
|
||||||
|
|
||||||
# Instance("OBUF", i_I=gtx.dclk, o_O=pmod_pads[0]),
|
# Instance("OBUF", i_I=gtx.dclk, o_O=pmod_pads[0]),
|
||||||
# Instance("OBUF", i_I=gtx.den, o_O=pmod_pads[1]),
|
# Instance("OBUF", i_I=gtx.den, o_O=pmod_pads[1]),
|
||||||
|
@ -177,23 +178,6 @@ class CXP_DownConn(Module, AutoCSR):
|
||||||
|
|
||||||
# DEBUG: datain
|
# DEBUG: datain
|
||||||
|
|
||||||
self.data_0 = CSRStorage(8)
|
|
||||||
self.data_1 = CSRStorage(8)
|
|
||||||
self.data_2 = CSRStorage(8)
|
|
||||||
self.data_3 = CSRStorage(8)
|
|
||||||
self.control_bit_0 = CSRStorage()
|
|
||||||
self.control_bit_1 = CSRStorage()
|
|
||||||
self.control_bit_2 = CSRStorage()
|
|
||||||
self.control_bit_3 = CSRStorage()
|
|
||||||
self.encoded_0 = CSRStatus(10)
|
|
||||||
self.encoded_1 = CSRStatus(10)
|
|
||||||
|
|
||||||
self.rxdata_0 = CSRStatus(10)
|
|
||||||
self.rxdata_1 = CSRStatus(10)
|
|
||||||
self.decoded_data_0 = CSRStatus(8)
|
|
||||||
self.decoded_data_1 = CSRStatus(8)
|
|
||||||
self.decoded_k_0 = CSRStatus()
|
|
||||||
self.decoded_k_1 = CSRStatus()
|
|
||||||
|
|
||||||
self.sync.cxp_gtx_tx += [
|
self.sync.cxp_gtx_tx += [
|
||||||
self.gtx.encoder.d[0].eq(0xBC),
|
self.gtx.encoder.d[0].eq(0xBC),
|
||||||
|
@ -204,39 +188,40 @@ class CXP_DownConn(Module, AutoCSR):
|
||||||
self.gtx.encoder.k[2].eq(1),
|
self.gtx.encoder.k[2].eq(1),
|
||||||
self.gtx.encoder.d[3].eq(0xB5),
|
self.gtx.encoder.d[3].eq(0xB5),
|
||||||
self.gtx.encoder.k[3].eq(0),
|
self.gtx.encoder.k[3].eq(0),
|
||||||
|
|
||||||
self.encoded_0.status.eq(self.gtx.encoder.output[0]),
|
|
||||||
self.encoded_1.status.eq(self.gtx.encoder.output[1]),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# keep it odd, so it will show data[n] where n is odd
|
self.rxdata_0 = CSRStatus(10)
|
||||||
stb_timer = Signal(reset=10, max=11)
|
self.rxdata_1 = CSRStatus(10)
|
||||||
|
self.rxdata_2 = CSRStatus(10)
|
||||||
|
self.rxdata_3 = CSRStatus(10)
|
||||||
|
self.decoded_data_0 = CSRStatus(8)
|
||||||
|
self.decoded_data_1 = CSRStatus(8)
|
||||||
|
self.decoded_data_2 = CSRStatus(8)
|
||||||
|
self.decoded_data_3 = CSRStatus(8)
|
||||||
|
self.decoded_k_0 = CSRStatus()
|
||||||
|
self.decoded_k_1 = CSRStatus()
|
||||||
|
self.decoded_k_2 = CSRStatus()
|
||||||
|
self.decoded_k_3 = CSRStatus()
|
||||||
|
|
||||||
self.sync.cxp_gtx_rx += [
|
self.sync.cxp_gtx_rx += [
|
||||||
If(stb_timer == 0,
|
self.rxdata_0.status.eq(self.gtx.decoders[0].input),
|
||||||
self.rxdata_0.status.eq(self.gtx.decoders[0].input),
|
self.decoded_data_0.status.eq(self.gtx.decoders[0].d),
|
||||||
self.decoded_data_0.status.eq(self.gtx.decoders[0].d),
|
self.decoded_k_0.status.eq(self.gtx.decoders[0].k),
|
||||||
self.decoded_k_0.status.eq(self.gtx.decoders[0].k),
|
|
||||||
|
|
||||||
self.rxdata_1.status.eq(self.gtx.decoders[1].input),
|
self.rxdata_1.status.eq(self.gtx.decoders[1].input),
|
||||||
self.decoded_data_1.status.eq(self.gtx.decoders[1].d),
|
self.decoded_data_1.status.eq(self.gtx.decoders[1].d),
|
||||||
self.decoded_k_1.status.eq(self.gtx.decoders[1].k),
|
self.decoded_k_1.status.eq(self.gtx.decoders[1].k),
|
||||||
stb_timer.eq(stb_timer.reset),
|
|
||||||
).Else(
|
self.rxdata_2.status.eq(self.gtx.decoders[2].input),
|
||||||
stb_timer.eq(stb_timer - 1),
|
self.decoded_data_2.status.eq(self.gtx.decoders[2].d),
|
||||||
)
|
self.decoded_k_2.status.eq(self.gtx.decoders[2].k),
|
||||||
|
|
||||||
|
self.rxdata_3.status.eq(self.gtx.decoders[3].input),
|
||||||
|
self.decoded_data_3.status.eq(self.gtx.decoders[3].d),
|
||||||
|
self.decoded_k_3.status.eq(self.gtx.decoders[3].k),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# The TX phase alignment will fail with a wrong TXUSRCLK frequency
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# NOTE: No need to connect cxp_gtx_tx, we don't use tx anyway (just for loopback)
|
|
||||||
|
|
||||||
# TODO: Connect slave cxp_gtx_rx clock tgt
|
|
||||||
# checkout channel interfaces & drtio_gtx
|
|
||||||
# checkout GTPTXPhaseAlignement for inspiration
|
|
||||||
|
|
||||||
class QPLL(Module):
|
class QPLL(Module):
|
||||||
def __init__(self, refclk, sys_clk_freq):
|
def __init__(self, refclk, sys_clk_freq):
|
||||||
self.clk = Signal()
|
self.clk = Signal()
|
||||||
|
@ -255,23 +240,15 @@ class QPLL(Module):
|
||||||
self.dready = Signal()
|
self.dready = Signal()
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
# WARNING: VCO cannot do 12.5GHz on ZC706
|
# VCO @ 10GHz, linerate = 1.25Gbps
|
||||||
# VCO freq = sys*qpll_fbdiv
|
# feedback divider = 80
|
||||||
# PLL output = VCO/2
|
qpll_fbdiv = 0b0100100000
|
||||||
qpll_fbdiv = 0b0100100000 # 80 div
|
|
||||||
qpll_fbdiv_ratio = 1
|
qpll_fbdiv_ratio = 1
|
||||||
|
|
||||||
fbdiv_real = 80
|
|
||||||
refclk_div = 1
|
refclk_div = 1
|
||||||
self.Xxout_div = 8
|
self.Xxout_div = 8
|
||||||
|
|
||||||
# qpll_fbdiv = 0b0101110000 # 100 div
|
# DEBUG: txuserclk
|
||||||
# qpll_fbdiv_ratio = 1
|
fbdiv_real = 80
|
||||||
|
|
||||||
# fbdiv_real = 100
|
|
||||||
# refclk_div = 2
|
|
||||||
# self.Xxout_div = 2
|
|
||||||
|
|
||||||
self.tx_usrclk_freq = (sys_clk_freq*fbdiv_real/self.Xxout_div)/40
|
self.tx_usrclk_freq = (sys_clk_freq*fbdiv_real/self.Xxout_div)/40
|
||||||
|
|
||||||
self.specials += [
|
self.specials += [
|
||||||
|
@ -328,123 +305,123 @@ class QPLL(Module):
|
||||||
|
|
||||||
# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped
|
# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped
|
||||||
# compared to the usual 8b10b binary representation.
|
# compared to the usual 8b10b binary representation.
|
||||||
class Comma_Detector(Module):
|
class Comma_Checker(Module):
|
||||||
def __init__(self, comma, check_period=1_000_000):
|
def __init__(self, comma, reset_period=10_000_000):
|
||||||
self.data = Signal(20)
|
self.data = Signal(20)
|
||||||
self.word_aligned = Signal()
|
self.comma_aligned = Signal()
|
||||||
|
self.comma_realigned = Signal()
|
||||||
|
self.comma_det = Signal()
|
||||||
|
|
||||||
self.aligner_en_rxclk = Signal()
|
self.aligner_en = Signal()
|
||||||
self.ready = Signal()
|
self.ready_sys = Signal()
|
||||||
self.restart = Signal()
|
self.restart_sys = Signal()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
|
|
||||||
|
# periodically reset rx until rx is connected and receiving valid data
|
||||||
# The built-in RXBYTEISALIGNED can be falsely asserted at linerate higher than 5Gbps
|
# as after connecting RXP/RXN, the whole RX need to be reset
|
||||||
# - UG476 (v1.12.1) p.228
|
|
||||||
|
reset_counter = Signal(reset=reset_period-1, max=reset_period)
|
||||||
# The validity of data & comma are checked externally
|
|
||||||
|
|
||||||
|
|
||||||
check_counter = Signal(reset=check_period-1, max=check_period)
|
|
||||||
# check = Signal()
|
|
||||||
self.sync += [
|
self.sync += [
|
||||||
self.restart.eq(0),
|
self.restart_sys.eq(0),
|
||||||
# check.eq(0),
|
If(~self.ready_sys,
|
||||||
# check_reset.i.eq(0),
|
If(reset_counter == 0,
|
||||||
If(~self.ready,
|
reset_counter.eq(reset_counter.reset),
|
||||||
If(check_counter == 0,
|
self.restart_sys.eq(1),
|
||||||
check_counter.eq(check_counter.reset),
|
|
||||||
# check.eq(1),
|
|
||||||
self.restart.eq(1),
|
|
||||||
# check_reset.i.eq(1),
|
|
||||||
).Else(
|
).Else(
|
||||||
check_counter.eq(check_counter - 1),
|
reset_counter.eq(reset_counter - 1),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# WIP:
|
|
||||||
|
# Data and comma checker
|
||||||
|
# From UG476 (v1.12.1) p.228
|
||||||
|
# The built-in RXBYTEISALIGNED can be falsely asserted at linerate higher than 5Gbps
|
||||||
|
# The validity of data and comma needed to be checked externally
|
||||||
|
|
||||||
comma_n = ~comma & 0b1111111111
|
comma_n = ~comma & 0b1111111111
|
||||||
|
|
||||||
has_error = Signal()
|
# DEBUG: remove after use
|
||||||
comma_aligned = Signal()
|
self.has_comma = Signal()
|
||||||
|
self.has_error = Signal()
|
||||||
|
|
||||||
comma_seen = Signal()
|
comma_seen = Signal()
|
||||||
error_seen = Signal()
|
error_seen = Signal()
|
||||||
one_counts = Signal(max=11)
|
one_counts = Signal(max=11)
|
||||||
|
|
||||||
counter_period = 5000
|
# From CXP-001-2021 section 9.2.5.1
|
||||||
|
# For high speed connection an IDLE word shall be transmitted at least once every 100 words
|
||||||
|
counter_period = 200
|
||||||
|
|
||||||
counter = Signal(reset=counter_period-1, max=counter_period)
|
counter = Signal(reset=counter_period-1, max=counter_period)
|
||||||
check_reset = Signal()
|
check_reset = Signal()
|
||||||
check = Signal()
|
check = Signal()
|
||||||
|
|
||||||
self.sync.cxp_gtx_rx += [
|
self.sync.cxp_gtx_rx += [
|
||||||
check.eq(0),
|
If(check_reset,
|
||||||
If(counter == 0,
|
|
||||||
counter.eq(counter.reset),
|
counter.eq(counter.reset),
|
||||||
|
check.eq(0),
|
||||||
|
).Elif(counter == 0,
|
||||||
check.eq(1),
|
check.eq(1),
|
||||||
).Else(
|
).Else(
|
||||||
counter.eq(counter - 1),
|
counter.eq(counter - 1),
|
||||||
|
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
has_error.eq(0),
|
|
||||||
one_counts.eq(reduce(add, [self.data[i] for i in range(10, 20)])),
|
|
||||||
If((one_counts != 4) & (one_counts != 5) & (one_counts != 6),
|
|
||||||
has_error.eq(1)
|
|
||||||
),
|
|
||||||
|
|
||||||
comma_aligned.eq(0),
|
|
||||||
If((self.data[:10] == comma) | (self.data[:10] == comma_n),
|
|
||||||
comma_aligned.eq(1)
|
|
||||||
),
|
|
||||||
|
|
||||||
# signal that need to be manually cleared
|
|
||||||
If(check_reset,
|
If(check_reset,
|
||||||
comma_seen.eq(0),
|
comma_seen.eq(0),
|
||||||
).Elif((self.data[:10] == comma) | (self.data[:10] == comma_n),
|
).Elif((self.data[:10] == comma) | (self.data[:10] == comma_n),
|
||||||
comma_seen.eq(1)
|
comma_seen.eq(1)
|
||||||
),
|
),
|
||||||
|
|
||||||
one_counts.eq(reduce(add, [self.data[i] for i in range(10, 20)])),
|
one_counts.eq(reduce(add, [self.data[i] for i in range(10)])),
|
||||||
If(check_reset,
|
If(check_reset,
|
||||||
error_seen.eq(0),
|
error_seen.eq(0),
|
||||||
).Elif((one_counts != 4) & (one_counts != 5) & (one_counts != 6),
|
).Elif((one_counts != 4) & (one_counts != 5) & (one_counts != 6),
|
||||||
error_seen.eq(1),
|
error_seen.eq(1),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
# DEBUG:
|
||||||
|
self.has_comma.eq(0),
|
||||||
|
If((self.data[:10] == comma) | (self.data[:10] == comma_n),
|
||||||
|
self.has_comma.eq(1),
|
||||||
|
),
|
||||||
|
|
||||||
|
self.has_error.eq(0),
|
||||||
|
If((one_counts != 4) & (one_counts != 5) & (one_counts != 6),
|
||||||
|
self.has_error.eq(1),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# DEBUG: expose signal
|
# DEBUG: expose signal
|
||||||
self.check_reset = Signal()
|
self.check_reset = Signal()
|
||||||
self.comma_aligned = Signal()
|
|
||||||
self.comma_seen = Signal()
|
|
||||||
self.has_error = Signal()
|
|
||||||
self.error_seen = Signal()
|
|
||||||
self.comb +=[
|
self.comb +=[
|
||||||
self.check_reset.eq(check_reset),
|
self.check_reset.eq(check_reset),
|
||||||
self.comma_aligned.eq(comma_aligned),
|
|
||||||
self.comma_seen.eq(comma_seen),
|
|
||||||
self.has_error.eq(has_error),
|
|
||||||
self.error_seen.eq(error_seen),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
self.submodules.rxfsm = rxfsm = ClockDomainsRenamer("cxp_gtx_rx")(FSM(reset_state="ALIGNING"))
|
self.submodules.rxfsm = rxfsm = ClockDomainsRenamer("cxp_gtx_rx")(FSM(reset_state="WAIT_COMMA"))
|
||||||
|
|
||||||
# the data from gtxe2 is delayed and checking at the output may not reflect the alignment inside the aligner
|
rxfsm.act("WAIT_COMMA",
|
||||||
# thus, failing to alignment on high linerate >5Gbps is common due to the aligner_en being asserted longer than necessary and lead to a lose of lock
|
If(self.comma_det,
|
||||||
# a timer is used to wait till the "aligned" data to arrive and do a system check like the datasheet suggested
|
# # start aligner early, so word aligned will fall
|
||||||
self.submodules.timer = timer = ClockDomainsRenamer("cxp_gtx_rx")(WaitTimer(5000))
|
# self.aligner_en_rxclk.eq(1),
|
||||||
|
NextState("ALIGNING"),
|
||||||
rxfsm.act("ALIGNING",
|
|
||||||
self.aligner_en_rxclk.eq(1),
|
|
||||||
If(self.word_aligned,
|
|
||||||
check_reset.eq(1),
|
|
||||||
NextState("WAIT_ALIGNED_DATA"),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
rxfsm.act("ALIGNING",
|
||||||
|
If(self.comma_aligned & (~self.comma_realigned),
|
||||||
|
NextState("WAIT_ALIGNED_DATA"),
|
||||||
|
).Else(
|
||||||
|
self.aligner_en.eq(1),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# wait for the aligned data to arrive at the FPGA RX interface
|
||||||
|
# as there is a delay before the data is avaiable after RXBYTEISALIGNED is asserted
|
||||||
|
self.submodules.timer = timer = ClockDomainsRenamer("cxp_gtx_rx")(WaitTimer(10_000))
|
||||||
|
|
||||||
rxfsm.act("WAIT_ALIGNED_DATA",
|
rxfsm.act("WAIT_ALIGNED_DATA",
|
||||||
timer.wait.eq(1),
|
timer.wait.eq(1),
|
||||||
If(timer.done,
|
If(timer.done,
|
||||||
|
@ -457,21 +434,21 @@ class Comma_Detector(Module):
|
||||||
If(check,
|
If(check,
|
||||||
check_reset.eq(1),
|
check_reset.eq(1),
|
||||||
If(comma_seen & (~error_seen),
|
If(comma_seen & (~error_seen),
|
||||||
NextState("READY"),
|
NextState("READY"),
|
||||||
).Else(
|
).Else(
|
||||||
NextState("ALIGNING")
|
NextState("WAIT_COMMA")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
ready = Signal()
|
ready = Signal()
|
||||||
self.specials += MultiReg(ready, self.ready)
|
self.specials += MultiReg(ready, self.ready_sys)
|
||||||
rxfsm.act("READY",
|
rxfsm.act("READY",
|
||||||
ready.eq(1),
|
ready.eq(1),
|
||||||
If(check,
|
If(check,
|
||||||
check_reset.eq(1),
|
check_reset.eq(1),
|
||||||
If(~(comma_seen & (~error_seen)),
|
If(~(comma_seen & (~error_seen)),
|
||||||
NextState("ALIGNING"),
|
NextState("WAIT_COMMA"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -539,13 +516,15 @@ class GTX(Module):
|
||||||
txdata = Signal(40)
|
txdata = Signal(40)
|
||||||
rxdata = Signal(40)
|
rxdata = Signal(40)
|
||||||
|
|
||||||
word_aligned = Signal()
|
comma_aligned = Signal()
|
||||||
|
comma_realigned = Signal()
|
||||||
|
comma_det = Signal()
|
||||||
comma_aligner_en = Signal()
|
comma_aligner_en = Signal()
|
||||||
# Note: the following parameters were set after consulting AR45360
|
# Note: the following parameters were set after consulting AR45360
|
||||||
self.specials += \
|
self.specials += \
|
||||||
Instance("GTXE2_CHANNEL",
|
Instance("GTXE2_CHANNEL",
|
||||||
# PMA Attributes
|
# PMA Attributes
|
||||||
p_PMA_RSV=0x00018480,
|
p_PMA_RSV=0x001E7080,
|
||||||
p_PMA_RSV2=0x2050, # PMA_RSV2[5] = 0: Eye scan feature disabled
|
p_PMA_RSV2=0x2050, # PMA_RSV2[5] = 0: Eye scan feature disabled
|
||||||
p_PMA_RSV3=0,
|
p_PMA_RSV3=0,
|
||||||
p_PMA_RSV4=1, # PMA_RSV[4],RX_CM_TRIM[2:0] = 0b1010: Common mode 800mV
|
p_PMA_RSV4=1, # PMA_RSV[4],RX_CM_TRIM[2:0] = 0b1010: Common mode 800mV
|
||||||
|
@ -599,7 +578,7 @@ class GTX(Module):
|
||||||
|
|
||||||
# TX data
|
# TX data
|
||||||
p_TX_DATA_WIDTH=40,
|
p_TX_DATA_WIDTH=40,
|
||||||
p_TX_INT_DATAWIDTH=1,
|
p_TX_INT_DATAWIDTH=1, # 1 if a line rate is greater than 6.6 Gbps
|
||||||
i_TXCHARDISPMODE=Cat(txdata[9], txdata[19], txdata[29], txdata[39]),
|
i_TXCHARDISPMODE=Cat(txdata[9], txdata[19], txdata[29], txdata[39]),
|
||||||
i_TXCHARDISPVAL=Cat(txdata[8], txdata[18], txdata[28], txdata[38]),
|
i_TXCHARDISPVAL=Cat(txdata[8], txdata[18], txdata[28], txdata[38]),
|
||||||
i_TXDATA=Cat(txdata[:8], txdata[10:18], txdata[20:28], txdata[30:38]),
|
i_TXDATA=Cat(txdata[:8], txdata[10:18], txdata[20:28], txdata[30:38]),
|
||||||
|
@ -632,7 +611,10 @@ class GTX(Module):
|
||||||
i_RXDFEXYDEN=1,
|
i_RXDFEXYDEN=1,
|
||||||
i_RXDFEXYDHOLD=0,
|
i_RXDFEXYDHOLD=0,
|
||||||
i_RXDFEXYDOVRDEN=0,
|
i_RXDFEXYDOVRDEN=0,
|
||||||
i_RXLPMEN=0, # RXLPMEN = 0: DFE mode is enabled for non scramble data
|
i_RXLPMEN=1, # RXLPMEN = 1: LPM mode is enable for non scramble 8b10b data
|
||||||
|
p_RXLPM_HF_CFG=0b00000011110000,
|
||||||
|
p_RXLPM_LF_CFG=0b00000011110000,
|
||||||
|
|
||||||
p_RX_DFE_GAIN_CFG=0x0207EA,
|
p_RX_DFE_GAIN_CFG=0x0207EA,
|
||||||
p_RX_DFE_VP_CFG=0b00011111100000011,
|
p_RX_DFE_VP_CFG=0b00011111100000011,
|
||||||
p_RX_DFE_UT_CFG=0b10001000000000000,
|
p_RX_DFE_UT_CFG=0b10001000000000000,
|
||||||
|
@ -662,7 +644,7 @@ class GTX(Module):
|
||||||
|
|
||||||
# RX data
|
# RX data
|
||||||
p_RX_DATA_WIDTH=40,
|
p_RX_DATA_WIDTH=40,
|
||||||
p_RX_INT_DATAWIDTH=1,
|
p_RX_INT_DATAWIDTH=1, # 1 if a line rate is greater than 6.6 Gbps
|
||||||
o_RXDISPERR=Cat(rxdata[9], rxdata[19], rxdata[29], rxdata[39]),
|
o_RXDISPERR=Cat(rxdata[9], rxdata[19], rxdata[29], rxdata[39]),
|
||||||
o_RXCHARISK=Cat(rxdata[8], rxdata[18], rxdata[28], rxdata[38]),
|
o_RXCHARISK=Cat(rxdata[8], rxdata[18], rxdata[28], rxdata[38]),
|
||||||
o_RXDATA=Cat(rxdata[:8], rxdata[10:18], rxdata[20:28], rxdata[30:38]),
|
o_RXDATA=Cat(rxdata[:8], rxdata[10:18], rxdata[20:28], rxdata[30:38]),
|
||||||
|
@ -675,7 +657,7 @@ class GTX(Module):
|
||||||
p_ALIGN_MCOMMA_VALUE=0b1010000011,
|
p_ALIGN_MCOMMA_VALUE=0b1010000011,
|
||||||
p_ALIGN_PCOMMA_DET="TRUE",
|
p_ALIGN_PCOMMA_DET="TRUE",
|
||||||
p_ALIGN_PCOMMA_VALUE=0b0101111100,
|
p_ALIGN_PCOMMA_VALUE=0b0101111100,
|
||||||
p_SHOW_REALIGN_COMMA="TRUE",
|
p_SHOW_REALIGN_COMMA="FALSE",
|
||||||
p_RXSLIDE_AUTO_WAIT=7,
|
p_RXSLIDE_AUTO_WAIT=7,
|
||||||
p_RXSLIDE_MODE="OFF",
|
p_RXSLIDE_MODE="OFF",
|
||||||
p_RX_SIG_VALID_DLY=10,
|
p_RX_SIG_VALID_DLY=10,
|
||||||
|
@ -683,7 +665,9 @@ class GTX(Module):
|
||||||
i_RXMCOMMAALIGNEN=comma_aligner_en,
|
i_RXMCOMMAALIGNEN=comma_aligner_en,
|
||||||
i_RXCOMMADETEN=1,
|
i_RXCOMMADETEN=1,
|
||||||
i_RXSLIDE=0,
|
i_RXSLIDE=0,
|
||||||
o_RXBYTEISALIGNED=word_aligned,
|
o_RXBYTEISALIGNED=comma_aligned,
|
||||||
|
o_RXBYTEREALIGN=comma_realigned,
|
||||||
|
o_RXCOMMADET=comma_det,
|
||||||
|
|
||||||
# RX 8B/10B Decoder Attributes
|
# RX 8B/10B Decoder Attributes
|
||||||
p_RX_DISPERR_SEQ_MATCH="FALSE",
|
p_RX_DISPERR_SEQ_MATCH="FALSE",
|
||||||
|
@ -716,8 +700,8 @@ class GTX(Module):
|
||||||
p_RX_DEFER_RESET_BUF_EN="TRUE",
|
p_RX_DEFER_RESET_BUF_EN="TRUE",
|
||||||
|
|
||||||
# CDR Attributes
|
# CDR Attributes
|
||||||
p_RXCDR_CFG=0x03_0000_23FF_1040_0020, # DFE @ <= 6.6Gb/s, 8B/10B encoded data, CDR setting < +/- 200ppm
|
p_RXCDR_CFG=0x03_0000_23FF_1008_0020, # LPM @ 0.5G-1.5625G , 8B/10B encoded data, CDR setting < +/- 200ppm
|
||||||
# (See UG476 (v1.12.1), p.205)
|
# (See UG476 (v1.12.1), p.206)
|
||||||
p_RXCDR_FR_RESET_ON_EIDLE=0b0,
|
p_RXCDR_FR_RESET_ON_EIDLE=0b0,
|
||||||
p_RXCDR_HOLD_DURING_EIDLE=0b0,
|
p_RXCDR_HOLD_DURING_EIDLE=0b0,
|
||||||
p_RXCDR_PH_RESET_ON_EIDLE=0b0,
|
p_RXCDR_PH_RESET_ON_EIDLE=0b0,
|
||||||
|
@ -822,13 +806,15 @@ class GTX(Module):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
self.submodules.comma_det = comma_det = Comma_Detector(0b0101111100)
|
self.submodules.comma_checker = comma_checker = Comma_Checker(0b0101111100)
|
||||||
self.comb += [
|
self.comb += [
|
||||||
comma_det.data.eq(rxdata),
|
comma_checker.data.eq(rxdata),
|
||||||
comma_det.word_aligned.eq(word_aligned),
|
comma_checker.comma_aligned.eq(comma_aligned),
|
||||||
comma_aligner_en.eq(comma_det.aligner_en_rxclk),
|
comma_checker.comma_realigned.eq(comma_realigned),
|
||||||
self.rx_ready.eq(comma_det.ready),
|
comma_checker.comma_det.eq(comma_det),
|
||||||
|
comma_aligner_en.eq(comma_checker.aligner_en),
|
||||||
|
self.rx_ready.eq(comma_checker.ready_sys),
|
||||||
|
|
||||||
rx_init.restart.eq(self.rx_restart | comma_det.restart),
|
rx_init.restart.eq(self.rx_restart | comma_checker.restart_sys),
|
||||||
tx_init.restart.eq(self.tx_restart),
|
tx_init.restart.eq(self.tx_restart),
|
||||||
]
|
]
|
||||||
|
|
|
@ -691,6 +691,11 @@ class CXP_FMC():
|
||||||
)
|
)
|
||||||
self.csr_devices.append("cxp")
|
self.csr_devices.append("cxp")
|
||||||
|
|
||||||
|
# max freq of cxp_gtx_rx = linerate/internal_datawidth = 12.5Gbps/40 = 312.5MHz
|
||||||
|
platform.add_period_constraint(self.cxp.downconn.gtx.cd_cxp_gtx_tx.clk, 3.2)
|
||||||
|
platform.add_period_constraint(self.cxp.downconn.gtx.cd_cxp_gtx_rx.clk, 3.2)
|
||||||
|
platform.add_false_path_constraints(self.cxp.downconn.gtx.cd_cxp_gtx_tx.clk, self.cxp.downconn.gtx.cd_cxp_gtx_rx.clk)
|
||||||
|
|
||||||
rtio_channels = []
|
rtio_channels = []
|
||||||
# FIXME remove this placeholder RTIO channel
|
# FIXME remove this placeholder RTIO channel
|
||||||
# There are too few RTIO channels and cannot be compiled (adr width issue of the lane distributor)
|
# There are too few RTIO channels and cannot be compiled (adr width issue of the lane distributor)
|
||||||
|
|
|
@ -22,38 +22,11 @@ pub enum CXP_SPEED {
|
||||||
CXP_12,
|
CXP_12,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loopback_testing(timer: &mut GlobalTimer, data: u8, control_bit: u8) {
|
pub fn loopback_testing(timer: &mut GlobalTimer, speed: CXP_SPEED) {
|
||||||
|
println!("==============================================================================");
|
||||||
|
CXP_GTX::change_linerate(timer, speed);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// send K28_5 for CDR to align
|
|
||||||
const K28_5: u8 = 0xBC;
|
|
||||||
const K28_1: u8 = 0x3C;
|
|
||||||
const D21_5: u8 = 21 | 5 << 5;
|
|
||||||
|
|
||||||
// NOTE: testing with IDLE word + manual comma alignment
|
|
||||||
// 62.5MHz OK
|
|
||||||
// 125MHz OK
|
|
||||||
// 156.25MHz
|
|
||||||
// 250MHz OK
|
|
||||||
// 312.5MHz
|
|
||||||
// 500MHz ?? havn't change CDR config yet
|
|
||||||
const LEN: usize = 4;
|
|
||||||
const DATA: [[u8; LEN]; 2] = [
|
|
||||||
// [K28_5, K28_1, K28_5, K28_1],
|
|
||||||
// [1, 1, 1, 1],
|
|
||||||
[K28_5, K28_1, K28_1, D21_5],
|
|
||||||
[1, 1, 1, 0],
|
|
||||||
];
|
|
||||||
|
|
||||||
csr::cxp::downconn_data_0_write(DATA[0][0]);
|
|
||||||
csr::cxp::downconn_data_1_write(DATA[0][1]);
|
|
||||||
csr::cxp::downconn_data_2_write(DATA[0][2]);
|
|
||||||
csr::cxp::downconn_data_3_write(DATA[0][3]);
|
|
||||||
|
|
||||||
csr::cxp::downconn_control_bit_0_write(DATA[1][0]);
|
|
||||||
csr::cxp::downconn_control_bit_1_write(DATA[1][1]);
|
|
||||||
csr::cxp::downconn_control_bit_2_write(DATA[1][2]);
|
|
||||||
csr::cxp::downconn_control_bit_3_write(DATA[1][3]);
|
|
||||||
|
|
||||||
info!("waiting for tx&rx setup...");
|
info!("waiting for tx&rx setup...");
|
||||||
timer.delay_us(50_000);
|
timer.delay_us(50_000);
|
||||||
info!(
|
info!(
|
||||||
|
@ -66,19 +39,16 @@ fn loopback_testing(timer: &mut GlobalTimer, data: u8, control_bit: u8) {
|
||||||
csr::cxp::downconn_txenable_write(1);
|
csr::cxp::downconn_txenable_write(1);
|
||||||
|
|
||||||
info!("waiting for rx to align...");
|
info!("waiting for rx to align...");
|
||||||
// timer.delay_us(50_000);
|
while csr::cxp::downconn_rx_ready_read() != 1 {}
|
||||||
// while csr::cxp::downconn_rx_ready_read() != 1 {}
|
info!("rx ready!");
|
||||||
// info!("rx ready!");
|
|
||||||
|
|
||||||
// println!("0xA8 = {:#06x}", read(0x62));
|
// loop {
|
||||||
// write(0x62, 0x001A);
|
for _ in 0..20 {
|
||||||
// println!("0xA8 = {:#06x}", read(0x62));
|
// NOTE: raw bits
|
||||||
|
// let data0 = csr::cxp::downconn_rxdata_0_read();
|
||||||
// for _ in 0..20 {
|
// let data1 = csr::cxp::downconn_rxdata_1_read();
|
||||||
loop {
|
// let data2 = csr::cxp::downconn_rxdata_2_read();
|
||||||
// NOTE: raw data
|
// let data3 = csr::cxp::downconn_rxdata_3_read();
|
||||||
let data0 = csr::cxp::downconn_rxdata_0_read();
|
|
||||||
let data1 = csr::cxp::downconn_rxdata_1_read();
|
|
||||||
// let rxready = csr::cxp::downconn_rx_ready_read();
|
// let rxready = csr::cxp::downconn_rx_ready_read();
|
||||||
// timer.delay_us(100);
|
// timer.delay_us(100);
|
||||||
// if data0 == 0b0101111100 || data0 == 0b1010000011 {
|
// if data0 == 0b0101111100 || data0 == 0b1010000011 {
|
||||||
|
@ -105,14 +75,30 @@ fn loopback_testing(timer: &mut GlobalTimer, data: u8, control_bit: u8) {
|
||||||
// timer.delay_us(1_000_000);
|
// timer.delay_us(1_000_000);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
println!("0b{:010b}{:010b}", data0, data1);
|
// timer.delay_us(1_000_000);
|
||||||
timer.delay_us(1_000_000);
|
// NOTE: raw bits
|
||||||
|
// let data0 = csr::cxp::downconn_rxdata_0_read();
|
||||||
|
// let data1 = csr::cxp::downconn_rxdata_1_read();
|
||||||
|
// let data2 = csr::cxp::downconn_rxdata_2_read();
|
||||||
|
// let data3 = csr::cxp::downconn_rxdata_3_read();
|
||||||
|
// println!(
|
||||||
|
// "0b{:010b} {:010b} {:010b} {:010b}",
|
||||||
|
// data0, data1, data2, data3
|
||||||
|
// );
|
||||||
|
|
||||||
// NOTE:decode data
|
// NOTE:decode data
|
||||||
// let data0_decoded = csr::cxp::downconn_decoded_data_0_read();
|
|
||||||
// let data0_k = csr::cxp::downconn_decoded_k_0_read();
|
// let data0_k = csr::cxp::downconn_decoded_k_0_read();
|
||||||
// let data1_decoded = csr::cxp::downconn_decoded_data_1_read();
|
|
||||||
// let data1_k = csr::cxp::downconn_decoded_k_1_read();
|
// let data1_k = csr::cxp::downconn_decoded_k_1_read();
|
||||||
|
// let data2_k = csr::cxp::downconn_decoded_k_2_read();
|
||||||
|
// let data3_k = csr::cxp::downconn_decoded_k_3_read();
|
||||||
|
let data0_decoded = csr::cxp::downconn_decoded_data_0_read();
|
||||||
|
let data1_decoded = csr::cxp::downconn_decoded_data_1_read();
|
||||||
|
let data2_decoded = csr::cxp::downconn_decoded_data_2_read();
|
||||||
|
let data3_decoded = csr::cxp::downconn_decoded_data_3_read();
|
||||||
|
println!(
|
||||||
|
"{:#04x} {:#04x} {:#04x} {:#04x}",
|
||||||
|
data0_decoded, data1_decoded, data2_decoded, data3_decoded,
|
||||||
|
);
|
||||||
// println!(
|
// println!(
|
||||||
// "decoded_data[0] = {:#04x} decoded_k[0] = {:#b} decoded_data[1] = {:#04x} decoded_k[1] = {:#b}",
|
// "decoded_data[0] = {:#04x} decoded_k[0] = {:#b} decoded_data[1] = {:#04x} decoded_k[1] = {:#b}",
|
||||||
// data0_decoded,
|
// data0_decoded,
|
||||||
|
@ -120,12 +106,11 @@ fn loopback_testing(timer: &mut GlobalTimer, data: u8, control_bit: u8) {
|
||||||
// data1_decoded,
|
// data1_decoded,
|
||||||
// data1_k,
|
// data1_k,
|
||||||
// );
|
// );
|
||||||
// timer.delay_us(1_000_000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup(timer: &mut GlobalTimer, speed: CXP_SPEED) {
|
pub fn setup(timer: &mut GlobalTimer) {
|
||||||
unsafe {
|
unsafe {
|
||||||
info!("turning on pmc loopback mode...");
|
info!("turning on pmc loopback mode...");
|
||||||
csr::cxp::downconn_loopback_mode_write(0b010); // Near-End PMA Loopback
|
csr::cxp::downconn_loopback_mode_write(0b010); // Near-End PMA Loopback
|
||||||
|
@ -147,12 +132,9 @@ pub fn setup(timer: &mut GlobalTimer, speed: CXP_SPEED) {
|
||||||
csr::cxp::downconn_txinit_phaligndone_read(),
|
csr::cxp::downconn_txinit_phaligndone_read(),
|
||||||
csr::cxp::downconn_rxinit_phaligndone_read(),
|
csr::cxp::downconn_rxinit_phaligndone_read(),
|
||||||
);
|
);
|
||||||
println!("==============================================================================");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CXP_GTX::change_linerate(timer, speed);
|
CXP_GTX::change_linerate(timer, CXP_SPEED::CXP_1);
|
||||||
|
|
||||||
loopback_testing(timer, 0x00, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod CXP_GTX {
|
pub mod CXP_GTX {
|
||||||
|
@ -189,70 +171,32 @@ pub mod CXP_GTX {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_qpll_settings(speed: CXP_SPEED) {
|
fn change_qpll_settings(speed: CXP_SPEED) {
|
||||||
match speed {
|
|
||||||
CXP_SPEED::CXP_12 => {
|
|
||||||
panic!("CXP 12.5Gbps is not supported on zc706");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this switches between High and Low band VCO
|
|
||||||
// NOT needed if VCO can do 12.5GHz
|
|
||||||
let qpll_cfg_reg0 = match speed {
|
|
||||||
// NOTE: for ZC706 QPLL VCO that cannot go up to 12.5GHz
|
|
||||||
CXP_SPEED::CXP_1 | CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 | CXP_SPEED::CXP_10 => 0x0181,
|
|
||||||
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 | CXP_SPEED::CXP_12 => 0x01C1,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Change QPLL_REFCLK_DIV
|
|
||||||
let qpll_div_reg0 = match speed {
|
|
||||||
// NOTE: for ZC706 QPLL VCO that cannot go up to 12.5GHz
|
|
||||||
CXP_SPEED::CXP_1 | CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 | CXP_SPEED::CXP_10 => 0x8068,
|
|
||||||
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 | CXP_SPEED::CXP_12 => 0x0068,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Change QPLL_FBDIV
|
// Change QPLL_FBDIV
|
||||||
let qpll_div_reg1 = match speed {
|
let qpll_div_reg = match speed {
|
||||||
CXP_SPEED::CXP_1 | CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 | CXP_SPEED::CXP_10 => 0x0120,
|
CXP_SPEED::CXP_1 | CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 | CXP_SPEED::CXP_10 => 0x0120, // FB_Divider = 80
|
||||||
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 | CXP_SPEED::CXP_12 => 0x0170,
|
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 | CXP_SPEED::CXP_12 => 0x0170, // FB_Divider = 100
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("0x32 = {:#018b}", qpll_read(0x32));
|
|
||||||
qpll_write(0x32, qpll_cfg_reg0);
|
|
||||||
println!("0x32 = {:#018b}", qpll_read(0x32));
|
|
||||||
|
|
||||||
println!("0x33 = {:#018b}", qpll_read(0x33));
|
|
||||||
qpll_write(0x33, qpll_div_reg0);
|
|
||||||
println!("0x33 = {:#018b}", qpll_read(0x33));
|
|
||||||
|
|
||||||
println!("0x36 = {:#018b}", qpll_read(0x36));
|
println!("0x36 = {:#018b}", qpll_read(0x36));
|
||||||
qpll_write(0x36, qpll_div_reg1);
|
qpll_write(0x36, qpll_div_reg);
|
||||||
println!("0x36 = {:#018b}", qpll_read(0x36));
|
println!("0x36 = {:#018b}", qpll_read(0x36));
|
||||||
|
|
||||||
let divider = match speed {
|
let rxout_div = match speed {
|
||||||
// NOTE: for ZC706 QPLL VCO that cannot go up to 12.5GHz
|
CXP_SPEED::CXP_1 => 0b100, // 8
|
||||||
CXP_SPEED::CXP_1 => 0b100, // Divided by 8
|
CXP_SPEED::CXP_2 | CXP_SPEED::CXP_3 => 0b011, // 4
|
||||||
CXP_SPEED::CXP_2 => 0b011, // Divided by 4
|
CXP_SPEED::CXP_5 | CXP_SPEED::CXP_6 => 0b010, // 2
|
||||||
CXP_SPEED::CXP_5 | CXP_SPEED::CXP_3 => 0b010, // Divided by 2
|
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => 0b001, // 1
|
||||||
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_6 => 0b001, // Divided by 1
|
|
||||||
CXP_SPEED::CXP_12 => 0b000,
|
|
||||||
// NOTE: for ZC706 QPLL VCO that go up to 12.5GHz
|
|
||||||
// CXP_SPEED::CXP_1 => 0b100, // Divided by 8
|
|
||||||
// CXP_SPEED::CXP_2 | CXP_SPEED::CXP_3 => 0b011, // Divided by 4
|
|
||||||
// CXP_SPEED::CXP_5 | CXP_SPEED::CXP_6 => 0b010, // Divided by 2
|
|
||||||
// CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => 0b001, // Divided by 1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_rx_div_write(divider);
|
csr::cxp::downconn_rx_div_write(rxout_div);
|
||||||
csr::cxp::downconn_tx_div_write(divider);
|
csr::cxp::downconn_tx_div_write(rxout_div);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_cdr_cfg(speed: CXP_SPEED) {
|
fn change_cdr_cfg(speed: CXP_SPEED) {
|
||||||
// NOTE: for ZC706 QPLL VCO that cannot go up to 12.5GHz
|
|
||||||
let cdr_cfg = match speed {
|
let cdr_cfg = match speed {
|
||||||
// Divided by 8
|
// rxout_div = 8
|
||||||
CXP_SPEED::CXP_1 => {
|
CXP_SPEED::CXP_1 => {
|
||||||
RX_CDR_CFG {
|
RX_CDR_CFG {
|
||||||
cfg_reg0: 0x0020, //0x0A8
|
cfg_reg0: 0x0020, //0x0A8
|
||||||
|
@ -262,8 +206,8 @@ pub mod CXP_GTX {
|
||||||
cfg_reg4: 0x0003, //0x0AC
|
cfg_reg4: 0x0003, //0x0AC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Divided by 4
|
// rxout_div = 4
|
||||||
CXP_SPEED::CXP_2 => {
|
CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 => {
|
||||||
RX_CDR_CFG {
|
RX_CDR_CFG {
|
||||||
cfg_reg0: 0x0020, //0x0A8
|
cfg_reg0: 0x0020, //0x0A8
|
||||||
cfg_reg1: 0x1010, //0x0A9
|
cfg_reg1: 0x1010, //0x0A9
|
||||||
|
@ -272,8 +216,8 @@ pub mod CXP_GTX {
|
||||||
cfg_reg4: 0x0003, //0x0AC
|
cfg_reg4: 0x0003, //0x0AC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Divided by 2
|
// rxout_div = 2
|
||||||
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_5 => {
|
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 => {
|
||||||
RX_CDR_CFG {
|
RX_CDR_CFG {
|
||||||
cfg_reg0: 0x0020, //0x0A8
|
cfg_reg0: 0x0020, //0x0A8
|
||||||
cfg_reg1: 0x1020, //0x0A9
|
cfg_reg1: 0x1020, //0x0A9
|
||||||
|
@ -282,17 +226,17 @@ pub mod CXP_GTX {
|
||||||
cfg_reg4: 0x0003, //0x0AC
|
cfg_reg4: 0x0003, //0x0AC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Divided by 1
|
// // Divided by 1
|
||||||
CXP_SPEED::CXP_6 => {
|
// CXP_SPEED::CXP_6 => {
|
||||||
RX_CDR_CFG {
|
// RX_CDR_CFG {
|
||||||
cfg_reg0: 0x0020, //0x0A8
|
// cfg_reg0: 0x0020, //0x0A8
|
||||||
cfg_reg1: 0x1040, //0x0A9
|
// cfg_reg1: 0x1040, //0x0A9
|
||||||
cfg_reg2: 0x23FF, //0x0AA
|
// cfg_reg2: 0x23FF, //0x0AA
|
||||||
cfg_reg3: 0x0000, //0x0AB
|
// cfg_reg3: 0x0000, //0x0AB
|
||||||
cfg_reg4: 0x0003, //0x0AC
|
// cfg_reg4: 0x0003, //0x0AC
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
// Divided by 1
|
// rxout_div = 1
|
||||||
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => {
|
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => {
|
||||||
RX_CDR_CFG {
|
RX_CDR_CFG {
|
||||||
cfg_reg0: 0x0020, //0x0A8
|
cfg_reg0: 0x0020, //0x0A8
|
||||||
|
|
Loading…
Reference in New Issue