Compare commits

..

6 Commits

Author SHA1 Message Date
morgan 0d0f9b5a6b Firmware: Runtime WRPLL
runtime: drive CLK_SEL to true when si549 is used
runtime & libboard_artiq: allow standalone to use io_expander
si549: add bit bang mmcm dynamic configuration
si549: add frequency counter for refclk
rtio_clocking & si549: add 125Mhz wrpll refclk setup
2024-03-11 14:46:38 +08:00
morgan a26e4ced44 Firmware: Satman WRPLL
satman: drive CLK_SEL to true when si549 is used
satman & si549: add main & helper si549 setup
satman & si549: add WRPLL select_recovered_clock
si549: add tag collector to process gtx & main tags
si549: add frequency counter to set BASE_ADPLL
si549: add set_adpll for main & helper PLL
si549: add main & helper PLL
FIQ & si549: replace dummy with a custom handler for gtx & main tags ISR
2024-03-08 16:59:45 +08:00
morgan 1e4ff8b887 Firmware: Si549 and io_expander
io_expander: set CLK_SEL pin to output when si549 is used
io_expander: gate virtual leds for standalone
si549: add bit bang i2c
si549: add si549 programming & main setup
2024-03-08 16:59:45 +08:00
morgan 56c008fa67 Gatewre: kasli_soc WRPLL setup
kasli_soc: add --with-wrpll arg to switch from si5324 to si549
kasli_soc: default to use si5435
kasli_soc: add wrpll for all variants
kasli_soc: add gtx & main tag nFIQ
kasli_soc: add WRPLL_REF_CLK config for firmware
2024-03-08 16:59:45 +08:00
morgan 8e1b62e126 Gateware: WRPLL
ddmtd: add DDMTD and deglitcher
wrpll: add helper clockdomain
wrpll: add frequency counter
wrpll: add gtx & main tag collection
wrpll: add gtx & main tag eventmanager for shared peripheral interrupt
wrpll: add SMA frequency multiplier to generate 125Mhz refclk
si549: add i2c and adpll programmer
2024-03-08 16:59:39 +08:00
morgan 5c5bd8535f kasli soc: refactor clock synth 2024-03-08 11:07:44 +08:00
12 changed files with 572 additions and 169 deletions

View File

