diff --git a/src/libboard_artiq/src/cxp_downconn.rs b/src/libboard_artiq/src/cxp_downconn.rs index 2ae44b8..0a1e5ec 100644 --- a/src/libboard_artiq/src/cxp_downconn.rs +++ b/src/libboard_artiq/src/cxp_downconn.rs @@ -2,25 +2,11 @@ use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs; use libboard_zynq::{println, timer::GlobalTimer}; use log::info; -// use log::info; -use crate::{cxp_proto, - pl::{csr, csr::CXP}}; +use crate::{cxp_phys, cxp_proto, pl::csr::CXP}; -#[derive(Clone, Copy, Debug)] -#[allow(non_camel_case_types)] -pub enum CXP_SPEED { - CXP_1, - CXP_2, - CXP_3, - CXP_5, - CXP_6, - CXP_10, - CXP_12, -} - -pub fn loopback_testing(channel: usize, timer: &mut GlobalTimer, speed: CXP_SPEED) { +pub fn loopback_testing(channel: usize, timer: &mut GlobalTimer, speed: cxp_phys::CXP_SPEED) { println!("=============================================================================="); - cxp_gtx::change_linerate(channel, timer, speed); + cxp_phys::change_linerate(channel, timer, speed); unsafe { info!("waiting for tx&rx setup..."); @@ -71,8 +57,11 @@ pub fn loopback_testing(channel: usize, timer: &mut GlobalTimer, speed: CXP_SPEE (CXP[channel].downconn_trigger_ack_write)(1); info!("after clr trig ack = {}", (CXP[channel].downconn_trigger_ack_read)()); - info!("decoder error = {}", (CXP[channel].downconn_decoder_error_read)()); - info!("test error = {}", (CXP[channel].downconn_test_error_read)()); + info!( + "decoder error = {}", + (CXP[channel].downconn_bootstrap_decoder_err_read)() + ); + info!("test error = {}", (CXP[channel].downconn_bootstrap_test_err_read)()); info!("packet type = {:#06X}", (CXP[channel].downconn_packet_type_read)()); cxp_proto::receive(channel).expect("loopback gtx rx error"); @@ -96,439 +85,3 @@ pub fn loopback_testing(channel: usize, timer: &mut GlobalTimer, speed: CXP_SPEE cxp_proto::print_packetu32(&pak_arr, &k_arr); } } - -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 - - // QPLL setup - 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"); - - // tx/rx setup - (CXP[channel].downconn_tx_start_init_write)(1); - (CXP[channel].downconn_rx_start_init_write)(1); - - 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)(), - ); - } - - cxp_gtx::change_linerate(channel, timer, CXP_SPEED::CXP_1); -} - -pub mod cxp_gtx { - use super::*; - - struct CdrConfig { - pub cfg_reg0: u16, // addr = 0xA8 - pub cfg_reg1: u16, // addr = 0xA9 - pub cfg_reg2: u16, // addr = 0xAA - pub cfg_reg3: u16, // addr = 0xAB - pub cfg_reg4: u16, // addr = 0xAC - } - - pub fn change_linerate(channel: usize, timer: &mut GlobalTimer, speed: CXP_SPEED) { - info!("Changing datarate to {:?}", speed); - // DEBUG: DRP pll for TXUSRCLK = freq(linerate)/20 - let settings = txusrclk::get_txusrclk_config(speed); - txusrclk::setup(channel, timer, settings); - - change_qpll_fb_divider(speed); - change_gtx_divider(channel, speed); - change_cdr_cfg(channel, 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); - } - } - - fn change_qpll_fb_divider(speed: CXP_SPEED) { - let qpll_div_reg = match speed { - CXP_SPEED::CXP_1 | CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 | CXP_SPEED::CXP_10 => 0x0120, // FB_Divider = 80 - CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 | CXP_SPEED::CXP_12 => 0x0170, // FB_Divider = 100 - }; - - println!("0x36 = {:#06x}", qpll_read(0x36)); - qpll_write(0x36, qpll_div_reg); - println!("0x36 = {:#06x}", qpll_read(0x36)); - } - - fn change_gtx_divider(channel: usize, 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 - CXP_SPEED::CXP_5 | CXP_SPEED::CXP_6 => 0x11, // RXOUT_DIV = 2 - 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)); - } - - fn change_cdr_cfg(channel: usize, speed: CXP_SPEED) { - let cdr_cfg = match speed { - // when RXOUT_DIV = 8 - CXP_SPEED::CXP_1 => { - CdrConfig { - cfg_reg0: 0x0020, //0x0A8 - cfg_reg1: 0x1008, //0x0A9 - cfg_reg2: 0x23FF, //0x0AA - cfg_reg3: 0x0000, //0x0AB - cfg_reg4: 0x0003, //0x0AC - } - } - // when RXOUT_DIV = 4 - CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 => { - CdrConfig { - cfg_reg0: 0x0020, //0x0A8 - cfg_reg1: 0x1010, //0x0A9 - cfg_reg2: 0x23FF, //0x0AA - cfg_reg3: 0x0000, //0x0AB - cfg_reg4: 0x0003, //0x0AC - } - } - // when RXOUT_DIV= 2 - CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 => { - CdrConfig { - cfg_reg0: 0x0020, //0x0A8 - cfg_reg1: 0x1020, //0x0A9 - cfg_reg2: 0x23FF, //0x0AA - cfg_reg3: 0x0000, //0x0AB - cfg_reg4: 0x0003, //0x0AC - } - } - // when RXOUT_DIV= 1 - CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => { - CdrConfig { - cfg_reg0: 0x0020, //0x0A8 - cfg_reg1: 0x1040, //0x0A9 - cfg_reg2: 0x23FF, //0x0AA - cfg_reg3: 0x0000, //0x0AB - cfg_reg4: 0x000B, //0x0AC - } - } - }; - - 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)] - fn gtx_read(channel: usize, address: u16) -> u16 { - unsafe { - (CXP[channel].downconn_gtx_daddr_write)(address); - (CXP[channel].downconn_gtx_dread_write)(1); - while (CXP[channel].downconn_gtx_dready_read)() != 1 {} - (CXP[channel].downconn_gtx_dout_read)() - } - } - - fn gtx_write(channel: usize, address: u16, value: u16) { - unsafe { - (CXP[channel].downconn_gtx_daddr_write)(address); - (CXP[channel].downconn_gtx_din_write)(value); - (CXP[channel].downconn_gtx_din_stb_write)(1); - while (CXP[channel].downconn_gtx_dready_read)() != 1 {} - } - } - - #[allow(dead_code)] - fn qpll_read(address: u8) -> u16 { - unsafe { - csr::cxp_phys::downconn_qpll_daddr_write(address); - csr::cxp_phys::downconn_qpll_dread_write(1); - while csr::cxp_phys::downconn_qpll_dready_read() != 1 {} - csr::cxp_phys::downconn_qpll_dout_read() - } - } - - fn qpll_write(address: u8, value: u16) { - unsafe { - csr::cxp_phys::downconn_qpll_daddr_write(address); - csr::cxp_phys::downconn_qpll_din_write(value); - csr::cxp_phys::downconn_qpll_din_stb_write(1); - while csr::cxp_phys::downconn_qpll_dready_read() != 1 {} - } - } -} - -pub mod txusrclk { - use super::*; - - pub struct PLLSetting { - 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(channel: usize) { - unsafe { - (CXP[channel].downconn_pll_dclk_write)(1); - (CXP[channel].downconn_pll_dclk_write)(0); - } - } - - fn set_addr(channel: usize, address: u8) { - unsafe { - (CXP[channel].downconn_pll_daddr_write)(address); - } - } - - fn set_data(channel: usize, value: u16) { - unsafe { - (CXP[channel].downconn_pll_din_write)(value); - } - } - - fn set_enable(channel: usize, en: bool) { - unsafe { - let val = if en { 1 } else { 0 }; - (CXP[channel].downconn_pll_den_write)(val); - } - } - - fn set_write_enable(channel: usize, en: bool) { - unsafe { - let val = if en { 1 } else { 0 }; - (CXP[channel].downconn_pll_dwen_write)(val); - } - } - - fn get_data(channel: usize) -> u16 { - unsafe { (CXP[channel].downconn_pll_dout_read)() } - } - - fn drp_ready(channel: usize) -> bool { - unsafe { (CXP[channel].downconn_pll_dready_read)() == 1 } - } - - #[allow(dead_code)] - fn read(channel: usize, address: u8) -> u16 { - set_addr(channel, address); - set_enable(channel, true); - // Set DADDR on the mmcm and assert DEN for one clock cycle - one_clock_cycle(channel); - - set_enable(channel, false); - while !drp_ready(channel) { - // keep the clock signal until data is ready - one_clock_cycle(channel); - } - get_data(channel) - } - - fn write(channel: usize, address: u8, value: u16) { - set_addr(channel, address); - set_data(channel, value); - set_write_enable(channel, true); - set_enable(channel, true); - // Set DADDR, DI on the mmcm and assert DWE, DEN for one clock cycle - one_clock_cycle(channel); - - set_write_enable(channel, false); - set_enable(channel, false); - while !drp_ready(channel) { - // keep the clock signal until write is finished - one_clock_cycle(channel); - } - } - - fn reset(channel: usize, rst: bool) { - unsafe { - let val = if rst { 1 } else { 0 }; - (CXP[channel].downconn_txpll_reset_write)(val) - } - } - - 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); - - // wait for the pll to lock - timer.delay_us(100); - - let locked = unsafe { (CXP[channel].downconn_txpll_locked_read)() == 1 }; - info!("txusrclk locked = {}", locked); - } - } - - pub fn get_txusrclk_config(speed: CXP_SPEED) -> PLLSetting { - match speed { - CXP_SPEED::CXP_1 => { - // CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 32 - // TXUSRCLK=62.5MHz - PLLSetting { - clkout0_reg1: 0x1410, //0x08 - clkout0_reg2: 0x0000, //0x09 - clkfbout_reg1: 0x1104, //0x14 - clkfbout_reg2: 0x0000, //0x15 - div_reg: 0x1041, //0x16 - lock_reg1: 0x03e8, //0x18 - lock_reg2: 0x5801, //0x19 - lock_reg3: 0xdbe9, //0x1A - power_reg: 0x0000, //0x28 - filt_reg1: 0x9808, //0x4E - filt_reg2: 0x9100, //0x4F - } - } - CXP_SPEED::CXP_2 => { - // CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 16 - // TXUSRCLK=62.5MHz - PLLSetting { - clkout0_reg1: 0x1208, //0x08 - clkout0_reg2: 0x0000, //0x09 - clkfbout_reg1: 0x1104, //0x14 - clkfbout_reg2: 0x0000, //0x15 - div_reg: 0x1041, //0x16 - lock_reg1: 0x03e8, //0x18 - lock_reg2: 0x5801, //0x19 - lock_reg3: 0xdbe9, //0x1A - power_reg: 0x0000, //0x28 - filt_reg1: 0x9808, //0x4E - filt_reg2: 0x9100, //0x4F - } - } - CXP_SPEED::CXP_3 => { - // CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 16 - // TXUSRCLK=78.125MHz - PLLSetting { - clkout0_reg1: 0x1208, //0x08 - clkout0_reg2: 0x0000, //0x09 - clkfbout_reg1: 0x1145, //0x14 - clkfbout_reg2: 0x0000, //0x15 - div_reg: 0x1041, //0x16 - lock_reg1: 0x03e8, //0x18 - lock_reg2: 0x7001, //0x19 - lock_reg3: 0xf3e9, //0x1A - power_reg: 0x0000, //0x28 - filt_reg1: 0x9908, //0x4E - filt_reg2: 0x1900, //0x4F - } - } - CXP_SPEED::CXP_5 => { - // CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 8 - // TXUSRCLK=125MHz - PLLSetting { - clkout0_reg1: 0x1104, //0x08 - clkout0_reg2: 0x0000, //0x09 - clkfbout_reg1: 0x1104, //0x14 - clkfbout_reg2: 0x0000, //0x15 - div_reg: 0x1041, //0x16 - lock_reg1: 0x03e8, //0x18 - lock_reg2: 0x5801, //0x19 - lock_reg3: 0xdbe9, //0x1A - power_reg: 0x0000, //0x28 - filt_reg1: 0x9808, //0x4E - filt_reg2: 0x9100, //0x4F - } - } - CXP_SPEED::CXP_6 => { - // CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 8 - // TXUSRCLK=156.25MHz - PLLSetting { - clkout0_reg1: 0x1104, //0x08 - clkout0_reg2: 0x0000, //0x09 - clkfbout_reg1: 0x1145, //0x14 - clkfbout_reg2: 0x0000, //0x15 - div_reg: 0x1041, //0x16 - lock_reg1: 0x03e8, //0x18 - lock_reg2: 0x7001, //0x19 - lock_reg3: 0xf3e9, //0x1A - power_reg: 0x0000, //0x28 - filt_reg1: 0x9908, //0x4E - filt_reg2: 0x1900, //0x4F - } - } - CXP_SPEED::CXP_10 => { - // CLKFBOUT_MULT = 8, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 4 - // TXUSRCLK=250MHz - PLLSetting { - clkout0_reg1: 0x1082, //0x08 - clkout0_reg2: 0x0000, //0x09 - clkfbout_reg1: 0x1104, //0x14 - clkfbout_reg2: 0x0000, //0x15 - div_reg: 0x1041, //0x16 - lock_reg1: 0x03e8, //0x18 - lock_reg2: 0x5801, //0x19 - lock_reg3: 0xdbe9, //0x1A - power_reg: 0x0000, //0x28 - filt_reg1: 0x9808, //0x4E - filt_reg2: 0x9100, //0x4F - } - } - CXP_SPEED::CXP_12 => { - // CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 4 - // TXUSRCLK=312.5MHz - PLLSetting { - clkout0_reg1: 0x1082, //0x08 - clkout0_reg2: 0x0000, //0x09 - clkfbout_reg1: 0x1145, //0x14 - clkfbout_reg2: 0x0000, //0x15 - div_reg: 0x1041, //0x16 - lock_reg1: 0x03e8, //0x18 - lock_reg2: 0x7001, //0x19 - lock_reg3: 0xf3e9, //0x1A - power_reg: 0x0000, //0x28 - filt_reg1: 0x9908, //0x4E - filt_reg2: 0x1900, //0x4F - } - } - } - } -}