forked from M-Labs/artiq-zynq
cxp_phys: low speed serial & GTX setup
phys: add tx & rx setup and linerate changer rx: add GTX and QPLL DRP to change linerate up to 12.5Gbps
This commit is contained in:
parent
c9b01a6324
commit
e2edc22373
205
src/libboard_artiq/src/cxp_phys.rs
Normal file
205
src/libboard_artiq/src/cxp_phys.rs
Normal file
@ -0,0 +1,205 @@
|
||||
use core::fmt;
|
||||
|
||||
use log::info;
|
||||
|
||||
use crate::pl::csr;
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
||||
impl fmt::Display for CXP_SPEED {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&CXP_SPEED::CXP_1 => write!(f, "1.25 Gbps"),
|
||||
&CXP_SPEED::CXP_2 => write!(f, "2.5 Gbps"),
|
||||
&CXP_SPEED::CXP_3 => write!(f, "3.125 Gbps"),
|
||||
&CXP_SPEED::CXP_5 => write!(f, "5 Gbps"),
|
||||
&CXP_SPEED::CXP_6 => write!(f, "6.25 Gbps"),
|
||||
&CXP_SPEED::CXP_10 => write!(f, "10 Gbps"),
|
||||
&CXP_SPEED::CXP_12 => write!(f, "12.5 Gbps"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup() {
|
||||
let init_speed = CXP_SPEED::CXP_1;
|
||||
info!("Setting up CXP phy and set linerate to {}", init_speed);
|
||||
tx::setup();
|
||||
tx::change_linerate(init_speed);
|
||||
rx::setup();
|
||||
rx::change_linerate(init_speed);
|
||||
}
|
||||
|
||||
pub mod tx {
|
||||
use super::*;
|
||||
|
||||
pub fn setup() {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_tx_enable_write(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_linerate(speed: CXP_SPEED) {
|
||||
unsafe {
|
||||
match speed {
|
||||
CXP_SPEED::CXP_1 | CXP_SPEED::CXP_2 | CXP_SPEED::CXP_3 | CXP_SPEED::CXP_5 | CXP_SPEED::CXP_6 => {
|
||||
csr::cxp_grabber::phy_tx_bitrate2x_enable_write(0);
|
||||
}
|
||||
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => {
|
||||
csr::cxp_grabber::phy_tx_bitrate2x_enable_write(1);
|
||||
}
|
||||
};
|
||||
csr::cxp_grabber::phy_tx_clk_reset_write(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod rx {
|
||||
use super::*;
|
||||
|
||||
pub fn setup() {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_gtx_refclk_stable_write(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_linerate(speed: CXP_SPEED) {
|
||||
change_qpll_fb_divider(speed);
|
||||
change_gtx_divider(speed);
|
||||
change_cdr_cfg(speed);
|
||||
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_qpll_reset_write(1);
|
||||
while csr::cxp_grabber::phy_rx_qpll_locked_read() != 1 {}
|
||||
// Changing RXOUT_DIV via DRP requires a manual reset
|
||||
// https://adaptivesupport.amd.com/s/question/0D52E00006hplwnSAA/re-gtx-line-rate-change
|
||||
csr::cxp_grabber::phy_rx_gtx_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, QPLL VCO @ 10GHz
|
||||
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 | CXP_SPEED::CXP_12 => 0x0170, // FB_Divider = 100, QPLL VCO @ 12.5GHz
|
||||
};
|
||||
|
||||
// DEBUG:
|
||||
// println!("QPLL DRP:");
|
||||
// println!("0x36 = {:#06x}", qpll_read(0x36));
|
||||
qpll_write(0x36, qpll_div_reg);
|
||||
// println!("0x36 = {:#06x}", qpll_read(0x36));
|
||||
}
|
||||
|
||||
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
|
||||
CXP_SPEED::CXP_5 | CXP_SPEED::CXP_6 => 0x11, // RXOUT_DIV = 2
|
||||
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => 0x00, // RXOUT_DIV = 1
|
||||
};
|
||||
|
||||
// DEBUG:
|
||||
// println!("RX GTX DRP:");
|
||||
// println!("channel {}, 0x88 = {:#06x}", channel, gtx_read(channel, 0x88));
|
||||
gtx_write(0x88, div_reg);
|
||||
// println!("channel {}, 0x88 = {:#06x}", channel, gtx_read(channel, 0x88));
|
||||
}
|
||||
|
||||
fn change_cdr_cfg(speed: CXP_SPEED) {
|
||||
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
|
||||
}
|
||||
|
||||
let cdr_cfg = match speed {
|
||||
// when RXOUT_DIV = 8
|
||||
CXP_SPEED::CXP_1 => CdrConfig {
|
||||
cfg_reg0: 0x0020,
|
||||
cfg_reg1: 0x1008,
|
||||
cfg_reg2: 0x23FF,
|
||||
cfg_reg3: 0x0000,
|
||||
cfg_reg4: 0x0003,
|
||||
},
|
||||
// when RXOUT_DIV = 4
|
||||
CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 => CdrConfig {
|
||||
cfg_reg0: 0x0020,
|
||||
cfg_reg1: 0x1010,
|
||||
cfg_reg2: 0x23FF,
|
||||
cfg_reg3: 0x0000,
|
||||
cfg_reg4: 0x0003,
|
||||
},
|
||||
// when RXOUT_DIV= 2
|
||||
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 => CdrConfig {
|
||||
cfg_reg0: 0x0020,
|
||||
cfg_reg1: 0x1020,
|
||||
cfg_reg2: 0x23FF,
|
||||
cfg_reg3: 0x0000,
|
||||
cfg_reg4: 0x0003,
|
||||
},
|
||||
// when RXOUT_DIV= 1
|
||||
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => CdrConfig {
|
||||
cfg_reg0: 0x0020,
|
||||
cfg_reg1: 0x1040,
|
||||
cfg_reg2: 0x23FF,
|
||||
cfg_reg3: 0x0000,
|
||||
cfg_reg4: 0x000B,
|
||||
},
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn gtx_read(address: u16) -> u16 {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_gtx_daddr_write(address);
|
||||
csr::cxp_grabber::phy_rx_gtx_dread_write(1);
|
||||
while csr::cxp_grabber::phy_rx_gtx_dready_read() != 1 {}
|
||||
csr::cxp_grabber::phy_rx_gtx_dout_read()
|
||||
}
|
||||
}
|
||||
|
||||
fn gtx_write(address: u16, value: u16) {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_gtx_daddr_write(address);
|
||||
csr::cxp_grabber::phy_rx_gtx_din_write(value);
|
||||
csr::cxp_grabber::phy_rx_gtx_din_stb_write(1);
|
||||
while csr::cxp_grabber::phy_rx_gtx_dready_read() != 1 {}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn qpll_read(address: u8) -> u16 {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_qpll_daddr_write(address);
|
||||
csr::cxp_grabber::phy_rx_qpll_dread_write(1);
|
||||
while csr::cxp_grabber::phy_rx_qpll_dready_read() != 1 {}
|
||||
csr::cxp_grabber::phy_rx_qpll_dout_read()
|
||||
}
|
||||
}
|
||||
|
||||
fn qpll_write(address: u8, value: u16) {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_qpll_daddr_write(address);
|
||||
csr::cxp_grabber::phy_rx_qpll_din_write(value);
|
||||
csr::cxp_grabber::phy_rx_qpll_din_stb_write(1);
|
||||
while csr::cxp_grabber::phy_rx_qpll_dready_read() != 1 {}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user