@ -1,28 +1,23 @@
from migen import *
from migen.genlib.cdc import PulseSynchronizer, MultiReg
from migen.genlib.fsm import FSM
from misoc.interconnect.csr import *
class DDMTDSamplerGTX(Module):
def __init__(self, gtx, main_dcxo_pads):
self.gtx_beating = Signal()
class DDMTDSampler(Module):
def __init__(self, cd_ref, main_clk_se):
self.ref_beating = Signal()
self.main_beating = Signal()
# # #
main_clk_se = Signal()
gtx_beating_FF = Signal()
ref_beating_FF = Signal()
main_beating_FF = Signal()
self.specials += [
Instance("IBUFDS",
i_I=main_dcxo_pads.p, i_IB=main_dcxo_pads.n,
o_O=main_clk_se),
# Two back to back FFs are used to prevent metastability
Instance("FD", i_C=ClockSignal("helper"),
i_D=gtx.cd_rtio_rx0.clk, o_Q=gtx_beating_FF),
i_D=cd_ref.clk, o_Q=ref_beating_FF),
Instance("FD", i_C=ClockSignal("helper"),
i_D=gtx_beating_FF, o_Q=self.gtx_beating),
i_D=ref_beating_FF, o_Q=self.ref_beating),
Instance("FD", i_C=ClockSignal("helper"),
i_D=main_clk_se, o_Q=main_beating_FF),
Instance("FD", i_C=ClockSignal("helper"),

View File

@ -27,7 +27,6 @@ import acpki
import drtio_aux_controller
import zynq_clocking
import wrpll
import si549
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
eem_iostandard_dict = {
@ -49,6 +48,19 @@ eem_iostandard_dict = {
def eem_iostandard(eem):
return IOStandard(eem_iostandard_dict[eem])
class ClockSynthesis(Module):
def __init__(self, platform):
self.se = Signal()
clk_synth = platform.request("cdr_clk_clean_fabric")
platform.add_period_constraint(clk_synth.p, 8.0)
self.specials += [
Instance("IBUFGDS",
p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="FALSE",
i_I=clk_synth.p, i_IB=clk_synth.n, o_O=self.se
),
]
class SMAClkinForward(Module):
def __init__(self, platform):
@ -122,24 +134,10 @@ class GenericStandalone(SoCCore):
self.config["HW_REV"] = description["hw_rev"]
self.submodules += SMAClkinForward(self.platform)
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
clk_synth = platform.request("cdr_clk_clean_fabric")
clk_synth_se = Signal()
self.submodules.clk_synth = ClockSynthesis(self.platform)
clk_synth_se_buf = Signal()
platform.add_period_constraint(clk_synth.p, 8.0)
self.specials += Instance("BUFG", i_I=self.clk_synth.se, o_O=clk_synth_se_buf)
self.specials += [
Instance("IBUFGDS",
p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="FALSE",
i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se
),
Instance("BUFG", i_I=clk_synth_se, o_O=clk_synth_se_buf),
]
fix_serdes_timing_path(platform)
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
@ -151,6 +149,23 @@ class GenericStandalone(SoCCore):
self.crg = self.ps7 # HACK for eem_7series to find the clock
self.crg.cd_sys = self.sys_crg.cd_sys
if with_wrpll:
self.submodules.wrpll_refclk = wrpll.SMAFrequencyMultiplier(platform.request("sma_clkin"))
self.submodules.wrpll = wrpll.WRPLL(
platform=self.platform,
cd_ref=self.wrpll_refclk.cd_ref,
main_clk_se=self.clk_synth.se)
self.csr_devices.append("wrpll_refclk")
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"] = "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"])
if has_grabber:
@ -224,8 +239,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 +272,22 @@ 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.clk_synth = ClockSynthesis(self.platform)
self.submodules.wrpll_refclk = wrpll.SMAFrequencyMultiplier(platform.request("sma_clkin"))
self.submodules.wrpll = wrpll.WRPLL(
platform=self.platform,
cd_ref=self.wrpll_refclk.cd_ref,
main_clk_se=self.clk_synth.se)
self.csr_devices.append("wrpll_refclk")
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"] = "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"])
@ -554,17 +581,15 @@ class GenericSatellite(SoCCore):
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
if with_wrpll:
self.submodules.main_dcxo = si549.Si549(platform.request("ddmtd_main_dcxo_i2c"))
self.submodules.helper_dcxo = si549.Si549(platform.request("ddmtd_helper_dcxo_i2c"))
self.submodules.clk_synth = ClockSynthesis(self.platform)
self.submodules.wrpll = wrpll.WRPLL(
gtx=self.gt_drtio,
main_dcxo_pads=platform.request("cdr_clk_clean_fabric"),
helper_dcxo_pads=platform.request("ddmtd_helper_clk"))
self.csr_devices.append("main_dcxo")
self.csr_devices.append("helper_dcxo")
platform=self.platform,
cd_ref=self.gt_drtio.cd_rtio_rx0,
main_clk_se=self.clk_synth.se)
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

@ -3,11 +3,11 @@ from migen.genlib.cdc import MultiReg, AsyncResetSynchronizer, PulseSynchronizer
from misoc.interconnect.csr import *
from misoc.interconnect.csr_eventmanager import *
from ddmtd import DDMTDSamplerGTX, DDMTD
from ddmtd import DDMTDSampler, DDMTD
from si549 import Si549
class FrequencyCounter(Module, AutoCSR):
def __init__(self, counter_width=24, domains=["gtx0_rtio_rx", "sys"]):
def __init__(self, domains, counter_width=24):
for domain in domains:
name = "counter_" + domain
counter = CSRStatus(counter_width, name=name)
@ -46,21 +46,24 @@ class FrequencyCounter(Module, AutoCSR):
class WRPLL(Module, AutoCSR):
def __init__(self, gtx, main_dcxo_pads, helper_dcxo_pads, COUNTER_BIT=32):
self.gtx_tag = CSRStatus(COUNTER_BIT)
def __init__(self, platform, cd_ref, main_clk_se, COUNTER_BIT=32):
self.helper_reset = CSRStorage(reset=1)
self.ref_tag = CSRStatus(COUNTER_BIT)
self.main_tag = CSRStatus(COUNTER_BIT)
ddmtd_counter = Signal(COUNTER_BIT)
gtx_tag_sys = Signal(COUNTER_BIT)
ref_tag_sys = Signal(COUNTER_BIT)
main_tag_sys = Signal(COUNTER_BIT)
gtx_tag_stb_sys = Signal()
ref_tag_stb_sys = Signal()
main_tag_stb_sys = Signal()
# # #
self.helper_reset = CSRStorage(reset=1)
self.submodules.main_dcxo = Si549(platform.request("ddmtd_main_dcxo_i2c"))
self.submodules.helper_dcxo = Si549(platform.request("ddmtd_helper_dcxo_i2c"))
helper_dcxo_pads = platform.request("ddmtd_helper_clk")
self.clock_domains.cd_helper = ClockDomain()
self.specials += [
Instance("IBUFGDS",
@ -69,39 +72,39 @@ class WRPLL(Module, AutoCSR):
AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage)
]
self.submodules.frequency_counter = FrequencyCounter()
self.submodules.frequency_counter = FrequencyCounter(["sys", cd_ref.name])
self.submodules.ddmtd_sampler = DDMTDSamplerGTX(gtx, main_dcxo_pads)
self.submodules.ddmtd_sampler = DDMTDSampler(cd_ref, main_clk_se)
self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1)
self.submodules.ddmtd_gtx = DDMTD(ddmtd_counter, self.ddmtd_sampler.gtx_beating)
self.submodules.ddmtd_ref = DDMTD(ddmtd_counter, self.ddmtd_sampler.ref_beating)
self.submodules.ddmtd_main = DDMTD(ddmtd_counter, self.ddmtd_sampler.main_beating)
# DDMTD tags collection
self.specials += [
MultiReg(self.ddmtd_gtx.h_tag, gtx_tag_sys),
MultiReg(self.ddmtd_ref.h_tag, ref_tag_sys),
MultiReg(self.ddmtd_main.h_tag, main_tag_sys)
]
gtx_tag_stb_ps = PulseSynchronizer("helper", "sys")
ref_tag_stb_ps = PulseSynchronizer("helper", "sys")
main_tag_stb_ps = PulseSynchronizer("helper", "sys")
self.submodules += [
gtx_tag_stb_ps,
ref_tag_stb_ps,
main_tag_stb_ps
]
self.sync.helper += [
gtx_tag_stb_ps.i.eq(self.ddmtd_gtx.h_tag_update),
ref_tag_stb_ps.i.eq(self.ddmtd_ref.h_tag_update),
main_tag_stb_ps.i.eq(self.ddmtd_main.h_tag_update)
]
self.sync += [
gtx_tag_stb_sys.eq(gtx_tag_stb_ps.o),
ref_tag_stb_sys.eq(ref_tag_stb_ps.o),
main_tag_stb_sys.eq(main_tag_stb_ps.o)
]
self.sync += [
If(gtx_tag_stb_sys,
self.gtx_tag.status.eq(gtx_tag_sys),
If(ref_tag_stb_sys,
self.ref_tag.status.eq(ref_tag_sys),
),
If(main_tag_stb_sys,
self.main_tag.status.eq(main_tag_sys)
@ -110,17 +113,81 @@ class WRPLL(Module, AutoCSR):
# PL->PS interrupt
self.submodules.gtx_tag_ev = EventManager()
self.gtx_tag_ev.stb = EventSourcePulse()
self.gtx_tag_ev.finalize()
self.submodules.ref_tag_ev = EventManager()
self.ref_tag_ev.stb = EventSourcePulse()
self.ref_tag_ev.finalize()
self.submodules.main_tag_ev = EventManager()
self.main_tag_ev.stb = EventSourcePulse()
self.main_tag_ev.finalize()
self.sync += [
self.gtx_tag_ev.stb.trigger.eq(gtx_tag_stb_sys),
self.ref_tag_ev.stb.trigger.eq(ref_tag_stb_sys),
self.main_tag_ev.stb.trigger.eq(main_tag_stb_sys)
]
self.submodules.ev = SharedIRQ(self.gtx_tag_ev, self.main_tag_ev)
self.submodules.ev = SharedIRQ(self.ref_tag_ev, self.main_tag_ev)
class SMAFrequencyMultiplier(Module, AutoCSR):
def __init__(self, sma_clkin):
sma_clkin_se = Signal()
mmcm_locked = Signal()
mmcm_fb_clk = Signal()
ref_clk = Signal()
self.clock_domains.cd_ref = ClockDomain()
self.refclk_reset = CSRStorage(reset=1)
self.mmcm_bypass = CSRStorage()
self.mmcm_locked = CSRStatus()
self.mmcm_reset = CSRStorage(reset=1)
self.mmcm_daddr = CSRStorage(7)
self.mmcm_din = CSRStorage(16)
self.mmcm_dwen = CSRStorage()
self.mmcm_den = CSRStorage()
self.mmcm_dclk = CSRStorage()
self.mmcm_dout = CSRStatus(16)
self.mmcm_dready = CSRStatus()
# # #
self.specials += [
Instance("IBUFDS",
i_I=sma_clkin.p, i_IB=sma_clkin.n,
o_O=sma_clkin_se),
# MMCME2 is capable to accept 10Mhz input while PLLE2 only support down to 19Mhz input (DS191)
# The MMCME2 can be reconfiged during runtime using the Dynamic Reconfiguration Ports
Instance("MMCME2_ADV",
p_BANDWIDTH="LOW", # lower jitter
o_LOCKED=self.mmcm_locked.status,
i_RST=self.mmcm_reset.storage,
p_CLKIN1_PERIOD=8, # ns
i_CLKIN1=sma_clkin_se,
i_CLKINSEL=1, # 1=CLKIN1 0=CLKIN2
# VCO @ 1.25Ghz
p_CLKFBOUT_MULT_F=10, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=mmcm_fb_clk, o_CLKFBOUT=mmcm_fb_clk,
# 125Mhz for WRPLL
p_CLKOUT0_DIVIDE_F=10, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=ref_clk,
# Dynamic Reconfiguration Ports
i_DADDR = self.mmcm_daddr.storage,
i_DI = self.mmcm_din.storage,
i_DWE = self.mmcm_dwen.storage,
i_DEN = self.mmcm_den.storage,
i_DCLK = self.mmcm_dclk.storage,
o_DO = self.mmcm_dout.status,
o_DRDY = self.mmcm_dready.status
),
Instance("BUFGMUX",
i_I0=ref_clk,
i_I1=sma_clkin_se,
i_S=self.mmcm_bypass.storage,
o_O=self.cd_ref.clk
),
AsyncResetSynchronizer(self.cd_ref, self.refclk_reset.storage),
]

View File

@ -25,7 +25,7 @@ void = { version = "1", default-features = false }
io = { path = "../libio", features = ["byteorder"] }
libboard_zynq = { path = "@@ZYNQ_RS@@/libboard_zynq" }
libsupport_zynq = { path = "@@ZYNQ_RS@@/libsupport_zynq", default-features = false, features = ["alloc_core", "dummy_fiq_handler"] }
libsupport_zynq = { path = "@@ZYNQ_RS@@/libsupport_zynq", default-features = false, features = ["alloc_core"] }
libregister = { path = "@@ZYNQ_RS@@/libregister" }
libconfig = { path = "@@ZYNQ_RS@@/libconfig", features = ["fat_lfn"] }
libcortex_a9 = { path = "@@ZYNQ_RS@@/libcortex_a9" }

View File

@ -1,14 +1,15 @@
#[cfg(has_wrpll)]
use libboard_artiq::si549;
use libboard_zynq::{println, stdio};
use libcortex_a9::{interrupt_handler, regs::MPIDR};
use libregister::RegisterR;
#[cfg(has_si549)]
use crate::si549;
interrupt_handler!(FIQ, fiq, __irq_stack0_start, __irq_stack1_start, {
match MPIDR.read().cpu_id() {
0 => {
// nFIQ is driven directly and bypass GIC
#[cfg(has_wrpll)]
#[cfg(has_si549)]
si549::wrpll::interrupt_handler();
return;
}

View File

@ -1,6 +1,7 @@
use libboard_zynq::i2c;
use log::info;
#[cfg(has_virtual_leds)]
use crate::pl::csr;
// Only the bare minimum registers. Bits/IO connections equivalent between IC types.
@ -37,6 +38,7 @@ const IODIR1: [u8; 2] = [
pub struct IoExpander {
address: u8,
#[cfg(has_virtual_leds)]
virtual_led_mapping: &'static [(u8, u8, u8)],
iodir: [u8; 2],
out_current: [u8; 2],
@ -46,17 +48,18 @@ pub struct IoExpander {
impl IoExpander {
pub fn new(i2c: &mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
#[cfg(hw_rev = "v1.0")]
#[cfg(all(hw_rev = "v1.0", has_virtual_leds))]
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)];
#[cfg(hw_rev = "v1.1")]
#[cfg(all(hw_rev = "v1.1", has_virtual_leds))]
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 7), (1, 1, 6)];
#[cfg(has_virtual_leds)]
const VIRTUAL_LED_MAPPING1: [(u8, u8, u8); 2] = [(2, 0, 6), (3, 1, 6)];
// Both expanders on SHARED I2C bus
let mut io_expander = match index {
0 => IoExpander {
address: 0x40,
#[cfg(has_virtual_leds)]
virtual_led_mapping: &VIRTUAL_LED_MAPPING0,
iodir: IODIR0,
out_current: [0; 2],
@ -70,6 +73,7 @@ impl IoExpander {
},
1 => IoExpander {
address: 0x42,
#[cfg(has_virtual_leds)]
virtual_led_mapping: &VIRTUAL_LED_MAPPING1,
iodir: IODIR1,
out_current: [0; 2],

View File

@ -1,5 +1,7 @@
#![no_std]
#![feature(never_type)]
#![feature(naked_functions)]
#![feature(asm)]
extern crate core_io;
extern crate crc;
@ -19,7 +21,8 @@ pub mod drtioaux;
#[cfg(has_drtio)]
pub mod drtioaux_async;
pub mod drtioaux_proto;
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
pub mod fiq;
#[cfg(feature = "target_kasli_soc")]
pub mod io_expander;
pub mod logger;
#[cfg(has_drtio)]

View File

@ -1,5 +1,3 @@
use core::result::Result::Ok;
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
use libboard_zynq::timer::GlobalTimer;
use log::info;
@ -17,7 +15,6 @@ pub struct DividerConfig {
pub struct FrequencySetting {
pub main: DividerConfig,
#[cfg(has_wrpll)]
pub helper: DividerConfig,
}
@ -27,7 +24,6 @@ mod i2c {
#[derive(Clone, Copy)]
pub enum DCXO {
Main,
#[cfg(has_wrpll)]
Helper,
}
@ -37,45 +33,40 @@ mod i2c {
fn sda_i(dcxo: DCXO) -> bool {
match dcxo {
DCXO::Main => unsafe { csr::main_dcxo::sda_in_read() == 1 },
#[cfg(has_wrpll)]
DCXO::Helper => unsafe { csr::helper_dcxo::sda_in_read() == 1 },
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_in_read() == 1 },
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_in_read() == 1 },
}
}
fn sda_oe(dcxo: DCXO, oe: bool) {
let val = if oe { 1 } else { 0 };
match dcxo {
DCXO::Main => unsafe { csr::main_dcxo::sda_oe_write(val) },
#[cfg(has_wrpll)]
DCXO::Helper => unsafe { csr::helper_dcxo::sda_oe_write(val) },
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_oe_write(val) },
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_oe_write(val) },
};
}
fn sda_o(dcxo: DCXO, o: bool) {
let val = if o { 1 } else { 0 };
match dcxo {
DCXO::Main => unsafe { csr::main_dcxo::sda_out_write(val) },
#[cfg(has_wrpll)]
DCXO::Helper => unsafe { csr::helper_dcxo::sda_out_write(val) },
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_out_write(val) },
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_out_write(val) },
};
}
fn scl_oe(dcxo: DCXO, oe: bool) {
let val = if oe { 1 } else { 0 };
match dcxo {
DCXO::Main => unsafe { csr::main_dcxo::scl_oe_write(val) },
#[cfg(has_wrpll)]
DCXO::Helper => unsafe { csr::helper_dcxo::scl_oe_write(val) },
DCXO::Main => unsafe { csr::wrpll::main_dcxo_scl_oe_write(val) },
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_oe_write(val) },
};
}
fn scl_o(dcxo: DCXO, o: bool) {
let val = if o { 1 } else { 0 };
match dcxo {
DCXO::Main => unsafe { csr::main_dcxo::scl_out_write(val) },
#[cfg(has_wrpll)]
DCXO::Helper => unsafe { csr::helper_dcxo::scl_out_write(val) },
DCXO::Main => unsafe { csr::wrpll::main_dcxo_scl_out_write(val) },
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_out_write(val) },
};
}
@ -219,7 +210,7 @@ fn read(dcxo: i2c::DCXO, reg: u8, timer: &mut GlobalTimer) -> Result<u8, &'stati
Ok(val)
}
fn setup(dcxo: i2c::DCXO, config: DividerConfig, timer: &mut GlobalTimer) -> Result<(), &'static str> {
fn setup(dcxo: i2c::DCXO, config: &DividerConfig, timer: &mut GlobalTimer) -> Result<(), &'static str> {
i2c::init(dcxo, timer)?;
write(dcxo, 255, 0x00, timer)?; // PAGE
@ -252,26 +243,25 @@ fn setup(dcxo: i2c::DCXO, config: DividerConfig, timer: &mut GlobalTimer) -> Res
Ok(())
}
pub fn main_setup(timer: &mut GlobalTimer, settings: FrequencySetting) -> Result<(), &'static str> {
pub fn main_setup(timer: &mut GlobalTimer, settings: &FrequencySetting) -> Result<(), &'static str> {
unsafe {
csr::main_dcxo::bitbang_enable_write(1);
csr::main_dcxo::i2c_address_write(ADDRESS);
csr::wrpll::main_dcxo_bitbang_enable_write(1);
csr::wrpll::main_dcxo_i2c_address_write(ADDRESS);
}
setup(i2c::DCXO::Main, settings.main, timer)?;
setup(i2c::DCXO::Main, &settings.main, timer)?;
// Si549 maximum settling time for large frequency change.
timer.delay_us(40_000);
unsafe {
csr::main_dcxo::bitbang_enable_write(0);
csr::wrpll::main_dcxo_bitbang_enable_write(0);
}
info!("Main Si549 started");
Ok(())
}
#[cfg(has_wrpll)]
pub mod wrpll {
use libcortex_a9::mutex::Mutex;
@ -291,8 +281,8 @@ pub mod wrpll {
static M_INTEGRATOR: Mutex<i32> = Mutex::new(0);
#[derive(Clone, Copy)]
pub enum FIQ {
GTXTag,
pub enum ISR {
RefTag,
MainTag,
}
@ -302,29 +292,29 @@ pub mod wrpll {
const BEATING_PERIOD: i32 = 0x8000;
const BEATING_HALFPERIOD: i32 = 0x4000;
static GTX_TAG: Mutex<u32> = Mutex::new(0);
static GTX_TAG_READY: Mutex<bool> = Mutex::new(false);
static REF_TAG: Mutex<u32> = Mutex::new(0);
static REF_TAG_READY: Mutex<bool> = Mutex::new(false);
static MAIN_TAG: Mutex<u32> = Mutex::new(0);
static MAIN_TAG_READY: Mutex<bool> = Mutex::new(false);
pub fn reset() {
clear_phase_diff_ready();
*GTX_TAG.lock() = 0;
*REF_TAG.lock() = 0;
*MAIN_TAG.lock() = 0;
}
pub fn clear_phase_diff_ready() {
*GTX_TAG_READY.lock() = false;
*REF_TAG_READY.lock() = false;
*MAIN_TAG_READY.lock() = false;
}
pub fn collect_tags(interrupt: FIQ) {
pub fn collect_tags(interrupt: ISR) {
match interrupt {
FIQ::GTXTag => {
*GTX_TAG.lock() = unsafe { csr::wrpll::gtx_tag_read() };
*GTX_TAG_READY.lock() = true;
ISR::RefTag => {
*REF_TAG.lock() = unsafe { csr::wrpll::ref_tag_read() };
*REF_TAG_READY.lock() = true;
}
FIQ::MainTag => {
ISR::MainTag => {
*MAIN_TAG.lock() = unsafe { csr::wrpll::main_tag_read() };
*MAIN_TAG_READY.lock() = true;
}
@ -332,12 +322,12 @@ pub mod wrpll {
}
pub fn phase_diff_ready() -> bool {
*GTX_TAG_READY.lock() && *MAIN_TAG_READY.lock()
*REF_TAG_READY.lock() && *MAIN_TAG_READY.lock()
}
pub fn get_period_error() -> i32 {
// n * BEATING_PERIOD - GTX_TAG(n) mod BEATING_PERIOD
let mut period_error = (*GTX_TAG.lock()).overflowing_neg().0.rem_euclid(BEATING_PERIOD as u32) as i32;
// n * BEATING_PERIOD - REF_TAG(n) mod BEATING_PERIOD
let mut period_error = (*REF_TAG.lock()).overflowing_neg().0.rem_euclid(BEATING_PERIOD as u32) as i32;
// mapping tags from [0, 2π] -> [-π, π]
if period_error > BEATING_HALFPERIOD {
@ -347,9 +337,9 @@ pub mod wrpll {
}
pub fn get_phase_error() -> i32 {
// MAIN_TAG(n) - GTX_TAG(n) mod BEATING_PERIOD
// MAIN_TAG(n) - REF_TAG(n) mod BEATING_PERIOD
let mut phase_error = (*MAIN_TAG.lock())
.overflowing_sub(*GTX_TAG.lock())
.overflowing_sub(*REF_TAG.lock())
.0
.rem_euclid(BEATING_PERIOD as u32) as i32;
@ -361,30 +351,30 @@ pub mod wrpll {
}
}
pub fn helper_setup(timer: &mut GlobalTimer, settings: FrequencySetting) -> Result<(), &'static str> {
pub fn helper_setup(timer: &mut GlobalTimer, settings: &FrequencySetting) -> Result<(), &'static str> {
unsafe {
csr::wrpll::helper_reset_write(1);
csr::helper_dcxo::bitbang_enable_write(1);
csr::helper_dcxo::i2c_address_write(ADDRESS);
csr::wrpll::helper_dcxo_bitbang_enable_write(1);
csr::wrpll::helper_dcxo_i2c_address_write(ADDRESS);
}
setup(i2c::DCXO::Helper, settings.helper, timer)?;
setup(i2c::DCXO::Helper, &settings.helper, timer)?;
// Si549 maximum settling time for large frequency change.
timer.delay_us(40_000);
unsafe {
csr::wrpll::helper_reset_write(0);
csr::helper_dcxo::bitbang_enable_write(0);
csr::wrpll::helper_dcxo_bitbang_enable_write(0);
}
info!("Helper Si549 started");
Ok(())
}
fn set_fiq(en: bool) {
fn set_isr(en: bool) {
let val = if en { 1 } else { 0 };
unsafe {
csr::wrpll::gtx_tag_ev_enable_write(val);
csr::wrpll::ref_tag_ev_enable_write(val);
csr::wrpll::main_tag_ev_enable_write(val);
}
}
@ -398,34 +388,34 @@ pub mod wrpll {
match dcxo {
i2c::DCXO::Main => unsafe {
if csr::main_dcxo::bitbang_enable_read() == 1 {
if csr::wrpll::main_dcxo_bitbang_enable_read() == 1 {
return Err("Main si549 bitbang mode is active when using gateware i2c");
}
while csr::main_dcxo::adpll_busy_read() == 1 {}
csr::main_dcxo::i2c_address_write(ADDRESS);
csr::main_dcxo::adpll_write(adpll as u32);
while csr::wrpll::main_dcxo_adpll_busy_read() == 1 {}
csr::wrpll::main_dcxo_i2c_address_write(ADDRESS);
csr::wrpll::main_dcxo_adpll_write(adpll as u32);
csr::main_dcxo::adpll_stb_write(1);
csr::main_dcxo::adpll_stb_write(0);
csr::wrpll::main_dcxo_adpll_stb_write(1);
csr::wrpll::main_dcxo_adpll_stb_write(0);
if csr::main_dcxo::nack_read() == 1 {
if csr::wrpll::main_dcxo_nack_read() == 1 {
return Err("Main si549 failed to ack adpll write");
}
},
i2c::DCXO::Helper => unsafe {
if csr::helper_dcxo::bitbang_enable_read() == 1 {
if csr::wrpll::helper_dcxo_bitbang_enable_read() == 1 {
return Err("Helper si549 bitbang mode is active when using gateware i2c");
}
while csr::helper_dcxo::adpll_busy_read() == 1 {}
csr::helper_dcxo::i2c_address_write(ADDRESS);
csr::helper_dcxo::adpll_write(adpll as u32);
while csr::wrpll::helper_dcxo_adpll_busy_read() == 1 {}
csr::wrpll::helper_dcxo_i2c_address_write(ADDRESS);
csr::wrpll::helper_dcxo_adpll_write(adpll as u32);
csr::helper_dcxo::adpll_stb_write(1);
csr::helper_dcxo::adpll_stb_write(0);
csr::wrpll::helper_dcxo_adpll_stb_write(1);
csr::wrpll::helper_dcxo_adpll_stb_write(0);
if csr::helper_dcxo::nack_read() == 1 {
if csr::wrpll::helper_dcxo_nack_read() == 1 {
return Err("Helper si549 failed to ack adpll write");
}
},
@ -439,9 +429,9 @@ pub mod wrpll {
let count2adpll =
|error: i32| (((error) as f64 * 1e6) / (0.0001164 * (1 << (TIMER_WIDTH - COUNTER_DIV)) as f64)) as i32;
let (gtx_count, main_count) = get_freq_counts(timer);
let (ref_count, main_count) = get_freq_counts(timer);
let mut base_adpll_lock = BASE_ADPLL.lock();
*base_adpll_lock = count2adpll(gtx_count as i32 - main_count as i32);
*base_adpll_lock = count2adpll(ref_count as i32 - main_count as i32);
set_adpll(i2c::DCXO::Main, *base_adpll_lock)?;
set_adpll(i2c::DCXO::Helper, *base_adpll_lock)?;
@ -453,10 +443,13 @@ pub mod wrpll {
csr::wrpll::frequency_counter_update_en_write(1);
timer.delay_us(150_000); // 8ns << TIMER_WIDTH
csr::wrpll::frequency_counter_update_en_write(0);
let gtx = csr::wrpll::frequency_counter_counter_gtx0_rtio_rx_read();
let main = csr::wrpll::frequency_counter_counter_sys_read();
#[cfg(wrpll_ref_clk = "GTX_CDR")]
let ref_count = csr::wrpll::frequency_counter_counter_rtio_rx0_read();
#[cfg(wrpll_ref_clk = "SMA_CLKIN")]
let ref_count = csr::wrpll::frequency_counter_counter_ref_read();
let main_count = csr::wrpll::frequency_counter_counter_sys_read();
(gtx, main)
(ref_count, main_count)
}
}
@ -468,31 +461,31 @@ pub mod wrpll {
Ok(())
}
fn clear_pending(interrupt: FIQ) {
fn clear_pending(interrupt: ISR) {
match interrupt {
FIQ::GTXTag => unsafe { csr::wrpll::gtx_tag_ev_pending_write(1) },
FIQ::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) },
ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_write(1) },
ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) },
};
}
fn is_pending(interrupt: FIQ) -> bool {
fn is_pending(interrupt: ISR) -> bool {
match interrupt {
FIQ::GTXTag => unsafe { csr::wrpll::gtx_tag_ev_pending_read() == 1 },
FIQ::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_read() == 1 },
ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_read() == 1 },
ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_read() == 1 },
}
}
pub fn interrupt_handler() {
if is_pending(FIQ::GTXTag) {
tag_collector::collect_tags(FIQ::GTXTag);
clear_pending(FIQ::GTXTag);
if is_pending(ISR::RefTag) {
tag_collector::collect_tags(ISR::RefTag);
clear_pending(ISR::RefTag);
helper_pll().expect("failed to run helper DCXO PLL");
}
if is_pending(FIQ::MainTag) {
tag_collector::collect_tags(FIQ::MainTag);
clear_pending(FIQ::MainTag);
if is_pending(ISR::MainTag) {
tag_collector::collect_tags(ISR::MainTag);
clear_pending(ISR::MainTag);
}
if tag_collector::phase_diff_ready() {
@ -528,24 +521,167 @@ pub mod wrpll {
}
pub fn select_recovered_clock(rc: bool, timer: &mut GlobalTimer) {
set_fiq(false);
set_isr(false);
if rc {
tag_collector::reset();
reset_plls().expect("failed to reset main and helper PLL");
info!("warming up GTX CDR...");
// gtx need a couple seconds for freq counter to read it properly
info!("warming up refclk...");
// refclk need a couple seconds for freq counter to read it properly
timer.delay_us(20_000_000);
set_base_adpll(timer).expect("failed to set base adpll");
// clear gateware pending flag
clear_pending(FIQ::GTXTag);
clear_pending(FIQ::MainTag);
clear_pending(ISR::RefTag);
clear_pending(ISR::MainTag);
// use nFIQ to avoid IRQ being disabled by mutex lock and mess up PLL
set_fiq(true);
set_isr(true);
info!("WRPLL interrupt enabled");
}
}
}
#[cfg(has_wrpll_refclk)]
pub mod wrpll_refclk {
use super::*;
pub struct MmcmSetting {
pub clkout0_reg1: u16, //0x08
pub clkout0_reg2: u16, //0x09
pub clkfbout_reg1: u16, //0x14
pub clkfbout_reg2: u16, //0x15
pub div_reg: u16, //0x16
pub lock_reg1: u16, //0x18
pub lock_reg2: u16, //0x19
pub lock_reg3: u16, //0x1A
pub power_reg: u16, //0x28
pub filt_reg1: u16, //0x4E
pub filt_reg2: u16, //0x4F
}
fn one_clock_cycle(timer: &mut GlobalTimer) {
unsafe {
csr::wrpll_refclk::mmcm_dclk_write(1);
timer.delay_us(1);
csr::wrpll_refclk::mmcm_dclk_write(0);
timer.delay_us(1);
}
}
fn set_addr(address: u8) {
unsafe {
csr::wrpll_refclk::mmcm_daddr_write(address);
}
}
fn set_data(value: u16) {
unsafe {
csr::wrpll_refclk::mmcm_din_write(value);
}
}
fn set_enable(en: bool) {
unsafe {
let val = if en { 1 } else { 0 };
csr::wrpll_refclk::mmcm_den_write(val);
}
}
fn set_write_enable(en: bool) {
unsafe {
let val = if en { 1 } else { 0 };
csr::wrpll_refclk::mmcm_dwen_write(val);
}
}
fn get_data() -> u16 {
unsafe { csr::wrpll_refclk::mmcm_dout_read() }
}
fn drp_ready() -> bool {
unsafe { csr::wrpll_refclk::mmcm_dready_read() == 1 }
}
#[allow(dead_code)]
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()
}
fn write(timer: &mut GlobalTimer, address: u8, value: u16) {
set_addr(address);
set_data(value);
set_write_enable(true);
set_enable(true);
// Set DADDR, DI on the MMCM and assert DWE, DEN for one clock cycle
one_clock_cycle(timer);
set_write_enable(false);
set_enable(false);
while !drp_ready() {
// keep the clock signal until write is finished
one_clock_cycle(timer);
}
}
fn reset(rst: bool) {
unsafe {
let val = if rst { 1 } else { 0 };
csr::wrpll_refclk::mmcm_reset_write(val)
}
}
pub fn setup(timer: &mut GlobalTimer, settings: MmcmSetting, mmcm_bypass: bool) -> Result<(), &'static str> {
unsafe {
csr::wrpll_refclk::refclk_reset_write(1);
}
if mmcm_bypass {
info!("Bypassing mmcm");
unsafe {
csr::wrpll_refclk::mmcm_bypass_write(1);
}
} else {
// Based on "DRP State Machine" from XAPP888
// hold reset HIGH during mmcm config
reset(true);
write(timer, 0x08, settings.clkout0_reg1);
write(timer, 0x09, settings.clkout0_reg2);
write(timer, 0x14, settings.clkfbout_reg1);
write(timer, 0x15, settings.clkfbout_reg2);
write(timer, 0x16, settings.div_reg);
write(timer, 0x18, settings.lock_reg1);
write(timer, 0x19, settings.lock_reg2);
write(timer, 0x1A, settings.lock_reg3);
write(timer, 0x28, settings.power_reg);
write(timer, 0x4E, settings.filt_reg1);
write(timer, 0x4F, settings.filt_reg2);
reset(false);
// wait for the mmcm to lock
timer.delay_us(100);
let locked = unsafe { csr::wrpll_refclk::mmcm_locked_read() == 1 };
if !locked {
return Err("mmcm failed to generate 125Mhz ref clock from SMA CLKIN");
}
}
unsafe {
csr::wrpll_refclk::refclk_reset_write(0);
}
Ok(())
}
}

View File

@ -21,7 +21,6 @@ pub use pl::csr::rtio_core;
use void::Void;
pub mod eh_artiq;
pub mod fiq;
pub mod i2c;
pub mod irq;
pub mod kernel;

View File

@ -8,14 +8,14 @@
#[macro_use]
extern crate alloc;
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
#[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
use core::cell::RefCell;
use ksupport;
use libasync::task;
#[cfg(has_drtio_eem)]
use libboard_artiq::drtio_eem;
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
#[cfg(feature = "target_kasli_soc")]
use libboard_artiq::io_expander;
use libboard_artiq::{identifier_read, logger, pl};
use libboard_zynq::{gic, mpcore, timer::GlobalTimer};
@ -43,7 +43,7 @@ extern "C" {
static __exceptions_start: u32;
}
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
#[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
async fn io_expanders_service(
i2c_bus: RefCell<&mut libboard_zynq::i2c::I2c>,
io_expander0: RefCell<io_expander::IoExpander>,
@ -101,7 +101,7 @@ pub fn main_core0() {
info!("gateware ident: {}", identifier_read(&mut [0; 64]));
ksupport::i2c::init();
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
#[cfg(feature = "target_kasli_soc")]
{
let i2c_bus = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() };
let mut io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap();
@ -112,6 +112,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);
@ -119,6 +124,7 @@ pub fn main_core0() {
io_expander1.set(1, 1, false);
io_expander0.service(i2c_bus).unwrap();
io_expander1.service(i2c_bus).unwrap();
#[cfg(has_virtual_leds)]
task::spawn(io_expanders_service(
RefCell::new(i2c_bus),
RefCell::new(io_expander0),

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,153 @@ 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 wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: &si549::FrequencySetting) {
// register values are directly copied from preconfigured mmcm
let (mmcm_setting, mmcm_bypass) = match clk {
RtioClock::Ext0_Synth0_10to125 => (
si549::wrpll_refclk::MmcmSetting {
// CLKFBOUT_MULT = 62.5, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 5
clkout0_reg1: 0x1083,
clkout0_reg2: 0x0080,
clkfbout_reg1: 0x179e,
clkfbout_reg2: 0x4c00,
div_reg: 0x1041,
lock_reg1: 0x00fa,
lock_reg2: 0x7c01,
lock_reg3: 0xffe9,
power_reg: 0x9900,
filt_reg1: 0x0808,
filt_reg2: 0x0800,
},
false,
),
RtioClock::Ext0_Synth0_80to125 => (
si549::wrpll_refclk::MmcmSetting {
// CLKFBOUT_MULT = 15.625, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
clkout0_reg1: 0x1145,
clkout0_reg2: 0x0000,
clkfbout_reg1: 0x11c7,
clkfbout_reg2: 0x5880,
div_reg: 0x1041,
lock_reg1: 0x028a,
lock_reg2: 0x7c01,
lock_reg3: 0xffe9,
power_reg: 0x9900,
filt_reg1: 0x0808,
filt_reg2: 0x9800,
},
false,
),
RtioClock::Ext0_Synth0_100to125 => (
si549::wrpll_refclk::MmcmSetting {
// CLKFBOUT_MULT = 12.5, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
clkout0_reg1: 0x1145,
clkout0_reg2: 0x0000,
clkfbout_reg1: 0x1145,
clkfbout_reg2: 0x4c00,
div_reg: 0x1041,
lock_reg1: 0x0339,
lock_reg2: 0x7c01,
lock_reg3: 0xffe9,
power_reg: 0x9900,
filt_reg1: 0x0808,
filt_reg2: 0x9800,
},
false,
),
RtioClock::Ext0_Synth0_125to125 => (
si549::wrpll_refclk::MmcmSetting {
// CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
clkout0_reg1: 0x1145,
clkout0_reg2: 0x0000,
clkfbout_reg1: 0x1145,
clkfbout_reg2: 0x0000,
div_reg: 0x1041,
lock_reg1: 0x03e8,
lock_reg2: 0x7001,
lock_reg3: 0xf3e9,
power_reg: 0x0100,
filt_reg1: 0x0808,
filt_reg2: 0x1100,
},
true,
),
_ => unreachable!(),
};
si549::wrpll::helper_setup(timer, &si549_settings).expect("cannot initialize helper Si549");
si549::wrpll_refclk::setup(timer, mmcm_setting, mmcm_bypass).expect("cannot initialize ref clk for wrpll");
si549::wrpll::select_recovered_clock(true, timer);
}
#[cfg(has_si549)]
fn get_si549_setting(clk: RtioClock) -> si549::FrequencySetting {
match clk {
RtioClock::Ext0_Synth0_10to125 => {
info!("using 10MHz reference to make 125MHz RTIO clock with WRPLL");
}
RtioClock::Ext0_Synth0_80to125 => {
info!("using 80MHz reference to make 125MHz RTIO clock with WRPLL");
}
RtioClock::Ext0_Synth0_100to125 => {
info!("using 100MHz reference to make 125MHz RTIO clock with WRPLL");
}
RtioClock::Ext0_Synth0_125to125 => {
info!("using 125MHz reference to make 125MHz RTIO clock with WRPLL");
}
RtioClock::Int_150 => {
info!("using internal 150MHz RTIO clock");
}
RtioClock::Int_100 => {
info!("using internal 100MHz RTIO clock");
}
RtioClock::Int_125 => {
info!("using internal 125MHz RTIO clock");
}
_ => {
warn!(
"rtio_clock setting '{:?}' is unsupported. Falling back to default internal 125MHz RTIO clock.",
clk
);
}
};
match clk {
RtioClock::Int_100 => {
si549::FrequencySetting {
main: si549::DividerConfig {
hsdiv: 0x06C,
lsdiv: 0,
fbdiv: 0x046C5F49797,
},
helper: si549::DividerConfig {
// 100Mhz*32767/32768
hsdiv: 0x06C,
lsdiv: 0,
fbdiv: 0x046C5670BBD,
},
}
}
_ => {
// Everything else use 125Mhz
si549::FrequencySetting {
main: si549::DividerConfig {
hsdiv: 0x058,
lsdiv: 0,
fbdiv: 0x04815791F25,
},
helper: si549::DividerConfig {
// 125Mhz*32767/32768
hsdiv: 0x058,
lsdiv: 0,
fbdiv: 0x04814E8F442,
},
}
}
}
}
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
let clk = get_rtio_clock_cfg(cfg);
#[cfg(has_si5324)]
@ -274,9 +423,29 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
}
}
#[cfg(has_si549)]
let si549_settings = get_si549_setting(clk);
#[cfg(has_si549)]
si549::main_setup(timer, &si549_settings).expect("cannot initialize main Si549");
#[cfg(has_drtio)]
init_drtio(timer);
#[cfg(not(has_drtio))]
init_rtio(timer);
#[cfg(has_si549)]
{
// SYS CLK switch will reset CSRs that are used by WRPLL
match clk {
RtioClock::Ext0_Synth0_10to125
| RtioClock::Ext0_Synth0_80to125
| RtioClock::Ext0_Synth0_100to125
| RtioClock::Ext0_Synth0_125to125 => {
wrpll_setup(timer, clk, &si549_settings);
}
_ => {}
}
}
}

View File

@ -837,7 +837,6 @@ const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
lsdiv: 0,
fbdiv: 0x04815791F25,
},
#[cfg(has_wrpll)]
helper: si549::DividerConfig {
// 125Mhz*32767/32768
hsdiv: 0x058,
@ -853,7 +852,6 @@ pub const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
lsdiv: 0,
fbdiv: 0x046C5F49797,
},
#[cfg(has_wrpll)]
helper: si549::DividerConfig {
// 100Mhz*32767/32768
hsdiv: 0x06C,
@ -915,7 +913,7 @@ pub extern "C" fn main_core0() -> i32 {
#[cfg(has_si5324)]
si5324::setup(&mut i2c, &SI5324_SETTINGS, si5324::Input::Ckin1, &mut timer).expect("cannot initialize Si5324");
#[cfg(has_si549)]
si549::main_setup(&mut timer, SI549_SETTINGS).expect("cannot initialize main Si549");
si549::main_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize main Si549");
timer.delay_us(100_000);
info!("Switching SYS clocks...");
@ -933,8 +931,8 @@ pub extern "C" fn main_core0() -> i32 {
unsafe {
csr::gt_drtio::txenable_write(0xffffffffu32 as _);
}
#[cfg(has_wrpll)]
si549::wrpll::helper_setup(&mut timer, SI549_SETTINGS).expect("cannot initialize helper Si549");
#[cfg(has_si549)]
si549::wrpll::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
#[cfg(has_drtio_routing)]
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
@ -980,7 +978,7 @@ pub extern "C" fn main_core0() -> i32 {
si5324::siphaser::calibrate_skew(&mut timer).expect("failed to calibrate skew");
}
#[cfg(has_wrpll)]
#[cfg(has_si549)]
si549::wrpll::select_recovered_clock(true, &mut timer);
// Various managers created here, so when link is dropped, all DMA traces
@ -1080,7 +1078,7 @@ pub extern "C" fn main_core0() -> i32 {
info!("uplink is down, switching to local oscillator clock");
#[cfg(has_siphaser)]
si5324::siphaser::select_recovered_clock(&mut i2c, false, &mut timer).expect("failed to switch clocks");
#[cfg(has_wrpll)]
#[cfg(has_si549)]
si549::wrpll::select_recovered_clock(false, &mut timer);
}
}