forked from M-Labs/artiq-zynq
phys fw: add reset
phys fw: change linerate to all channels phys fw: refactor and update csr phys fw: reorder reset csr phys fw: set all gtx channel to be same linerate phys fw: clenaup phys fw: add csr control CH len
This commit is contained in:
parent
675c535812
commit
392f38ed7e
|
@ -4,6 +4,8 @@ use log::info;
|
||||||
|
|
||||||
use crate::pl::{csr, csr::CXP};
|
use crate::pl::{csr, csr::CXP};
|
||||||
|
|
||||||
|
const CHANNEL_LEN: usize = csr::CXP_LEN;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub enum CXP_SPEED {
|
pub enum CXP_SPEED {
|
||||||
|
@ -19,36 +21,35 @@ pub enum CXP_SPEED {
|
||||||
pub fn setup(timer: &mut GlobalTimer) {
|
pub fn setup(timer: &mut GlobalTimer) {
|
||||||
down_conn::setup(timer);
|
down_conn::setup(timer);
|
||||||
up_conn::setup();
|
up_conn::setup();
|
||||||
|
change_linerate(CXP_SPEED::CXP_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_linerate(channel: usize, timer: &mut GlobalTimer, speed: CXP_SPEED) {
|
pub fn change_linerate(speed: CXP_SPEED) {
|
||||||
info!("Changing channel {}'s datarate to {:?}", channel, speed);
|
info!("Changing all channels datarate to {:?}", speed);
|
||||||
down_conn::change_linerate(channel, timer, speed);
|
down_conn::change_linerate(speed);
|
||||||
up_conn::change_linerate(channel, speed);
|
up_conn::change_linerate(speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
mod up_conn {
|
mod up_conn {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn setup() {
|
pub fn setup() {
|
||||||
// TODO: do a for loop for channel?
|
|
||||||
let channel: usize = 0;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
change_linerate(channel, CXP_SPEED::CXP_1);
|
csr::cxp_phys::upconn_tx_enable_write(1);
|
||||||
(CXP[channel].upconn_tx_enable_write)(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_linerate(channel: usize, speed: CXP_SPEED) {
|
pub fn change_linerate(speed: CXP_SPEED) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(CXP[channel].upconn_clk_reset_write)(1);
|
|
||||||
match speed {
|
match speed {
|
||||||
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => {
|
CXP_SPEED::CXP_1 | CXP_SPEED::CXP_2 | CXP_SPEED::CXP_3 | CXP_SPEED::CXP_5 | CXP_SPEED::CXP_6 => {
|
||||||
(CXP[channel].upconn_bitrate2x_enable_write)(1);
|
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::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn setup(timer: &mut GlobalTimer) {
|
pub fn setup(timer: &mut GlobalTimer) {
|
||||||
// TODO: do a for loop for channel?
|
|
||||||
let channel: usize = 0;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
info!("turning on pmc loopback mode...");
|
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
|
// QPLL setup
|
||||||
csr::cxp_phys::downconn_qpll_reset_write(1);
|
csr::cxp_phys::downconn_qpll_reset_write(1);
|
||||||
|
@ -69,41 +70,44 @@ mod down_conn {
|
||||||
while csr::cxp_phys::downconn_qpll_locked_read() != 1 {}
|
while csr::cxp_phys::downconn_qpll_locked_read() != 1 {}
|
||||||
info!("QPLL locked");
|
info!("QPLL locked");
|
||||||
|
|
||||||
// tx/rx setup
|
for channel in 0..CHANNEL_LEN {
|
||||||
(CXP[channel].downconn_tx_start_init_write)(1);
|
// tx/rx setup
|
||||||
(CXP[channel].downconn_rx_start_init_write)(1);
|
(CXP[channel].downconn_tx_start_init_write)(1);
|
||||||
|
(CXP[channel].downconn_rx_start_init_write)(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG: printout
|
||||||
info!("waiting for tx & rx setup...");
|
info!("waiting for tx & rx setup...");
|
||||||
timer.delay_us(50_000);
|
timer.delay_us(50_000);
|
||||||
info!(
|
for channel in 0..CHANNEL_LEN {
|
||||||
"tx_phaligndone = {} | rx_phaligndone = {}",
|
info!(
|
||||||
(CXP[channel].downconn_txinit_phaligndone_read)(),
|
"tx_phaligndone = {} | rx_phaligndone = {}",
|
||||||
(CXP[channel].downconn_rxinit_phaligndone_read)(),
|
(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
|
// DEBUG: DRP pll for TXUSRCLK = freq(linerate)/20
|
||||||
let settings = txusrclk::get_txusrclk_config(speed);
|
let settings = txusrclk::get_txusrclk_config(speed);
|
||||||
txusrclk::setup(channel, timer, settings);
|
txusrclk::setup(settings);
|
||||||
|
|
||||||
change_qpll_fb_divider(speed);
|
change_qpll_fb_divider(speed);
|
||||||
change_gtx_divider(channel, speed);
|
change_gtx_divider(speed);
|
||||||
change_cdr_cfg(channel, speed);
|
change_cdr_cfg(speed);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp_phys::downconn_qpll_reset_write(1);
|
csr::cxp_phys::downconn_qpll_reset_write(1);
|
||||||
info!("waiting for QPLL/CPLL to lock...");
|
info!("waiting for QPLL/CPLL to lock...");
|
||||||
while csr::cxp_phys::downconn_qpll_locked_read() != 1 {}
|
while csr::cxp_phys::downconn_qpll_locked_read() != 1 {}
|
||||||
info!("QPLL locked");
|
info!("QPLL locked");
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
for channel in 0..CHANNEL_LEN {
|
||||||
(CXP[channel].downconn_tx_restart_write)(1);
|
(CXP[channel].downconn_tx_restart_write)(1);
|
||||||
(CXP[channel].downconn_rx_restart_write)(1);
|
(CXP[channel].downconn_rx_restart_write)(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +122,7 @@ mod down_conn {
|
||||||
println!("0x36 = {:#06x}", qpll_read(0x36));
|
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 {
|
let div_reg = match speed {
|
||||||
CXP_SPEED::CXP_1 => 0x33, // RXOUT_DIV = 8
|
CXP_SPEED::CXP_1 => 0x33, // RXOUT_DIV = 8
|
||||||
CXP_SPEED::CXP_2 | CXP_SPEED::CXP_3 => 0x22, // RXOUT_DIV = 4
|
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
|
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => 0x00, // RXOUT_DIV = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("0x88 = {:#06x}", gtx_read(channel, 0x88));
|
for channel in 0..CHANNEL_LEN {
|
||||||
gtx_write(channel, 0x88, div_reg);
|
println!("channel {}, 0x88 = {:#06x}", channel, gtx_read(channel, 0x88));
|
||||||
println!("0x88 = {:#06x}", 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 {
|
struct CdrConfig {
|
||||||
pub cfg_reg0: u16, // addr = 0xA8
|
pub cfg_reg0: u16, // addr = 0xA8
|
||||||
pub cfg_reg1: u16, // addr = 0xA9
|
pub cfg_reg1: u16, // addr = 0xA9
|
||||||
|
@ -175,11 +181,13 @@ mod down_conn {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
gtx_write(channel, 0x0A8, cdr_cfg.cfg_reg0);
|
for channel in 0..CHANNEL_LEN {
|
||||||
gtx_write(channel, 0x0A9, cdr_cfg.cfg_reg1);
|
gtx_write(channel, 0x0A8, cdr_cfg.cfg_reg0);
|
||||||
gtx_write(channel, 0x0AA, cdr_cfg.cfg_reg2);
|
gtx_write(channel, 0x0A9, cdr_cfg.cfg_reg1);
|
||||||
gtx_write(channel, 0x0AB, cdr_cfg.cfg_reg3);
|
gtx_write(channel, 0x0AA, cdr_cfg.cfg_reg2);
|
||||||
gtx_write(channel, 0x0AC, cdr_cfg.cfg_reg4);
|
gtx_write(channel, 0x0AB, cdr_cfg.cfg_reg3);
|
||||||
|
gtx_write(channel, 0x0AC, cdr_cfg.cfg_reg4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -224,6 +232,7 @@ mod down_conn {
|
||||||
pub mod txusrclk {
|
pub mod txusrclk {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
pub struct PLLSetting {
|
pub struct PLLSetting {
|
||||||
pub clkout0_reg1: u16, //0x08
|
pub clkout0_reg1: u16, //0x08
|
||||||
pub clkout0_reg2: u16, //0x09
|
pub clkout0_reg2: u16, //0x09
|
||||||
|
@ -317,41 +326,41 @@ mod down_conn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup(channel: usize, timer: &mut GlobalTimer, settings: PLLSetting) {
|
pub fn setup(settings: PLLSetting) {
|
||||||
if false {
|
for channel in 0..CHANNEL_LEN {
|
||||||
info!("0x08 = {:#06x}", read(channel, 0x08));
|
if false {
|
||||||
info!("0x09 = {:#06x}", read(channel, 0x09));
|
info!("0x08 = {:#06x}", read(channel, 0x08));
|
||||||
info!("0x14 = {:#06x}", read(channel, 0x14));
|
info!("0x09 = {:#06x}", read(channel, 0x09));
|
||||||
info!("0x15 = {:#06x}", read(channel, 0x15));
|
info!("0x14 = {:#06x}", read(channel, 0x14));
|
||||||
info!("0x16 = {:#06x}", read(channel, 0x16));
|
info!("0x15 = {:#06x}", read(channel, 0x15));
|
||||||
info!("0x18 = {:#06x}", read(channel, 0x18));
|
info!("0x16 = {:#06x}", read(channel, 0x16));
|
||||||
info!("0x19 = {:#06x}", read(channel, 0x19));
|
info!("0x18 = {:#06x}", read(channel, 0x18));
|
||||||
info!("0x1A = {:#06x}", read(channel, 0x1A));
|
info!("0x19 = {:#06x}", read(channel, 0x19));
|
||||||
info!("0x28 = {:#06x}", read(channel, 0x28));
|
info!("0x1A = {:#06x}", read(channel, 0x1A));
|
||||||
info!("0x4E = {:#06x}", read(channel, 0x4E));
|
info!("0x28 = {:#06x}", read(channel, 0x28));
|
||||||
info!("0x4F = {:#06x}", read(channel, 0x4F));
|
info!("0x4E = {:#06x}", read(channel, 0x4E));
|
||||||
} else {
|
info!("0x4F = {:#06x}", read(channel, 0x4F));
|
||||||
// Based on "DRP State Machine" from XAPP888
|
} else {
|
||||||
// hold reset HIGH during pll config
|
// Based on "DRP State Machine" from XAPP888
|
||||||
reset(channel, true);
|
// hold reset HIGH during pll config
|
||||||
write(channel, 0x08, settings.clkout0_reg1);
|
reset(channel, true);
|
||||||
write(channel, 0x09, settings.clkout0_reg2);
|
write(channel, 0x08, settings.clkout0_reg1);
|
||||||
write(channel, 0x14, settings.clkfbout_reg1);
|
write(channel, 0x09, settings.clkout0_reg2);
|
||||||
write(channel, 0x15, settings.clkfbout_reg2);
|
write(channel, 0x14, settings.clkfbout_reg1);
|
||||||
write(channel, 0x16, settings.div_reg);
|
write(channel, 0x15, settings.clkfbout_reg2);
|
||||||
write(channel, 0x18, settings.lock_reg1);
|
write(channel, 0x16, settings.div_reg);
|
||||||
write(channel, 0x19, settings.lock_reg2);
|
write(channel, 0x18, settings.lock_reg1);
|
||||||
write(channel, 0x1A, settings.lock_reg3);
|
write(channel, 0x19, settings.lock_reg2);
|
||||||
write(channel, 0x28, settings.power_reg);
|
write(channel, 0x1A, settings.lock_reg3);
|
||||||
write(channel, 0x4E, settings.filt_reg1);
|
write(channel, 0x28, settings.power_reg);
|
||||||
write(channel, 0x4F, settings.filt_reg2);
|
write(channel, 0x4E, settings.filt_reg1);
|
||||||
reset(channel, false);
|
write(channel, 0x4F, settings.filt_reg2);
|
||||||
|
reset(channel, false);
|
||||||
|
|
||||||
// wait for the pll to lock
|
info!("waiting for PLL of txusrclk to lock...");
|
||||||
timer.delay_us(100);
|
while unsafe { (CXP[channel].downconn_txpll_locked_read)() == 0 } {}
|
||||||
|
info!("txusrclk locked :D");
|
||||||
let locked = unsafe { (CXP[channel].downconn_txpll_locked_read)() == 1 };
|
}
|
||||||
info!("txusrclk locked = {}", locked);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue