si5324: bring on par with mainline ARTIQ (#132)

si5324 driver in runtime should be now equal in function to the one in artiq.

kasli-soc has no way of doing a hard reset on the peripheral, but zc706 does.

Reviewed-on: M-Labs/artiq-zynq#132
Co-authored-by: mwojcik <mw@m-labs.hk>
Co-committed-by: mwojcik <mw@m-labs.hk>
This commit is contained in:
mwojcik 2021-08-04 09:12:38 +08:00 committed by sb10q
parent f543501012
commit e3d3cb2311
4 changed files with 46 additions and 22 deletions

View File

@ -108,6 +108,9 @@ class GenericStandalone(SoCCore):
platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]") 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") 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.crg = self.ps7 # HACK for eem_7series to find the clock self.crg = self.ps7 # HACK for eem_7series to find the clock
self.submodules.rtio_crg = RTIOCRG(self.platform) self.submodules.rtio_crg = RTIOCRG(self.platform)
self.csr_devices.append("rtio_crg") self.csr_devices.append("rtio_crg")

View File

@ -11,6 +11,7 @@ from migen_axi.integration.soc_core import SoCCore
from migen_axi.platforms import zc706 from migen_axi.platforms import zc706
from misoc.interconnect.csr import * from misoc.interconnect.csr import *
from misoc.integration import cpu_interface from misoc.integration import cpu_interface
from misoc.cores import gpio
from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware import rtio, nist_clock, nist_qc2
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2 from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2
@ -81,6 +82,10 @@ class ZC706(SoCCore):
platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]") 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") platform.add_platform_command("set_input_jitter clk_fpga_0 0.24")
self.rustc_cfg["HAS_SI5324"] = None
self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n)
self.csr_devices.append("si5324_rst_n")
self.submodules.rtio_crg = RTIOCRG(self.platform, self.ps7.cd_sys.clk) self.submodules.rtio_crg = RTIOCRG(self.platform, self.ps7.cd_sys.clk)
self.csr_devices.append("rtio_crg") self.csr_devices.append("rtio_crg")
self.rustc_cfg["has_rtio_crg_clock_sel"] = None self.rustc_cfg["has_rtio_crg_clock_sel"] = None

View File

