sayma: fix/cleanup DRTIO-DAC sync interaction

This commit is contained in:
Sebastien Bourdeauducq 2020-04-06 22:34:05 +08:00
parent facc0357d8
commit 61d4614b61
6 changed files with 63 additions and 34 deletions

View File

@ -2,7 +2,7 @@ use board_misoc::config;
#[cfg(si5324_as_synthesizer)] #[cfg(si5324_as_synthesizer)]
use board_artiq::si5324; use board_artiq::si5324;
#[cfg(has_drtio)] #[cfg(has_drtio)]
use board_misoc::csr; use board_misoc::{csr, clock};
#[derive(Debug)] #[derive(Debug)]
pub enum RtioClock { pub enum RtioClock {
@ -161,6 +161,10 @@ pub fn init() {
unsafe { unsafe {
csr::drtio_transceiver::stable_clkin_write(1); csr::drtio_transceiver::stable_clkin_write(1);
} }
clock::spin_us(1500); // wait for CPLL/QPLL lock
unsafe {
csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
}
#[cfg(has_rtio_crg)] #[cfg(has_rtio_crg)]
{ {

View File

@ -160,7 +160,6 @@ pub mod jesd204sync {
} }
} }
fn measure_ddmdt_phase_raw() -> Result<i32, &'static str> { fn measure_ddmdt_phase_raw() -> Result<i32, &'static str> {
Ok(jdac::basic_request(0, jdac_common::DDMTD_SYSREF_RAW, 0)? as i32) Ok(jdac::basic_request(0, jdac_common::DDMTD_SYSREF_RAW, 0)? as i32)
} }
@ -567,4 +566,12 @@ pub mod jesd204sync {
error!("failed to align SYSREF at DAC: {}", e); error!("failed to align SYSREF at DAC: {}", e);
} }
} }
pub fn resync_dacs() -> Result<(), &'static str> {
info!("resychronizing DACs");
for dacno in 0..csr::JDCG.len() {
ad9154_sync(dacno as u8)?;
}
Ok(())
}
} }

View File

