diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index f1519b646..ca942caa5 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -44,6 +44,8 @@ use board_artiq::drtioaux; use board_artiq::drtio_routing; use board_artiq::{mailbox, rpc_queue}; use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; +#[cfg(has_wrpll)] +use board_artiq::si549; #[cfg(has_drtio_eem)] use board_artiq::drtio_eem; #[cfg(has_rtio_analyzer)] @@ -269,6 +271,8 @@ pub extern fn main() -> i32 { #[cfg(soc_platform = "kasli")] irq::enable_interrupts(); + #[cfg(has_wrpll)] + irq::enable(csr::WRPLL_INTERRUPT); logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(|| boot::start_user(startup as usize) @@ -304,8 +308,11 @@ pub extern fn exception(regs: *const TrapFrame) { let pc = mepc::read(); let cause = mcause::read().cause(); match cause { - mcause::Trap::Interrupt(source) => { - info!("Called interrupt with {:?}", source); + mcause::Trap::Interrupt(_source) => { + #[cfg(has_wrpll)] + if irq::is_pending(csr::WRPLL_INTERRUPT) { + si549::wrpll::interrupt_handler(); + } }, mcause::Trap::Exception(mcause::Exception::UserEnvCall) => { diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 3f11da950..64236c749 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -1,8 +1,11 @@ use board_misoc::config; +#[cfg(has_si5324)] use board_artiq::si5324; +#[cfg(has_si549)] +use board_artiq::si549; use board_misoc::{csr, clock}; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)] #[allow(non_camel_case_types)] pub enum RtioClock { Default, @@ -89,13 +92,14 @@ pub mod crg { // Si5324 input to select for locking to an external clock (as opposed to // a recovered link clock in DRTIO satellites, which is handled elsewhere). -#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] +#[cfg(all(has_si5324, soc_platform = "kasli", hw_rev = "v2.0"))] const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin1; -#[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] +#[cfg(all(has_si5324, soc_platform = "kasli", not(hw_rev = "v2.0")))] const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin2; -#[cfg(all(soc_platform = "kc705"))] +#[cfg(all(has_si5324, soc_platform = "kc705"))] const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin2; +#[cfg(has_si5324)] fn setup_si5324_pll(cfg: RtioClock) { let (si5324_settings, si5324_ref_input) = match cfg { RtioClock::Ext0_Synth0_10to125 => { // 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW @@ -214,7 +218,7 @@ fn setup_si5324_pll(cfg: RtioClock) { si5324::setup(&si5324_settings, si5324_ref_input).expect("cannot initialize Si5324"); } -fn setup_si5324(clock_cfg: RtioClock) { +fn sysclk_setup(clock_cfg: RtioClock) { let switched = unsafe { csr::crg::switch_done_read() }; @@ -222,6 +226,8 @@ fn setup_si5324(clock_cfg: RtioClock) { info!("Clocking has already been set up."); return; } + + #[cfg(has_si5324)] match clock_cfg { RtioClock::Ext0_Bypass => { info!("using external RTIO clock with PLL bypass"); @@ -230,7 +236,10 @@ fn setup_si5324(clock_cfg: RtioClock) { _ => setup_si5324_pll(clock_cfg), } - // switch sysclk source to si5324 + #[cfg(has_si549)] + si549::main_setup(&get_si549_setting(clock_cfg)).expect("cannot initialize main Si549"); + + // switch sysclk source #[cfg(not(has_drtio))] { info!("Switching sys clock, rebooting..."); @@ -244,9 +253,153 @@ fn setup_si5324(clock_cfg: RtioClock) { } +#[cfg(all(has_si549, has_wrpll))] +fn wrpll_setup(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: 0x1008, + filt_reg2: 0x8800, + }, + 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: 0x9908, + filt_reg2: 0x8100, + }, + 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: 0x9108, + filt_reg2: 0x0100, + }, + 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: 0x9908, + filt_reg2: 0x1100, + }, + true, + ), + _ => unreachable!(), + }; + + si549::helper_setup(&si549_settings).expect("cannot initialize helper Si549"); + si549::wrpll_refclk::setup(mmcm_setting, mmcm_bypass).expect("cannot initialize ref clk for wrpll"); + si549::wrpll::select_recovered_clock(true); +} + +#[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_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() { let clock_cfg = get_rtio_clock_cfg(); - setup_si5324(clock_cfg); + sysclk_setup(clock_cfg); #[cfg(has_drtio)] { @@ -282,4 +435,18 @@ pub fn init() { error!("RTIO clock failed"); } } + + #[cfg(all(has_si549, has_wrpll))] + { + // SYS CLK switch will reset CSRs that are used by WRPLL + match clock_cfg { + RtioClock::Ext0_Synth0_10to125 + | RtioClock::Ext0_Synth0_80to125 + | RtioClock::Ext0_Synth0_100to125 + | RtioClock::Ext0_Synth0_125to125 => { + wrpll_setup(clock_cfg, &get_si549_setting(clock_cfg)); + } + _ => {} + } + } }