diff --git a/src/libboard_artiq/src/cxp_phys.rs b/src/libboard_artiq/src/cxp_phys.rs index cfcd361..bc42bb5 100644 --- a/src/libboard_artiq/src/cxp_phys.rs +++ b/src/libboard_artiq/src/cxp_phys.rs @@ -4,6 +4,8 @@ use log::info; use crate::pl::{csr, csr::CXP}; +const CHANNEL_LEN: usize = csr::CXP_LEN; + #[derive(Clone, Copy, Debug)] #[allow(non_camel_case_types)] pub enum CXP_SPEED { @@ -19,36 +21,35 @@ pub enum CXP_SPEED { pub fn setup(timer: &mut GlobalTimer) { down_conn::setup(timer); up_conn::setup(); + change_linerate(CXP_SPEED::CXP_1); } -pub fn change_linerate(channel: usize, timer: &mut GlobalTimer, speed: CXP_SPEED) { - info!("Changing channel {}'s datarate to {:?}", channel, speed); - down_conn::change_linerate(channel, timer, speed); - up_conn::change_linerate(channel, speed); +pub fn change_linerate(speed: CXP_SPEED) { + info!("Changing all channels datarate to {:?}", speed); + down_conn::change_linerate(speed); + up_conn::change_linerate(speed); } mod up_conn { use super::*; pub fn setup() { - // TODO: do a for loop for channel? - let channel: usize = 0; unsafe { - change_linerate(channel, CXP_SPEED::CXP_1); - (CXP[channel].upconn_tx_enable_write)(1); + csr::cxp_phys::upconn_tx_enable_write(1); } } - pub fn change_linerate(channel: usize, speed: CXP_SPEED) { + pub fn change_linerate(speed: CXP_SPEED) { unsafe { - (CXP[channel].upconn_clk_reset_write)(1); match speed { - CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => { - (CXP[channel].upconn_bitrate2x_enable_write)(1); + CXP_SPEED::CXP_1 | CXP_SPEED::CXP_2 | CXP_SPEED::CXP_3 | CXP_SPEED::CXP_5 | CXP_SPEED::CXP_6 => { + csr::cxp_phys::upconn_bitrate2x_enable_write(0); + } + CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => { + csr::cxp_phys::upconn_bitrate2x_enable_write(1); } - _ => {} }; - (CXP[channel].upconn_clk_reset_write)(0); + csr::cxp_phys::upconn_clk_reset_write(1); } } } @@ -57,11 +58,11 @@ mod down_conn { use super::*; pub fn setup(timer: &mut GlobalTimer) { - // TODO: do a for loop for channel? - let channel: usize = 0; unsafe { info!("turning on pmc loopback mode..."); - (CXP[channel].downconn_loopback_mode_write)(0b010); // Near-End PMA Loopback + for channel in 0..CHANNEL_LEN { + (CXP[channel].downconn_loopback_mode_write)(0b010); // Near-End PMA Loopback + } // QPLL setup csr::cxp_phys::downconn_qpll_reset_write(1); @@ -69,41 +70,44 @@ mod down_conn { while csr::cxp_phys::downconn_qpll_locked_read() != 1 {} info!("QPLL locked"); - // tx/rx setup - (CXP[channel].downconn_tx_start_init_write)(1); - (CXP[channel].downconn_rx_start_init_write)(1); + for channel in 0..CHANNEL_LEN { + // tx/rx setup + (CXP[channel].downconn_tx_start_init_write)(1); + (CXP[channel].downconn_rx_start_init_write)(1); + } + // DEBUG: printout info!("waiting for tx & rx setup..."); timer.delay_us(50_000); - info!( - "tx_phaligndone = {} | rx_phaligndone = {}", - (CXP[channel].downconn_txinit_phaligndone_read)(), - (CXP[channel].downconn_rxinit_phaligndone_read)(), - ); + for channel in 0..CHANNEL_LEN { + info!( + "tx_phaligndone = {} | rx_phaligndone = {}", + (CXP[channel].downconn_txinit_phaligndone_read)(), + (CXP[channel].downconn_rxinit_phaligndone_read)(), + ); + } } - - change_linerate(channel, timer, CXP_SPEED::CXP_1); } - pub fn change_linerate(channel: usize, timer: &mut GlobalTimer, speed: CXP_SPEED) { + pub fn change_linerate(speed: CXP_SPEED) { // DEBUG: DRP pll for TXUSRCLK = freq(linerate)/20 let settings = txusrclk::get_txusrclk_config(speed); - txusrclk::setup(channel, timer, settings); + txusrclk::setup(settings); change_qpll_fb_divider(speed); - change_gtx_divider(channel, speed); - change_cdr_cfg(channel, speed); + change_gtx_divider(speed); + change_cdr_cfg(speed); unsafe { csr::cxp_phys::downconn_qpll_reset_write(1); info!("waiting for QPLL/CPLL to lock..."); while csr::cxp_phys::downconn_qpll_locked_read() != 1 {} info!("QPLL locked"); - } - unsafe { - (CXP[channel].downconn_tx_restart_write)(1); - (CXP[channel].downconn_rx_restart_write)(1); + for channel in 0..CHANNEL_LEN { + (CXP[channel].downconn_tx_restart_write)(1); + (CXP[channel].downconn_rx_restart_write)(1); + } } } @@ -118,7 +122,7 @@ mod down_conn { println!("0x36 = {:#06x}", qpll_read(0x36)); } - fn change_gtx_divider(channel: usize, speed: CXP_SPEED) { + fn change_gtx_divider(speed: CXP_SPEED) { let div_reg = match speed { CXP_SPEED::CXP_1 => 0x33, // RXOUT_DIV = 8 CXP_SPEED::CXP_2 | CXP_SPEED::CXP_3 => 0x22, // RXOUT_DIV = 4 @@ -126,12 +130,14 @@ mod down_conn { CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => 0x00, // RXOUT_DIV = 1 }; - println!("0x88 = {:#06x}", gtx_read(channel, 0x88)); - gtx_write(channel, 0x88, div_reg); - println!("0x88 = {:#06x}", gtx_read(channel, 0x88)); + for channel in 0..CHANNEL_LEN { + println!("channel {}, 0x88 = {:#06x}", channel, gtx_read(channel, 0x88)); + gtx_write(channel, 0x88, div_reg); + println!("channel {}, 0x88 = {:#06x}", channel, gtx_read(channel, 0x88)); + } } - fn change_cdr_cfg(channel: usize, speed: CXP_SPEED) { + fn change_cdr_cfg(speed: CXP_SPEED) { struct CdrConfig { pub cfg_reg0: u16, // addr = 0xA8 pub cfg_reg1: u16, // addr = 0xA9 @@ -175,11 +181,13 @@ mod down_conn { }, }; - gtx_write(channel, 0x0A8, cdr_cfg.cfg_reg0); - gtx_write(channel, 0x0A9, cdr_cfg.cfg_reg1); - gtx_write(channel, 0x0AA, cdr_cfg.cfg_reg2); - gtx_write(channel, 0x0AB, cdr_cfg.cfg_reg3); - gtx_write(channel, 0x0AC, cdr_cfg.cfg_reg4); + for channel in 0..CHANNEL_LEN { + gtx_write(channel, 0x0A8, cdr_cfg.cfg_reg0); + gtx_write(channel, 0x0A9, cdr_cfg.cfg_reg1); + gtx_write(channel, 0x0AA, cdr_cfg.cfg_reg2); + gtx_write(channel, 0x0AB, cdr_cfg.cfg_reg3); + gtx_write(channel, 0x0AC, cdr_cfg.cfg_reg4); + } } #[allow(dead_code)] @@ -224,6 +232,7 @@ mod down_conn { pub mod txusrclk { use super::*; + #[derive(Copy, Clone)] pub struct PLLSetting { pub clkout0_reg1: u16, //0x08 pub clkout0_reg2: u16, //0x09 @@ -317,41 +326,41 @@ mod down_conn { } } - pub fn setup(channel: usize, timer: &mut GlobalTimer, settings: PLLSetting) { - if false { - info!("0x08 = {:#06x}", read(channel, 0x08)); - info!("0x09 = {:#06x}", read(channel, 0x09)); - info!("0x14 = {:#06x}", read(channel, 0x14)); - info!("0x15 = {:#06x}", read(channel, 0x15)); - info!("0x16 = {:#06x}", read(channel, 0x16)); - info!("0x18 = {:#06x}", read(channel, 0x18)); - info!("0x19 = {:#06x}", read(channel, 0x19)); - info!("0x1A = {:#06x}", read(channel, 0x1A)); - info!("0x28 = {:#06x}", read(channel, 0x28)); - info!("0x4E = {:#06x}", read(channel, 0x4E)); - info!("0x4F = {:#06x}", read(channel, 0x4F)); - } else { - // Based on "DRP State Machine" from XAPP888 - // hold reset HIGH during pll config - reset(channel, true); - write(channel, 0x08, settings.clkout0_reg1); - write(channel, 0x09, settings.clkout0_reg2); - write(channel, 0x14, settings.clkfbout_reg1); - write(channel, 0x15, settings.clkfbout_reg2); - write(channel, 0x16, settings.div_reg); - write(channel, 0x18, settings.lock_reg1); - write(channel, 0x19, settings.lock_reg2); - write(channel, 0x1A, settings.lock_reg3); - write(channel, 0x28, settings.power_reg); - write(channel, 0x4E, settings.filt_reg1); - write(channel, 0x4F, settings.filt_reg2); - reset(channel, false); + pub fn setup(settings: PLLSetting) { + for channel in 0..CHANNEL_LEN { + if false { + info!("0x08 = {:#06x}", read(channel, 0x08)); + info!("0x09 = {:#06x}", read(channel, 0x09)); + info!("0x14 = {:#06x}", read(channel, 0x14)); + info!("0x15 = {:#06x}", read(channel, 0x15)); + info!("0x16 = {:#06x}", read(channel, 0x16)); + info!("0x18 = {:#06x}", read(channel, 0x18)); + info!("0x19 = {:#06x}", read(channel, 0x19)); + info!("0x1A = {:#06x}", read(channel, 0x1A)); + info!("0x28 = {:#06x}", read(channel, 0x28)); + info!("0x4E = {:#06x}", read(channel, 0x4E)); + info!("0x4F = {:#06x}", read(channel, 0x4F)); + } else { + // Based on "DRP State Machine" from XAPP888 + // hold reset HIGH during pll config + reset(channel, true); + write(channel, 0x08, settings.clkout0_reg1); + write(channel, 0x09, settings.clkout0_reg2); + write(channel, 0x14, settings.clkfbout_reg1); + write(channel, 0x15, settings.clkfbout_reg2); + write(channel, 0x16, settings.div_reg); + write(channel, 0x18, settings.lock_reg1); + write(channel, 0x19, settings.lock_reg2); + write(channel, 0x1A, settings.lock_reg3); + write(channel, 0x28, settings.power_reg); + write(channel, 0x4E, settings.filt_reg1); + write(channel, 0x4F, settings.filt_reg2); + reset(channel, false); - // wait for the pll to lock - timer.delay_us(100); - - let locked = unsafe { (CXP[channel].downconn_txpll_locked_read)() == 1 }; - info!("txusrclk locked = {}", locked); + info!("waiting for PLL of txusrclk to lock..."); + while unsafe { (CXP[channel].downconn_txpll_locked_read)() == 0 } {} + info!("txusrclk locked :D"); + } } }