diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 29e1a901e..e9b7db5db 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -33,10 +33,9 @@ fn read(addr: u16) -> u8 { } } -pub fn jesd_unreset() { +pub fn jesd_reset(reset: bool) { unsafe { - csr::ad9154_crg::ibuf_disable_write(0); - csr::ad9154_crg::jreset_write(0); + csr::ad9154_crg::jreset_write(if reset { 1 } else { 0 }); } } diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 6d2787ad7..30bef71c9 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -367,6 +367,18 @@ pub mod hmc7043 { Ok(()) } + pub fn enable_fpga_ibuf() { + /* + * Never missing an opportunity to be awful, the HMC7043 produces broadband noise + * prior to intialization, which can upset the FPGA. + * One mitigation technique is to disable the input buffer until the HMC7043 is + * slightly better behaved. + */ + unsafe { + csr::ad9154_crg::ibuf_disable_write(0); + } + } + pub fn sysref_offset_dac(dacno: u8, phase_offset: u16) { /* Analog delay resolution: 25ps * Digital delay resolution: 1/2 input clock cycle = 416ps for 1.2GHz @@ -427,6 +439,7 @@ pub fn init() -> Result<(), &'static str> { hmc7043::init(); hmc7043::test_gpo()?; hmc7043::check_phased()?; + hmc7043::enable_fpga_ibuf(); Ok(()) } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 77e76cc09..c4c3f674a 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -111,7 +111,7 @@ fn startup() { board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] { - board_artiq::ad9154::jesd_unreset(); + board_artiq::ad9154::jesd_reset(false); board_artiq::ad9154::init(); if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index b109ef96f..849901e88 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -273,11 +273,6 @@ pub extern fn main() -> i32 { csr::drtio_transceiver::stable_clkin_write(1); } - #[cfg(has_ad9154)] - { - board_artiq::ad9154::jesd_unreset(); - board_artiq::ad9154::init(); - } #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); @@ -285,12 +280,34 @@ pub extern fn main() -> i32 { while !drtio_link_rx_up() { process_errors(); } + info!("link is up, switching to recovered clock"); si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); si5324::siphaser::calibrate_skew(SIPHASER_PHASE).expect("failed to calibrate skew"); + + #[cfg(has_ad9154)] + { + /* + * One side of the JESD204 elastic buffer is clocked by the Si5324, the other + * by the RTM. + * The elastic buffer can operate only when those two clocks are derived from + * the same oscillator. + * This is the case when either of those conditions is true: + * (1) The DRTIO master and the RTM are clocked directly from a common external + * source, *and* the Si5324 has locked to the recovered clock. + * This clocking scheme provides less noise and phase drift at the DACs. + * (2) The RTM clock is connected to the Si5324 output. + * To handle those cases, we simply keep the JESD204 core in reset unless the + * Si5324 is locked to the recovered clock. + */ + board_artiq::ad9154::jesd_reset(false); + board_artiq::ad9154::init(); + } + drtioaux::reset(0); drtio_reset(false); drtio_reset_phy(false); + while drtio_link_rx_up() { process_errors(); process_aux_packets(); @@ -309,6 +326,10 @@ pub extern fn main() -> i32 { } } } + + #[cfg(has_ad9154)] + board_artiq::ad9154::jesd_reset(true); + drtio_reset_phy(true); drtio_reset(true); drtio_tsc_loaded(); diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6e7872278..289363184 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -577,7 +577,7 @@ class Satellite(BaseSoC, RTMCommon): self.comb += platform.request("sfp_tx_disable", 0).eq(0) self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=self.ad9154_crg.refclk, + clock_pads=platform.request("si5324_clkout"), data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) @@ -599,7 +599,7 @@ class Satellite(BaseSoC, RTMCommon): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), - si5324_clkout_fabric=platform.request("adc_sysref")) + si5324_clkout_fabric=platform.request("si5324_clkout_fabric")) platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {mmcm_ps}]", mmcm_ps=self.siphaser.mmcm_ps_output) platform.add_false_path_constraints( @@ -612,11 +612,6 @@ class Satellite(BaseSoC, RTMCommon): self.csr_devices.append("i2c") self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - # ensure pins are properly biased and terminated - si5324_clkout = platform.request("si5324_clkout", 0) - self.specials += Instance( - "IBUFDS_GTE3", i_CEB=0, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, - attr={("DONT_TOUCH", "true")}) self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( self.drtio0.coarse_ts, self.ad9154_crg.jref)