forked from M-Labs/artiq-zynq
downconn fw: use new csr
downconn fw: fix compilation warning downconn FW: rename csr downconn fw: cleanup downconn fw: add rx memory test
This commit is contained in:
parent
186534ff01
commit
97c110b626
|
@ -3,7 +3,8 @@ use libboard_zynq::{println, timer::GlobalTimer};
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
// use log::info;
|
// use log::info;
|
||||||
use crate::{cxp_proto, pl::csr};
|
use crate::{cxp_proto,
|
||||||
|
pl::{csr, csr::CXP}};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
@ -17,64 +18,62 @@ pub enum CXP_SPEED {
|
||||||
CXP_12,
|
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!("==============================================================================");
|
println!("==============================================================================");
|
||||||
cxp_gtx::change_linerate(timer, speed);
|
cxp_gtx::change_linerate(channel, timer, speed);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
info!("waiting for tx&rx setup...");
|
info!("waiting for tx&rx setup...");
|
||||||
timer.delay_us(50_000);
|
timer.delay_us(50_000);
|
||||||
info!(
|
info!(
|
||||||
"tx_phaligndone = {} | rx_phaligndone = {}",
|
"tx_phaligndone = {} | rx_phaligndone = {}",
|
||||||
csr::cxp::downconn_phy_txinit_phaligndone_read(),
|
(CXP[channel].downconn_txinit_phaligndone_read)(),
|
||||||
csr::cxp::downconn_phy_rxinit_phaligndone_read(),
|
(CXP[channel].downconn_rxinit_phaligndone_read)(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// enable txdata tranmission thought MGTXTXP, required by PMA loopback
|
// 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...");
|
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!");
|
info!("rx ready!");
|
||||||
|
|
||||||
csr::cxp::downconn_phy_tx_stb_write(1);
|
(CXP[channel].downconn_tx_stb_write)(1);
|
||||||
cxp_proto::downconn_send_test_packet();
|
cxp_proto::downconn_send_test_packet(channel);
|
||||||
timer.delay_us(20000); // wait packet has arrive at rx
|
|
||||||
csr::cxp::downconn_phy_tx_stb_write(0);
|
|
||||||
|
|
||||||
// cxp_proto::downconn_debug_send_trig_ack();
|
cxp_proto::downconn_debug_send_trig_ack(channel);
|
||||||
|
|
||||||
cxp_proto::downconn_debug_send(&cxp_proto::Packet::CtrlRead {
|
cxp_proto::downconn_debug_send(
|
||||||
|
channel,
|
||||||
|
&cxp_proto::Packet::CtrlRead {
|
||||||
addr: 0x00,
|
addr: 0x00,
|
||||||
length: 0x04,
|
length: 0x04,
|
||||||
});
|
},
|
||||||
|
)
|
||||||
|
.expect("loopback gtx tx error");
|
||||||
|
|
||||||
timer.delay_us(200); // wait packet has arrive at async fifo in
|
timer.delay_us(200); // wait packet has arrive at RX async fifo
|
||||||
csr::cxp::downconn_phy_tx_stb_write(1);
|
(CXP[channel].downconn_tx_stb_write)(0);
|
||||||
timer.delay_us(200);
|
|
||||||
csr::cxp::downconn_phy_tx_stb_write(0);
|
|
||||||
|
|
||||||
info!("trig ack = {}", csr::cxp::downconn_trig_ack_read());
|
info!("trig ack = {}", (CXP[channel].downconn_trigger_ack_read)());
|
||||||
csr::cxp::downconn_trig_clr_write(1);
|
(CXP[channel].downconn_trigger_ack_write)(1);
|
||||||
info!("after clr trig ack = {}", csr::cxp::downconn_trig_ack_read());
|
info!("after clr trig ack = {}", (CXP[channel].downconn_trigger_ack_read)());
|
||||||
|
|
||||||
info!("decoder error = {}", csr::cxp::downconn_decoder_error_read());
|
info!("decoder error = {}", (CXP[channel].downconn_decoder_error_read)());
|
||||||
info!("test error = {}", csr::cxp::downconn_test_error_read());
|
info!("test error = {}", (CXP[channel].downconn_test_error_read)());
|
||||||
info!("packet type = {:#06X}", csr::cxp::downconn_packet_type_read());
|
info!("packet type = {:#06X}", (CXP[channel].downconn_packet_type_read)());
|
||||||
|
|
||||||
// TODO: investigate how to make my packet appear
|
|
||||||
// TODO: discard idle word
|
|
||||||
|
|
||||||
|
cxp_proto::receive(channel);
|
||||||
// DEBUG: print loopback packets
|
// DEBUG: print loopback packets
|
||||||
const LEN: usize = 20;
|
const LEN: usize = 20;
|
||||||
let mut pak_arr: [u32; LEN] = [0; LEN];
|
let mut pak_arr: [u32; LEN] = [0; LEN];
|
||||||
let mut k_arr: [u8; LEN] = [0; LEN];
|
let mut k_arr: [u8; LEN] = [0; LEN];
|
||||||
let mut i: usize = 0;
|
let mut i: usize = 0;
|
||||||
while csr::cxp::downconn_debug_out_dout_valid_read() == 1 {
|
while (CXP[channel].downconn_debug_out_dout_valid_read)() == 1 {
|
||||||
pak_arr[i] = csr::cxp::downconn_debug_out_dout_pak_read();
|
pak_arr[i] = (CXP[channel].downconn_debug_out_dout_pak_read)();
|
||||||
k_arr[i] = csr::cxp::downconn_debug_out_kout_pak_read();
|
k_arr[i] = (CXP[channel].downconn_debug_out_kout_pak_read)();
|
||||||
// println!("received {:#04X}", pak_arr[i]);
|
// println!("received {:#04X}", pak_arr[i]);
|
||||||
csr::cxp::downconn_debug_out_inc_write(1);
|
(CXP[channel].downconn_debug_out_inc_write)(1);
|
||||||
i += 1;
|
i += 1;
|
||||||
if i == LEN {
|
if i == LEN {
|
||||||
break;
|
break;
|
||||||
|
@ -85,67 +84,69 @@ pub fn loopback_testing(timer: &mut GlobalTimer, speed: CXP_SPEED) {
|
||||||
}
|
}
|
||||||
|
|
||||||
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...");
|
||||||
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
|
// 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...");
|
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");
|
info!("QPLL locked");
|
||||||
|
|
||||||
// tx/rx setup
|
// tx/rx setup
|
||||||
csr::cxp::downconn_phy_tx_start_init_write(1);
|
(CXP[channel].downconn_tx_start_init_write)(1);
|
||||||
csr::cxp::downconn_phy_rx_start_init_write(1);
|
(CXP[channel].downconn_rx_start_init_write)(1);
|
||||||
|
|
||||||
info!("waiting for tx & rx setup...");
|
info!("waiting for tx & rx setup...");
|
||||||
timer.delay_us(50_000);
|
timer.delay_us(50_000);
|
||||||
info!(
|
info!(
|
||||||
"tx_phaligndone = {} | rx_phaligndone = {}",
|
"tx_phaligndone = {} | rx_phaligndone = {}",
|
||||||
csr::cxp::downconn_phy_txinit_phaligndone_read(),
|
(CXP[channel].downconn_txinit_phaligndone_read)(),
|
||||||
csr::cxp::downconn_phy_rxinit_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 {
|
pub mod cxp_gtx {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
struct CdrConfig {
|
struct CdrConfig {
|
||||||
pub cfg_reg0: u16, //0x0A8
|
pub cfg_reg0: u16, // addr = 0xA8
|
||||||
pub cfg_reg1: u16, //0x0A9
|
pub cfg_reg1: u16, // addr = 0xA9
|
||||||
pub cfg_reg2: u16, //0x0AA
|
pub cfg_reg2: u16, // addr = 0xAA
|
||||||
pub cfg_reg3: u16, //0x0AB
|
pub cfg_reg3: u16, // addr = 0xAB
|
||||||
pub cfg_reg4: u16, //0x0AC
|
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);
|
info!("Changing datarate to {:?}", 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(timer, settings);
|
txusrclk::setup(channel, timer, settings);
|
||||||
|
|
||||||
change_qpll_settings(speed);
|
change_qpll_fb_divider(speed);
|
||||||
change_cdr_cfg(speed);
|
change_gtx_divider(channel, speed);
|
||||||
|
change_cdr_cfg(channel, speed);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_phy_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::downconn_phy_qpll_locked_read() != 1 {}
|
while csr::cxp_phys::downconn_qpll_locked_read() != 1 {}
|
||||||
info!("QPLL locked");
|
info!("QPLL locked");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_phy_tx_restart_write(1);
|
(CXP[channel].downconn_tx_restart_write)(1);
|
||||||
csr::cxp::downconn_phy_rx_restart_write(1);
|
(CXP[channel].downconn_rx_restart_write)(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_qpll_settings(speed: CXP_SPEED) {
|
fn change_qpll_fb_divider(speed: CXP_SPEED) {
|
||||||
// Change QPLL_FBDIV
|
|
||||||
let qpll_div_reg = match 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_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
|
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));
|
println!("0x36 = {:#06x}", qpll_read(0x36));
|
||||||
qpll_write(0x36, qpll_div_reg);
|
qpll_write(0x36, qpll_div_reg);
|
||||||
println!("0x36 = {:#06x}", qpll_read(0x36));
|
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 {
|
let cdr_cfg = match speed {
|
||||||
// rxout_div = 8
|
// when RXOUT_DIV = 8
|
||||||
CXP_SPEED::CXP_1 => {
|
CXP_SPEED::CXP_1 => {
|
||||||
CdrConfig {
|
CdrConfig {
|
||||||
cfg_reg0: 0x0020, //0x0A8
|
cfg_reg0: 0x0020, //0x0A8
|
||||||
|
@ -181,7 +182,7 @@ pub mod cxp_gtx {
|
||||||
cfg_reg4: 0x0003, //0x0AC
|
cfg_reg4: 0x0003, //0x0AC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// rxout_div = 4
|
// when RXOUT_DIV = 4
|
||||||
CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 => {
|
CXP_SPEED::CXP_2 | CXP_SPEED::CXP_5 => {
|
||||||
CdrConfig {
|
CdrConfig {
|
||||||
cfg_reg0: 0x0020, //0x0A8
|
cfg_reg0: 0x0020, //0x0A8
|
||||||
|
@ -191,7 +192,7 @@ pub mod cxp_gtx {
|
||||||
cfg_reg4: 0x0003, //0x0AC
|
cfg_reg4: 0x0003, //0x0AC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// rxout_div = 2
|
// when RXOUT_DIV= 2
|
||||||
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 => {
|
CXP_SPEED::CXP_3 | CXP_SPEED::CXP_6 => {
|
||||||
CdrConfig {
|
CdrConfig {
|
||||||
cfg_reg0: 0x0020, //0x0A8
|
cfg_reg0: 0x0020, //0x0A8
|
||||||
|
@ -201,7 +202,7 @@ pub mod cxp_gtx {
|
||||||
cfg_reg4: 0x0003, //0x0AC
|
cfg_reg4: 0x0003, //0x0AC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// rxout_div = 1
|
// when RXOUT_DIV= 1
|
||||||
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => {
|
CXP_SPEED::CXP_10 | CXP_SPEED::CXP_12 => {
|
||||||
CdrConfig {
|
CdrConfig {
|
||||||
cfg_reg0: 0x0020, //0x0A8
|
cfg_reg0: 0x0020, //0x0A8
|
||||||
|
@ -213,50 +214,48 @@ pub mod cxp_gtx {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
gtx_write(0x0A8, cdr_cfg.cfg_reg0);
|
gtx_write(channel, 0x0A8, cdr_cfg.cfg_reg0);
|
||||||
gtx_write(0x0A9, cdr_cfg.cfg_reg1);
|
gtx_write(channel, 0x0A9, cdr_cfg.cfg_reg1);
|
||||||
gtx_write(0x0AA, cdr_cfg.cfg_reg2);
|
gtx_write(channel, 0x0AA, cdr_cfg.cfg_reg2);
|
||||||
gtx_write(0x0AB, cdr_cfg.cfg_reg3);
|
gtx_write(channel, 0x0AB, cdr_cfg.cfg_reg3);
|
||||||
gtx_write(0x0AC, cdr_cfg.cfg_reg4);
|
gtx_write(channel, 0x0AC, cdr_cfg.cfg_reg4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn gtx_read(address: u16) -> u16 {
|
fn gtx_read(channel: usize, address: u16) -> u16 {
|
||||||
// DEBUG:
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_phy_gtx_daddr_write(address);
|
(CXP[channel].downconn_gtx_daddr_write)(address);
|
||||||
csr::cxp::downconn_phy_gtx_dread_write(1);
|
(CXP[channel].downconn_gtx_dread_write)(1);
|
||||||
while csr::cxp::downconn_phy_gtx_dready_read() != 1 {}
|
while (CXP[channel].downconn_gtx_dready_read)() != 1 {}
|
||||||
csr::cxp::downconn_phy_gtx_dout_read()
|
(CXP[channel].downconn_gtx_dout_read)()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtx_write(address: u16, value: u16) {
|
fn gtx_write(channel: usize, address: u16, value: u16) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_phy_gtx_daddr_write(address);
|
(CXP[channel].downconn_gtx_daddr_write)(address);
|
||||||
csr::cxp::downconn_phy_gtx_din_write(value);
|
(CXP[channel].downconn_gtx_din_write)(value);
|
||||||
csr::cxp::downconn_phy_gtx_din_stb_write(1);
|
(CXP[channel].downconn_gtx_din_stb_write)(1);
|
||||||
while csr::cxp::downconn_phy_gtx_dready_read() != 1 {}
|
while (CXP[channel].downconn_gtx_dready_read)() != 1 {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn qpll_read(address: u8) -> u16 {
|
fn qpll_read(address: u8) -> u16 {
|
||||||
// DEBUG:
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_phy_qpll_daddr_write(address);
|
csr::cxp_phys::downconn_qpll_daddr_write(address);
|
||||||
csr::cxp::downconn_phy_qpll_dread_write(1);
|
csr::cxp_phys::downconn_qpll_dread_write(1);
|
||||||
while csr::cxp::downconn_phy_qpll_dready_read() != 1 {}
|
while csr::cxp_phys::downconn_qpll_dready_read() != 1 {}
|
||||||
csr::cxp::downconn_phy_qpll_dout_read()
|
csr::cxp_phys::downconn_qpll_dout_read()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qpll_write(address: u8, value: u16) {
|
fn qpll_write(address: u8, value: u16) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_phy_qpll_daddr_write(address);
|
csr::cxp_phys::downconn_qpll_daddr_write(address);
|
||||||
csr::cxp::downconn_phy_qpll_din_write(value);
|
csr::cxp_phys::downconn_qpll_din_write(value);
|
||||||
csr::cxp::downconn_phy_qpll_din_stb_write(1);
|
csr::cxp_phys::downconn_qpll_din_stb_write(1);
|
||||||
while csr::cxp::downconn_phy_qpll_dready_read() != 1 {}
|
while csr::cxp_phys::downconn_qpll_dready_read() != 1 {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,119 +277,119 @@ pub mod txusrclk {
|
||||||
pub filt_reg2: u16, //0x4F
|
pub filt_reg2: u16, //0x4F
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_clock_cycle() {
|
fn one_clock_cycle(channel: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_phy_pll_dclk_write(1);
|
(CXP[channel].downconn_pll_dclk_write)(1);
|
||||||
csr::cxp::downconn_phy_pll_dclk_write(0);
|
(CXP[channel].downconn_pll_dclk_write)(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_addr(address: u8) {
|
fn set_addr(channel: usize, address: u8) {
|
||||||
unsafe {
|
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 {
|
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 {
|
unsafe {
|
||||||
let val = if en { 1 } else { 0 };
|
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 {
|
unsafe {
|
||||||
let val = if en { 1 } else { 0 };
|
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 {
|
fn get_data(channel: usize) -> u16 {
|
||||||
unsafe { csr::cxp::downconn_phy_pll_dout_read() }
|
unsafe { (CXP[channel].downconn_pll_dout_read)() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drp_ready() -> bool {
|
fn drp_ready(channel: usize) -> bool {
|
||||||
unsafe { csr::cxp::downconn_phy_pll_dready_read() == 1 }
|
unsafe { (CXP[channel].downconn_pll_dready_read)() == 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn read(address: u8) -> u16 {
|
fn read(channel: usize, address: u8) -> u16 {
|
||||||
set_addr(address);
|
set_addr(channel, address);
|
||||||
set_enable(true);
|
set_enable(channel, true);
|
||||||
// Set DADDR on the mmcm and assert DEN for one clock cycle
|
// Set DADDR on the mmcm and assert DEN for one clock cycle
|
||||||
one_clock_cycle();
|
one_clock_cycle(channel);
|
||||||
|
|
||||||
set_enable(false);
|
set_enable(channel, false);
|
||||||
while !drp_ready() {
|
while !drp_ready(channel) {
|
||||||
// keep the clock signal until data is ready
|
// 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) {
|
fn write(channel: usize, address: u8, value: u16) {
|
||||||
set_addr(address);
|
set_addr(channel, address);
|
||||||
set_data(value);
|
set_data(channel, value);
|
||||||
set_write_enable(true);
|
set_write_enable(channel, true);
|
||||||
set_enable(true);
|
set_enable(channel, true);
|
||||||
// Set DADDR, DI on the mmcm and assert DWE, DEN for one clock cycle
|
// 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_write_enable(channel, false);
|
||||||
set_enable(false);
|
set_enable(channel, false);
|
||||||
while !drp_ready() {
|
while !drp_ready(channel) {
|
||||||
// keep the clock signal until write is finished
|
// 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 {
|
unsafe {
|
||||||
let val = if rst { 1 } else { 0 };
|
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 {
|
if false {
|
||||||
info!("0x08 = {:#06x}", read(0x08));
|
info!("0x08 = {:#06x}", read(channel, 0x08));
|
||||||
info!("0x09 = {:#06x}", read(0x09));
|
info!("0x09 = {:#06x}", read(channel, 0x09));
|
||||||
info!("0x14 = {:#06x}", read(0x14));
|
info!("0x14 = {:#06x}", read(channel, 0x14));
|
||||||
info!("0x15 = {:#06x}", read(0x15));
|
info!("0x15 = {:#06x}", read(channel, 0x15));
|
||||||
info!("0x16 = {:#06x}", read(0x16));
|
info!("0x16 = {:#06x}", read(channel, 0x16));
|
||||||
info!("0x18 = {:#06x}", read(0x18));
|
info!("0x18 = {:#06x}", read(channel, 0x18));
|
||||||
info!("0x19 = {:#06x}", read(0x19));
|
info!("0x19 = {:#06x}", read(channel, 0x19));
|
||||||
info!("0x1A = {:#06x}", read(0x1A));
|
info!("0x1A = {:#06x}", read(channel, 0x1A));
|
||||||
info!("0x28 = {:#06x}", read(0x28));
|
info!("0x28 = {:#06x}", read(channel, 0x28));
|
||||||
info!("0x4E = {:#06x}", read(0x4E));
|
info!("0x4E = {:#06x}", read(channel, 0x4E));
|
||||||
info!("0x4F = {:#06x}", read(0x4F));
|
info!("0x4F = {:#06x}", read(channel, 0x4F));
|
||||||
} else {
|
} else {
|
||||||
// Based on "DRP State Machine" from XAPP888
|
// Based on "DRP State Machine" from XAPP888
|
||||||
// hold reset HIGH during pll config
|
// hold reset HIGH during pll config
|
||||||
reset(true);
|
reset(channel, true);
|
||||||
write(0x08, settings.clkout0_reg1);
|
write(channel, 0x08, settings.clkout0_reg1);
|
||||||
write(0x09, settings.clkout0_reg2);
|
write(channel, 0x09, settings.clkout0_reg2);
|
||||||
write(0x14, settings.clkfbout_reg1);
|
write(channel, 0x14, settings.clkfbout_reg1);
|
||||||
write(0x15, settings.clkfbout_reg2);
|
write(channel, 0x15, settings.clkfbout_reg2);
|
||||||
write(0x16, settings.div_reg);
|
write(channel, 0x16, settings.div_reg);
|
||||||
write(0x18, settings.lock_reg1);
|
write(channel, 0x18, settings.lock_reg1);
|
||||||
write(0x19, settings.lock_reg2);
|
write(channel, 0x19, settings.lock_reg2);
|
||||||
write(0x1A, settings.lock_reg3);
|
write(channel, 0x1A, settings.lock_reg3);
|
||||||
write(0x28, settings.power_reg);
|
write(channel, 0x28, settings.power_reg);
|
||||||
write(0x4E, settings.filt_reg1);
|
write(channel, 0x4E, settings.filt_reg1);
|
||||||
write(0x4F, settings.filt_reg2);
|
write(channel, 0x4F, settings.filt_reg2);
|
||||||
reset(false);
|
reset(channel, false);
|
||||||
|
|
||||||
// wait for the pll to lock
|
// wait for the pll to lock
|
||||||
timer.delay_us(100);
|
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);
|
info!("txusrclk locked = {}", locked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -519,5 +518,3 @@ pub mod txusrclk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add recv like in drtioaux
|
|
||||||
|
|
Loading…
Reference in New Issue