ad9154: simplify, focus on AD9154 config and do not include JESD

This commit is contained in:
Sebastien Bourdeauducq 2019-10-06 20:06:54 +08:00
parent fdba0bfbbc
commit c4c884b8ce
1 changed files with 10 additions and 190 deletions

View File

@ -33,42 +33,6 @@ fn read(addr: u16) -> u8 {
} }
} }
pub fn jesd_reset(reset: bool) {
unsafe {
csr::ad9154_crg::jreset_write(if reset { 1 } else { 0 });
}
}
fn jesd_enable(dacno: u8, en: bool) {
unsafe {
(csr::AD9154[dacno as usize].jesd_control_enable_write)(if en {1} else {0})
}
}
fn jesd_ready(dacno: u8) -> bool {
unsafe {
(csr::AD9154[dacno as usize].jesd_control_ready_read)() != 0
}
}
fn jesd_prbs(dacno: u8, en: bool) {
unsafe {
(csr::AD9154[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00})
}
}
fn jesd_stpl(dacno: u8, en: bool) {
unsafe {
(csr::AD9154[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0})
}
}
fn jesd_jsync(dacno: u8) -> bool {
unsafe {
(csr::AD9154[dacno as usize].jesd_control_jsync_read)() != 0
}
}
// ad9154 mode 1 // ad9154 mode 1
// linerate 5Gbps or 6Gbps // linerate 5Gbps or 6Gbps
// deviceclock_fpga 125MHz or 150MHz // deviceclock_fpga 125MHz or 150MHz
@ -130,7 +94,7 @@ const JESD_SETTINGS: JESDSettings = JESDSettings {
jesdv: 1 jesdv: 1
}; };
fn dac_reset(dacno: u8) { pub fn reset_and_detect(dacno: u8) -> Result<(), &'static str> {
spi_setup(dacno); spi_setup(dacno);
// reset // reset
write(ad9154_reg::SPI_INTFCONFA, write(ad9154_reg::SPI_INTFCONFA,
@ -145,17 +109,15 @@ fn dac_reset(dacno: u8) {
0*ad9154_reg::ADDRINC_M | 0*ad9154_reg::ADDRINC | 0*ad9154_reg::ADDRINC_M | 0*ad9154_reg::ADDRINC |
1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE); 1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE);
clock::spin_us(100); clock::spin_us(100);
}
fn dac_detect(dacno: u8) -> Result<(), &'static str> {
spi_setup(dacno);
if (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16) != 0x9154 { if (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16) != 0x9154 {
return Err("invalid AD9154 identification"); return Err("invalid AD9154 identification");
} else {
info!("AD9154-{} found", dacno);
} }
Ok(()) Ok(())
} }
fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { pub fn setup(dacno: u8, linerate: u64) -> Result<(), &'static str> {
spi_setup(dacno); spi_setup(dacno);
info!("AD9154-{} initializing...", dacno); info!("AD9154-{} initializing...", dacno);
write(ad9154_reg::PWRCNTRL0, write(ad9154_reg::PWRCNTRL0,
@ -370,7 +332,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> {
write(ad9154_reg::LMFC_VAR_1, 0x0a); write(ad9154_reg::LMFC_VAR_1, 0x0a);
write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock
// datasheet seems to say ENABLE and ARM should be separate steps, // datasheet seems to say ENABLE and ARM should be separate steps,
// so enable now so it can be armed in dac_sync(). // so enable now so it can be armed in sync().
write(ad9154_reg::SYNC_CONTROL, write(ad9154_reg::SYNC_CONTROL,
0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | 0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE |
0*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY); 0*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY);
@ -392,7 +354,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> {
} }
#[allow(dead_code)] #[allow(dead_code)]
fn dac_status(dacno: u8) { fn status(dacno: u8) {
spi_setup(dacno); spi_setup(dacno);
info!("SERDES_PLL_LOCK: {}", info!("SERDES_PLL_LOCK: {}",
(read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB)); (read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB));
@ -445,61 +407,13 @@ fn dac_status(dacno: u8) {
info!("NITDISPARITY: 0x{:02x}", read(ad9154_reg::NIT_W)); info!("NITDISPARITY: 0x{:02x}", read(ad9154_reg::NIT_W));
} }
fn dac_monitor(dacno: u8) { pub fn prbs(dacno: u8) -> Result<(), &'static str> {
spi_setup(dacno);
write(ad9154_reg::IRQ_STATUS0, 0x00);
write(ad9154_reg::IRQ_STATUS1, 0x00);
write(ad9154_reg::IRQ_STATUS2, 0x00);
write(ad9154_reg::IRQ_STATUS3, 0x00);
write(ad9154_reg::IRQEN_STATUSMODE0,
ad9154_reg::IRQEN_SMODE_LANEFIFOERR |
ad9154_reg::IRQEN_SMODE_SERPLLLOCK |
ad9154_reg::IRQEN_SMODE_SERPLLLOST |
ad9154_reg::IRQEN_SMODE_DACPLLLOCK |
ad9154_reg::IRQEN_SMODE_DACPLLLOST);
write(ad9154_reg::IRQEN_STATUSMODE1,
ad9154_reg::IRQEN_SMODE_PRBS0 |
ad9154_reg::IRQEN_SMODE_PRBS1 |
ad9154_reg::IRQEN_SMODE_PRBS2 |
ad9154_reg::IRQEN_SMODE_PRBS3);
write(ad9154_reg::IRQEN_STATUSMODE2,
ad9154_reg::IRQEN_SMODE_SYNC_TRIP0 |
ad9154_reg::IRQEN_SMODE_SYNC_WLIM0 |
ad9154_reg::IRQEN_SMODE_SYNC_ROTATE0 |
ad9154_reg::IRQEN_SMODE_SYNC_LOCK0 |
ad9154_reg::IRQEN_SMODE_NCO_ALIGN0 |
ad9154_reg::IRQEN_SMODE_BLNKDONE0 |
ad9154_reg::IRQEN_SMODE_PDPERR0);
write(ad9154_reg::IRQEN_STATUSMODE3,
ad9154_reg::IRQEN_SMODE_SYNC_TRIP1 |
ad9154_reg::IRQEN_SMODE_SYNC_WLIM1 |
ad9154_reg::IRQEN_SMODE_SYNC_ROTATE1 |
ad9154_reg::IRQEN_SMODE_SYNC_LOCK1 |
ad9154_reg::IRQEN_SMODE_NCO_ALIGN1 |
ad9154_reg::IRQEN_SMODE_BLNKDONE1 |
ad9154_reg::IRQEN_SMODE_PDPERR1);
write(ad9154_reg::IRQ_STATUS0, 0x00);
write(ad9154_reg::IRQ_STATUS1, 0x00);
write(ad9154_reg::IRQ_STATUS2, 0x00);
write(ad9154_reg::IRQ_STATUS3, 0x00);
}
fn dac_prbs(dacno: u8) -> Result<(), &'static str> {
let mut prbs_errors: u32 = 0; let mut prbs_errors: u32 = 0;
spi_setup(dacno); spi_setup(dacno);
/* follow phy prbs testing (p58 of ad9154 datasheet) */ /* follow phy prbs testing (p58 of ad9154 datasheet) */
info!("AD9154-{} running PRBS test...", dacno); info!("AD9154-{} running PRBS test...", dacno);
/* step 1: start sending prbs7 pattern from the transmitter */
jesd_prbs(dacno, true);
clock::spin_us(500000);
/* step 2: select prbs mode */ /* step 2: select prbs mode */
write(ad9154_reg::PHY_PRBS_TEST_CTRL, write(ad9154_reg::PHY_PRBS_TEST_CTRL,
0b00*ad9154_reg::PHY_PRBS_PAT_SEL); 0b00*ad9154_reg::PHY_PRBS_PAT_SEL);
@ -547,8 +461,6 @@ fn dac_prbs(dacno: u8) -> Result<(), &'static str> {
prbs_errors += lane_errors prbs_errors += lane_errors
} }
jesd_prbs(dacno, false);
if prbs_errors > 0 { if prbs_errors > 0 {
return Err("PRBS failed") return Err("PRBS failed")
} }
@ -556,7 +468,7 @@ fn dac_prbs(dacno: u8) -> Result<(), &'static str> {
Ok(()) Ok(())
} }
fn dac_stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> { pub fn stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> {
spi_setup(dacno); spi_setup(dacno);
info!("AD9154-{} running STPL test...", dacno); info!("AD9154-{} running STPL test...", dacno);
@ -565,7 +477,6 @@ fn dac_stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> {
return ((seed + 1)*0x31415979 + 1) & 0xffff; return ((seed + 1)*0x31415979 + 1) & 0xffff;
} }
jesd_stpl(dacno, true);
for i in 0..m { for i in 0..m {
let mut data: u32; let mut data: u32;
let mut errors: u8 = 0; let mut errors: u8 = 0;
@ -609,86 +520,12 @@ fn dac_stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> {
return Err("STPL failed") return Err("STPL failed")
} }
} }
jesd_stpl(dacno, false);
info!(" ...passed"); info!(" ...passed");
Ok(()) Ok(())
} }
fn dac_cfg(dacno: u8) -> Result<(), &'static str> { pub fn sync(dacno: u8) -> Result<bool, &'static str> {
#[cfg(rtio_frequency = "125.0")]
const LINERATE: u64 = 5_000_000_000;
#[cfg(rtio_frequency = "150.0")]
const LINERATE: u64 = 5_000_000_000;
spi_setup(dacno);
jesd_enable(dacno, false);
jesd_prbs(dacno, false);
jesd_stpl(dacno, false);
clock::spin_us(10000);
jesd_enable(dacno, true);
dac_setup(dacno, LINERATE)?;
jesd_enable(dacno, false);
clock::spin_us(10000);
jesd_enable(dacno, true);
dac_monitor(dacno);
clock::spin_us(50000);
let t = clock::get_ms();
while !jesd_ready(dacno) {
if clock::get_ms() > t + 200 {
return Err("JESD ready timeout");
}
}
clock::spin_us(10000);
if read(ad9154_reg::CODEGRPSYNCFLG) != 0xff {
return Err("bad CODEGRPSYNCFLG")
}
if !jesd_jsync(dacno) {
return Err("bad SYNC")
}
if read(ad9154_reg::FRAMESYNCFLG) != 0xff {
return Err("bad FRAMESYNCFLG")
}
if read(ad9154_reg::GOODCHKSUMFLG) != 0xff {
return Err("bad GOODCHECKSUMFLG")
}
if read(ad9154_reg::INITLANESYNCFLG) != 0xff {
return Err("bad INITLANESYNCFLG")
}
Ok(())
}
fn dac_cfg_and_test(dacno: u8) -> Result<(), &'static str> {
dac_cfg(dacno)?;
dac_prbs(dacno)?;
dac_stpl(dacno, 4, 2)?;
dac_cfg(dacno)?;
Ok(())
}
/*
* work around for:
* https://github.com/m-labs/artiq/issues/727
* https://github.com/m-labs/artiq/issues/1127
*/
fn dac_cfg_and_test_retry(dacno: u8) -> Result<(), &'static str> {
let mut attempt = 0;
loop {
attempt += 1;
dac_reset(dacno);
let outcome = dac_cfg_and_test(dacno);
match outcome {
Ok(_) => return outcome,
Err(e) => {
warn!("AD9154-{} config attempt #{} failed ({})", dacno, attempt, e);
if attempt >= 10 {
return outcome;
}
}
}
}
}
pub fn dac_sync(dacno: u8) -> Result<bool, &'static str> {
spi_setup(dacno); spi_setup(dacno);
write(ad9154_reg::SYNC_CONTROL, write(ad9154_reg::SYNC_CONTROL,
@ -709,20 +546,3 @@ pub fn dac_sync(dacno: u8) -> Result<bool, &'static str> {
let realign_occured = sync_status & ad9154_reg::SYNC_ROTATE != 0; let realign_occured = sync_status & ad9154_reg::SYNC_ROTATE != 0;
Ok(realign_occured) Ok(realign_occured)
} }
fn init_dac(dacno: u8) -> Result<(), &'static str> {
let dacno = dacno as u8;
dac_reset(dacno);
dac_detect(dacno)?;
dac_cfg_and_test_retry(dacno)?;
Ok(())
}
pub fn init() {
for dacno in 0..csr::AD9154.len() {
match init_dac(dacno as u8) {
Ok(_) => (),
Err(e) => error!("failed to initialize AD9154-{}: {}", dacno, e)
}
}
}