drtio: implement Si5324 phaser gateware and partial firmware support

pull/954/head
Sebastien Bourdeauducq 2018-03-07 00:06:39 +08:00
parent 994ceca9ff
commit c34d00cbc9
5 changed files with 147 additions and 29 deletions

View File

@ -1,6 +1,6 @@
use core::result;
use board::clock;
#[cfg(not(si5324_soft_reset))]
#[cfg(any(not(si5324_soft_reset), has_si_phaser))]
use board::csr;
use i2c;
@ -47,6 +47,11 @@ pub struct FrequencySettings {
pub crystal_ref: bool
}
pub enum Input {
Ckin1,
Ckin2,
}
fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySettings> {
if settings.nc1_ls != 0 && (settings.nc1_ls % 2) == 1 {
return Err("NC1_LS must be 0 or even")
@ -160,8 +165,11 @@ fn has_xtal() -> Result<bool> {
Ok((read(129)? & 0x01) == 0) // LOSX_INT=0
}
fn has_clkin2() -> Result<bool> {
Ok((read(129)? & 0x04) == 0) // LOS2_INT=0
fn has_ckin(input: Input) -> Result<bool> {
match input {
Input::Ckin1 => Ok((read(129)? & 0x02) == 0), // LOS1_INT=0
Input::Ckin2 => Ok((read(129)? & 0x04) == 0), // LOS2_INT=0
}
}
fn locked() -> Result<bool> {
@ -180,7 +188,7 @@ fn monitor_lock() -> Result<()> {
Ok(())
}
pub fn setup(settings: &FrequencySettings) -> Result<()> {
pub fn setup(settings: &FrequencySettings, input: Input) -> Result<()> {
let s = map_frequency_settings(settings)?;
#[cfg(not(si5324_soft_reset))]
@ -203,12 +211,16 @@ pub fn setup(settings: &FrequencySettings) -> Result<()> {
#[cfg(si5324_soft_reset)]
soft_reset()?;
let cksel_reg = match input {
Input::Ckin1 => 0b00,
Input::Ckin2 => 0b01,
};
if settings.crystal_ref {
write(0, read(0)? | 0x40)?; // FREE_RUN=1
}
write(2, (read(2)? & 0x0f) | (s.bwsel << 4))?;
write(21, read(21)? & 0xfe)?; // CKSEL_PIN=0
write(3, (read(3)? & 0x3f) | (0b01 << 6) | 0x10)?; // CKSEL_REG=b01 SQ_ICAL=1
write(3, (read(3)? & 0x3f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1
write(4, (read(4)? & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
write(6, (read(6)? & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
write(25, (s.n1_hs << 5 ) as u8)?;
@ -233,20 +245,40 @@ pub fn setup(settings: &FrequencySettings) -> Result<()> {
if !has_xtal()? {
return Err("Si5324 misses XA/XB signal");
}
if !has_clkin2()? {
return Err("Si5324 misses CLKIN2 signal");
if !has_ckin(input)? {
return Err("Si5324 misses clock input signal");
}
monitor_lock()?;
Ok(())
}
pub fn select_ext_input(external: bool) -> Result<()> {
if external {
write(3, (read(3)? & 0x3f) | (0b00 << 6))?; // CKSEL_REG=b00
} else {
write(3, (read(3)? & 0x3f) | (0b01 << 6))?; // CKSEL_REG=b01
pub fn select_input(input: Input) -> Result<()> {
let cksel_reg = match input {
Input::Ckin1 => 0b00,
Input::Ckin2 => 0b01,
};
write(3, (read(3)? & 0x3f) | (cksel_reg << 6))?;
if !has_ckin(input)? {
return Err("Si5324 misses clock input signal");
}
monitor_lock()?;
Ok(())
}
#[cfg(has_si_phaser)]
pub fn select_recovered_clock(rc: bool) -> Result<()> {
write(3, (read(3)? & 0xdf) | (1 << 5))?; // DHOLD=1
unsafe {
csr::si_phaser::switch_clocks_write(if rc { 1 } else { 0 });
}
write(3, (read(3)? & 0xdf) | (1 << 5))?; // DHOLD=0
monitor_lock()?;
Ok(())
}
#[cfg(has_si_phaser)]
pub fn calibrate_skew() -> Result<()> {
// TODO: implement
Ok(())
}

View File

@ -152,7 +152,7 @@ fn setup_si5324_as_synthesizer()
bwsel : 3,
crystal_ref: true
};
board_artiq::si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324");
board_artiq::si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin2).expect("cannot initialize Si5324");
}
#[cfg(has_ethmac)]

View File

@ -195,14 +195,14 @@ fn process_errors() {
#[cfg(rtio_frequency = "150.0")]
const SI5324_SETTINGS: si5324::FrequencySettings
= si5324::FrequencySettings {
n1_hs : 9,
nc1_ls : 4,
= si5324::FrequencySettings {
n1_hs : 6,
nc1_ls : 6,
n2_hs : 10,
n2_ls : 33732,
n31 : 9370,
n32 : 7139,
bwsel : 3,
n2_ls : 270,
n31 : 75,
n32 : 75,
bwsel : 4,
crystal_ref: true
};
@ -225,7 +225,7 @@ fn startup() {
/* must be the first SPI init because of HMC830 SPI mode selection */
hmc830_7043::init().expect("cannot initialize HMC830/7043");
i2c::init();
si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324");
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
unsafe {
csr::drtio_transceiver::stable_clkin_write(1);
}
@ -235,7 +235,8 @@ fn startup() {
process_errors();
}
info!("link is up, switching to recovered clock");
si5324::select_ext_input(true).expect("failed to switch clocks");
si5324::select_recovered_clock(true).expect("failed to switch clocks");
si5324::calibrate_skew().expect("failed to calibrate skew");
drtio_reset(false);
drtio_reset_phy(false);
while drtio_link_rx_up() {
@ -245,7 +246,7 @@ fn startup() {
drtio_reset_phy(true);
drtio_reset(true);
info!("link is down, switching to local crystal clock");
si5324::select_ext_input(false).expect("failed to switch clocks");
si5324::select_recovered_clock(false).expect("failed to switch clocks");
}
}

View File

@ -0,0 +1,85 @@
from migen import *
from migen.genlib.cdc import MultiReg
from misoc.interconnect.csr import *
# This code assumes 125MHz system clock and 150MHz RTIO frequency.
class SiPhaser7Series(Module, AutoCSR):
def __init__(self, si5324_clkin, si5324_clkout_fabric):
self.switch_clocks = CSRStorage()
self.phase_shift = CSR()
self.phase_shift_done = CSRStatus()
self.sample_result = CSRStatus()
# 125MHz system clock to 150MHz. VCO @ 625MHz.
# Used to provide a startup clock to the transceiver through the Si,
# we do not use the crystal reference so that the PFD (f3) frequency
# can be high.
mmcm_freerun_fb = Signal()
mmcm_freerun_output = Signal()
self.specials += \
Instance("MMCME2_BASE",
p_CLKIN1_PERIOD=1e9/125e6,
i_CLKIN1=ClockSignal("sys"),
i_RST=ResetSignal("sys"),
p_CLKFBOUT_MULT_F=6.0, p_DIVCLK_DIVIDE=1,
o_CLKFBOUT=mmcm_freerun_fb, i_CLKFBIN=mmcm_freerun_fb,
p_CLKOUT0_DIVIDE_F=5.0, o_CLKOUT0=mmcm_freerun_output,
)
# 150MHz to 150MHz with controllable phase shift, VCO @ 1200MHz.
# Inserted between CDR and output to Si, used to correct
# non-determinstic skew of Si5324.
mmcm_ps_fb = Signal()
mmcm_ps_output = Signal()
self.specials += \
Instance("MMCME2_ADV",
p_CLKIN1_PERIOD=1e9/150e6,
i_CLKIN1=ClockSignal("rtio_rx0"),
i_RST=ResetSignal("rtio_rx0"),
i_CLKINSEL=1, # yes, 1=CLKIN1 0=CLKIN2
p_CLKFBOUT_MULT_F=8.0,
p_CLKOUT0_DIVIDE_F=8.0,
p_DIVCLK_DIVIDE=1,
o_CLKFBOUT=mmcm_ps_fb, i_CLKFBIN=mmcm_ps_fb,
p_CLKOUT0_USE_FINE_PS="TRUE",
o_CLKOUT0=mmcm_ps_output,
i_PSCLK=ClockSignal(),
i_PSEN=self.phase_shift.re,
i_PSINCDEC=self.phase_shift.r,
o_PSDONE=self.phase_shift_done.status,
)
si5324_clkin_se = Signal()
self.specials += [
Instance("BUFGMUX",
i_I0=mmcm_freerun_output,
i_I1=mmcm_ps_output,
i_S=self.switch_clocks.storage,
o_O=si5324_clkin_se
),
Instance("OBUFDS",
i_I=si5324_clkin_se,
o_O=si5324_clkin.p, o_OB=si5324_clkin.n
)
]
si5324_clkout_se = Signal()
self.specials += \
Instance("IBUFDS",
p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE",
i_I=si5324_clkout_fabric.p, i_IB=si5324_clkout_fabric.n,
o_O=si5324_clkout_se),
clkout_sample1 = Signal() # IOB register
self.sync.rtio_rx0 += clkout_sample1.eq(si5324_clkout_se)
self.specials += MultiReg(clkout_sample1, self.sample_result.status)

View File

@ -21,6 +21,7 @@ from artiq.gateware.amp import AMPSoC
from artiq.gateware import rtio
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi2
from artiq.gateware.drtio.transceiver import gtp_7series
from artiq.gateware.drtio.si_phaser import SiPhaser7Series
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite
from artiq.build_soc import build_artiq_soc
@ -573,12 +574,11 @@ class Satellite(BaseSoC):
self.add_memory_group("drtio_aux", ["drtio0_aux"])
self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6)
si5324_clkin = platform.request("si5324_clkin")
self.specials += \
Instance("OBUFDS",
i_I=ClockSignal("rtio_rx0"),
o_O=si5324_clkin.p, o_OB=si5324_clkin.n
)
self.submodules.si_phaser = SiPhaser7Series(
si5324_clkin=platform.request("si5324_clkin"),
si5324_clkout_fabric=platform.request("si5324_clkout_fabric")
)
self.csr_devices.append("si_phaser")
i2c = self.platform.request("i2c")
self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda])
self.csr_devices.append("i2c")