1
0
Fork 0

cxp downconn: replace QPLL with CPLL

cxp downconn: add QPLL with its reset CSR
cxp downconn: set QPLL as CLK source for GTX
cxp downconn: remove PLL_reset signal from tx_init to prevent race
condition
cxp downconn: rename cxp_gtx to GTX
This commit is contained in:
morgan 2024-07-29 17:22:32 +08:00
parent 563e06ca8d
commit ccd3e6618a
1 changed files with 131 additions and 41 deletions

View File

@ -24,17 +24,29 @@ class CXP_DownConn(Module, AutoCSR):
self.rxinit_phaligndone = CSRStatus() self.rxinit_phaligndone = CSRStatus()
self.rx_ready = CSRStatus() self.rx_ready = CSRStatus()
self.qpll_reset = CSR()
self.qpll_locked = CSRStatus()
# # # # # #
# TODO: QPLL (GTXE2_COMMON) here self.submodules.qpll = QPLL(refclk, sys_clk_freq)
# CPLL too slow for 12.5Gbps :(
# single & master tx_mode can lock with rx in loopback # single & master tx_mode can lock with rx in loopback
self.submodules.gtx = CXP_GTX(refclk, pads, sys_clk_freq, tx_mode="single", rx_mode="single") self.submodules.gtx = GTX(refclk, self.qpll, pads, sys_clk_freq, tx_mode="single", rx_mode="single")
self.comb += [ # 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 :<
self.sync += [
# PLL
self.qpll.reset.eq(self.qpll_reset.re),
self.qpll_locked.status.eq(self.qpll.lock),
# GTX
self.txinit_phaligndone.status.eq(self.gtx.tx_init.Xxphaligndone), self.txinit_phaligndone.status.eq(self.gtx.tx_init.Xxphaligndone),
# self.rxinit_phaligndone.status.eq(self.gtx.rx_init.Xxphaligndone), self.rxinit_phaligndone.status.eq(self.gtx.rx_init.Xxphaligndone),
self.rx_ready.status.eq(self.gtx.rx_ready), self.rx_ready.status.eq(self.gtx.rx_ready),
self.gtx.txenable.eq(self.txenable.storage[0]), self.gtx.txenable.eq(self.txenable.storage[0]),
@ -52,7 +64,17 @@ class CXP_DownConn(Module, AutoCSR):
# DEBUG:SMA # DEBUG:SMA
self.specials += [ self.specials += [
Instance("OBUF", i_I=self.gtx.rxoutclk, o_O=debug_sma.p_tx), Instance("OBUF", i_I=self.gtx.rxoutclk, o_O=debug_sma.p_tx),
Instance("OBUF", i_I=self.gtx.cd_cxp_gtx_tx.clk, o_O=debug_sma.n_rx) Instance("OBUF", i_I=self.gtx.cd_cxp_gtx_tx.clk, o_O=debug_sma.n_rx),
# pmod 0-7 pin
Instance("OBUF", i_I=self.qpll.lock, o_O=pmod_pads[0]),
Instance("OBUF", i_I=self.qpll.reset, o_O=pmod_pads[1]),
Instance("OBUF", i_I=self.gtx.tx_init.gtXxreset, o_O=pmod_pads[2]),
# Instance("OBUF", i_I=, o_O=pmod_pads[3]),
# Instance("OBUF", i_I=, o_O=pmod_pads[4]),
# Instance("OBUF", i_I=, o_O=pmod_pads[5]),
# Instance("OBUF", i_I=, o_O=pmod_pads[6]),
# Instance("OBUF", i_I=, o_O=pmod_pads[7]),
] ]
# DEBUG: datain # DEBUG: datain
@ -117,6 +139,88 @@ class CXP_DownConn(Module, AutoCSR):
# checkout channel interfaces & drtio_gtx # checkout channel interfaces & drtio_gtx
# checkout GTPTXPhaseAlignement for inspiration # checkout GTPTXPhaseAlignement for inspiration
class QPLL(Module):
def __init__(self, refclk, sys_clk_freq):
self.clk = Signal()
self.refclk = Signal()
self.lock = Signal()
self.reset = Signal()
# # #
# WARNING: VCO cannot do 12.5GHz on ZC706
# VCO freq = sys*qpll_fbdiv
# PLL output = VCO/2
qpll_fbdiv = 0b0100100000
qpll_fbdiv_ratio = 1
fbdiv_real = 80
refclk_div = 1
self.Xxout_div = 4
self.tx_usrclk_freq = (sys_clk_freq*fbdiv_real/self.Xxout_div)/20
# QPLL reset
pll_reset_cycles = ceil(sys_clk_freq/125e6)
pll_reset_timer = WaitTimer(pll_reset_cycles)
self.submodules += pll_reset_timer
reset = Signal()
startup_fsm = FSM(reset_state="IDLE")
self.submodules += startup_fsm
startup_fsm.act("IDLE",
If(self.reset, NextState("RESET_PLL"))
)
startup_fsm.act("RESET_PLL",
reset.eq(1),
pll_reset_timer.wait.eq(1),
If(pll_reset_timer.done, NextState("IDLE"))
)
self.specials += [
Instance("GTXE2_COMMON",
i_QPLLREFCLKSEL=0b001,
i_GTREFCLK0=refclk,
i_QPLLPD=0,
i_QPLLRESET=reset,
i_QPLLLOCKEN=1,
o_QPLLLOCK=self.lock,
o_QPLLOUTCLK=self.clk,
o_QPLLOUTREFCLK=self.refclk,
# See UG476 (v1.12.1) Table 2-16
p_QPLL_FBDIV=qpll_fbdiv,
p_QPLL_FBDIV_RATIO=qpll_fbdiv_ratio,
p_QPLL_REFCLK_DIV=refclk_div,
# From 7 Series FPGAs Transceivers Wizard
p_BIAS_CFG=0x0000040000001000,
p_COMMON_CFG=0x00000000,
p_QPLL_CFG=0x0680181,
p_QPLL_CLKOUT_CFG=0b0000,
p_QPLL_COARSE_FREQ_OVRD=0b010000,
p_QPLL_COARSE_FREQ_OVRD_EN=0b0,
p_QPLL_CP=0b0000011111,
p_QPLL_CP_MONITOR_EN=0b0,
p_QPLL_DMONITOR_SEL=0b0,
p_QPLL_FBDIV_MONITOR_EN= 0b0,
p_QPLL_INIT_CFG=0x000006,
p_QPLL_LOCK_CFG=0x21E8,
p_QPLL_LPF=0b1111,
# Reserved, values cannot be modified
i_BGBYPASSB=0b1,
i_BGMONITORENB=0b1,
i_BGPDB=0b1,
i_BGRCALOVRD=0b11111,
i_RCALENB=0b1,
i_QPLLRSVD1=0b0,
i_QPLLRSVD2=0b11111,
)
]
# Changes the phase of the transceiver RX clock to align the comma to # Changes the phase of the transceiver RX clock to align the comma to
# the LSBs of RXDATA, fixing the latency. # the LSBs of RXDATA, fixing the latency.
# #
@ -224,26 +328,20 @@ class CXP_BruteforceClockAligner(Module):
class CXP_GTX(Module): class GTX(Module):
# Settings: # Settings:
# * GTX reference clock @ 125MHz # * GTX reference clock @ 125MHz
# * GTX data width = 20 # * GTX data width = 20
# * GTX PLL frequency @ 3.125GHz # * GTX PLL frequency @ 3.125GHz
# * GTX line rate (TX & RX) @ 3.125Gb/s # * GTX line rate (TX & RX) @ 3.125Gb/s
# * GTX TX/RX USRCLK @ PLL/datawidth = 156MHz # * GTX TX/RX USRCLK @ PLL/datawidth = 156MHz
def __init__(self, refclk, pads, sys_clk_freq, tx_mode="single", rx_mode="single"): def __init__(self, refclk, qpll, pads, sys_clk_freq, tx_mode="single", rx_mode="single"):
assert tx_mode in ["single", "master", "slave"] assert tx_mode in ["single", "master", "slave"]
assert rx_mode in ["single", "master", "slave"] assert rx_mode in ["single", "master", "slave"]
cpll_div = 4 # linerate = USRCLK * datawidth
cpll_div45 = 5
refclk_div = 1
Xxout_div = 2
# linerate = sys * cpll_mult
cpll_mult = 2 * cpll_div * cpll_div45 / (Xxout_div * refclk_div)
pll_fbout_mult = 10 pll_fbout_mult = 10
txusr_pll_div = pll_fbout_mult*20/cpll_mult # 20 is datawidth txusr_pll_div = pll_fbout_mult*sys_clk_freq/qpll.tx_usrclk_freq # 20 is datawidth
self.rx_restart = Signal() self.rx_restart = Signal()
self.tx_restart = Signal() self.tx_restart = Signal()
@ -262,16 +360,16 @@ class CXP_GTX(Module):
# # # # # #
cpllreset = Signal()
cplllock = Signal()
# TX generates cxp_tx clock, init must be in system domain # TX generates cxp_tx clock, init must be in system domain
self.submodules.tx_init = tx_init = GTXInit(sys_clk_freq, False, mode=tx_mode) self.submodules.tx_init = tx_init = GTXInit(sys_clk_freq, False, mode=tx_mode)
# RX receives restart commands from RTIO domain # RX receives restart commands from RTIO domain
self.submodules.rx_init = rx_init = ClockDomainsRenamer("cxp_gtx_tx")(GTXInit(sys_clk_freq, True, mode=rx_mode)) self.submodules.rx_init = rx_init = ClockDomainsRenamer("cxp_gtx_tx")(GTXInit(qpll.tx_usrclk_freq, True, mode=rx_mode))
# DEBUG: change back to cxp_gtx_tx once QPLL works
# self.submodules.rx_init = rx_init = GTXInit(sys_clk_freq, True, mode=rx_mode)
self.comb += [ self.comb += [
cpllreset.eq(tx_init.cpllreset), tx_init.cplllock.eq(qpll.lock),
tx_init.cplllock.eq(cplllock), rx_init.cplllock.eq(qpll.lock)
rx_init.cplllock.eq(cplllock)
] ]
txdata = Signal(20) txdata = Signal(20)
@ -293,29 +391,21 @@ class CXP_GTX(Module):
p_PD_TRANS_TIME_FROM_P2=0x3c, p_PD_TRANS_TIME_FROM_P2=0x3c,
p_PD_TRANS_TIME_NONE_P2=0x3c, p_PD_TRANS_TIME_NONE_P2=0x3c,
p_PD_TRANS_TIME_TO_P2=0x64, p_PD_TRANS_TIME_TO_P2=0x64,
i_CPLLPD=1,
# CPLL # QPLL
p_CPLL_CFG=0xBC07DC, i_QPLLCLK=qpll.clk,
p_CPLL_FBDIV=cpll_div, i_QPLLREFCLK=qpll.refclk,
p_CPLL_FBDIV_45=cpll_div45, p_RXOUT_DIV=qpll.Xxout_div,
p_CPLL_REFCLK_DIV=refclk_div, p_TXOUT_DIV=qpll.Xxout_div,
p_RXOUT_DIV=Xxout_div, i_RXSYSCLKSEL=0b11, # use QPLL & QPLL's REFCLK
p_TXOUT_DIV=Xxout_div, i_TXSYSCLKSEL=0b11, # use QPLL & CPLL's REFCLK
p_CPLL_INIT_CFG=0x00001E,
p_CPLL_LOCK_CFG=0x01E8,
i_CPLLRESET=cpllreset,
i_CPLLPD=cpllreset,
o_CPLLLOCK=cplllock,
i_CPLLLOCKEN=1,
i_CPLLREFCLKSEL=0b001,
i_TSTIN=2**20-1,
i_GTREFCLK0=refclk,
# TX clock # TX clock
p_TXBUF_EN="FALSE", p_TXBUF_EN="FALSE",
p_TX_XCLK_SEL="TXUSR", p_TX_XCLK_SEL="TXUSR",
o_TXOUTCLK=self.txoutclk, o_TXOUTCLK=self.txoutclk,
i_TXSYSCLKSEL=0b00, # i_TXSYSCLKSEL=0b00,
i_TXOUTCLKSEL=0b11, i_TXOUTCLKSEL=0b11,
# TX Startup/Reset # TX Startup/Reset
@ -386,7 +476,7 @@ class CXP_GTX(Module):
# RX clock # RX clock
i_RXDDIEN=1, i_RXDDIEN=1,
i_RXSYSCLKSEL=0b00, # i_RXSYSCLKSEL=0b00,
i_RXOUTCLKSEL=0b010, i_RXOUTCLKSEL=0b010,
o_RXOUTCLK=self.rxoutclk, o_RXOUTCLK=self.rxoutclk,
i_RXUSRCLK=ClockSignal("cxp_gtx_rx"), i_RXUSRCLK=ClockSignal("cxp_gtx_rx"),
@ -531,7 +621,7 @@ class CXP_GTX(Module):
# 125MHz: align <1s # 125MHz: align <1s
# 156.25MHz: align <15s # 156.25MHz: align <15s
# 250MHz: cannot align # 250MHz: cannot align
clock_aligner = CXP_BruteforceClockAligner(0b0101111100, 1_000_000) clock_aligner = CXP_BruteforceClockAligner(0b0101111100, 800_000)
self.submodules += clock_aligner self.submodules += clock_aligner
self.comb += [ self.comb += [
clock_aligner.rxdata.eq(rxdata), clock_aligner.rxdata.eq(rxdata),