1
0
Fork 0

Compare commits

..

No commits in common. "a6b1701de3cb28608941fe7a248fbcdda0d5a817" and "1f8ef6bf96ac02a2f8724aa4bb74c32628decce2" have entirely different histories.

2 changed files with 250 additions and 565 deletions

View File

@ -1,5 +1,6 @@
from migen import * from migen import *
from migen.genlib.cdc import MultiReg, PulseSynchronizer from migen.genlib.cdc import MultiReg, PulseSynchronizer
from migen.genlib.misc import WaitTimer
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
@ -19,10 +20,14 @@ class CXP_DownConn(Module, AutoCSR):
self.tx_restart = CSR() self.tx_restart = CSR()
self.txenable = CSRStorage() self.txenable = CSRStorage()
self.txinit_phaligndone = CSRStatus() self.txinit_phaligndone = CSRStatus()
self.rxinit_phaligndone = CSRStatus() self.rxinit_phaligndone = CSRStatus()
self.rx_ready = CSRStatus() self.rx_ready = CSRStatus()
self.tx_div = CSRStorage(3)
self.rx_div = CSRStorage(3)
self.qpll_reset = CSR() self.qpll_reset = CSR()
self.qpll_locked = CSRStatus() self.qpll_locked = CSRStatus()
@ -42,6 +47,7 @@ class CXP_DownConn(Module, AutoCSR):
# PLL # PLL
qpll.reset.eq(self.qpll_reset.re), qpll.reset.eq(self.qpll_reset.re),
self.qpll_locked.status.eq(qpll.lock), self.qpll_locked.status.eq(qpll.lock),
# GTX # GTX
self.txinit_phaligndone.status.eq(gtx.tx_init.Xxphaligndone), self.txinit_phaligndone.status.eq(gtx.tx_init.Xxphaligndone),
self.rxinit_phaligndone.status.eq(gtx.rx_init.Xxphaligndone), self.rxinit_phaligndone.status.eq(gtx.rx_init.Xxphaligndone),
@ -52,76 +58,11 @@ class CXP_DownConn(Module, AutoCSR):
gtx.rx_restart.eq(self.rx_restart.re), gtx.rx_restart.eq(self.rx_restart.re),
gtx.tx_init.clk_path_ready.eq(self.tx_start_init.storage), gtx.tx_init.clk_path_ready.eq(self.tx_start_init.storage),
gtx.rx_init.clk_path_ready.eq(self.rx_start_init.storage), gtx.rx_init.clk_path_ready.eq(self.rx_start_init.storage),
] # gtx.rx_alignment_en.eq(self.rx_data_alignment.storage),
# GTX Channels DRP # GTX DRP
self.tx_div = CSRStorage(3)
self.rx_div = CSRStorage(3)
self.gtx_daddr = CSRStorage(9)
self.gtx_dread = CSR()
self.gtx_din_stb = CSR()
self.gtx_din = CSRStorage(16)
self.gtx_dout = CSRStatus(16)
self.gtx_dready = CSR()
self.comb += gtx.dclk.eq(ClockSignal("sys"))
self.sync += [
gtx.tx_rate.eq(self.tx_div.storage), gtx.tx_rate.eq(self.tx_div.storage),
gtx.rx_rate.eq(self.rx_div.storage), gtx.rx_rate.eq(self.rx_div.storage),
gtx.den.eq(0),
gtx.dwen.eq(0),
If(self.gtx_dread.re,
gtx.den.eq(1),
gtx.daddr.eq(self.gtx_daddr.storage),
).Elif(self.gtx_din_stb.re,
gtx.den.eq(1),
gtx.dwen.eq(1),
gtx.daddr.eq(self.gtx_daddr.storage),
gtx.din.eq(self.gtx_din.storage),
),
If(gtx.dready,
self.gtx_dready.w.eq(1),
self.gtx_dout.status.eq(gtx.dout),
),
If(self.gtx_dready.re,
self.gtx_dready.w.eq(0),
),
]
# QPLL DRP
self.qpll_daddr = CSRStorage(8)
self.qpll_dread = CSR()
self.qpll_din_stb = CSR()
self.qpll_din = CSRStorage(16)
self.qpll_dout = CSRStatus(16)
self.qpll_dready = CSR()
self.comb += qpll.dclk.eq(ClockSignal("sys"))
self.sync += [
qpll.den.eq(0),
qpll.dwen.eq(0),
If(self.qpll_dread.re,
qpll.den.eq(1),
qpll.daddr.eq(self.qpll_daddr.storage),
).Elif(self.qpll_din_stb.re,
qpll.den.eq(1),
qpll.dwen.eq(1),
qpll.daddr.eq(self.qpll_daddr.storage),
qpll.din.eq(self.qpll_din.storage),
),
If(qpll.dready,
self.qpll_dready.w.eq(1),
self.qpll_dout.status.eq(qpll.dout),
),
If(self.qpll_dready.re,
self.qpll_dready.w.eq(0),
),
] ]
# DEBUG: txusrclk PLL DRG # DEBUG: txusrclk PLL DRG
@ -160,22 +101,18 @@ class CXP_DownConn(Module, AutoCSR):
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_det.aligner_en_rxclk, o_O=pmod_pads[0]),
Instance("OBUF", i_I=gtx.comma_det.restart, o_O=pmod_pads[1]), Instance("OBUF", i_I=gtx.comma_det.rxinit_done, 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_det.restart, 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_det.comma_aligned, 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_det.ready, 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_det.valid_data, o_O=pmod_pads[5]),
Instance("OBUF", i_I=gtx.comma_det.has_error, o_O=pmod_pads[6]), # Instance("OBUF", i_I=, o_O=pmod_pads[7]),
Instance("OBUF", i_I=gtx.comma_det.ready, o_O=pmod_pads[7]),
# 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.dwen, o_O=pmod_pads[2]),
# Instance("OBUF", i_I=gtx.dready, o_O=pmod_pads[3]),
] ]
# DEBUG: datain # DEBUG: datain
counter_max = 2
counter = Signal(max=counter_max)
self.data_0 = CSRStorage(8) self.data_0 = CSRStorage(8)
self.data_1 = CSRStorage(8) self.data_1 = CSRStorage(8)
@ -195,24 +132,28 @@ class CXP_DownConn(Module, AutoCSR):
self.decoded_k_0 = CSRStatus() self.decoded_k_0 = CSRStatus()
self.decoded_k_1 = CSRStatus() self.decoded_k_1 = CSRStatus()
self.sync.cxp_gtx_tx += [ self.shifted = CSRStatus(9)
self.gtx.encoder.d[0].eq(0xBC),
self.gtx.encoder.k[0].eq(1),
self.gtx.encoder.d[1].eq(0x3C),
self.gtx.encoder.k[1].eq(1),
self.gtx.encoder.d[2].eq(0x3C),
self.gtx.encoder.k[2].eq(1),
self.gtx.encoder.d[3].eq(0xB5),
self.gtx.encoder.k[3].eq(0),
self.sync.cxp_gtx_tx += [
If(counter == 0,
self.gtx.encoder.d[0].eq(self.data_0.storage),
self.gtx.encoder.k[0].eq(self.control_bit_0.storage),
self.gtx.encoder.d[1].eq(self.data_1.storage),
self.gtx.encoder.k[1].eq(self.control_bit_1.storage),
counter.eq(counter+1),
).Elif(counter == 1,
self.gtx.encoder.d[0].eq(self.data_2.storage),
self.gtx.encoder.k[0].eq(self.control_bit_2.storage),
self.gtx.encoder.d[1].eq(self.data_3.storage),
self.gtx.encoder.k[1].eq(self.control_bit_3.storage),
counter.eq(0),
),
self.encoded_0.status.eq(self.gtx.encoder.output[0]), self.encoded_0.status.eq(self.gtx.encoder.output[0]),
self.encoded_1.status.eq(self.gtx.encoder.output[1]), self.encoded_1.status.eq(self.gtx.encoder.output[1]),
] ]
# keep it odd, so it will show data[n] where n is odd
stb_timer = Signal(reset=10, max=11)
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),
@ -220,10 +161,9 @@ class CXP_DownConn(Module, AutoCSR):
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), # If(self.gtx.clk_aligner.comma_det.detected,
).Else( # self.shifted.status.eq(self.gtx.clk_aligner.comma_det.bitshift),
stb_timer.eq(stb_timer - 1), # )
)
] ]
@ -244,35 +184,37 @@ class QPLL(Module):
self.lock = Signal() self.lock = Signal()
self.reset = Signal() self.reset = Signal()
# Dynamic Reconfiguration Ports
self.daddr = Signal(8)
self.dclk = Signal()
self.den = Signal()
self.dwen = Signal()
self.din = Signal(16)
self.dout = Signal(16)
self.dready = Signal()
# # # # # #
# WARNING: VCO cannot do 12.5GHz on ZC706 # WARNING: VCO cannot do 12.5GHz on ZC706
# VCO freq = sys*qpll_fbdiv # VCO freq = sys*qpll_fbdiv
# PLL output = VCO/2 # PLL output = VCO/2
qpll_fbdiv = 0b0100100000 # 80 div qpll_fbdiv = 0b0100100000
qpll_fbdiv_ratio = 1 qpll_fbdiv_ratio = 1
fbdiv_real = 80 fbdiv_real = 80
refclk_div = 1 refclk_div = 1
self.Xxout_div = 8 self.Xxout_div = 8
# qpll_fbdiv = 0b0101110000 # 100 div self.tx_usrclk_freq = (sys_clk_freq*fbdiv_real/self.Xxout_div)/20
# qpll_fbdiv_ratio = 1
# fbdiv_real = 100 # QPLL reset
# refclk_div = 2 pll_reset_cycles = ceil(sys_clk_freq/125e6)
# self.Xxout_div = 2 pll_reset_timer = WaitTimer(pll_reset_cycles)
self.submodules += pll_reset_timer
self.tx_usrclk_freq = (sys_clk_freq*fbdiv_real/self.Xxout_div)/40 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 += [ self.specials += [
Instance("GTXE2_COMMON", Instance("GTXE2_COMMON",
@ -280,7 +222,7 @@ class QPLL(Module):
i_GTREFCLK0=refclk, i_GTREFCLK0=refclk,
i_QPLLPD=0, i_QPLLPD=0,
i_QPLLRESET=self.reset, i_QPLLRESET=reset,
i_QPLLLOCKEN=1, i_QPLLLOCKEN=1,
o_QPLLLOCK=self.lock, o_QPLLLOCK=self.lock,
o_QPLLOUTCLK=self.clk, o_QPLLOUTCLK=self.clk,
@ -314,24 +256,15 @@ class QPLL(Module):
i_RCALENB=0b1, i_RCALENB=0b1,
i_QPLLRSVD1=0b0, i_QPLLRSVD1=0b0,
i_QPLLRSVD2=0b11111, i_QPLLRSVD2=0b11111,
# Dynamic Reconfiguration Ports
i_DRPADDR=self.daddr,
i_DRPCLK=self.dclk,
i_DRPEN=self.den,
i_DRPWE=self.dwen,
i_DRPDI=self.din,
o_DRPDO=self.dout,
o_DRPRDY=self.dready,
) )
] ]
# 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.
class Comma_Detector(Module): class Comma_Detector(Module):
def __init__(self, comma, check_period=1_000_000): def __init__(self, comma, check_period=50_000, width=20):
self.data = Signal(20) self.data = Signal(width)
self.word_aligned = Signal() self.rxinit_done = Signal()
self.aligner_en_rxclk = Signal() self.aligner_en_rxclk = Signal()
self.ready = Signal() self.ready = Signal()
@ -341,142 +274,93 @@ class Comma_Detector(Module):
# The built-in RXBYTEISALIGNED can be falsely asserted at linerate higher than 5Gbps self.comma_aligned = Signal()
# - UG476 (v1.12.1) p.228 self.valid_data = Signal()
# The validity of data & comma are checked externally self.submodules.recheck_ps = recheck_ps = PulseSynchronizer("sys", "cxp_gtx_rx")
aligned = Signal()
self.specials += MultiReg(self.comma_aligned, aligned)
check_counter = Signal(reset=check_period-1, max=check_period) valid_data = Signal()
# check = Signal() self.specials += MultiReg(self.valid_data, valid_data)
self.sync += [
self.restart.eq(0),
# check.eq(0),
# check_reset.i.eq(0),
If(~self.ready,
If(check_counter == 0,
check_counter.eq(check_counter.reset),
# check.eq(1),
self.restart.eq(1),
# check_reset.i.eq(1),
).Else(
check_counter.eq(check_counter - 1),
)
)
]
# WIP:
comma_n = ~comma & 0b1111111111 comma_n = ~comma & 0b1111111111
has_error = Signal() rx1cnt = Signal(max=11)
comma_aligned = Signal()
comma_seen = Signal()
error_seen = Signal()
one_counts = Signal(max=11)
counter_period = 5000
counter = Signal(reset=counter_period-1, max=counter_period)
check_reset = Signal()
check = Signal()
self.sync.cxp_gtx_rx += [ self.sync.cxp_gtx_rx += [
rx1cnt.eq(reduce(add, [self.data[i] for i in range(10)])),
If(recheck_ps.o,
self.comma_aligned.eq(0)
).Elif((self.data[:10] == comma) | (self.data[:10] == comma_n),
self.comma_aligned.eq(1)
),
If(recheck_ps.o,
self.valid_data.eq(0)
).Elif((rx1cnt == 4) | (rx1cnt == 5) | (rx1cnt == 6),
self.valid_data.eq(1)
),
]
check_counter = Signal(reset=check_period-1, max=check_period)
check = Signal()
aligner_en_sys = Signal()
self.specials += MultiReg(aligner_en_sys, self.aligner_en_rxclk, odomain="cxp_gtx_rx")
self.sync += [
check.eq(0), check.eq(0),
If(counter == 0, If(check_counter == 0,
counter.eq(counter.reset), check_counter.eq(check_counter.reset),
check.eq(1), check.eq(1),
).Else( ).Else(
counter.eq(counter - 1), check_counter.eq(check_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,
comma_seen.eq(0),
).Elif((self.data[:10] == comma) | (self.data[:10] == comma_n),
comma_seen.eq(1)
),
one_counts.eq(reduce(add, [self.data[i] for i in range(10, 20)])),
If(check_reset,
error_seen.eq(0),
).Elif((one_counts != 4) & (one_counts != 5) & (one_counts != 6),
error_seen.eq(1),
),
] ]
# DEBUG: expose signal
self.check_reset = Signal()
self.comma_aligned = Signal()
self.comma_seen = Signal()
self.has_error = Signal()
self.error_seen = Signal()
self.comb +=[
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.fsm = fsm = FSM(reset_state="IDLE")
# the data from gtxe2 is delayed and checking at the output may not reflect the alignment inside the aligner fsm.act("IDLE",
# 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 aligner_en_sys.eq(1),
# a timer is used to wait till the "aligned" data to arrive and do a system check like the datasheet suggested
self.submodules.timer = timer = ClockDomainsRenamer("cxp_gtx_rx")(WaitTimer(5000))
rxfsm.act("ALIGNING",
self.aligner_en_rxclk.eq(1),
If(self.word_aligned,
check_reset.eq(1),
NextState("WAIT_ALIGNED_DATA"),
)
)
rxfsm.act("WAIT_ALIGNED_DATA",
timer.wait.eq(1),
If(timer.done,
check_reset.eq(1),
NextState("CHECKING"),
)
)
rxfsm.act("CHECKING",
If(check, If(check,
check_reset.eq(1), recheck_ps.i.eq(1),
If(comma_seen & (~error_seen), If(aligned,
NextState("WAIT_NO_ERROR"),
).Else(
self.restart.eq(1),
)
)
)
fsm.act("WAIT_NO_ERROR",
aligner_en_sys.eq(1),
If(check,
recheck_ps.i.eq(1),
If(aligned & valid_data,
NextState("READY"), NextState("READY"),
).Else( ).Else(
NextState("ALIGNING") self.restart.eq(1),
NextState("IDLE"),
) )
) )
) )
ready = Signal() fsm.act("READY",
self.specials += MultiReg(ready, self.ready) self.ready.eq(1),
rxfsm.act("READY",
ready.eq(1),
If(check, If(check,
check_reset.eq(1), recheck_ps.i.eq(1),
If(~(comma_seen & (~error_seen)), If(~(aligned & valid_data),
NextState("ALIGNING"), self.restart.eq(1),
NextState("IDLE"),
) )
) )
) )
class GTX(Module): class GTX(Module):
# Settings: # Settings:
# * GTX reference clock @ 125MHz # * GTX reference clock @ 125MHz
@ -490,7 +374,7 @@ class GTX(Module):
# linerate = USRCLK * datawidth # linerate = USRCLK * datawidth
pll_fbout_mult = 8 pll_fbout_mult = 8
txusr_pll_div = pll_fbout_mult*sys_clk_freq/qpll.tx_usrclk_freq txusr_pll_div = pll_fbout_mult*sys_clk_freq/qpll.tx_usrclk_freq # 20 is datawidth
self.tx_restart = Signal() self.tx_restart = Signal()
self.rx_restart = Signal() self.rx_restart = Signal()
@ -502,18 +386,9 @@ class GTX(Module):
self.tx_rate = Signal(3) self.tx_rate = Signal(3)
self.rx_rate = Signal(3) self.rx_rate = Signal(3)
# Dynamic Reconfiguration Ports self.submodules.encoder = ClockDomainsRenamer("cxp_gtx_tx")(Encoder(2, True))
self.daddr = Signal(9)
self.dclk = Signal()
self.den = Signal()
self.dwen = Signal()
self.din = Signal(16)
self.dout = Signal(16)
self.dready = Signal()
self.submodules.encoder = ClockDomainsRenamer("cxp_gtx_tx")(Encoder(4, True))
self.submodules.decoders = [ClockDomainsRenamer("cxp_gtx_rx")( self.submodules.decoders = [ClockDomainsRenamer("cxp_gtx_rx")(
(Decoder(True))) for _ in range(4)] (Decoder(True))) for _ in range(2)]
# transceiver direct clock outputs # transceiver direct clock outputs
@ -536,11 +411,10 @@ class GTX(Module):
rx_init.cplllock.eq(qpll.lock) rx_init.cplllock.eq(qpll.lock)
] ]
txdata = Signal(40) txdata = Signal(20)
rxdata = Signal(40) rxdata = Signal(20)
word_aligned = Signal() comma_align_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",
@ -598,11 +472,11 @@ class GTX(Module):
i_TXINHIBIT=~self.txenable, i_TXINHIBIT=~self.txenable,
# TX data # TX data
p_TX_DATA_WIDTH=40, p_TX_DATA_WIDTH=20,
p_TX_INT_DATAWIDTH=1, p_TX_INT_DATAWIDTH=0,
i_TXCHARDISPMODE=Cat(txdata[9], txdata[19], txdata[29], txdata[39]), i_TXCHARDISPMODE=Cat(txdata[9], txdata[19]),
i_TXCHARDISPVAL=Cat(txdata[8], txdata[18], txdata[28], txdata[38]), i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]),
i_TXDATA=Cat(txdata[:8], txdata[10:18], txdata[20:28], txdata[30:38]), i_TXDATA=Cat(txdata[:8], txdata[10:18]),
i_TXUSRCLK=ClockSignal("cxp_gtx_tx"), i_TXUSRCLK=ClockSignal("cxp_gtx_tx"),
i_TXUSRCLK2=ClockSignal("cxp_gtx_tx"), i_TXUSRCLK2=ClockSignal("cxp_gtx_tx"),
@ -661,29 +535,27 @@ class GTX(Module):
p_CLK_COR_SEQ_2_ENABLE=0b1111, p_CLK_COR_SEQ_2_ENABLE=0b1111,
# RX data # RX data
p_RX_DATA_WIDTH=40, p_RX_DATA_WIDTH=20,
p_RX_INT_DATAWIDTH=1, p_RX_INT_DATAWIDTH=0,
o_RXDISPERR=Cat(rxdata[9], rxdata[19], rxdata[29], rxdata[39]), o_RXDISPERR=Cat(rxdata[9], rxdata[19]),
o_RXCHARISK=Cat(rxdata[8], rxdata[18], rxdata[28], rxdata[38]), o_RXCHARISK=Cat(rxdata[8], rxdata[18]),
o_RXDATA=Cat(rxdata[:8], rxdata[10:18], rxdata[20:28], rxdata[30:38]), o_RXDATA=Cat(rxdata[:8], rxdata[10:18]),
# RX Byte and Word Alignment Attributes # RX Byte and Word Alignment Attributes
p_ALIGN_COMMA_DOUBLE="FALSE", p_ALIGN_COMMA_DOUBLE="FALSE",
p_ALIGN_COMMA_ENABLE=0b1111111111, p_ALIGN_COMMA_ENABLE=0b1111111111,
p_ALIGN_COMMA_WORD=4, # align comma to rxdata[:10] only p_ALIGN_COMMA_WORD=2, # allow rxslide to shift 20 times
p_ALIGN_MCOMMA_DET="TRUE", p_ALIGN_MCOMMA_DET="TRUE",
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,
i_RXPCOMMAALIGNEN=comma_aligner_en, i_RXPCOMMAALIGNEN=comma_align_en,
i_RXMCOMMAALIGNEN=comma_aligner_en, i_RXMCOMMAALIGNEN=comma_align_en,
i_RXCOMMADETEN=1, i_RXCOMMADETEN=1, # enable auto word alignment
i_RXSLIDE=0,
o_RXBYTEISALIGNED=word_aligned,
# RX 8B/10B Decoder Attributes # RX 8B/10B Decoder Attributes
p_RX_DISPERR_SEQ_MATCH="FALSE", p_RX_DISPERR_SEQ_MATCH="FALSE",
@ -729,16 +601,6 @@ class GTX(Module):
o_GTXTXP=pads.txp, o_GTXTXP=pads.txp,
o_GTXTXN=pads.txn, o_GTXTXN=pads.txn,
# Dynamic Reconfiguration Ports
p_IS_DRPCLK_INVERTED=0b0,
i_DRPADDR=self.daddr,
i_DRPCLK=self.dclk,
i_DRPEN=self.den,
i_DRPWE=self.dwen,
i_DRPDI=self.din,
o_DRPDO=self.dout,
o_DRPRDY=self.dready,
# ! loopback for debugging # ! loopback for debugging
i_LOOPBACK = self.loopback_mode, i_LOOPBACK = self.loopback_mode,
p_TX_LOOPBACK_DRIVE_HIZ = "FALSE", p_TX_LOOPBACK_DRIVE_HIZ = "FALSE",
@ -788,7 +650,7 @@ class GTX(Module):
p_CLKFBOUT_MULT=pll_fbout_mult, p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=pll_fbout_mult, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=txpll_fb_clk, o_CLKFBOUT=txpll_fb_clk, i_CLKFBIN=txpll_fb_clk, o_CLKFBOUT=txpll_fb_clk,
# frequency = linerate/40 # frequency = linerate/20
p_CLKOUT0_DIVIDE=txusr_pll_div, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=txpll_clkout, p_CLKOUT0_DIVIDE=txusr_pll_div, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=txpll_clkout,
# Dynamic Reconfiguration Ports # Dynamic Reconfiguration Ports
@ -814,19 +676,17 @@ class GTX(Module):
] ]
self.comb += [ self.comb += [
txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1], self.encoder.output[2], self.encoder.output[3])), txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1])),
self.decoders[0].input.eq(rxdata[:10]), self.decoders[0].input.eq(rxdata[:10]),
self.decoders[1].input.eq(rxdata[10:20]), self.decoders[1].input.eq(rxdata[10:])
self.decoders[2].input.eq(rxdata[20:30]),
self.decoders[3].input.eq(rxdata[30:]),
] ]
self.submodules.comma_det = comma_det = Comma_Detector(0b0101111100) self.submodules.comma_det = comma_det = Comma_Detector(0b0101111100)
self.comb += [ self.comb += [
comma_det.data.eq(rxdata), comma_det.data.eq(rxdata),
comma_det.word_aligned.eq(word_aligned), comma_det.rxinit_done.eq(rx_init.done),
comma_aligner_en.eq(comma_det.aligner_en_rxclk), comma_align_en.eq(comma_det.aligner_en_rxclk),
self.rx_ready.eq(comma_det.ready), self.rx_ready.eq(comma_det.ready),
rx_init.restart.eq(self.rx_restart | comma_det.restart), rx_init.restart.eq(self.rx_restart | comma_det.restart),

View File

@ -2,7 +2,6 @@ use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
use libboard_zynq::{println, timer::GlobalTimer}; use libboard_zynq::{println, timer::GlobalTimer};
use log::info; use log::info;
// use log::info;
use crate::pl::csr; use crate::pl::csr;
pub struct CXP_DownConn_Settings { pub struct CXP_DownConn_Settings {
@ -66,61 +65,46 @@ 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); 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)); // csr::cxp::data_3_write(data);
// write(0x62, 0x001A); // csr::cxp::control_bit_3_write(control_bit);
// println!("0xA8 = {:#06x}", read(0x62)); // println!(
// "data[0] = {:#04x} control bit = {:#b} encoded = {:#012b}",
// csr::cxp::downconn_data_0_read(),
// csr::cxp::downconn_control_bit_0_read(),
// csr::cxp::downconn_encoded_0_read(),
// );
// println!(
// "data[1] = {:#04x} control bit = {:#b} encoded = {:#012b}",
// csr::cxp::downconn_data_1_read(),
// csr::cxp::downconn_control_bit_1_read(),
// csr::cxp::downconn_encoded_1_read(),
// );
// for _ in 0..20 { // for _ in 0..20 {
loop { loop {
// NOTE: raw data
let data0 = csr::cxp::downconn_rxdata_0_read();
let data1 = csr::cxp::downconn_rxdata_1_read();
// let rxready = csr::cxp::downconn_rx_ready_read();
// timer.delay_us(100); // timer.delay_us(100);
// if data0 == 0b0101111100 || data0 == 0b1010000011 { println!(
// println!( "data = {:#022b} | rx ready = {}",
// "data[0] = {:#012b} comma = {} | rx ready = {}", (csr::cxp::downconn_rxdata_0_read() as u32 | ((csr::cxp::downconn_rxdata_1_read() as u32) << 10)),
// data0, csr::cxp::downconn_rx_ready_read()
// data0 == 0b0101111100 || data0 == 0b1010000011, );
// rxready,
// );
// timer.delay_us(1_000_000);
// } else if data0 == 0b1001111100 || data0 == 0b0110000011 {
// println!(
// "data[0] = {:#012b} K28.1 | rx ready = {}",
// data0,
// rxready,
// );
// timer.delay_us(1_000_000);
// } else {
// println!(
// "data[0] = {:#012b} | rx ready = {}",
// data0,
// rxready,
// );
// timer.delay_us(1_000_000);
// }
println!("0b{:010b}{:010b}", data0, data1);
timer.delay_us(1_000_000); timer.delay_us(1_000_000);
// println!(
// NOTE:decode data // "data[0] = {:#012b} data[1] = {:#012b}",
// let data0_decoded = csr::cxp::downconn_decoded_data_0_read(); // csr::cxp::rxdata_0_read(),
// let data0_k = csr::cxp::downconn_decoded_k_0_read(); // csr::cxp::rxdata_1_read(),
// let data1_decoded = csr::cxp::downconn_decoded_data_1_read(); // );
// let data1_k = csr::cxp::downconn_decoded_k_1_read();
// 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, // csr::cxp::downconn_decoded_data_0_read(),
// data0_k, // csr::cxp::downconn_decoded_k_0_read(),
// data1_decoded, // csr::cxp::downconn_decoded_data_1_read(),
// data1_k, // csr::cxp::downconn_decoded_k_1_read(),
// ); // );
// timer.delay_us(1_000_000);
} }
} }
} }
@ -150,30 +134,19 @@ pub fn setup(timer: &mut GlobalTimer, speed: CXP_SPEED) {
println!("=============================================================================="); println!("==============================================================================");
} }
CXP_GTX::change_linerate(timer, speed); change_linerate(timer, speed);
loopback_testing(timer, 0x00, 0); loopback_testing(timer, 0x00, 0);
} }
pub mod CXP_GTX {
use super::*;
struct RX_CDR_CFG {
pub cfg_reg0: u16, //0x0A8
pub cfg_reg1: u16, //0x0A9
pub cfg_reg2: u16, //0x0AA
pub cfg_reg3: u16, //0x0AB
pub cfg_reg4: u16, //0x0AC
}
pub fn change_linerate(timer: &mut GlobalTimer, speed: CXP_SPEED) { pub fn change_linerate(timer: &mut GlobalTimer, speed: CXP_SPEED) {
info!("Changing datarate to {:?}", speed); info!("Changing datarate to {:?}", speed);
// DEBUG: DRP pll for TXUSRCLK = freq(linerate)/20 // DEBUG: DRP pll for TXUSRCLK = freq(linerate)/20
let settings = txusrclk::get_txusrclk_config(speed); let settings = txusrclk::get_txusrclk_config(speed);
txusrclk::setup(timer, settings); txusrclk::setup(timer, settings);
// TODO: set QPLL_FBDIV via DRP
change_qpll_settings(speed); change_qpll_settings(speed);
change_cdr_cfg(speed);
unsafe { unsafe {
csr::cxp::downconn_qpll_reset_write(1); csr::cxp::downconn_qpll_reset_write(1);
@ -189,58 +162,11 @@ 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
let qpll_div_reg1 = match speed {
CXP_SPEED::CXP_1 | CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 | CXP_SPEED::CXP_10 => 0x0120,
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 | CXP_SPEED::CXP_12 => 0x0170,
};
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));
qpll_write(0x36, qpll_div_reg1);
println!("0x36 = {:#018b}", qpll_read(0x36));
let divider = match speed { let divider = match speed {
// NOTE: for ZC706 QPLL VCO that cannot go up to 12.5GHz
CXP_SPEED::CXP_1 => 0b100, // Divided by 8 CXP_SPEED::CXP_1 => 0b100, // Divided by 8
CXP_SPEED::CXP_2 => 0b011, // Divided by 4 CXP_SPEED::CXP_2 | CXP_SPEED::CXP_3 => 0b011, // Divided by 4
CXP_SPEED::CXP_5 | CXP_SPEED::CXP_3 => 0b010, // Divided by 2 CXP_SPEED::CXP_5 | CXP_SPEED::CXP_6 => 0b010, // Divided by 2
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_6 => 0b001, // Divided by 1 CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => 0b010, // 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 {
@ -249,107 +175,6 @@ pub mod CXP_GTX {
} }
} }
fn change_cdr_cfg(speed: CXP_SPEED) {
// NOTE: for ZC706 QPLL VCO that cannot go up to 12.5GHz
let cdr_cfg = match speed {
// Divided by 8
CXP_SPEED::CXP_1 => {
RX_CDR_CFG {
cfg_reg0: 0x0020, //0x0A8
cfg_reg1: 0x1008, //0x0A9
cfg_reg2: 0x23FF, //0x0AA
cfg_reg3: 0x0000, //0x0AB
cfg_reg4: 0x0003, //0x0AC
}
}
// Divided by 4
CXP_SPEED::CXP_2 => {
RX_CDR_CFG {
cfg_reg0: 0x0020, //0x0A8
cfg_reg1: 0x1010, //0x0A9
cfg_reg2: 0x23FF, //0x0AA
cfg_reg3: 0x0000, //0x0AB
cfg_reg4: 0x0003, //0x0AC
}
}
// Divided by 2
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_5 => {
RX_CDR_CFG {
cfg_reg0: 0x0020, //0x0A8
cfg_reg1: 0x1020, //0x0A9
cfg_reg2: 0x23FF, //0x0AA
cfg_reg3: 0x0000, //0x0AB
cfg_reg4: 0x0003, //0x0AC
}
}
// Divided by 1
CXP_SPEED::CXP_6 => {
RX_CDR_CFG {
cfg_reg0: 0x0020, //0x0A8
cfg_reg1: 0x1040, //0x0A9
cfg_reg2: 0x23FF, //0x0AA
cfg_reg3: 0x0000, //0x0AB
cfg_reg4: 0x0003, //0x0AC
}
}
// Divided by 1
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => {
RX_CDR_CFG {
cfg_reg0: 0x0020, //0x0A8
cfg_reg1: 0x1040, //0x0A9
cfg_reg2: 0x23FF, //0x0AA
cfg_reg3: 0x0000, //0x0AB
cfg_reg4: 0x000B, //0x0AC
}
}
};
gtx_write(0x0A8, cdr_cfg.cfg_reg0);
gtx_write(0x0A9, cdr_cfg.cfg_reg1);
gtx_write(0x0AA, cdr_cfg.cfg_reg2);
gtx_write(0x0AB, cdr_cfg.cfg_reg3);
gtx_write(0x0AC, cdr_cfg.cfg_reg4);
}
fn gtx_read(address: u16) -> u16 {
// DEBUG: DRPCLK need to be on for a few cycle before accessing other DRP ports
unsafe {
csr::cxp::downconn_gtx_daddr_write(address);
csr::cxp::downconn_gtx_dread_write(1);
while (csr::cxp::downconn_gtx_dready_read() != 1) {}
csr::cxp::downconn_gtx_dout_read()
}
}
fn gtx_write(address: u16, value: u16) {
// DEBUG: DRPCLK need to be on for a few cycle before accessing other DRP ports
unsafe {
csr::cxp::downconn_gtx_daddr_write(address);
csr::cxp::downconn_gtx_din_write(value);
csr::cxp::downconn_gtx_din_stb_write(1);
while (csr::cxp::downconn_gtx_dready_read() != 1) {}
}
}
fn qpll_read(address: u8) -> u16 {
unsafe {
csr::cxp::downconn_qpll_daddr_write(address);
csr::cxp::downconn_qpll_dread_write(1);
while (csr::cxp::downconn_qpll_dready_read() != 1) {}
csr::cxp::downconn_qpll_dout_read()
}
}
fn qpll_write(address: u8, value: u16) {
unsafe {
csr::cxp::downconn_qpll_daddr_write(address);
csr::cxp::downconn_qpll_din_write(value);
csr::cxp::downconn_qpll_din_stb_write(1);
while (csr::cxp::downconn_qpll_dready_read() != 1) {}
}
}
}
pub mod txusrclk { pub mod txusrclk {
use super::*; use super::*;
@ -487,23 +312,6 @@ pub mod txusrclk {
pub fn get_txusrclk_config(speed: CXP_SPEED) -> PLLSetting { pub fn get_txusrclk_config(speed: CXP_SPEED) -> PLLSetting {
match speed { match speed {
CXP_SPEED::CXP_1 => { CXP_SPEED::CXP_1 => {
// CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 32
// TXUSRCLK=62.5MHz
PLLSetting {
clkout0_reg1: 0x1410, //0x08
clkout0_reg2: 0x0000, //0x09
clkfbout_reg1: 0x1104, //0x14
clkfbout_reg2: 0x0000, //0x15
div_reg: 0x1041, //0x16
lock_reg1: 0x03e8, //0x18
lock_reg2: 0x5801, //0x19
lock_reg3: 0xdbe9, //0x1A
power_reg: 0x0000, //0x28
filt_reg1: 0x9808, //0x4E
filt_reg2: 0x9100, //0x4F
}
}
CXP_SPEED::CXP_2 => {
// CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 16 // CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 16
// TXUSRCLK=62.5MHz // TXUSRCLK=62.5MHz
PLLSetting { PLLSetting {
@ -520,24 +328,7 @@ pub mod txusrclk {
filt_reg2: 0x9100, //0x4F filt_reg2: 0x9100, //0x4F
} }
} }
CXP_SPEED::CXP_3 => { CXP_SPEED::CXP_2 => {
// CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 16
// TXUSRCLK=78.125MHz
PLLSetting {
clkout0_reg1: 0x1208, //0x08
clkout0_reg2: 0x0000, //0x09
clkfbout_reg1: 0x1145, //0x14
clkfbout_reg2: 0x0000, //0x15
div_reg: 0x1041, //0x16
lock_reg1: 0x03e8, //0x18
lock_reg2: 0x7001, //0x19
lock_reg3: 0xf3e9, //0x1A
power_reg: 0x0000, //0x28
filt_reg1: 0x9908, //0x4E
filt_reg2: 0x1900, //0x4F
}
}
CXP_SPEED::CXP_5 => {
// CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 8 // CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 8
// TXUSRCLK=125MHz // TXUSRCLK=125MHz
PLLSetting { PLLSetting {
@ -554,9 +345,9 @@ pub mod txusrclk {
filt_reg2: 0x9100, //0x4F filt_reg2: 0x9100, //0x4F
} }
} }
CXP_SPEED::CXP_6 => { CXP_SPEED::CXP_3 => {
// CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 8 // CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 8
// TXUSRCLK=156.25MHz // TXUSRCLK=125MHz
PLLSetting { PLLSetting {
clkout0_reg1: 0x1104, //0x08 clkout0_reg1: 0x1104, //0x08
clkout0_reg2: 0x0000, //0x09 clkout0_reg2: 0x0000, //0x09
@ -571,7 +362,7 @@ pub mod txusrclk {
filt_reg2: 0x1900, //0x4F filt_reg2: 0x1900, //0x4F
} }
} }
CXP_SPEED::CXP_10 => { CXP_SPEED::CXP_5 => {
// CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 4 // CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 4
// TXUSRCLK=250MHz // TXUSRCLK=250MHz
PLLSetting { PLLSetting {
@ -588,7 +379,7 @@ pub mod txusrclk {
filt_reg2: 0x9100, //0x4F filt_reg2: 0x9100, //0x4F
} }
} }
CXP_SPEED::CXP_12 => { CXP_SPEED::CXP_6 => {
// CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 4 // CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 4
// TXUSRCLK=312.5MHz // TXUSRCLK=312.5MHz
PLLSetting { PLLSetting {
@ -605,6 +396,40 @@ pub mod txusrclk {
filt_reg2: 0x1900, //0x4F filt_reg2: 0x1900, //0x4F
} }
} }
CXP_SPEED::CXP_10 => {
// CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 2
// TXUSRCLK=500MHz
PLLSetting {
clkout0_reg1: 0x1041, //0x08
clkout0_reg2: 0x0000, //0x09
clkfbout_reg1: 0x1104, //0x14
clkfbout_reg2: 0x0000, //0x15
div_reg: 0x1041, //0x16
lock_reg1: 0x03e8, //0x18
lock_reg2: 0x5801, //0x19
lock_reg3: 0xdbe9, //0x1A
power_reg: 0x0000, //0x28
filt_reg1: 0x9808, //0x4E
filt_reg2: 0x9100, //0x4F
}
}
CXP_SPEED::CXP_12 => {
// CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 2
// TXUSRCLK=625MHz
PLLSetting {
clkout0_reg1: 0x1041, //0x08
clkout0_reg2: 0x0000, //0x09
clkfbout_reg1: 0x1145, //0x14
clkfbout_reg2: 0x0000, //0x15
div_reg: 0x1041, //0x16
lock_reg1: 0x03e8, //0x18
lock_reg2: 0x7001, //0x19
lock_reg3: 0xf3e9, //0x1A
power_reg: 0x0000, //0x28
filt_reg1: 0x9908, //0x4E
filt_reg2: 0x1900, //0x4F
}
}
} }
} }
} }