@ -465,6 +465,10 @@ pub extern fn main() -> i32 {
csr::drtio_transceiver::stable_clkin_write(1); csr::drtio_transceiver::stable_clkin_write(1);
} }
clock::spin_us(1500); // wait for CPLL/QPLL lock clock::spin_us(1500); // wait for CPLL/QPLL lock
#[cfg(not(has_jdcg))]
unsafe {
csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
}
#[cfg(has_wrpll)] #[cfg(has_wrpll)]
wrpll::diagnostics(); wrpll::diagnostics();
init_rtio_crg(); init_rtio_crg();
@ -493,6 +497,11 @@ pub extern fn main() -> i32 {
let mut hardware_tick_ts = 0; let mut hardware_tick_ts = 0;
loop { loop {
#[cfg(has_jdcg)]
unsafe {
// Hide from uplink until RTM is ready
csr::drtio_transceiver::txenable_write(0xfffffffeu32 as _);
}
while !drtiosat_link_rx_up() { while !drtiosat_link_rx_up() {
drtiosat_process_errors(); drtiosat_process_errors();
for mut rep in repeaters.iter_mut() { for mut rep in repeaters.iter_mut() {
@ -510,33 +519,12 @@ pub extern fn main() -> i32 {
#[cfg(has_wrpll)] #[cfg(has_wrpll)]
wrpll::select_recovered_clock(true); wrpll::select_recovered_clock(true);
#[cfg(has_jdcg)]
{
/*
* 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.
*/
jdcg::jesd::reset(false);
if repeaters[0].is_up() {
let _ = jdcg::jdac::init();
}
}
drtioaux::reset(0); drtioaux::reset(0);
drtiosat_reset(false); drtiosat_reset(false);
drtiosat_reset_phy(false); drtiosat_reset_phy(false);
#[cfg(has_jdcg)] #[cfg(has_jdcg)]
let mut rep0_was_up = repeaters[0].is_up(); let mut was_up = false;
while drtiosat_link_rx_up() { while drtiosat_link_rx_up() {
drtiosat_process_errors(); drtiosat_process_errors();
process_aux_packets(&mut repeaters, &mut routing_table, &mut rank); process_aux_packets(&mut repeaters, &mut routing_table, &mut rank);
@ -548,8 +536,14 @@ pub extern fn main() -> i32 {
info!("TSC loaded from uplink"); info!("TSC loaded from uplink");
#[cfg(has_jdcg)] #[cfg(has_jdcg)]
{ {
if rep0_was_up { // We assume that the RTM on repeater0 is up.
jdcg::jesd204sync::sysref_auto_align(); // Uplink should not send a TSC load command unless the link is
// up, and we are hiding when the RTM is down.
if let Err(e) = jdcg::jesd204sync::sysref_rtio_align() {
error!("failed to align SYSREF with TSC ({})", e);
}
if let Err(e) = jdcg::jesd204sync::resync_dacs() {
error!("DAC resync failed after SYSREF/TSC realignment ({})", e);
} }
} }
for rep in repeaters.iter() { for rep in repeaters.iter() {
@ -563,12 +557,29 @@ pub extern fn main() -> i32 {
} }
#[cfg(has_jdcg)] #[cfg(has_jdcg)]
{ {
let rep0_is_up = repeaters[0].is_up(); let is_up = repeaters[0].is_up();
if rep0_is_up && !rep0_was_up { if is_up && !was_up {
/*
* One side of the JESD204 elastic buffer is clocked by the jitter filter
* (Si5324 or WRPLL), 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 jitter filter has locked to the recovered clock.
* This clocking scheme may provide less noise and phase drift at the DACs.
* (2) The RTM clock is connected to the jitter filter output.
* To handle those cases, we simply keep the JESD204 core in reset unless the
* jitter filter is locked to the recovered clock.
*/
jdcg::jesd::reset(false);
let _ = jdcg::jdac::init(); let _ = jdcg::jdac::init();
jdcg::jesd204sync::sysref_auto_align(); jdcg::jesd204sync::sysref_auto_align();
unsafe {
csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); // unhide
}
} }
rep0_was_up = rep0_is_up; was_up = is_up;
} }
} }

View File

@ -30,6 +30,7 @@ class ChannelInterface:
class TransceiverInterface(AutoCSR): class TransceiverInterface(AutoCSR):
def __init__(self, channel_interfaces): def __init__(self, channel_interfaces):
self.stable_clkin = CSRStorage() self.stable_clkin = CSRStorage()
self.txenable = CSRStorage(len(channel_interfaces))
self.clock_domains.cd_rtio = ClockDomain() self.clock_domains.cd_rtio = ClockDomain()
for i in range(len(channel_interfaces)): for i in range(len(channel_interfaces)):
name = "rtio_rx" + str(i) name = "rtio_rx" + str(i)

View File

@ -29,6 +29,7 @@ class GTHSingle(Module):
# # # # # #
self.txenable = Signal()
nwords = dw//10 nwords = dw//10
self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")(
Encoder(nwords, True)) Encoder(nwords, True))
@ -467,7 +468,6 @@ class GTHSingle(Module):
i_GTREFCLK0=refclk, i_GTREFCLK0=refclk,
# TX clock # TX clock
o_TXOUTCLK=self.txoutclk, o_TXOUTCLK=self.txoutclk,
i_TXSYSCLKSEL=0b00, i_TXSYSCLKSEL=0b00,
i_TXPLLCLKSEL=0b00, i_TXPLLCLKSEL=0b00,
@ -487,7 +487,7 @@ class GTHSingle(Module):
o_TXSYNCOUT=self.txsyncout, o_TXSYNCOUT=self.txsyncout,
# TX data # TX data
i_TXINHIBIT=~self.txenable,
i_TXCTRL0=Cat(*[txdata[10*i+8] for i in range(nwords)]), i_TXCTRL0=Cat(*[txdata[10*i+8] for i in range(nwords)]),
i_TXCTRL1=Cat(*[txdata[10*i+9] for i in range(nwords)]), i_TXCTRL1=Cat(*[txdata[10*i+9] for i in range(nwords)]),
i_TXDATA=Cat(*[txdata[10*i:10*i+8] for i in range(nwords)]), i_TXDATA=Cat(*[txdata[10*i:10*i+8] for i in range(nwords)]),
@ -675,6 +675,8 @@ class GTH(Module, TransceiverInterface):
self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths)
TransceiverInterface.__init__(self, channel_interfaces) TransceiverInterface.__init__(self, channel_interfaces)
for n, gth in enumerate(self.gths):
self.comb += gth.txenable.eq(self.txenable.storage[n])
self.clock_domains.cd_rtiox = ClockDomain(reset_less=True) self.clock_domains.cd_rtiox = ClockDomain(reset_less=True)
if create_buf: if create_buf:
# GTH PLLs recover on their own from an interrupted clock input, # GTH PLLs recover on their own from an interrupted clock input,

View File

@ -19,6 +19,7 @@ class GTPSingle(Module):
# # # # # #
self.stable_clkin = Signal() self.stable_clkin = Signal()
self.txenable = Signal()
self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")(
Encoder(2, True)) Encoder(2, True))
self.submodules.decoders = decoders = [ClockDomainsRenamer("rtio_rx")( self.submodules.decoders = decoders = [ClockDomainsRenamer("rtio_rx")(
@ -611,7 +612,7 @@ class GTPSingle(Module):
i_TXDEEMPH =0, i_TXDEEMPH =0,
i_TXDIFFCTRL =0b1000, i_TXDIFFCTRL =0b1000,
i_TXDIFFPD =0, i_TXDIFFPD =0,
i_TXINHIBIT =0, i_TXINHIBIT =~self.txenable,
i_TXMAINCURSOR =0b0000000, i_TXMAINCURSOR =0b0000000,
i_TXPISOPD =0, i_TXPISOPD =0,
# Transmit Ports - TX Fabric Clock Output Control Ports # Transmit Ports - TX Fabric Clock Output Control Ports
@ -747,8 +748,11 @@ class GTP(Module, TransceiverInterface):
self.submodules.tx_phase_alignment = GTPTXPhaseAlignement(self.gtps) self.submodules.tx_phase_alignment = GTPTXPhaseAlignement(self.gtps)
TransceiverInterface.__init__(self, channel_interfaces) TransceiverInterface.__init__(self, channel_interfaces)
for gtp in self.gtps: for n, gtp in enumerate(self.gtps):
self.comb += gtp.stable_clkin.eq(self.stable_clkin.storage) self.comb += [
gtp.stable_clkin.eq(self.stable_clkin.storage),
gtp.txenable.eq(self.txenable.storage[n])
]
self.comb += [ self.comb += [
self.cd_rtio.clk.eq(self.gtps[master].cd_rtio_tx.clk), self.cd_rtio.clk.eq(self.gtps[master].cd_rtio_tx.clk),