From 3838dfc1d108cf3c08984bfd455f94365819f526 Mon Sep 17 00:00:00 2001 From: Spaqin Date: Fri, 6 Jan 2023 07:13:38 +0800 Subject: [PATCH] DRTIO: RTIO/SYS clock merge, KC705 --- artiq/firmware/runtime/rtio_clocking.rs | 33 +--- artiq/firmware/satman/main.rs | 13 -- .../gateware/drtio/transceiver/gtx_7series.py | 65 +++---- .../drtio/transceiver/gtx_7series_init.py | 10 +- artiq/gateware/targets/kc705.py | 161 ++++++++---------- 5 files changed, 102 insertions(+), 180 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 6af4ea3e9..52ab35915 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -63,40 +63,12 @@ fn get_rtio_clock_cfg() -> RtioClock { #[cfg(has_rtio_crg)] pub mod crg { - #[cfg(has_rtio_clock_switch)] - use super::RtioClock; use board_misoc::{clock, csr}; pub fn check() -> bool { unsafe { csr::rtio_crg::pll_locked_read() != 0 } } - #[cfg(has_rtio_clock_switch)] - pub fn init(clk: RtioClock) -> bool { - let clk_sel: u8 = match clk { - RtioClock::Ext0_Bypass => { - info!("Using external clock"); - 1 - }, - RtioClock::Int_125 => { - info!("Using internal RTIO clock"); - 0 - }, - _ => { - warn!("rtio_clock setting '{:?}' is not supported. Using default internal RTIO clock instead", clk); - 0 - } - }; - unsafe { - csr::rtio_crg::pll_reset_write(1); - csr::rtio_crg::clock_sel_write(clk_sel); - csr::rtio_crg::pll_reset_write(0); - } - clock::spin_us(150); - return check() - } - - #[cfg(not(has_rtio_clock_switch))] pub fn init() -> bool { info!("Using internal RTIO clock"); unsafe { @@ -223,7 +195,7 @@ fn setup_si5324(clock_cfg: RtioClock) { #[cfg(soc_platform = "metlino")] let si5324_ext_input = si5324::Input::Ckin2; #[cfg(soc_platform = "kc705")] - let si5324_ext_input = si5324::Input::Ckin2; + let si5324_ext_input = si5324::Input::Ckin1; match clock_cfg { RtioClock::Ext0_Bypass => { info!("using external RTIO clock with PLL bypass"); @@ -277,9 +249,6 @@ pub fn init() { #[cfg(has_rtio_crg)] { - #[cfg(has_rtio_clock_switch)] - let result = crg::init(clock_cfg); - #[cfg(not(has_rtio_clock_switch))] let result = crg::init(); if !result { error!("RTIO clock failed"); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 7ac232827..366aa1d5b 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -426,19 +426,6 @@ fn hardware_tick(ts: &mut u64) { } } -#[cfg(all(has_si5324, rtio_frequency = "150.0"))] -const SI5324_SETTINGS: si5324::FrequencySettings - = si5324::FrequencySettings { - n1_hs : 6, - nc1_ls : 6, - n2_hs : 10, - n2_ls : 270, - n31 : 75, - n32 : 75, - bwsel : 4, - crystal_ref: true -}; - #[cfg(all(has_si5324, rtio_frequency = "125.0"))] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { diff --git a/artiq/gateware/drtio/transceiver/gtx_7series.py b/artiq/gateware/drtio/transceiver/gtx_7series.py index 3d96971ca..fe901d90c 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series.py @@ -1,5 +1,6 @@ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import MultiReg from misoc.cores.code_8b10b import Encoder, Decoder from misoc.interconnect.csr import * @@ -16,13 +17,12 @@ class GTX_20X(Module): # * GTX PLL frequency @ 2.5GHz # * GTX line rate (TX & RX) @ 2.5Gb/s # * GTX TX/RX USRCLK @ 125MHz == coarse RTIO frequency - def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq=125e6, tx_mode="single", rx_mode="single"): + def __init__(self, refclk, pads, clk_freq=125e6, tx_mode="single", rx_mode="single"): assert tx_mode in ["single", "master", "slave"] assert rx_mode in ["single", "master", "slave"] self.txenable = Signal() - self.submodules.encoder = ClockDomainsRenamer("rtio_tx")( - Encoder(2, True)) + self.submodules.encoder = Encoder(2, True) self.submodules.decoders = [ClockDomainsRenamer("rtio_rx")( (Decoder(True))) for _ in range(2)] self.rx_ready = Signal() @@ -36,11 +36,11 @@ class GTX_20X(Module): cpllreset = Signal() cplllock = Signal() - # TX generates RTIO clock, init must be in system domain - self.submodules.tx_init = tx_init = GTXInit(sys_clk_freq, False, mode=tx_mode) - # RX receives restart commands from RTIO domain - self.submodules.rx_init = rx_init = ClockDomainsRenamer("rtio_tx")( - GTXInit(rtio_clk_freq, True, mode=rx_mode)) + # TX generates SYS clock, init must be in bootstrap domain + self.submodules.tx_init = tx_init = ClockDomainsRenamer("bootstrap")( + GTXInit(clk_freq, False, mode=tx_mode)) + # RX receives restart commands from SYS domain + self.submodules.rx_init = rx_init = GTXInit(clk_freq, True, mode=rx_mode) self.comb += [ cpllreset.eq(tx_init.cpllreset), tx_init.cplllock.eq(cplllock), @@ -113,8 +113,8 @@ class GTX_20X(Module): i_TXCHARDISPMODE=Cat(txdata[9], txdata[19]), i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]), i_TXDATA=Cat(txdata[:8], txdata[10:18]), - i_TXUSRCLK=ClockSignal("rtio_tx"), - i_TXUSRCLK2=ClockSignal("rtio_tx"), + i_TXUSRCLK=ClockSignal("sys"), + i_TXUSRCLK2=ClockSignal("sys"), # TX electrical i_TXBUFDIFFCTRL=0b100, @@ -247,19 +247,10 @@ class GTX_20X(Module): p_ES_EYE_SCAN_EN="TRUE", # Must be TRUE for GTX ) - # TX clocking - tx_reset_deglitched = Signal() - tx_reset_deglitched.attr.add("no_retiming") - self.sync += tx_reset_deglitched.eq(~tx_init.done) - self.clock_domains.cd_rtio_tx = ClockDomain() - if tx_mode == "single" or tx_mode == "master": - self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk) - self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) - # RX clocking rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") - self.sync.rtio += rx_reset_deglitched.eq(~rx_init.done) + self.sync += rx_reset_deglitched.eq(~rx_init.done) self.clock_domains.cd_rtio_rx = ClockDomain() if rx_mode == "single" or rx_mode == "master": self.specials += Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), @@ -271,7 +262,7 @@ class GTX_20X(Module): self.decoders[1].input.eq(rxdata[10:]) ] - clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq) + clock_aligner = BruteforceClockAligner(0b0101111100, clk_freq) self.submodules += clock_aligner self.comb += [ clock_aligner.rxdata.eq(rxdata), @@ -282,17 +273,18 @@ class GTX_20X(Module): class GTX(Module, TransceiverInterface): - def __init__(self, clock_pads, pads, sys_clk_freq, rtio_clk_freq=125e6, master=0): + def __init__(self, clock_pads, pads, clk_freq=125e6, master=0): self.nchannels = nchannels = len(pads) self.gtxs = [] - self.rtio_clk_freq = rtio_clk_freq + self.rtio_clk_freq = clk_freq # # # refclk = Signal() - stable_clkin_n = Signal() + + clk_enable = Signal() self.specials += Instance("IBUFDS_GTE2", - i_CEB=stable_clkin_n, + i_CEB=~clk_enable, i_I=clock_pads.p, i_IB=clock_pads.n, o_O=refclk, @@ -301,7 +293,6 @@ class GTX(Module, TransceiverInterface): p_CLKSWING_CFG="0b11" ) - rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): if nchannels == 1: @@ -309,12 +300,7 @@ class GTX(Module, TransceiverInterface): else: mode = "master" if i == master else "slave" # Note: RX phase alignment is to be done on individual lanes, not multi-lane. - gtx = GTX_20X(refclk, pads[i], sys_clk_freq, rtio_clk_freq=rtio_clk_freq, tx_mode=mode, rx_mode="single") - # Fan-out (to slave) / Fan-in (from master) of the TXUSRCLK - if mode == "slave": - self.comb += gtx.cd_rtio_tx.clk.eq(rtio_tx_clk) - else: - self.comb += rtio_tx_clk.eq(gtx.cd_rtio_tx.clk) + gtx = GTX_20X(refclk, pads[i], clk_freq, tx_mode=mode, rx_mode="single") self.gtxs.append(gtx) setattr(self.submodules, "gtx"+str(i), gtx) channel_interface = ChannelInterface(gtx.encoder, gtx.decoders) @@ -326,15 +312,16 @@ class GTX(Module, TransceiverInterface): TransceiverInterface.__init__(self, channel_interfaces) for n, gtx in enumerate(self.gtxs): self.comb += [ - stable_clkin_n.eq(~self.stable_clkin.storage), - gtx.txenable.eq(self.txenable.storage[n]) + gtx.txenable.eq(self.txenable.storage[n]), + gtx.tx_init.stable_clkin.eq(clk_enable) ] + # rx_init is in SYS domain, rather than bootstrap + self.specials += MultiReg(clk_enable, gtx.rx_init.stable_clkin) + + # stable_clkin resets after reboot since it's in SYS domain + # still need to keep clk_enable high after this + self.sync.bootstrap += clk_enable.eq(self.stable_clkin.storage | self.gtxs[0].tx_init.done) - # Connect master's `rtio_tx` clock to `rtio` clock - self.comb += [ - self.cd_rtio.clk.eq(self.gtxs[master].cd_rtio_tx.clk), - self.cd_rtio.rst.eq(reduce(or_, [gtx.cd_rtio_tx.rst for gtx in self.gtxs])) - ] # Connect slave i's `rtio_rx` clock to `rtio_rxi` clock for i in range(nchannels): self.comb += [ diff --git a/artiq/gateware/drtio/transceiver/gtx_7series_init.py b/artiq/gateware/drtio/transceiver/gtx_7series_init.py index 70c69a19c..5552c308f 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series_init.py @@ -11,11 +11,13 @@ class GTXInit(Module): # Choose between Auto Mode and Manual Mode for TX/RX phase alignment with buffer bypassed: # * Auto Mode: When only single lane is involved, as suggested by Xilinx (AR59612) # * Manual Mode: When only multi-lane is involved, as suggested by Xilinx (AR59612) - def __init__(self, sys_clk_freq, rx, mode="single"): + def __init__(self, clk_freq, rx, mode="single"): assert isinstance(rx, bool) assert mode in ["single", "master", "slave"] self.mode = mode + self.stable_clkin = Signal() + self.done = Signal() self.restart = Signal() @@ -83,13 +85,13 @@ class GTXInit(Module): # After configuration, transceiver resets have to stay low for # at least 500ns (see AR43482) - startup_cycles = ceil(500*sys_clk_freq/1000000000) + startup_cycles = ceil(500*clk_freq/1000000000) startup_timer = WaitTimer(startup_cycles) self.submodules += startup_timer # PLL reset should be 1 period of refclk # (i.e. 1/(125MHz) for the case of RTIO @ 125MHz) - pll_reset_cycles = ceil(sys_clk_freq/125e6) + pll_reset_cycles = ceil(clk_freq/125e6) pll_reset_timer = WaitTimer(pll_reset_cycles) self.submodules += pll_reset_timer @@ -108,7 +110,7 @@ class GTXInit(Module): startup_fsm.act("INITIAL", startup_timer.wait.eq(1), - If(startup_timer.done, NextState("RESET_ALL")) + If(startup_timer.done & self.stable_clkin, NextState("RESET_ALL")) ) startup_fsm.act("RESET_ALL", gtXxreset.eq(1), diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index e04088a92..3ad5f5bdf 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -24,65 +24,20 @@ from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import * from artiq.build_soc import * - -class _RTIOCRG(Module, AutoCSR): - def __init__(self, platform, rtio_internal_clk, use_sma=True): - self._clock_sel = CSRStorage() - self._pll_reset = CSRStorage(reset=1) - self._pll_locked = CSRStatus() - self.clock_domains.cd_rtio = ClockDomain() - self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) - - # 100 MHz when using 125MHz input - self.clock_domains.cd_ext_clkout = ClockDomain(reset_less=True) - platform.add_period_constraint(self.cd_ext_clkout.clk, 5.0) - if use_sma: - ext_clkout = platform.request("user_sma_gpio_p_33") - self.sync.ext_clkout += ext_clkout.eq(~ext_clkout) - - rtio_external_clk = Signal() - if use_sma: - user_sma_clock = platform.request("user_sma_clock") - platform.add_period_constraint(user_sma_clock.p, 8.0) - self.specials += Instance("IBUFDS", - i_I=user_sma_clock.p, i_IB=user_sma_clock.n, - o_O=rtio_external_clk) - - pll_locked = Signal() - rtio_clk = Signal() - rtiox4_clk = Signal() - ext_clkout_clk = Signal() +class SMAClkinForward(Module): + def __init__(self, platform): + sma_clkin = platform.request("user_sma_clock") + sma_clkin_se = Signal() + sma_clkin_buffered = Signal() + cdr_clk_se = Signal() + cdr_clk = platform.request("si5324_clkin_33") self.specials += [ - Instance("PLLE2_ADV", - p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, - - p_REF_JITTER1=0.01, - p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, - i_CLKIN1=rtio_internal_clk, i_CLKIN2=rtio_external_clk, - # Warning: CLKINSEL=0 means CLKIN2 is selected - i_CLKINSEL=~self._clock_sel.storage, - - # VCO @ 1GHz when using 125MHz input - p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, - i_CLKFBIN=self.cd_rtio.clk, - i_RST=self._pll_reset.storage, - - o_CLKFBOUT=rtio_clk, - - p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0, - o_CLKOUT0=rtiox4_clk, - - p_CLKOUT1_DIVIDE=5, p_CLKOUT1_PHASE=0.0, - o_CLKOUT1=ext_clkout_clk), - Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), - Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), - Instance("BUFG", i_I=ext_clkout_clk, o_O=self.cd_ext_clkout.clk), - - AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), - MultiReg(pll_locked, self._pll_locked.status) + Instance("IBUFDS", i_I=sma_clkin.p, i_IB=sma_clkin.n, o_O=sma_clkin_se), + Instance("BUFG", i_I=sma_clkin_se, o_O=sma_clkin_buffered), + Instance("ODDR", i_C=sma_clkin_buffered, i_CE=1, i_D1=0, i_D2=1, o_Q=cdr_clk_se), + Instance("OBUFDS", i_I=cdr_clk_se, o_O=cdr_clk.p, o_OB=cdr_clk.n) ] - # The default voltage for these signals on KC705 is 2.5V, and the Migen platform # follows this default. But since the SMAs are on the same bank as the DDS, # which is set to 3.3V by reprogramming the KC705 power ICs, we need to @@ -138,6 +93,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): integrated_sram_size=8192, ethmac_nrxslots=4, ethmac_ntxslots=4, + rtio_sys_merge=True, **kwargs) AMPSoC.__init__(self) add_identifier(self, gateware_identifier_str=gateware_identifier_str) @@ -149,6 +105,31 @@ class _StandaloneBase(MiniSoC, AMPSoC): if isinstance(self.platform.toolchain, XilinxISEToolchain): self.platform.toolchain.bitgen_opt += " -g compress" + self.platform.add_extension(_reprogrammed3v3_io) + + cdr_clk_out = self.platform.request("si5324_clkout") + cdr_clk = Signal() + cdr_clk_buf = Signal() + + self.config["HAS_SI5324"] = None + self.config["SI5324_AS_SYNTHESIZER"] = None + self.submodules.si5324_rst_n = gpio.GPIOOut(self.platform.request("si5324_33").rst_n) + self.csr_devices.append("si5324_rst_n") + self.specials += [ + Instance("IBUFDS_GTE2", + i_CEB=0, + i_I=cdr_clk_out.p, i_IB=cdr_clk_out.n, + o_O=cdr_clk, + p_CLKCM_CFG=1, + p_CLKRCV_TRST=1, + p_CLKSWING_CFG="2'b11"), + Instance("BUFG", i_I=cdr_clk, o_O=cdr_clk_buf) + ] + + self.crg.configure(cdr_clk_buf) + + self.submodules += SMAClkinForward(self.platform) + self.submodules.timer1 = timer.Timer() self.csr_devices.append("timer1") self.interrupt_devices.append("timer1") @@ -158,7 +139,6 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.platform.request("user_led", 1))) self.csr_devices.append("leds") - self.platform.add_extension(_reprogrammed3v3_io) self.platform.add_extension(_ams101_dac) i2c = self.platform.request("i2c") @@ -169,9 +149,6 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.config["HAS_DDS"] = None def add_rtio(self, rtio_channels): - self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) - self.csr_devices.append("rtio_crg") - self.config["HAS_RTIO_CLOCK_SWITCH"] = None self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") @@ -187,11 +164,6 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) - self.platform.add_false_path_constraints( - self.crg.cd_sys.clk, - self.rtio_crg.cd_rtio.clk) - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, self.get_native_sdram_if(), cpu_dw=self.cpu_dw) self.csr_devices.append("rtio_analyzer") @@ -208,6 +180,7 @@ class _MasterBase(MiniSoC, AMPSoC): mem_map.update(MiniSoC.mem_map) def __init__(self, gateware_identifier_str=None, drtio_100mhz=False, **kwargs): + clk_freq = 100e6 if drtio_100mhz else 125e6 MiniSoC.__init__(self, cpu_type="vexriscv", cpu_bus_width=64, @@ -216,6 +189,8 @@ class _MasterBase(MiniSoC, AMPSoC): integrated_sram_size=8192, ethmac_nrxslots=4, ethmac_ntxslots=4, + clk_freq=clk_freq, + rtio_sys_merge=True, **kwargs) AMPSoC.__init__(self) add_identifier(self, gateware_identifier_str=gateware_identifier_str) @@ -236,14 +211,11 @@ class _MasterBase(MiniSoC, AMPSoC): platform.request("sfp"), platform.request("user_sma_mgt") ] - rtio_clk_freq = 100e6 if drtio_100mhz else 125e6 - # 1000BASE_BX10 Ethernet compatible, 100/125MHz RTIO clock self.submodules.drtio_transceiver = gtx_7series.GTX( clock_pads=platform.request("si5324_clkout"), pads=data_pads, - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq) + clk_freq=self.clk_freq) self.csr_devices.append("drtio_transceiver") self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) @@ -292,29 +264,31 @@ class _MasterBase(MiniSoC, AMPSoC): self.config["HAS_SI5324"] = None self.config["SI5324_AS_SYNTHESIZER"] = None - self.comb += [ - platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")), - platform.request("user_sma_clock_n").eq(ClockSignal("rtio")) - ] - rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq # Constrain TX & RX timing for the first transceiver channel # (First channel acts as master for phase alignment for all channels' TX) gtx0 = self.drtio_transceiver.gtxs[0] + + txout_buf = Signal() + self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf) + self.crg.configure(txout_buf, clk_sw=gtx0.tx_init.done) + + self.comb += [ + platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")), + platform.request("user_sma_clock_n").eq(gtx0.txoutclk) + ] + platform.add_period_constraint(gtx0.txoutclk, rtio_clk_period) platform.add_period_constraint(gtx0.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gtx0.txoutclk, gtx0.rxoutclk) + self.crg.cd_sys.clk, gtx0.rxoutclk) # Constrain RX timing for the each transceiver channel # (Each channel performs single-lane phase alignment for RX) for gtx in self.drtio_transceiver.gtxs[1:]: platform.add_period_constraint(gtx.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( - self.crg.cd_sys.clk, gtx0.txoutclk, gtx.rxoutclk) + self.crg.cd_sys.clk, gtx.rxoutclk) - self.submodules.rtio_crg = RTIOClockMultiplier(self.drtio_transceiver.rtio_clk_freq) - self.csr_devices.append("rtio_crg") fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): @@ -345,12 +319,15 @@ class _SatelliteBase(BaseSoC): mem_map.update(BaseSoC.mem_map) def __init__(self, gateware_identifier_str=None, sma_as_sat=False, drtio_100mhz=False, **kwargs): + clk_freq = 100e6 if drtio_100mhz else 125e6 BaseSoC.__init__(self, cpu_type="vexriscv", cpu_bus_width=64, sdram_controller_type="minicon", l2_size=128*1024, integrated_sram_size=8192, + clk_freq=clk_freq, + rtio_sys_merge=True, **kwargs) add_identifier(self, gateware_identifier_str=gateware_identifier_str) @@ -372,14 +349,13 @@ class _SatelliteBase(BaseSoC): if sma_as_sat: data_pads = data_pads[::-1] - rtio_clk_freq = 100e6 if drtio_100mhz else 125e6 + rtio_clk_freq = clk_freq # 1000BASE_BX10 Ethernet compatible, 100/125MHz RTIO clock self.submodules.drtio_transceiver = gtx_7series.GTX( clock_pads=platform.request("si5324_clkout"), pads=data_pads, - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq) + clk_freq=self.clk_freq) self.csr_devices.append("drtio_transceiver") self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) @@ -432,6 +408,7 @@ class _SatelliteBase(BaseSoC): self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin_33"), rx_synchronizer=self.rx_synchronizer, + ref_clk=ClockSignal("bootstrap"), ultrascale=False, rtio_clk_freq=self.drtio_transceiver.rtio_clk_freq) platform.add_false_path_constraints( @@ -445,20 +422,22 @@ class _SatelliteBase(BaseSoC): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - self.comb += [ - platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")), - platform.request("user_sma_clock_n").eq(ClockSignal("rtio")) - ] - rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq # Constrain TX & RX timing for the first transceiver channel # (First channel acts as master for phase alignment for all channels' TX) gtx0 = self.drtio_transceiver.gtxs[0] + + txout_buf = Signal() + self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf) + self.crg.configure(txout_buf, clk_sw=gtx0.tx_init.done) + + self.comb += [ + platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")), + platform.request("user_sma_clock_n").eq(gtx0.txoutclk) + ] + platform.add_period_constraint(gtx0.txoutclk, rtio_clk_period) platform.add_period_constraint(gtx0.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gtx0.txoutclk, gtx0.rxoutclk) # Constrain RX timing for the each transceiver channel # (Each channel performs single-lane phase alignment for RX) for gtx in self.drtio_transceiver.gtxs[1:]: @@ -466,8 +445,6 @@ class _SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtx.rxoutclk) - self.submodules.rtio_crg = RTIOClockMultiplier(self.drtio_transceiver.rtio_clk_freq) - self.csr_devices.append("rtio_crg") fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels):