cxp_phys: low speed serial & GTX setup

downconn: add QPLL & GTX setup
downconn: add DRP to change linerate up to 12.5Gbps
downconn testing: add txuserclk config
upconn: add low speed serital setup
upconn & downconn: add linerate changer
This commit is contained in:
morgan 2024-10-15 10:31:35 +08:00
parent 0a52f8bb1f
commit d9765a288a

View File

@ -0,0 +1,197 @@
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,
}
pub fn setup() {
rx::setup();
tx::setup();
change_linerate(CXP_SPEED::CXP_1);
}
pub fn change_linerate(speed: CXP_SPEED) {
info!("Changing all channels datarate to {:?}", speed);
rx::change_linerate(speed);
tx::change_linerate(speed);
}
mod tx {
use super::*;
pub fn setup() {
unsafe {
csr::cxp_phys::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_phys::tx_bitrate2x_enable_write(0);
}
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => {
csr::cxp_phys::tx_bitrate2x_enable_write(1);
}
};
csr::cxp_phys::tx_clk_reset_write(1);
}
}
}
mod rx {
use super::*;
pub fn setup() {
unsafe {
csr::cxp_phys::rx_qpll_reset_write(1);
info!("waiting for QPLL/CPLL to lock...");
while csr::cxp_phys::rx_qpll_locked_read() != 1 {}
info!("QPLL locked");
csr::cxp_phys::rx_gtx_start_init_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_phys::rx_qpll_reset_write(1);
info!("waiting for QPLL/CPLL to lock...");
while csr::cxp_phys::rx_qpll_locked_read() != 1 {}
info!("QPLL locked");
csr::cxp_phys::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_phys::rx_gtx_daddr_write(address);
csr::cxp_phys::rx_gtx_dread_write(1);
while csr::cxp_phys::rx_gtx_dready_read() != 1 {}
csr::cxp_phys::rx_gtx_dout_read()
}
}
fn gtx_write(address: u16, value: u16) {
unsafe {
csr::cxp_phys::rx_gtx_daddr_write(address);
csr::cxp_phys::rx_gtx_din_write(value);
csr::cxp_phys::rx_gtx_din_stb_write(1);
while csr::cxp_phys::rx_gtx_dready_read() != 1 {}
}
}
#[allow(dead_code)]
fn qpll_read(address: u8) -> u16 {
unsafe {
csr::cxp_phys::rx_qpll_daddr_write(address);
csr::cxp_phys::rx_qpll_dread_write(1);
while csr::cxp_phys::rx_qpll_dready_read() != 1 {}
csr::cxp_phys::rx_qpll_dout_read()
}
}
fn qpll_write(address: u8, value: u16) {
unsafe {
csr::cxp_phys::rx_qpll_daddr_write(address);
csr::cxp_phys::rx_qpll_din_write(value);
csr::cxp_phys::rx_qpll_din_stb_write(1);
while csr::cxp_phys::rx_qpll_dready_read() != 1 {}
}
}
}