forked from M-Labs/artiq
sayma: fix/cleanup DRTIO-DAC sync interaction
This commit is contained in:
parent
facc0357d8
commit
61d4614b61
|
@ -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)]
|
||||||
{
|
{
|
||||||
|
|
|
@ -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(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
|
|
Loading…
Reference in New Issue