@ -45,7 +45,7 @@ mod mgmt;
mod analyzer; mod analyzer;
mod irq; mod irq;
mod i2c; mod i2c;
#[cfg(feature = "target_kasli_soc")] #[cfg(has_si5324)]
mod si5324; mod si5324;
fn init_gateware() { fn init_gateware() {
@ -162,7 +162,7 @@ async fn report_async_rtio_errors() {
} }
} }
#[cfg(feature = "target_kasli_soc")] #[cfg(has_si5324)]
// 125MHz output, from crystal, 7 Hz // 125MHz output, from crystal, 7 Hz
const SI5324_SETTINGS: si5324::FrequencySettings const SI5324_SETTINGS: si5324::FrequencySettings
= si5324::FrequencySettings { = si5324::FrequencySettings {
@ -199,9 +199,9 @@ pub fn main_core0() {
info!("detected gateware: {}", identifier_read(&mut [0; 64])); info!("detected gateware: {}", identifier_read(&mut [0; 64]));
i2c::init(); i2c::init();
#[cfg(feature = "target_kasli_soc")] #[cfg(has_si5324)]
si5324::setup(unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() }, si5324::setup(unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() },
&SI5324_SETTINGS, si5324::Input::Ckin2).expect("cannot initialize Si5324"); &SI5324_SETTINGS, si5324::Input::Ckin2, timer).expect("cannot initialize Si5324");
let cfg = match Config::new() { let cfg = match Config::new() {
Ok(cfg) => cfg, Ok(cfg) => cfg,

View File

@ -1,11 +1,22 @@
use core::result; use core::result;
use log::info; use log::info;
use libboard_zynq::i2c::I2c; use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds};
use embedded_hal::blocking::delay::DelayUs;
#[cfg(not(si5324_soft_reset))]
use pl::csr;
type Result<T> = result::Result<T, &'static str>; type Result<T> = result::Result<T, &'static str>;
const ADDRESS: u8 = 0x68; const ADDRESS: u8 = 0x68;
#[cfg(not(si5324_soft_reset))]
fn hard_reset(timer: GlobalTimer) {
unsafe { csr::si5324_rst_n::out_write(0); }
timer.delay_us(1_000);
unsafe { csr::si5324_rst_n::out_write(1); }
timer.delay_us(10_000);
}
// NOTE: the logical parameters DO NOT MAP to physical values written // NOTE: the logical parameters DO NOT MAP to physical values written
// into registers. They have to be mapped; see the datasheet. // into registers. They have to be mapped; see the datasheet.
// DSPLLsim reports the logical parameters in the design summary, not // DSPLLsim reports the logical parameters in the design summary, not
@ -134,9 +145,10 @@ fn ident(i2c: &mut I2c) -> Result<u16> {
Ok(((read(i2c, 134)? as u16) << 8) | (read(i2c, 135)? as u16)) Ok(((read(i2c, 134)? as u16) << 8) | (read(i2c, 135)? as u16))
} }
fn soft_reset(i2c: &mut I2c) -> Result<()> { #[cfg(si5324_soft_reset)]
//TODO write_no_ack_value(i2c, 136, read(136)? | 0x80)?; fn soft_reset(i2c: &mut I2c, timer: GlobalTimer) -> Result<()> {
//TODO clock::spin_us(10_000); write_no_ack_value(i2c, 136, read(i2c, 136)? | 0x80)?;
timer.delay_us(10_000);
Ok(()) Ok(())
} }
@ -155,20 +167,23 @@ fn locked(i2c: &mut I2c) -> Result<bool> {
Ok((read(i2c, 130)? & 0x01) == 0) // LOL_INT=0 Ok((read(i2c, 130)? & 0x01) == 0) // LOL_INT=0
} }
fn monitor_lock(i2c: &mut I2c) -> Result<()> { fn monitor_lock(i2c: &mut I2c, timer: GlobalTimer) -> Result<()> {
info!("waiting for Si5324 lock..."); info!("waiting for Si5324 lock...");
// TODO let t = clock::get_ms(); let timeout = timer.get_time() + Milliseconds(20_000);
while !locked(i2c)? { while !locked(i2c)? {
// Yes, lock can be really slow. // Yes, lock can be really slow.
/*if clock::get_ms() > t + 20000 { if timer.get_time() > timeout {
return Err("Si5324 lock timeout"); return Err("Si5324 lock timeout");
}*/ }
} }
info!(" ...locked"); info!(" ...locked");
Ok(()) Ok(())
} }
fn init(i2c: &mut I2c) -> Result<()> { fn init(i2c: &mut I2c, timer: GlobalTimer) -> Result<()> {
#[cfg(not(si5324_soft_reset))]
hard_reset(timer);
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
{ {
i2c.pca9548_select(0x70, 0)?; i2c.pca9548_select(0x70, 0)?;
@ -179,16 +194,17 @@ fn init(i2c: &mut I2c) -> Result<()> {
return Err("Si5324 does not have expected product number"); return Err("Si5324 does not have expected product number");
} }
soft_reset(i2c)?; #[cfg(si5324_soft_reset)]
soft_reset(i2c, timer)?;
Ok(()) Ok(())
} }
pub fn bypass(i2c: &mut I2c, input: Input) -> Result<()> { pub fn bypass(i2c: &mut I2c, input: Input, timer: GlobalTimer) -> Result<()> {
let cksel_reg = match input { let cksel_reg = match input {
Input::Ckin1 => 0b00, Input::Ckin1 => 0b00,
Input::Ckin2 => 0b01, Input::Ckin2 => 0b01,
}; };
init(i2c)?; init(i2c, timer)?;
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0 rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00 rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
@ -197,14 +213,14 @@ pub fn bypass(i2c: &mut I2c, input: Input) -> Result<()> {
Ok(()) Ok(())
} }
pub fn setup(i2c: &mut I2c, settings: &FrequencySettings, input: Input) -> Result<()> { pub fn setup(i2c: &mut I2c, settings: &FrequencySettings, input: Input, timer: GlobalTimer) -> Result<()> {
let s = map_frequency_settings(settings)?; let s = map_frequency_settings(settings)?;
let cksel_reg = match input { let cksel_reg = match input {
Input::Ckin1 => 0b00, Input::Ckin1 => 0b00,
Input::Ckin2 => 0b01, Input::Ckin2 => 0b01,
}; };
init(i2c)?; init(i2c, timer)?;
if settings.crystal_ref { if settings.crystal_ref {
rmw(i2c, 0, |v| v | 0x40)?; // FREE_RUN=1 rmw(i2c, 0, |v| v | 0x40)?; // FREE_RUN=1
} }
@ -239,11 +255,11 @@ pub fn setup(i2c: &mut I2c, settings: &FrequencySettings, input: Input) -> Resul
return Err("Si5324 misses clock input signal"); return Err("Si5324 misses clock input signal");
} }
monitor_lock(i2c)?; monitor_lock(i2c, timer)?;
Ok(()) Ok(())
} }
pub fn select_input(i2c: &mut I2c, input: Input) -> Result<()> { pub fn select_input(i2c: &mut I2c, input: Input, timer: GlobalTimer) -> Result<()> {
let cksel_reg = match input { let cksel_reg = match input {
Input::Ckin1 => 0b00, Input::Ckin1 => 0b00,
Input::Ckin2 => 0b01, Input::Ckin2 => 0b01,
@ -252,6 +268,6 @@ pub fn select_input(i2c: &mut I2c, input: Input) -> Result<()> {
if !has_ckin(i2c, input)? { if !has_ckin(i2c, input)? {
return Err("Si5324 misses clock input signal"); return Err("Si5324 misses clock input signal");
} }
monitor_lock(i2c)?; monitor_lock(i2c, timer)?;
Ok(()) Ok(())
} }