Compare commits
4 Commits
0d0f9b5a6b
...
673e2fa6de
Author | SHA1 | Date |
---|---|---|
morgan | 673e2fa6de | |
morgan | 5225e2182c | |
morgan | 386b5889fa | |
morgan | 6b130543db |
|
@ -1,23 +1,28 @@
|
|||
from migen import *
|
||||
from migen.genlib.cdc import PulseSynchronizer, MultiReg
|
||||
from migen.genlib.fsm import FSM
|
||||
from misoc.interconnect.csr import *
|
||||
|
||||
|
||||
class DDMTDSampler(Module):
|
||||
def __init__(self, cd_ref, main_clk_se):
|
||||
self.ref_beating = Signal()
|
||||
class DDMTDSamplerGTX(Module):
|
||||
def __init__(self, gtx, main_dcxo_pads):
|
||||
self.gtx_beating = Signal()
|
||||
self.main_beating = Signal()
|
||||
|
||||
# # #
|
||||
|
||||
ref_beating_FF = Signal()
|
||||
main_clk_se = Signal()
|
||||
gtx_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=cd_ref.clk, o_Q=ref_beating_FF),
|
||||
i_D=gtx.cd_rtio_rx0.clk, o_Q=gtx_beating_FF),
|
||||
Instance("FD", i_C=ClockSignal("helper"),
|
||||
i_D=ref_beating_FF, o_Q=self.ref_beating),
|
||||
i_D=gtx_beating_FF, o_Q=self.gtx_beating),
|
||||
Instance("FD", i_C=ClockSignal("helper"),
|
||||
i_D=main_clk_se, o_Q=main_beating_FF),
|
||||
Instance("FD", i_C=ClockSignal("helper"),
|
||||
|
|
|
@ -27,6 +27,7 @@ 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 = {
|
||||
|
@ -48,19 +49,6 @@ 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):
|
||||
|
@ -134,10 +122,24 @@ class GenericStandalone(SoCCore):
|
|||
|
||||
self.config["HW_REV"] = description["hw_rev"]
|
||||
|
||||
self.submodules.clk_synth = ClockSynthesis(self.platform)
|
||||
clk_synth_se_buf = Signal()
|
||||
self.specials += Instance("BUFG", i_I=self.clk_synth.se, o_O=clk_synth_se_buf)
|
||||
|
||||
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()
|
||||
clk_synth_se_buf = Signal()
|
||||
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=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)
|
||||
|
@ -149,23 +151,6 @@ 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:
|
||||
|
@ -239,6 +224,8 @@ 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(
|
||||
|
@ -272,22 +259,8 @@ 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")
|
||||
|
||||
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.config["HAS_SI5324"] = None
|
||||
self.config["SI5324_SOFT_RESET"] = None
|
||||
|
||||
self.rtio_channels = []
|
||||
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
|
||||
|
@ -581,15 +554,17 @@ class GenericSatellite(SoCCore):
|
|||
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
||||
|
||||
if with_wrpll:
|
||||
self.submodules.clk_synth = ClockSynthesis(self.platform)
|
||||
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.wrpll = wrpll.WRPLL(
|
||||
platform=self.platform,
|
||||
cd_ref=self.gt_drtio.cd_rtio_rx0,
|
||||
main_clk_se=self.clk_synth.se)
|
||||
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")
|
||||
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"),
|
||||
|
|
|
@ -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 DDMTDSampler, DDMTD
|
||||
from si549 import Si549
|
||||
from ddmtd import DDMTDSamplerGTX, DDMTD
|
||||
|
||||
|
||||
class FrequencyCounter(Module, AutoCSR):
|
||||
def __init__(self, domains, counter_width=24):
|
||||
def __init__(self, counter_width=24, domains=["gtx0_rtio_rx", "sys"]):
|
||||
for domain in domains:
|
||||
name = "counter_" + domain
|
||||
counter = CSRStatus(counter_width, name=name)
|
||||
|
@ -46,24 +46,21 @@ class FrequencyCounter(Module, AutoCSR):
|
|||
|
||||
|
||||
class WRPLL(Module, AutoCSR):
|
||||
def __init__(self, platform, cd_ref, main_clk_se, COUNTER_BIT=32):
|
||||
self.helper_reset = CSRStorage(reset=1)
|
||||
self.ref_tag = CSRStatus(COUNTER_BIT)
|
||||
def __init__(self, gtx, main_dcxo_pads, helper_dcxo_pads, COUNTER_BIT=32):
|
||||
|
||||
self.gtx_tag = CSRStatus(COUNTER_BIT)
|
||||
self.main_tag = CSRStatus(COUNTER_BIT)
|
||||
|
||||
ddmtd_counter = Signal(COUNTER_BIT)
|
||||
|
||||
ref_tag_sys = Signal(COUNTER_BIT)
|
||||
gtx_tag_sys = Signal(COUNTER_BIT)
|
||||
main_tag_sys = Signal(COUNTER_BIT)
|
||||
ref_tag_stb_sys = Signal()
|
||||
gtx_tag_stb_sys = Signal()
|
||||
main_tag_stb_sys = Signal()
|
||||
|
||||
# # #
|
||||
|
||||
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.helper_reset = CSRStorage(reset=1)
|
||||
self.clock_domains.cd_helper = ClockDomain()
|
||||
self.specials += [
|
||||
Instance("IBUFGDS",
|
||||
|
@ -72,39 +69,39 @@ class WRPLL(Module, AutoCSR):
|
|||
AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage)
|
||||
]
|
||||
|
||||
self.submodules.frequency_counter = FrequencyCounter(["sys", cd_ref.name])
|
||||
self.submodules.frequency_counter = FrequencyCounter()
|
||||
|
||||
self.submodules.ddmtd_sampler = DDMTDSampler(cd_ref, main_clk_se)
|
||||
self.submodules.ddmtd_sampler = DDMTDSamplerGTX(gtx, main_dcxo_pads)
|
||||
|
||||
self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1)
|
||||
self.submodules.ddmtd_ref = DDMTD(ddmtd_counter, self.ddmtd_sampler.ref_beating)
|
||||
self.submodules.ddmtd_gtx = DDMTD(ddmtd_counter, self.ddmtd_sampler.gtx_beating)
|
||||
self.submodules.ddmtd_main = DDMTD(ddmtd_counter, self.ddmtd_sampler.main_beating)
|
||||
|
||||
# DDMTD tags collection
|
||||
|
||||
self.specials += [
|
||||
MultiReg(self.ddmtd_ref.h_tag, ref_tag_sys),
|
||||
MultiReg(self.ddmtd_gtx.h_tag, gtx_tag_sys),
|
||||
MultiReg(self.ddmtd_main.h_tag, main_tag_sys)
|
||||
]
|
||||
|
||||
ref_tag_stb_ps = PulseSynchronizer("helper", "sys")
|
||||
gtx_tag_stb_ps = PulseSynchronizer("helper", "sys")
|
||||
main_tag_stb_ps = PulseSynchronizer("helper", "sys")
|
||||
self.submodules += [
|
||||
ref_tag_stb_ps,
|
||||
gtx_tag_stb_ps,
|
||||
main_tag_stb_ps
|
||||
]
|
||||
self.sync.helper += [
|
||||
ref_tag_stb_ps.i.eq(self.ddmtd_ref.h_tag_update),
|
||||
gtx_tag_stb_ps.i.eq(self.ddmtd_gtx.h_tag_update),
|
||||
main_tag_stb_ps.i.eq(self.ddmtd_main.h_tag_update)
|
||||
]
|
||||
self.sync += [
|
||||
ref_tag_stb_sys.eq(ref_tag_stb_ps.o),
|
||||
gtx_tag_stb_sys.eq(gtx_tag_stb_ps.o),
|
||||
main_tag_stb_sys.eq(main_tag_stb_ps.o)
|
||||
]
|
||||
|
||||
self.sync += [
|
||||
If(ref_tag_stb_sys,
|
||||
self.ref_tag.status.eq(ref_tag_sys),
|
||||
If(gtx_tag_stb_sys,
|
||||
self.gtx_tag.status.eq(gtx_tag_sys),
|
||||
),
|
||||
If(main_tag_stb_sys,
|
||||
self.main_tag.status.eq(main_tag_sys)
|
||||
|
@ -113,81 +110,17 @@ class WRPLL(Module, AutoCSR):
|
|||
|
||||
# PL->PS interrupt
|
||||
|
||||
self.submodules.ref_tag_ev = EventManager()
|
||||
self.ref_tag_ev.stb = EventSourcePulse()
|
||||
self.ref_tag_ev.finalize()
|
||||
self.submodules.gtx_tag_ev = EventManager()
|
||||
self.gtx_tag_ev.stb = EventSourcePulse()
|
||||
self.gtx_tag_ev.finalize()
|
||||
|
||||
self.submodules.main_tag_ev = EventManager()
|
||||
self.main_tag_ev.stb = EventSourcePulse()
|
||||
self.main_tag_ev.finalize()
|
||||
|
||||
self.sync += [
|
||||
self.ref_tag_ev.stb.trigger.eq(ref_tag_stb_sys),
|
||||
self.gtx_tag_ev.stb.trigger.eq(gtx_tag_stb_sys),
|
||||
self.main_tag_ev.stb.trigger.eq(main_tag_stb_sys)
|
||||
]
|
||||
|
||||
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),
|
||||
]
|
||||
self.submodules.ev = SharedIRQ(self.gtx_tag_ev, self.main_tag_ev)
|
|
@ -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"] }
|
||||
libsupport_zynq = { path = "@@ZYNQ_RS@@/libsupport_zynq", default-features = false, features = ["alloc_core", "dummy_fiq_handler"] }
|
||||
libregister = { path = "@@ZYNQ_RS@@/libregister" }
|
||||
libconfig = { path = "@@ZYNQ_RS@@/libconfig", features = ["fat_lfn"] }
|
||||
libcortex_a9 = { path = "@@ZYNQ_RS@@/libcortex_a9" }
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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.
|
||||
|
@ -38,7 +37,6 @@ 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],
|
||||
|
@ -48,18 +46,17 @@ pub struct IoExpander {
|
|||
|
||||
impl IoExpander {
|
||||
pub fn new(i2c: &mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
|
||||
#[cfg(all(hw_rev = "v1.0", has_virtual_leds))]
|
||||
#[cfg(hw_rev = "v1.0")]
|
||||
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)];
|
||||
#[cfg(all(hw_rev = "v1.1", has_virtual_leds))]
|
||||
#[cfg(hw_rev = "v1.1")]
|
||||
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],
|
||||
|
@ -73,7 +70,6 @@ impl IoExpander {
|
|||
},
|
||||
1 => IoExpander {
|
||||
address: 0x42,
|
||||
#[cfg(has_virtual_leds)]
|
||||
virtual_led_mapping: &VIRTUAL_LED_MAPPING1,
|
||||
iodir: IODIR1,
|
||||
out_current: [0; 2],
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#![no_std]
|
||||
#![feature(never_type)]
|
||||
#![feature(naked_functions)]
|
||||
#![feature(asm)]
|
||||
|
||||
extern crate core_io;
|
||||
extern crate crc;
|
||||
|
@ -21,8 +19,7 @@ pub mod drtioaux;
|
|||
#[cfg(has_drtio)]
|
||||
pub mod drtioaux_async;
|
||||
pub mod drtioaux_proto;
|
||||
pub mod fiq;
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
|
||||
pub mod io_expander;
|
||||
pub mod logger;
|
||||
#[cfg(has_drtio)]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use core::result::Result::Ok;
|
||||
|
||||
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
|
||||
use libboard_zynq::timer::GlobalTimer;
|
||||
use log::info;
|
||||
|
@ -15,6 +17,7 @@ pub struct DividerConfig {
|
|||
|
||||
pub struct FrequencySetting {
|
||||
pub main: DividerConfig,
|
||||
#[cfg(has_wrpll)]
|
||||
pub helper: DividerConfig,
|
||||
}
|
||||
|
||||
|
@ -24,6 +27,7 @@ mod i2c {
|
|||
#[derive(Clone, Copy)]
|
||||
pub enum DCXO {
|
||||
Main,
|
||||
#[cfg(has_wrpll)]
|
||||
Helper,
|
||||
}
|
||||
|
||||
|
@ -33,40 +37,45 @@ mod i2c {
|
|||
|
||||
fn sda_i(dcxo: DCXO) -> bool {
|
||||
match dcxo {
|
||||
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_in_read() == 1 },
|
||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_in_read() == 1 },
|
||||
DCXO::Main => unsafe { csr::main_dcxo::sda_in_read() == 1 },
|
||||
#[cfg(has_wrpll)]
|
||||
DCXO::Helper => unsafe { csr::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::wrpll::main_dcxo_sda_oe_write(val) },
|
||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_oe_write(val) },
|
||||
DCXO::Main => unsafe { csr::main_dcxo::sda_oe_write(val) },
|
||||
#[cfg(has_wrpll)]
|
||||
DCXO::Helper => unsafe { csr::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::wrpll::main_dcxo_sda_out_write(val) },
|
||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_out_write(val) },
|
||||
DCXO::Main => unsafe { csr::main_dcxo::sda_out_write(val) },
|
||||
#[cfg(has_wrpll)]
|
||||
DCXO::Helper => unsafe { csr::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::wrpll::main_dcxo_scl_oe_write(val) },
|
||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_oe_write(val) },
|
||||
DCXO::Main => unsafe { csr::main_dcxo::scl_oe_write(val) },
|
||||
#[cfg(has_wrpll)]
|
||||
DCXO::Helper => unsafe { csr::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::wrpll::main_dcxo_scl_out_write(val) },
|
||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_out_write(val) },
|
||||
DCXO::Main => unsafe { csr::main_dcxo::scl_out_write(val) },
|
||||
#[cfg(has_wrpll)]
|
||||
DCXO::Helper => unsafe { csr::helper_dcxo::scl_out_write(val) },
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -210,7 +219,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
|
||||
|
@ -243,25 +252,26 @@ fn setup(dcxo: i2c::DCXO, config: &DividerConfig, timer: &mut GlobalTimer) -> Re
|
|||
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::wrpll::main_dcxo_bitbang_enable_write(1);
|
||||
csr::wrpll::main_dcxo_i2c_address_write(ADDRESS);
|
||||
csr::main_dcxo::bitbang_enable_write(1);
|
||||
csr::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::wrpll::main_dcxo_bitbang_enable_write(0);
|
||||
csr::main_dcxo::bitbang_enable_write(0);
|
||||
}
|
||||
|
||||
info!("Main Si549 started");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(has_wrpll)]
|
||||
pub mod wrpll {
|
||||
|
||||
use libcortex_a9::mutex::Mutex;
|
||||
|
@ -281,8 +291,8 @@ pub mod wrpll {
|
|||
static M_INTEGRATOR: Mutex<i32> = Mutex::new(0);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ISR {
|
||||
RefTag,
|
||||
pub enum FIQ {
|
||||
GTXTag,
|
||||
MainTag,
|
||||
}
|
||||
|
||||
|
@ -292,29 +302,29 @@ pub mod wrpll {
|
|||
const BEATING_PERIOD: i32 = 0x8000;
|
||||
const BEATING_HALFPERIOD: i32 = 0x4000;
|
||||
|
||||
static REF_TAG: Mutex<u32> = Mutex::new(0);
|
||||
static REF_TAG_READY: Mutex<bool> = Mutex::new(false);
|
||||
static GTX_TAG: Mutex<u32> = Mutex::new(0);
|
||||
static GTX_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();
|
||||
*REF_TAG.lock() = 0;
|
||||
*GTX_TAG.lock() = 0;
|
||||
*MAIN_TAG.lock() = 0;
|
||||
}
|
||||
|
||||
pub fn clear_phase_diff_ready() {
|
||||
*REF_TAG_READY.lock() = false;
|
||||
*GTX_TAG_READY.lock() = false;
|
||||
*MAIN_TAG_READY.lock() = false;
|
||||
}
|
||||
|
||||
pub fn collect_tags(interrupt: ISR) {
|
||||
pub fn collect_tags(interrupt: FIQ) {
|
||||
match interrupt {
|
||||
ISR::RefTag => {
|
||||
*REF_TAG.lock() = unsafe { csr::wrpll::ref_tag_read() };
|
||||
*REF_TAG_READY.lock() = true;
|
||||
FIQ::GTXTag => {
|
||||
*GTX_TAG.lock() = unsafe { csr::wrpll::gtx_tag_read() };
|
||||
*GTX_TAG_READY.lock() = true;
|
||||
}
|
||||
ISR::MainTag => {
|
||||
FIQ::MainTag => {
|
||||
*MAIN_TAG.lock() = unsafe { csr::wrpll::main_tag_read() };
|
||||
*MAIN_TAG_READY.lock() = true;
|
||||
}
|
||||
|
@ -322,12 +332,12 @@ pub mod wrpll {
|
|||
}
|
||||
|
||||
pub fn phase_diff_ready() -> bool {
|
||||
*REF_TAG_READY.lock() && *MAIN_TAG_READY.lock()
|
||||
*GTX_TAG_READY.lock() && *MAIN_TAG_READY.lock()
|
||||
}
|
||||
|
||||
pub fn get_period_error() -> 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;
|
||||
// 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;
|
||||
|
||||
// mapping tags from [0, 2π] -> [-π, π]
|
||||
if period_error > BEATING_HALFPERIOD {
|
||||
|
@ -337,9 +347,9 @@ pub mod wrpll {
|
|||
}
|
||||
|
||||
pub fn get_phase_error() -> i32 {
|
||||
// MAIN_TAG(n) - REF_TAG(n) mod BEATING_PERIOD
|
||||
// MAIN_TAG(n) - GTX_TAG(n) mod BEATING_PERIOD
|
||||
let mut phase_error = (*MAIN_TAG.lock())
|
||||
.overflowing_sub(*REF_TAG.lock())
|
||||
.overflowing_sub(*GTX_TAG.lock())
|
||||
.0
|
||||
.rem_euclid(BEATING_PERIOD as u32) as i32;
|
||||
|
||||
|
@ -351,30 +361,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::wrpll::helper_dcxo_bitbang_enable_write(1);
|
||||
csr::wrpll::helper_dcxo_i2c_address_write(ADDRESS);
|
||||
csr::helper_dcxo::bitbang_enable_write(1);
|
||||
csr::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::wrpll::helper_dcxo_bitbang_enable_write(0);
|
||||
csr::helper_dcxo::bitbang_enable_write(0);
|
||||
}
|
||||
info!("Helper Si549 started");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_isr(en: bool) {
|
||||
fn set_fiq(en: bool) {
|
||||
let val = if en { 1 } else { 0 };
|
||||
unsafe {
|
||||
csr::wrpll::ref_tag_ev_enable_write(val);
|
||||
csr::wrpll::gtx_tag_ev_enable_write(val);
|
||||
csr::wrpll::main_tag_ev_enable_write(val);
|
||||
}
|
||||
}
|
||||
|
@ -388,34 +398,34 @@ pub mod wrpll {
|
|||
|
||||
match dcxo {
|
||||
i2c::DCXO::Main => unsafe {
|
||||
if csr::wrpll::main_dcxo_bitbang_enable_read() == 1 {
|
||||
if csr::main_dcxo::bitbang_enable_read() == 1 {
|
||||
return Err("Main si549 bitbang mode is active when using gateware i2c");
|
||||
}
|
||||
|
||||
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);
|
||||
while csr::main_dcxo::adpll_busy_read() == 1 {}
|
||||
csr::main_dcxo::i2c_address_write(ADDRESS);
|
||||
csr::main_dcxo::adpll_write(adpll as u32);
|
||||
|
||||
csr::wrpll::main_dcxo_adpll_stb_write(1);
|
||||
csr::wrpll::main_dcxo_adpll_stb_write(0);
|
||||
csr::main_dcxo::adpll_stb_write(1);
|
||||
csr::main_dcxo::adpll_stb_write(0);
|
||||
|
||||
if csr::wrpll::main_dcxo_nack_read() == 1 {
|
||||
if csr::main_dcxo::nack_read() == 1 {
|
||||
return Err("Main si549 failed to ack adpll write");
|
||||
}
|
||||
},
|
||||
i2c::DCXO::Helper => unsafe {
|
||||
if csr::wrpll::helper_dcxo_bitbang_enable_read() == 1 {
|
||||
if csr::helper_dcxo::bitbang_enable_read() == 1 {
|
||||
return Err("Helper si549 bitbang mode is active when using gateware i2c");
|
||||
}
|
||||
|
||||
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);
|
||||
while csr::helper_dcxo::adpll_busy_read() == 1 {}
|
||||
csr::helper_dcxo::i2c_address_write(ADDRESS);
|
||||
csr::helper_dcxo::adpll_write(adpll as u32);
|
||||
|
||||
csr::wrpll::helper_dcxo_adpll_stb_write(1);
|
||||
csr::wrpll::helper_dcxo_adpll_stb_write(0);
|
||||
csr::helper_dcxo::adpll_stb_write(1);
|
||||
csr::helper_dcxo::adpll_stb_write(0);
|
||||
|
||||
if csr::wrpll::helper_dcxo_nack_read() == 1 {
|
||||
if csr::helper_dcxo::nack_read() == 1 {
|
||||
return Err("Helper si549 failed to ack adpll write");
|
||||
}
|
||||
},
|
||||
|
@ -429,9 +439,9 @@ pub mod wrpll {
|
|||
let count2adpll =
|
||||
|error: i32| (((error) as f64 * 1e6) / (0.0001164 * (1 << (TIMER_WIDTH - COUNTER_DIV)) as f64)) as i32;
|
||||
|
||||
let (ref_count, main_count) = get_freq_counts(timer);
|
||||
let (gtx_count, main_count) = get_freq_counts(timer);
|
||||
let mut base_adpll_lock = BASE_ADPLL.lock();
|
||||
*base_adpll_lock = count2adpll(ref_count as i32 - main_count as i32);
|
||||
*base_adpll_lock = count2adpll(gtx_count as i32 - main_count as i32);
|
||||
set_adpll(i2c::DCXO::Main, *base_adpll_lock)?;
|
||||
set_adpll(i2c::DCXO::Helper, *base_adpll_lock)?;
|
||||
|
||||
|
@ -443,13 +453,10 @@ 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);
|
||||
#[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();
|
||||
let gtx = csr::wrpll::frequency_counter_counter_gtx0_rtio_rx_read();
|
||||
let main = csr::wrpll::frequency_counter_counter_sys_read();
|
||||
|
||||
(ref_count, main_count)
|
||||
(gtx, main)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -461,31 +468,31 @@ pub mod wrpll {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn clear_pending(interrupt: ISR) {
|
||||
fn clear_pending(interrupt: FIQ) {
|
||||
match interrupt {
|
||||
ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_write(1) },
|
||||
ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) },
|
||||
FIQ::GTXTag => unsafe { csr::wrpll::gtx_tag_ev_pending_write(1) },
|
||||
FIQ::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) },
|
||||
};
|
||||
}
|
||||
|
||||
fn is_pending(interrupt: ISR) -> bool {
|
||||
fn is_pending(interrupt: FIQ) -> bool {
|
||||
match interrupt {
|
||||
ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_read() == 1 },
|
||||
ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_read() == 1 },
|
||||
FIQ::GTXTag => unsafe { csr::wrpll::gtx_tag_ev_pending_read() == 1 },
|
||||
FIQ::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_read() == 1 },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interrupt_handler() {
|
||||
if is_pending(ISR::RefTag) {
|
||||
tag_collector::collect_tags(ISR::RefTag);
|
||||
clear_pending(ISR::RefTag);
|
||||
if is_pending(FIQ::GTXTag) {
|
||||
tag_collector::collect_tags(FIQ::GTXTag);
|
||||
clear_pending(FIQ::GTXTag);
|
||||
|
||||
helper_pll().expect("failed to run helper DCXO PLL");
|
||||
}
|
||||
|
||||
if is_pending(ISR::MainTag) {
|
||||
tag_collector::collect_tags(ISR::MainTag);
|
||||
clear_pending(ISR::MainTag);
|
||||
if is_pending(FIQ::MainTag) {
|
||||
tag_collector::collect_tags(FIQ::MainTag);
|
||||
clear_pending(FIQ::MainTag);
|
||||
}
|
||||
|
||||
if tag_collector::phase_diff_ready() {
|
||||
|
@ -521,167 +528,24 @@ pub mod wrpll {
|
|||
}
|
||||
|
||||
pub fn select_recovered_clock(rc: bool, timer: &mut GlobalTimer) {
|
||||
set_isr(false);
|
||||
set_fiq(false);
|
||||
|
||||
if rc {
|
||||
tag_collector::reset();
|
||||
reset_plls().expect("failed to reset main and helper PLL");
|
||||
|
||||
info!("warming up refclk...");
|
||||
// refclk need a couple seconds for freq counter to read it properly
|
||||
info!("warming up GTX CDR...");
|
||||
// gtx 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(ISR::RefTag);
|
||||
clear_pending(ISR::MainTag);
|
||||
clear_pending(FIQ::GTXTag);
|
||||
clear_pending(FIQ::MainTag);
|
||||
|
||||
// use nFIQ to avoid IRQ being disabled by mutex lock and mess up PLL
|
||||
set_isr(true);
|
||||
set_fiq(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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
#[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_si549)]
|
||||
#[cfg(has_wrpll)]
|
||||
si549::wrpll::interrupt_handler();
|
||||
return;
|
||||
}
|
|
@ -21,6 +21,7 @@ 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;
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
|
||||
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
|
||||
use core::cell::RefCell;
|
||||
|
||||
use ksupport;
|
||||
use libasync::task;
|
||||
#[cfg(has_drtio_eem)]
|
||||
use libboard_artiq::drtio_eem;
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
|
||||
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_virtual_leds))]
|
||||
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
|
||||
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(feature = "target_kasli_soc")]
|
||||
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
|
||||
{
|
||||
let i2c_bus = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() };
|
||||
let mut io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap();
|
||||
|
@ -112,11 +112,6 @@ 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);
|
||||
|
@ -124,7 +119,6 @@ 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),
|
||||
|
|
|
@ -4,8 +4,6 @@ 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;
|
||||
|
@ -262,153 +260,6 @@ 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)]
|
||||
|
@ -423,29 +274,9 @@ 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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -837,6 +837,7 @@ const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
|
|||
lsdiv: 0,
|
||||
fbdiv: 0x04815791F25,
|
||||
},
|
||||
#[cfg(has_wrpll)]
|
||||
helper: si549::DividerConfig {
|
||||
// 125Mhz*32767/32768
|
||||
hsdiv: 0x058,
|
||||
|
@ -852,6 +853,7 @@ pub const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
|
|||
lsdiv: 0,
|
||||
fbdiv: 0x046C5F49797,
|
||||
},
|
||||
#[cfg(has_wrpll)]
|
||||
helper: si549::DividerConfig {
|
||||
// 100Mhz*32767/32768
|
||||
hsdiv: 0x06C,
|
||||
|
@ -913,7 +915,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...");
|
||||
|
@ -931,8 +933,8 @@ pub extern "C" fn main_core0() -> i32 {
|
|||
unsafe {
|
||||
csr::gt_drtio::txenable_write(0xffffffffu32 as _);
|
||||
}
|
||||
#[cfg(has_si549)]
|
||||
si549::wrpll::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
|
||||
#[cfg(has_wrpll)]
|
||||
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()];
|
||||
|
@ -978,7 +980,7 @@ pub extern "C" fn main_core0() -> i32 {
|
|||
si5324::siphaser::calibrate_skew(&mut timer).expect("failed to calibrate skew");
|
||||
}
|
||||
|
||||
#[cfg(has_si549)]
|
||||
#[cfg(has_wrpll)]
|
||||
si549::wrpll::select_recovered_clock(true, &mut timer);
|
||||
|
||||
// Various managers created here, so when link is dropped, all DMA traces
|
||||
|
@ -1078,7 +1080,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_si549)]
|
||||
#[cfg(has_wrpll)]
|
||||
si549::wrpll::select_recovered_clock(false, &mut timer);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue