master WRPLL: init

gw: add rtio_frequency
gw: add wrpll ref clock config
gw: add mmcm and expose mmcm config port
fw: add mmcm read
fw: add CLK_SEL to expander
This commit is contained in:
morgan 2024-02-28 17:22:55 +08:00
parent 9d5d883b1b
commit c7df09b6a3
5 changed files with 190 additions and 5 deletions

View File

@ -224,8 +224,6 @@ class GenericMaster(SoCCore):
self.config["HW_REV"] = description["hw_rev"]
self.submodules += SMAClkinForward(self.platform)
data_pads = [platform.request("sfp", i) for i in range(4)]
self.submodules.gt_drtio = gtx_7series.GTX(
@ -259,8 +257,18 @@ class GenericMaster(SoCCore):
self.comb += ext_async_rst.eq(self.sys_crg.clk_sw_fsm.o_clk_sw & ~gtx0.tx_init.done)
self.specials += MultiReg(self.sys_crg.clk_sw_fsm.o_clk_sw & self.sys_crg.mmcm_locked, self.gt_drtio.clk_path_ready, odomain="bootstrap")
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
if with_wrpll:
self.submodules.sma_pll = wrpll.SMA_PLL(platform.request("sma_clkin"))
self.csr_devices.append("sma_pll")
self.submodules.main_dcxo = si549.Si549(platform.request("ddmtd_main_dcxo_i2c"))
self.csr_devices.append("main_dcxo")
self.config["HAS_SI549"] = None
self.config["WRPLL_REF_CLK"] = "SMA_CLKIN"
else:
self.submodules += SMAClkinForward(self.platform)
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
self.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
@ -565,6 +573,7 @@ class GenericSatellite(SoCCore):
self.csr_devices.append("wrpll")
self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq)
self.config["HAS_SI549"] = None
self.config["WRPLL_REF_CLK"] = "GTX_CDR"
else:
self.submodules.siphaser = SiPhaser7Series(
si5324_clkin=platform.request("cdr_clk"),

View File

@ -123,4 +123,65 @@ class WRPLL(Module, AutoCSR):
self.main_tag_ev.stb.trigger.eq(main_tag_stb_sys)
]
self.submodules.ev = SharedIRQ(self.ref_tag_ev, self.main_tag_ev)
self.submodules.ev = SharedIRQ(self.ref_tag_ev, self.main_tag_ev)
class SMA_PLL(Module, AutoCSR):
def __init__(self, sma_clkin):
freq = 125e9
period = 1e9/freq # ns
mmcm_locked = Signal()
mmcm_fb_clk = Signal()
ref_clk = Signal()
self.clock_domains.cd_ref = ClockDomain()
self.mmcm_locked = CSRStatus()
self.mmcm_reset = CSRStorage() #TODO for i_RST
self.drp_addr = CSRStorage(7)
self.drp_in = CSRStorage(16)
self.drp_w_en = CSRStorage()
self.drp_en = CSRStorage()
self.drp_clk = CSRStorage()
self.drp_out = CSRStatus(16)
self.drp_ready = CSRStatus()
# # #
self.specials += [
# MMCME2 is capable to accept 10Mhz input while PLLE2 only support down to 19Mhz input (DS191)
Instance("MMCME2_ADV",
p_BANDWIDTH="LOW", # lower jitter
o_LOCKED=self.mmcm_locked.status,
p_CLKIN1_PERIOD=period,
i_CLKIN1=ClockSignal("sys"),
i_RST=ResetSignal("sys"),
i_CLKINSEL=1, # 1=CLKIN1 0=CLKIN2
# VCO @ 1Ghz
p_CLKFBOUT_MULT_F=8.0,
# p_CLKFBOUT_MULT = 1.0, # M = p_CLKFBOUT_MULT_F/p_CLKFBOUT_MULT
p_DIVCLK_DIVIDE=1,
i_CLKFBIN=mmcm_fb_clk, o_CLKFBOUT=mmcm_fb_clk,
# 62.5MHz
p_CLKOUT0_DIVIDE_F=16, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=ref_clk,
# Dynamic Reconfiguration Port
i_DADDR = self.drp_addr.storage,
i_DI = self.drp_in.storage,
i_DWE = self.drp_w_en.storage,
i_DEN = self.drp_en.storage,
i_DCLK = self.drp_clk.storage,
o_DO = self.drp_out.status,
o_DRDY = self.drp_ready.status
),
Instance("BUFG", i_I=ref_clk, o_O=self.cd_ref.clk),
AsyncResetSynchronizer(self.cd_ref, ~self.mmcm_locked.status),
# debug output
Instance("OBUFDS", i_I=self.cd_ref.clk, o_O=sma_clkin.p, o_OB=sma_clkin.n)
]

