Clock input settings improvements #152

Merged
sb10q merged 12 commits from mwojcik/artiq-zynq:clock_input_improv into master 2021-11-29 11:18:00 +08:00
4 changed files with 233 additions and 84 deletions

View File

@ -24,7 +24,7 @@ The following configuration keys are available:
- ``ip``: IPv4 address.
- ``ip6``: IPv6 address.
- ``startup``: startup kernel in ELF format (as produced by ``artiq_compile``).
- ``rtioclk``: source of RTIO clock; valid values are ``external`` and ``internal``.
- ``rtio_clock``: source of RTIO clock; valid values are ``ext0_bypass`` and ``int_125``.
- ``boot``: SD card "boot.bin" file, for replacing the boot firmware/gateware. Write only.
Configurations can be read/written/removed via ``artiq_coremgmt``. Config erase is

View File

@ -113,8 +113,8 @@ class GenericStandalone(SoCCore):
platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]")
platform.add_platform_command("set_input_jitter clk_fpga_0 0.24")
self.rustc_cfg["HAS_SI5324"] = None
self.rustc_cfg["SI5324_SOFT_RESET"] = None
self.rustc_cfg["has_si5324"] = None
self.rustc_cfg["si5324_soft_reset"] = None
self.crg = self.ps7 # HACK for eem_7series to find the clock
self.submodules.rtio_crg = RTIOCRG(self.platform)
@ -393,6 +393,9 @@ class GenericSatellite(SoCCore):
self.add_memory_group("drtioaux_mem", drtioaux_memory_group)
self.add_csr_group("drtiorep", drtiorep_csr_group)
self.rustc_cfg["has_si5324"] = None
self.rustc_cfg["si5324_soft_reset"] = None
if self.acpki:
self.rustc_cfg["ki_impl"] = "acp"
self.submodules.rtio = acpki.KernelInitiator(self.rtio_tsc,

View File

@ -18,12 +18,9 @@ use libasync::{task, block_async};
use libsupport_zynq::ram;
use nb;
use void::Void;
use embedded_hal::blocking::delay::DelayMs;
use libconfig::Config;
use libcortex_a9::l2c::enable_l2_cache;
use libboard_artiq::{logger, identifier_read, init_gateware, pl};
#[cfg(has_si5324)]
use libboard_artiq::si5324;
mod proto_async;
mod comms;
@ -35,6 +32,7 @@ mod rtio;
#[path = "rtio_acp.rs"]
mod rtio;
mod rtio_mgt;
mod rtio_clocking;
mod kernel;
mod moninj;
mod eh_artiq;
@ -44,65 +42,6 @@ mod analyzer;
mod irq;
mod i2c;
fn init_rtio(timer: &mut GlobalTimer, _cfg: &Config) {
#[cfg(has_rtio_crg_clock_sel)]
let clock_sel =
if let Ok(rtioclk) = _cfg.read_str("rtioclk") {
match rtioclk.as_ref() {
"internal" => {
info!("using internal RTIO clock");
0
},
"external" => {
info!("using external RTIO clock");
1
},
other => {
warn!("RTIO clock specification '{}' not recognized", other);
info!("using internal RTIO clock");
0
},
}
} else {
info!("using internal RTIO clock (default)");
0
};
loop {
unsafe {
pl::csr::rtio_crg::pll_reset_write(1);
#[cfg(has_rtio_crg_clock_sel)]
pl::csr::rtio_crg::clock_sel_write(clock_sel);
pl::csr::rtio_crg::pll_reset_write(0);
}
timer.delay_ms(1);
let locked = unsafe { pl::csr::rtio_crg::pll_locked_read() != 0 };
if locked {
info!("RTIO PLL locked");
break;
} else {
warn!("RTIO PLL failed to lock, retrying...");
timer.delay_ms(500);
}
}
unsafe {
pl::csr::rtio_core::reset_phy_write(1);
}
}
#[cfg(has_drtio)]
fn init_drtio(timer: &mut GlobalTimer)
{
unsafe {
pl::csr::drtio_transceiver::stable_clkin_write(1);
}
timer.delay_ms(2); // wait for CPLL/QPLL lock
unsafe {
pl::csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
}
}
fn wait_for_async_rtio_error() -> nb::Result<(), Void> {
unsafe {
@ -136,19 +75,7 @@ async fn report_async_rtio_errors() {
}
}
#[cfg(has_si5324)]
// 125MHz output, from crystal, 7 Hz
const SI5324_SETTINGS: si5324::FrequencySettings
= si5324::FrequencySettings {
n1_hs : 10,
nc1_ls : 4,
n2_hs : 10,
n2_ls : 19972,
n31 : 4565,
n32 : 4565,
bwsel : 4,
crystal_ref: true
};
static mut LOG_BUFFER: [u8; 1<<17] = [0; 1<<17];
@ -173,9 +100,6 @@ pub fn main_core0() {
info!("detected gateware: {}", identifier_read(&mut [0; 64]));
i2c::init();
#[cfg(has_si5324)]
si5324::setup(unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() },
&SI5324_SETTINGS, si5324::Input::Ckin2, &mut timer).expect("cannot initialize Si5324");
let cfg = match Config::new() {
Ok(cfg) => cfg,
@ -185,10 +109,8 @@ pub fn main_core0() {
}
};
#[cfg(has_drtio)]
init_drtio(&mut timer);
rtio_clocking::init(&mut timer, &cfg);
init_rtio(&mut timer, &cfg);
task::spawn(report_async_rtio_errors());
comms::main(timer, cfg);

View File

@ -0,0 +1,224 @@
use log::{info, warn};
use libboard_zynq::timer::GlobalTimer;
use embedded_hal::blocking::delay::DelayMs;
use libconfig::Config;
use libboard_artiq::pl;
#[cfg(has_si5324)]
use libboard_zynq::i2c::I2c;
#[cfg(has_si5324)]
use crate::i2c;
#[cfg(has_si5324)]
use libboard_artiq::si5324;
#[derive(Debug, PartialEq, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum RtioClock {
Default,
Int_125,
Int_100,
Int_150,
Ext0_Bypass,
Ext0_Synth0_10to125,
Ext0_Synth0_100to125,
Ext0_Synth0_125to125,
}
fn get_rtio_clock_cfg(cfg: &Config) -> RtioClock {
let mut res = RtioClock::Default;
if let Ok(clk) = cfg.read_str("rtio_clock") {
res = match clk.as_ref() {
"int_125" => RtioClock::Int_125,
"int_100" => RtioClock::Int_100,
"int_150" => RtioClock::Int_150,
"ext0_bypass" => RtioClock::Ext0_Bypass,
"ext0_bypass_125" => RtioClock::Ext0_Bypass,
"ext0_bypass_100" => RtioClock::Ext0_Bypass,
"ext0_synth0_10to125" => RtioClock::Ext0_Synth0_10to125,
"ext0_synth0_100to125" => RtioClock::Ext0_Synth0_100to125,
"ext0_synth0_125to125" => RtioClock::Ext0_Synth0_125to125,
_ => {
warn!("Unrecognised rtio_clock setting. Falling back to default.");
RtioClock::Default
}
};
}
else {
warn!("error reading configuration. Falling back to default.");
}
if res == RtioClock::Default {
warn!("Using default configuration - internal 125MHz RTIO clock.");
return RtioClock::Int_125;
}
res
}
fn init_rtio(timer: &mut GlobalTimer, _clk: RtioClock) {
#[cfg(has_rtio_crg_clock_sel)]
let clock_sel = match _clk {
RtioClock::Ext0_Bypass => {
info!("Using bypassed 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
}
};
loop {
unsafe {
pl::csr::rtio_crg::pll_reset_write(1);
#[cfg(has_rtio_crg_clock_sel)]
pl::csr::rtio_crg::clock_sel_write(clock_sel);
pl::csr::rtio_crg::pll_reset_write(0);
}
timer.delay_ms(1);
let locked = unsafe { pl::csr::rtio_crg::pll_locked_read() != 0 };
if locked {
info!("RTIO PLL locked");
break;
} else {
warn!("RTIO PLL failed to lock, retrying...");
timer.delay_ms(500);
}
}
unsafe {
pl::csr::rtio_core::reset_phy_write(1);
}
}
#[cfg(has_drtio)]
fn init_drtio(timer: &mut GlobalTimer)
{
unsafe {
pl::csr::drtio_transceiver::stable_clkin_write(1);

This isn't right - if the clock setting (e.g. int_100, ext0_synth0_125to125, ...) is unrecognized, it should error out, not silently select one Si5324 configuration.

It is theoretically possible to support exactly the same clock settings on KC705, ZC706, Kasli and Kasli-SoC. For KC705 and ZC706 you'd need to forward the external clock input to the Si5324 and clock RTIO from the Si5324. But I don't think NIST (@dhslichter) want this change and we should only support the existing options (which would be int_125 and ext0_bypass_125 - and ext0_bypass_100 as per their new request) on KC705 and ZC706.

This isn't right - if the clock setting (e.g. int_100, ext0_synth0_125to125, ...) is unrecognized, it should error out, not silently select one Si5324 configuration. It is theoretically possible to support exactly the same clock settings on KC705, ZC706, Kasli and Kasli-SoC. For KC705 and ZC706 you'd need to forward the external clock input to the Si5324 and clock RTIO from the Si5324. But I don't think NIST (@dhslichter) want this change and we should only support the existing options (which would be ``int_125`` and ``ext0_bypass_125`` - and ``ext0_bypass_100`` as per their new request) on KC705 and ZC706.

Also the only reason why all the mainline ARTIQ Si5324 settings aren't in artiq-zynq is they haven't been ported yet.

Also the only reason why all the mainline ARTIQ Si5324 settings aren't in artiq-zynq is they haven't been ported yet.

if the clock setting (e.g. int_100, ext0_synth0_125to125, ...) is unrecognized, it should error out, not silently select one Si5324 configuration.

True that. Unlike in mainline, there are now options that can pass by unnoticed, and this should be taken care of. I'll break it down and add a warning.

Also the only reason why all the mainline ARTIQ Si5324 settings aren't in artiq-zynq is they haven't been ported yet.

I assume then since they're not necessary yet, porting them makes no sense at this point? Even though it would be the matter of just moving these settings as is?

ext0_bypass_125 - and ext0_bypass_100 as per their new request

I know you mentioned exactly ext0_bypass_125 in artiq #1735, but from the perspective of this code I can't find a functional difference between bypass_125 and _100. Would you like to have them added as separate, recognised options (that would map to just bypass internally) so it's more explicit?

> if the clock setting (e.g. int_100, ext0_synth0_125to125, ...) is unrecognized, it should error out, not silently select one Si5324 configuration. True that. Unlike in mainline, there are now options that can pass by unnoticed, and this should be taken care of. I'll break it down and add a warning. > Also the only reason why all the mainline ARTIQ Si5324 settings aren't in artiq-zynq is they haven't been ported yet. I assume then since they're not necessary yet, porting them makes no sense at this point? Even though it would be the matter of just moving these settings as is? > ext0_bypass_125 - and ext0_bypass_100 as per their new request I know you mentioned exactly ``ext0_bypass_125`` in artiq #1735, but from the perspective of this code I can't find a functional difference between bypass_125 and \_100. Would you like to have them added as separate, recognised options (that would map to just bypass internally) so it's more explicit?

Unlike in mainline, there are now options that can pass by unnoticed

The situation here has absolutely no difference with mainline.
Mainline has KC705 (external/internal) and Kasli (via Si5324).
Here we have ZC706 (external/internal) and Kasli-SoC (via Si5324).

I assume then since they're not necessary yet, porting them makes no sense at this point?

It makes sense for Kasli-SoC.

from the perspective of this code I can't find a functional difference between bypass_125 and _100

Right, just match any of them (explicitly) and select the bypass.

> Unlike in mainline, there are now options that can pass by unnoticed The situation here has absolutely no difference with mainline. Mainline has KC705 (external/internal) and Kasli (via Si5324). Here we have ZC706 (external/internal) and Kasli-SoC (via Si5324). > I assume then since they're not necessary yet, porting them makes no sense at this point? It makes sense for Kasli-SoC. > from the perspective of this code I can't find a functional difference between bypass_125 and _100 Right, just match any of them (explicitly) and select the bypass.
}
timer.delay_ms(2); // wait for CPLL/QPLL lock
unsafe {
pl::csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
}
}
#[cfg(has_si5324)]
fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) {
let si5324_settings = match clk {
RtioClock::Ext0_Synth0_10to125 => { // 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW
info!("using 10MHz reference to make 125MHz RTIO clock with PLL");
si5324::FrequencySettings {
n1_hs : 10,
nc1_ls : 4,
n2_hs : 10,
n2_ls : 300,
n31 : 6,
n32 : 6,
bwsel : 4,
crystal_ref: false
}
},
RtioClock::Ext0_Synth0_100to125 => { // 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth
info!("using 10MHz reference to make 125MHz RTIO clock with PLL");
si5324::FrequencySettings {
n1_hs : 10,
nc1_ls : 4,
n2_hs : 10,
n2_ls : 260,
n31 : 52,
n32 : 52,
bwsel : 4,
crystal_ref: false
}
},
RtioClock::Ext0_Synth0_125to125 => { // 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth
info!("using 10MHz reference to make 125MHz RTIO clock with PLL");
si5324::FrequencySettings {
n1_hs : 5,
nc1_ls : 8,
n2_hs : 7,
n2_ls : 360,
n31 : 63,
n32 : 63,
bwsel : 4,
crystal_ref: false
}
},
RtioClock::Int_150 => { // 150MHz output, from crystal
info!("using internal 150MHz RTIO clock");
si5324::FrequencySettings {
n1_hs : 9,
nc1_ls : 4,
n2_hs : 10,
n2_ls : 33732,
n31 : 7139,
n32 : 7139,
bwsel : 3,
crystal_ref: true
}
},
RtioClock::Int_100 => { // 100MHz output, from crystal.
info!("using internal 100MHz RTIO clock");
si5324::FrequencySettings {
n1_hs : 9,
nc1_ls : 6,
n2_hs : 10,
n2_ls : 33732,
n31 : 7139,
n32 : 7139,
bwsel : 3,
crystal_ref: true
}
},
RtioClock::Int_125 => { // 125MHz output, from crystal, 7 Hz
info!("using internal 125MHz RTIO clock");
si5324::FrequencySettings {
n1_hs : 10,
nc1_ls : 4,
n2_hs : 10,
n2_ls : 19972,
n31 : 4565,
n32 : 4565,
bwsel : 4,
crystal_ref: true
}
}
_ => { // same setting as Int_125, but fallback to default
warn!("rtio_clock setting '{:?}' is unsupported. Falling back to default internal 125MHz RTIO clock.", clk);
si5324::FrequencySettings {
n1_hs : 10,
nc1_ls : 4,
n2_hs : 10,
n2_ls : 19972,
n31 : 4565,
n32 : 4565,
bwsel : 4,
crystal_ref: true
}
}
};
let si5324_ref_input = si5324::Input::Ckin2;
si5324::setup(i2c, &si5324_settings, si5324_ref_input, timer).expect("cannot initialize Si5324");
}
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
let clk = get_rtio_clock_cfg(cfg);
#[cfg(has_si5324)]
{
let i2c = unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() };
let si5324_ext_input = si5324::Input::Ckin2;
match clk {
RtioClock::Ext0_Bypass => si5324::bypass(i2c, si5324_ext_input, timer).expect("cannot bypass Si5324"),
_ => setup_si5324(i2c, timer, clk),
}
}
#[cfg(has_drtio)]
init_drtio(timer);
init_rtio(timer, clk);
}