diff --git a/src/libboard_artiq/src/cxp_downconn.rs b/src/libboard_artiq/src/cxp_downconn.rs index 150189f..3d6af4f 100644 --- a/src/libboard_artiq/src/cxp_downconn.rs +++ b/src/libboard_artiq/src/cxp_downconn.rs @@ -3,7 +3,8 @@ use libboard_zynq::{println, timer::GlobalTimer}; use log::info; // use log::info; -use crate::{cxp_proto, pl::csr}; +use crate::{cxp_proto, + pl::{csr, csr::CXP}}; #[derive(Clone, Copy, Debug)] #[allow(non_camel_case_types)] @@ -17,64 +18,62 @@ pub enum CXP_SPEED { CXP_12, } -pub fn loopback_testing(timer: &mut GlobalTimer, speed: CXP_SPEED) { +pub fn loopback_testing(channel: usize, timer: &mut GlobalTimer, speed: CXP_SPEED) { println!("=============================================================================="); - cxp_gtx::change_linerate(timer, speed); + cxp_gtx::change_linerate(channel, timer, speed); unsafe { info!("waiting for tx&rx setup..."); timer.delay_us(50_000); info!( "tx_phaligndone = {} | rx_phaligndone = {}", - csr::cxp::downconn_phy_txinit_phaligndone_read(), - csr::cxp::downconn_phy_rxinit_phaligndone_read(), + (CXP[channel].downconn_txinit_phaligndone_read)(), + (CXP[channel].downconn_rxinit_phaligndone_read)(), ); // enable txdata tranmission thought MGTXTXP, required by PMA loopback - csr::cxp::downconn_phy_txenable_write(1); + (CXP[channel].downconn_txenable_write)(1); info!("waiting for rx to align..."); - while csr::cxp::downconn_phy_rx_ready_read() != 1 {} + while (CXP[channel].downconn_rx_ready_read)() != 1 {} info!("rx ready!"); - csr::cxp::downconn_phy_tx_stb_write(1); - cxp_proto::downconn_send_test_packet(); - timer.delay_us(20000); // wait packet has arrive at rx - csr::cxp::downconn_phy_tx_stb_write(0); + (CXP[channel].downconn_tx_stb_write)(1); + cxp_proto::downconn_send_test_packet(channel); - // cxp_proto::downconn_debug_send_trig_ack(); + cxp_proto::downconn_debug_send_trig_ack(channel); - cxp_proto::downconn_debug_send(&cxp_proto::Packet::CtrlRead { - addr: 0x00, - length: 0x04, - }); + cxp_proto::downconn_debug_send( + channel, + &cxp_proto::Packet::CtrlRead { + addr: 0x00, + length: 0x04, + }, + ) + .expect("loopback gtx tx error"); - timer.delay_us(200); // wait packet has arrive at async fifo in - csr::cxp::downconn_phy_tx_stb_write(1); - timer.delay_us(200); - csr::cxp::downconn_phy_tx_stb_write(0); + timer.delay_us(200); // wait packet has arrive at RX async fifo + (CXP[channel].downconn_tx_stb_write)(0); - info!("trig ack = {}", csr::cxp::downconn_trig_ack_read()); - csr::cxp::downconn_trig_clr_write(1); - info!("after clr trig ack = {}", csr::cxp::downconn_trig_ack_read()); + info!("trig ack = {}", (CXP[channel].downconn_trigger_ack_read)()); + (CXP[channel].downconn_trigger_ack_write)(1); + info!("after clr trig ack = {}", (CXP[channel].downconn_trigger_ack_read)()); - info!("decoder error = {}", csr::cxp::downconn_decoder_error_read()); - info!("test error = {}", csr::cxp::downconn_test_error_read()); - info!("packet type = {:#06X}", csr::cxp::downconn_packet_type_read()); - - // TODO: investigate how to make my packet appear - // TODO: discard idle word + info!("decoder error = {}", (CXP[channel].downconn_decoder_error_read)()); + info!("test error = {}", (CXP[channel].downconn_test_error_read)()); + info!("packet type = {:#06X}", (CXP[channel].downconn_packet_type_read)()); + cxp_proto::receive(channel); // DEBUG: print loopback packets const LEN: usize = 20; let mut pak_arr: [u32; LEN] = [0; LEN]; let mut k_arr: [u8; LEN] = [0; LEN]; let mut i: usize = 0; - while csr::cxp::downconn_debug_out_dout_valid_read() == 1 { - pak_arr[i] = csr::cxp::downconn_debug_out_dout_pak_read(); - k_arr[i] = csr::cxp::downconn_debug_out_kout_pak_read(); + while (CXP[channel].downconn_debug_out_dout_valid_read)() == 1 { + pak_arr[i] = (CXP[channel].downconn_debug_out_dout_pak_read)(); + k_arr[i] = (CXP[channel].downconn_debug_out_kout_pak_read)(); // println!("received {:#04X}", pak_arr[i]); - csr::cxp::downconn_debug_out_inc_write(1); + (CXP[channel].downconn_debug_out_inc_write)(1); i += 1; if i == LEN { break; @@ -85,67 +84,69 @@ pub fn loopback_testing(timer: &mut GlobalTimer, speed: CXP_SPEED) { } pub fn setup(timer: &mut GlobalTimer) { + // TODO: do a for loop for channel? + let channel: usize = 0; unsafe { info!("turning on pmc loopback mode..."); - csr::cxp::downconn_phy_loopback_mode_write(0b010); // Near-End PMA Loopback + (CXP[channel].downconn_loopback_mode_write)(0b010); // Near-End PMA Loopback // QPLL setup - csr::cxp::downconn_phy_qpll_reset_write(1); + csr::cxp_phys::downconn_qpll_reset_write(1); info!("waiting for QPLL/CPLL to lock..."); - while csr::cxp::downconn_phy_qpll_locked_read() != 1 {} + while csr::cxp_phys::downconn_qpll_locked_read() != 1 {} info!("QPLL locked"); // tx/rx setup - csr::cxp::downconn_phy_tx_start_init_write(1); - csr::cxp::downconn_phy_rx_start_init_write(1); + (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 = {}", - csr::cxp::downconn_phy_txinit_phaligndone_read(), - csr::cxp::downconn_phy_rxinit_phaligndone_read(), + (CXP[channel].downconn_txinit_phaligndone_read)(), + (CXP[channel].downconn_rxinit_phaligndone_read)(), ); } - cxp_gtx::change_linerate(timer, CXP_SPEED::CXP_1); + cxp_gtx::change_linerate(channel, timer, CXP_SPEED::CXP_1); } pub mod cxp_gtx { use super::*; struct CdrConfig { - pub cfg_reg0: u16, //0x0A8 - pub cfg_reg1: u16, //0x0A9 - pub cfg_reg2: u16, //0x0AA - pub cfg_reg3: u16, //0x0AB - pub cfg_reg4: u16, //0x0AC + 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(timer: &mut GlobalTimer, speed: CXP_SPEED) { + 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(timer, settings); + txusrclk::setup(channel, timer, settings); - change_qpll_settings(speed); - change_cdr_cfg(speed); + change_qpll_fb_divider(speed); + change_gtx_divider(channel, speed); + change_cdr_cfg(channel, speed); unsafe { - csr::cxp::downconn_phy_qpll_reset_write(1); + csr::cxp_phys::downconn_qpll_reset_write(1); info!("waiting for QPLL/CPLL to lock..."); - while csr::cxp::downconn_phy_qpll_locked_read() != 1 {} + while csr::cxp_phys::downconn_qpll_locked_read() != 1 {} info!("QPLL locked"); } unsafe { - csr::cxp::downconn_phy_tx_restart_write(1); - csr::cxp::downconn_phy_rx_restart_write(1); + (CXP[channel].downconn_tx_restart_write)(1); + (CXP[channel].downconn_rx_restart_write)(1); } } - fn change_qpll_settings(speed: CXP_SPEED) { - // Change QPLL_FBDIV + 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 @@ -154,24 +155,24 @@ pub mod cxp_gtx { println!("0x36 = {:#06x}", qpll_read(0x36)); qpll_write(0x36, qpll_div_reg); println!("0x36 = {:#06x}", qpll_read(0x36)); - - // DEBUG: remove txoutdiv - let txrxout_div = match speed { - CXP_SPEED::CXP_1 => 0x33, // 8 - CXP_SPEED::CXP_2 | CXP_SPEED::CXP_3 => 0x22, // 4 - CXP_SPEED::CXP_5 | CXP_SPEED::CXP_6 => 0x11, // 2 - CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => 0x00, // 1 - }; - - // OUT_DIV - println!("0x88 = {:#06x}", gtx_read(0x88)); - gtx_write(0x88, txrxout_div); - println!("0x88 = {:#06x}", gtx_read(0x88)); } - fn change_cdr_cfg(speed: CXP_SPEED) { + 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 { - // rxout_div = 8 + // when RXOUT_DIV = 8 CXP_SPEED::CXP_1 => { CdrConfig { cfg_reg0: 0x0020, //0x0A8 @@ -181,7 +182,7 @@ pub mod cxp_gtx { cfg_reg4: 0x0003, //0x0AC } } - // rxout_div = 4 + // when RXOUT_DIV = 4 CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 => { CdrConfig { cfg_reg0: 0x0020, //0x0A8 @@ -191,7 +192,7 @@ pub mod cxp_gtx { cfg_reg4: 0x0003, //0x0AC } } - // rxout_div = 2 + // when RXOUT_DIV= 2 CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 => { CdrConfig { cfg_reg0: 0x0020, //0x0A8 @@ -201,7 +202,7 @@ pub mod cxp_gtx { cfg_reg4: 0x0003, //0x0AC } } - // rxout_div = 1 + // when RXOUT_DIV= 1 CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => { CdrConfig { cfg_reg0: 0x0020, //0x0A8 @@ -213,50 +214,48 @@ pub mod cxp_gtx { } }; - gtx_write(0x0A8, cdr_cfg.cfg_reg0); - gtx_write(0x0A9, cdr_cfg.cfg_reg1); - gtx_write(0x0AA, cdr_cfg.cfg_reg2); - gtx_write(0x0AB, cdr_cfg.cfg_reg3); - gtx_write(0x0AC, cdr_cfg.cfg_reg4); + 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(address: u16) -> u16 { - // DEBUG: + fn gtx_read(channel: usize, address: u16) -> u16 { unsafe { - csr::cxp::downconn_phy_gtx_daddr_write(address); - csr::cxp::downconn_phy_gtx_dread_write(1); - while csr::cxp::downconn_phy_gtx_dready_read() != 1 {} - csr::cxp::downconn_phy_gtx_dout_read() + (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(address: u16, value: u16) { + fn gtx_write(channel: usize, address: u16, value: u16) { unsafe { - csr::cxp::downconn_phy_gtx_daddr_write(address); - csr::cxp::downconn_phy_gtx_din_write(value); - csr::cxp::downconn_phy_gtx_din_stb_write(1); - while csr::cxp::downconn_phy_gtx_dready_read() != 1 {} + (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 { - // DEBUG: unsafe { - csr::cxp::downconn_phy_qpll_daddr_write(address); - csr::cxp::downconn_phy_qpll_dread_write(1); - while csr::cxp::downconn_phy_qpll_dready_read() != 1 {} - csr::cxp::downconn_phy_qpll_dout_read() + 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::downconn_phy_qpll_daddr_write(address); - csr::cxp::downconn_phy_qpll_din_write(value); - csr::cxp::downconn_phy_qpll_din_stb_write(1); - while csr::cxp::downconn_phy_qpll_dready_read() != 1 {} + 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 {} } } } @@ -278,119 +277,119 @@ pub mod txusrclk { pub filt_reg2: u16, //0x4F } - fn one_clock_cycle() { + fn one_clock_cycle(channel: usize) { unsafe { - csr::cxp::downconn_phy_pll_dclk_write(1); - csr::cxp::downconn_phy_pll_dclk_write(0); + (CXP[channel].downconn_pll_dclk_write)(1); + (CXP[channel].downconn_pll_dclk_write)(0); } } - fn set_addr(address: u8) { + fn set_addr(channel: usize, address: u8) { unsafe { - csr::cxp::downconn_phy_pll_daddr_write(address); + (CXP[channel].downconn_pll_daddr_write)(address); } } - fn set_data(value: u16) { + fn set_data(channel: usize, value: u16) { unsafe { - csr::cxp::downconn_phy_pll_din_write(value); + (CXP[channel].downconn_pll_din_write)(value); } } - fn set_enable(en: bool) { + fn set_enable(channel: usize, en: bool) { unsafe { let val = if en { 1 } else { 0 }; - csr::cxp::downconn_phy_pll_den_write(val); + (CXP[channel].downconn_pll_den_write)(val); } } - fn set_write_enable(en: bool) { + fn set_write_enable(channel: usize, en: bool) { unsafe { let val = if en { 1 } else { 0 }; - csr::cxp::downconn_phy_pll_dwen_write(val); + (CXP[channel].downconn_pll_dwen_write)(val); } } - fn get_data() -> u16 { - unsafe { csr::cxp::downconn_phy_pll_dout_read() } + fn get_data(channel: usize) -> u16 { + unsafe { (CXP[channel].downconn_pll_dout_read)() } } - fn drp_ready() -> bool { - unsafe { csr::cxp::downconn_phy_pll_dready_read() == 1 } + fn drp_ready(channel: usize) -> bool { + unsafe { (CXP[channel].downconn_pll_dready_read)() == 1 } } #[allow(dead_code)] - fn read(address: u8) -> u16 { - set_addr(address); - set_enable(true); + 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(); + one_clock_cycle(channel); - set_enable(false); - while !drp_ready() { + set_enable(channel, false); + while !drp_ready(channel) { // keep the clock signal until data is ready - one_clock_cycle(); + one_clock_cycle(channel); } - get_data() + get_data(channel) } - fn write(address: u8, value: u16) { - set_addr(address); - set_data(value); - set_write_enable(true); - set_enable(true); + 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(); + one_clock_cycle(channel); - set_write_enable(false); - set_enable(false); - while !drp_ready() { + set_write_enable(channel, false); + set_enable(channel, false); + while !drp_ready(channel) { // keep the clock signal until write is finished - one_clock_cycle(); + one_clock_cycle(channel); } } - fn reset(rst: bool) { + fn reset(channel: usize, rst: bool) { unsafe { let val = if rst { 1 } else { 0 }; - csr::cxp::downconn_phy_txpll_reset_write(val) + (CXP[channel].downconn_txpll_reset_write)(val) } } - pub fn setup(timer: &mut GlobalTimer, settings: PLLSetting) { + pub fn setup(channel: usize, timer: &mut GlobalTimer, settings: PLLSetting) { if false { - info!("0x08 = {:#06x}", read(0x08)); - info!("0x09 = {:#06x}", read(0x09)); - info!("0x14 = {:#06x}", read(0x14)); - info!("0x15 = {:#06x}", read(0x15)); - info!("0x16 = {:#06x}", read(0x16)); - info!("0x18 = {:#06x}", read(0x18)); - info!("0x19 = {:#06x}", read(0x19)); - info!("0x1A = {:#06x}", read(0x1A)); - info!("0x28 = {:#06x}", read(0x28)); - info!("0x4E = {:#06x}", read(0x4E)); - info!("0x4F = {:#06x}", read(0x4F)); + 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(true); - write(0x08, settings.clkout0_reg1); - write(0x09, settings.clkout0_reg2); - write(0x14, settings.clkfbout_reg1); - write(0x15, settings.clkfbout_reg2); - write(0x16, settings.div_reg); - write(0x18, settings.lock_reg1); - write(0x19, settings.lock_reg2); - write(0x1A, settings.lock_reg3); - write(0x28, settings.power_reg); - write(0x4E, settings.filt_reg1); - write(0x4F, settings.filt_reg2); - reset(false); + 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 { csr::cxp::downconn_phy_txpll_locked_read() == 1 }; + let locked = unsafe { (CXP[channel].downconn_txpll_locked_read)() == 1 }; info!("txusrclk locked = {}", locked); } } @@ -519,5 +518,3 @@ pub mod txusrclk { } } } - -// TODO: add recv like in drtioaux