View File

@ -547,3 +547,64 @@ pub mod wrpll {
}
}
}
#[cfg(has_sma_pll)]
pub mod sma_pll {
use super::*;
// Based on "DRP State Machine" section from XAPP888
mod mmcm {
use super::*;
fn one_clock_cycle(timer: &mut GlobalTimer) {
unsafe {
csr::sma_pll::drp_clk_write(1);
timer.delay_us(1);
csr::sma_pll::drp_clk_write(0);
timer.delay_us(1);
}
}
fn set_addr(address: u8) {
unsafe {
csr::sma_pll::drp_addr_write(address);
}
}
fn set_enable(en: bool) {
unsafe {
let val = if en { 1 } else { 0 };
csr::sma_pll::drp_en_write(val);
}
}
fn get_data() -> u16 {
unsafe { csr::sma_pll::drp_out_read() }
}
fn drp_ready() -> bool {
unsafe { csr::sma_pll::drp_ready_read() == 1 }
}
pub fn read(timer: &mut GlobalTimer, address: u8) -> u16 {
set_addr(address);
set_enable(true);
// Set DADDR on the MMCM and assert DEN for one clock cycle
one_clock_cycle(timer);
set_enable(false);
while !drp_ready() {
// keep the clock signal until data is ready
one_clock_cycle(timer);
}
get_data()
}
}
pub fn setup(timer: &mut GlobalTimer) {
for addr in 7..12 {
info!("address = {:#x} | val = {:016b}", addr, mmcm::read(timer, addr));
}
info!("running SMA PLL");
}
}

View File

@ -104,6 +104,11 @@ pub fn main_core0() {
io_expander1
.init(i2c_bus)
.expect("I2C I/O expander #1 initialization failed");
// Drive CLK_SEL to true
#[cfg(has_si549)]
io_expander0.set(1, 7, true);
// Drive TX_DISABLE to false on SFP0..3
io_expander0.set(0, 1, false);
io_expander1.set(0, 1, false);

View File

@ -4,6 +4,8 @@ use ksupport::i2c;
use libboard_artiq::pl;
#[cfg(has_si5324)]
use libboard_artiq::si5324;
#[cfg(has_si549)]
use libboard_artiq::si549;
#[cfg(has_si5324)]
use libboard_zynq::i2c::I2c;
use libboard_zynq::timer::GlobalTimer;
@ -260,6 +262,48 @@ fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) {
si5324::setup(i2c, &si5324_settings, si5324_ref_input, timer).expect("cannot initialize Si5324");
}
#[cfg(has_si549)]
fn setup_si549(timer: &mut GlobalTimer, clk: RtioClock) {
let si549_settings = match clk {
RtioClock::Int_100 => {
info!("using internal 100MHz RTIO clock");
si549::FrequencySetting {
main: si549::DividerConfig {
hsdiv: 0x06C,
lsdiv: 0,
fbdiv: 0x046C5F49797,
},
}
}
RtioClock::Int_125 => {
info!("using internal 125MHz RTIO clock");
si549::FrequencySetting {
main: si549::DividerConfig {
hsdiv: 0x058,
lsdiv: 0,
fbdiv: 0x04815791F25,
},
}
}
_ => {
// same setting as Int_125, but fallback to default
warn!(
"rtio_clock setting '{:?}' is unsupported. Falling back to default 125MHz RTIO clock.",
clk
);
si549::FrequencySetting {
main: si549::DividerConfig {
hsdiv: 0x058,
lsdiv: 0,
fbdiv: 0x04815791F25,
},
}
}
};
si549::main_setup(timer, si549_settings).expect("cannot initialize main Si549");
}
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
let clk = get_rtio_clock_cfg(cfg);
#[cfg(has_si5324)]
@ -273,6 +317,11 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
_ => setup_si5324(i2c, timer, clk),
}
}
#[cfg(has_si549)]
{
si549::sma_pll::setup(timer);
setup_si549(timer, clk);
}
#[cfg(has_drtio)]
init_drtio(timer);