Compare commits
No commits in common. "0502737481b271a96b8d0baad28f487a51050789" and "7b25bc710ecde039b98679fad39396acadfd17e6" have entirely different histories.
0502737481
...
7b25bc710e
|
@ -1,10 +1,10 @@
|
||||||
[package]
|
[package]
|
||||||
name = "libboard_artiq"
|
name = "libboard_artiqzynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["M-Labs"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "libboard_artiq"
|
name = "libboard_artiqzynq"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
|
@ -2,13 +2,11 @@ use core::slice;
|
||||||
use crc;
|
use crc;
|
||||||
|
|
||||||
use io::{ProtoRead, ProtoWrite, Cursor, Error as IoError};
|
use io::{ProtoRead, ProtoWrite, Cursor, Error as IoError};
|
||||||
//use board_misoc::{mem::DRTIOAUX_MEM}; // <- port
|
use board_misoc::{csr::DRTIOAUX, mem::DRTIOAUX_MEM}; // <- port
|
||||||
//^ uses generated files (like csr, but mem) - todo check after initial generation
|
use clock;
|
||||||
use pl::csr::DRTIOAUX;
|
use proto_artiq::drtioaux_proto::Error as ProtocolError;
|
||||||
use drtioaux_proto::Error as ProtocolError;
|
|
||||||
use libboard_zynq::{timer::GlobalTimer, time::Milliseconds};
|
|
||||||
|
|
||||||
pub use drtioaux_proto::Packet;
|
pub use proto_artiq::drtioaux_proto::Packet;
|
||||||
|
|
||||||
// this is parametric over T because there's no impl Fail for !.
|
// this is parametric over T because there's no impl Fail for !.
|
||||||
#[derive(Fail, Debug)]
|
#[derive(Fail, Debug)]
|
||||||
|
@ -107,12 +105,11 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error<!>> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
|
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>) -> Result<Packet, Error<!>> {
|
||||||
timer: GlobalTimer) -> Result<Packet, Error<!>>
|
let timeout_ms = timeout_ms.unwrap_or(10);
|
||||||
{
|
// only place with clock
|
||||||
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
|
let limit = clock::get_ms() + timeout_ms;
|
||||||
let limit = timer.get_time() + timeout_ms;
|
while clock::get_ms() < limit {
|
||||||
while timer.get_time() < limit {
|
|
||||||
match recv(linkno)? {
|
match recv(linkno)? {
|
||||||
None => (),
|
None => (),
|
||||||
Some(packet) => return Ok(packet),
|
Some(packet) => return Ok(packet),
|
|
@ -1,3 +1,5 @@
|
||||||
|
pub mod clock;
|
||||||
|
|
||||||
// has csr; taken from runtime main
|
// has csr; taken from runtime main
|
||||||
#[path = "../../../build/pl.rs"]
|
#[path = "../../../build/pl.rs"]
|
||||||
pub mod pl;
|
pub mod pl;
|
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
authors = ["M-Labs"]
|
||||||
|
name = "proto_artiq"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "proto_artiq"
|
||||||
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
failure = { version = "0.1", default-features = false }
|
||||||
|
failure_derive = { version = "0.1", default-features = false }
|
||||||
|
byteorder = { version = "1.0", default-features = false }
|
||||||
|
cslice = { version = "0.3" }
|
||||||
|
log = { version = "0.4", default-features = false, optional = true }
|
||||||
|
io = { path = "../libio", features = ["byteorder"] }
|
||||||
|
dyld = { path = "../libdyld" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
alloc = ["io/alloc"]
|
|
@ -0,0 +1,18 @@
|
||||||
|
#![no_std]
|
||||||
|
#![cfg_attr(feature = "alloc", feature(alloc))]
|
||||||
|
|
||||||
|
extern crate failure;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate failure_derive;
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
extern crate alloc;
|
||||||
|
extern crate cslice;
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
extern crate io;
|
||||||
|
extern crate dyld;
|
||||||
|
|
||||||
|
// Internal protocols.
|
||||||
|
pub mod drtioaux_proto;
|
|
@ -37,4 +37,3 @@ dyld = { path = "../libdyld" }
|
||||||
dwarf = { path = "../libdwarf" }
|
dwarf = { path = "../libdwarf" }
|
||||||
unwind = { path = "../libunwind" }
|
unwind = { path = "../libunwind" }
|
||||||
libc = { path = "../libc" }
|
libc = { path = "../libc" }
|
||||||
libboard_artiq = { path = "../libboard_artiq" }
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
use core::cell::Cell;
|
||||||
|
use core::fmt::Write;
|
||||||
|
use log::{Log, LevelFilter};
|
||||||
|
use log_buffer::LogBuffer;
|
||||||
|
use libcortex_a9::mutex::{Mutex, MutexGuard};
|
||||||
|
use libboard_zynq::{println, timer::GlobalTimer};
|
||||||
|
|
||||||
|
pub struct LogBufferRef<'a> {
|
||||||
|
buffer: MutexGuard<'a, LogBuffer<&'static mut [u8]>>,
|
||||||
|
old_log_level: LevelFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LogBufferRef<'a> {
|
||||||
|
fn new(buffer: MutexGuard<'a, LogBuffer<&'static mut [u8]>>) -> LogBufferRef<'a> {
|
||||||
|
let old_log_level = log::max_level();
|
||||||
|
log::set_max_level(LevelFilter::Off);
|
||||||
|
LogBufferRef { buffer, old_log_level }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.buffer.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.buffer.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract(&mut self) -> &str {
|
||||||
|
self.buffer.extract()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Drop for LogBufferRef<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
log::set_max_level(self.old_log_level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BufferLogger {
|
||||||
|
buffer: Mutex<LogBuffer<&'static mut [u8]>>,
|
||||||
|
uart_filter: Cell<LevelFilter>,
|
||||||
|
buffer_filter: Cell<LevelFilter>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut LOGGER: Option<BufferLogger> = None;
|
||||||
|
|
||||||
|
impl BufferLogger {
|
||||||
|
pub fn new(buffer: &'static mut [u8]) -> BufferLogger {
|
||||||
|
BufferLogger {
|
||||||
|
buffer: Mutex::new(LogBuffer::new(buffer)),
|
||||||
|
uart_filter: Cell::new(LevelFilter::Info),
|
||||||
|
buffer_filter: Cell::new(LevelFilter::Trace),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register(self) {
|
||||||
|
unsafe {
|
||||||
|
LOGGER = Some(self);
|
||||||
|
log::set_logger(LOGGER.as_ref().unwrap())
|
||||||
|
.expect("global logger can only be initialized once");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_logger() -> &'static mut Option<BufferLogger> {
|
||||||
|
&mut LOGGER
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn buffer<'a>(&'a self) -> Option<LogBufferRef<'a>> {
|
||||||
|
self.buffer
|
||||||
|
.try_lock()
|
||||||
|
.map(LogBufferRef::new)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uart_log_level(&self) -> LevelFilter {
|
||||||
|
self.uart_filter.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_uart_log_level(&self, max_level: LevelFilter) {
|
||||||
|
self.uart_filter.set(max_level)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn buffer_log_level(&self) -> LevelFilter {
|
||||||
|
self.buffer_filter.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this should be reserved for mgmt module
|
||||||
|
pub fn set_buffer_log_level(&self, max_level: LevelFilter) {
|
||||||
|
self.buffer_filter.set(max_level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// required for impl Log
|
||||||
|
unsafe impl Sync for BufferLogger {}
|
||||||
|
|
||||||
|
impl Log for BufferLogger {
|
||||||
|
fn enabled(&self, _metadata: &log::Metadata) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&self, record: &log::Record) {
|
||||||
|
if self.enabled(record.metadata()) {
|
||||||
|
let timestamp = unsafe {
|
||||||
|
GlobalTimer::get()
|
||||||
|
}.get_us().0;
|
||||||
|
let seconds = timestamp / 1_000_000;
|
||||||
|
let micros = timestamp % 1_000_000;
|
||||||
|
|
||||||
|
if record.level() <= self.buffer_log_level() {
|
||||||
|
let mut buffer = self.buffer.lock();
|
||||||
|
writeln!(buffer, "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
|
||||||
|
record.level(), record.target(), record.args()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if record.level() <= self.uart_log_level() {
|
||||||
|
println!("[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
|
||||||
|
record.level(), record.target(), record.args());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&self) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,8 +23,6 @@ use embedded_hal::blocking::delay::DelayMs;
|
||||||
use libconfig::Config;
|
use libconfig::Config;
|
||||||
use libregister::RegisterW;
|
use libregister::RegisterW;
|
||||||
use libcortex_a9::l2c::enable_l2_cache;
|
use libcortex_a9::l2c::enable_l2_cache;
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
|
||||||
use libboard_artiq::{si5324, logger};
|
|
||||||
|
|
||||||
mod proto_core_io;
|
mod proto_core_io;
|
||||||
mod proto_async;
|
mod proto_async;
|
||||||
|
@ -42,11 +40,13 @@ mod kernel;
|
||||||
mod moninj;
|
mod moninj;
|
||||||
mod eh_artiq;
|
mod eh_artiq;
|
||||||
mod panic;
|
mod panic;
|
||||||
|
mod logger;
|
||||||
mod mgmt;
|
mod mgmt;
|
||||||
mod analyzer;
|
mod analyzer;
|
||||||
mod irq;
|
mod irq;
|
||||||
mod i2c;
|
mod i2c;
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
mod si5324;
|
||||||
|
|
||||||
fn init_gateware() {
|
fn init_gateware() {
|
||||||
// Set up PS->PL clocks
|
// Set up PS->PL clocks
|
||||||
|
|
|
@ -6,7 +6,7 @@ use core::cell::RefCell;
|
||||||
use alloc::{rc::Rc, vec::Vec, string::String};
|
use alloc::{rc::Rc, vec::Vec, string::String};
|
||||||
use log::{self, info, debug, warn, error, LevelFilter};
|
use log::{self, info, debug, warn, error, LevelFilter};
|
||||||
|
|
||||||
use libboard_artiq::logger::{BufferLogger, LogBufferRef};
|
use crate::logger::{BufferLogger, LogBufferRef};
|
||||||
use crate::proto_async::*;
|
use crate::proto_async::*;
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
|
|
|
@ -0,0 +1,258 @@
|
||||||
|
use core::result;
|
||||||
|
use log::info;
|
||||||
|
use libboard_zynq::i2c::I2c;
|
||||||
|
|
||||||
|
type Result<T> = result::Result<T, &'static str>;
|
||||||
|
|
||||||
|
const ADDRESS: u8 = 0x68;
|
||||||
|
|
||||||
|
// NOTE: the logical parameters DO NOT MAP to physical values written
|
||||||
|
// into registers. They have to be mapped; see the datasheet.
|
||||||
|
// DSPLLsim reports the logical parameters in the design summary, not
|
||||||
|
// the physical register values.
|
||||||
|
pub struct FrequencySettings {
|
||||||
|
pub n1_hs: u8,
|
||||||
|
pub nc1_ls: u32,
|
||||||
|
pub n2_hs: u8,
|
||||||
|
pub n2_ls: u32,
|
||||||
|
pub n31: u32,
|
||||||
|
pub n32: u32,
|
||||||
|
pub bwsel: u8,
|
||||||
|
pub crystal_ref: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Input {
|
||||||
|
Ckin1,
|
||||||
|
Ckin2,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySettings> {
|
||||||
|
if settings.nc1_ls != 0 && (settings.nc1_ls % 2) == 1 {
|
||||||
|
return Err("NC1_LS must be 0 or even")
|
||||||
|
}
|
||||||
|
if settings.nc1_ls > (1 << 20) {
|
||||||
|
return Err("NC1_LS is too high")
|
||||||
|
}
|
||||||
|
if (settings.n2_ls % 2) == 1 {
|
||||||
|
return Err("N2_LS must be even")
|
||||||
|
}
|
||||||
|
if settings.n2_ls > (1 << 20) {
|
||||||
|
return Err("N2_LS is too high")
|
||||||
|
}
|
||||||
|
if settings.n31 > (1 << 19) {
|
||||||
|
return Err("N31 is too high")
|
||||||
|
}
|
||||||
|
if settings.n32 > (1 << 19) {
|
||||||
|
return Err("N32 is too high")
|
||||||
|
}
|
||||||
|
let r = FrequencySettings {
|
||||||
|
n1_hs: match settings.n1_hs {
|
||||||
|
4 => 0b000,
|
||||||
|
5 => 0b001,
|
||||||
|
6 => 0b010,
|
||||||
|
7 => 0b011,
|
||||||
|
8 => 0b100,
|
||||||
|
9 => 0b101,
|
||||||
|
10 => 0b110,
|
||||||
|
11 => 0b111,
|
||||||
|
_ => return Err("N1_HS has an invalid value")
|
||||||
|
},
|
||||||
|
nc1_ls: settings.nc1_ls - 1,
|
||||||
|
n2_hs: match settings.n2_hs {
|
||||||
|
4 => 0b000,
|
||||||
|
5 => 0b001,
|
||||||
|
6 => 0b010,
|
||||||
|
7 => 0b011,
|
||||||
|
8 => 0b100,
|
||||||
|
9 => 0b101,
|
||||||
|
10 => 0b110,
|
||||||
|
11 => 0b111,
|
||||||
|
_ => return Err("N2_HS has an invalid value")
|
||||||
|
},
|
||||||
|
n2_ls: settings.n2_ls - 1,
|
||||||
|
n31: settings.n31 - 1,
|
||||||
|
n32: settings.n32 - 1,
|
||||||
|
bwsel: settings.bwsel,
|
||||||
|
crystal_ref: settings.crystal_ref
|
||||||
|
};
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
||||||
|
i2c.start().unwrap();
|
||||||
|
if !i2c.write(ADDRESS << 1).unwrap() {
|
||||||
|
return Err("Si5324 failed to ack write address")
|
||||||
|
}
|
||||||
|
if !i2c.write(reg).unwrap() {
|
||||||
|
return Err("Si5324 failed to ack register")
|
||||||
|
}
|
||||||
|
if !i2c.write(val).unwrap() {
|
||||||
|
return Err("Si5324 failed to ack value")
|
||||||
|
}
|
||||||
|
i2c.stop().unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_no_ack_value(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
||||||
|
i2c.start().unwrap();
|
||||||
|
if !i2c.write(ADDRESS << 1).unwrap() {
|
||||||
|
return Err("Si5324 failed to ack write address")
|
||||||
|
}
|
||||||
|
if !i2c.write(reg).unwrap() {
|
||||||
|
return Err("Si5324 failed to ack register")
|
||||||
|
}
|
||||||
|
i2c.write(val).unwrap();
|
||||||
|
i2c.stop().unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(i2c: &mut I2c, reg: u8) -> Result<u8> {
|
||||||
|
i2c.start().unwrap();
|
||||||
|
if !i2c.write(ADDRESS << 1).unwrap() {
|
||||||
|
return Err("Si5324 failed to ack write address")
|
||||||
|
}
|
||||||
|
if !i2c.write(reg).unwrap() {
|
||||||
|
return Err("Si5324 failed to ack register")
|
||||||
|
}
|
||||||
|
i2c.restart().unwrap();
|
||||||
|
if !i2c.write((ADDRESS << 1) | 1).unwrap() {
|
||||||
|
return Err("Si5324 failed to ack read address")
|
||||||
|
}
|
||||||
|
let val = i2c.read(false).unwrap();
|
||||||
|
i2c.stop().unwrap();
|
||||||
|
Ok(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rmw<F>(i2c: &mut I2c, reg: u8, f: F) -> Result<()> where
|
||||||
|
F: Fn(u8) -> u8 {
|
||||||
|
let value = read(i2c, reg)?;
|
||||||
|
write(i2c, reg, f(value))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ident(i2c: &mut I2c) -> Result<u16> {
|
||||||
|
Ok(((read(i2c, 134)? as u16) << 8) | (read(i2c, 135)? as u16))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn soft_reset(i2c: &mut I2c) -> Result<()> {
|
||||||
|
//TODO write_no_ack_value(i2c, 136, read(136)? | 0x80)?;
|
||||||
|
//TODO clock::spin_us(10_000);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_xtal(i2c: &mut I2c) -> Result<bool> {
|
||||||
|
Ok((read(i2c, 129)? & 0x01) == 0) // LOSX_INT=0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_ckin(i2c: &mut I2c, input: Input) -> Result<bool> {
|
||||||
|
match input {
|
||||||
|
Input::Ckin1 => Ok((read(i2c, 129)? & 0x02) == 0), // LOS1_INT=0
|
||||||
|
Input::Ckin2 => Ok((read(i2c, 129)? & 0x04) == 0), // LOS2_INT=0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn locked(i2c: &mut I2c) -> Result<bool> {
|
||||||
|
Ok((read(i2c, 130)? & 0x01) == 0) // LOL_INT=0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn monitor_lock(i2c: &mut I2c) -> Result<()> {
|
||||||
|
info!("waiting for Si5324 lock...");
|
||||||
|
// TODO let t = clock::get_ms();
|
||||||
|
while !locked(i2c)? {
|
||||||
|
// Yes, lock can be really slow.
|
||||||
|
/*if clock::get_ms() > t + 20000 {
|
||||||
|
return Err("Si5324 lock timeout");
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
info!(" ...locked");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(i2c: &mut I2c) -> Result<()> {
|
||||||
|
info!("init test");
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
{
|
||||||
|
i2c.pca9548_select(0x70, 0)?;
|
||||||
|
i2c.pca9548_select(0x71, 1 << 3)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ident(i2c)? != 0x0182 {
|
||||||
|
return Err("Si5324 does not have expected product number");
|
||||||
|
}
|
||||||
|
|
||||||
|
soft_reset(i2c)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bypass(i2c: &mut I2c, input: Input) -> Result<()> {
|
||||||
|
let cksel_reg = match input {
|
||||||
|
Input::Ckin1 => 0b00,
|
||||||
|
Input::Ckin2 => 0b01,
|
||||||
|
};
|
||||||
|
init(i2c)?;
|
||||||
|
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
|
||||||
|
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG
|
||||||
|
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
|
||||||
|
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
|
||||||
|
rmw(i2c, 0, |v| (v & 0xfd) | 0x02)?; // BYPASS_REG=1
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup(i2c: &mut I2c, settings: &FrequencySettings, input: Input) -> Result<()> {
|
||||||
|
let s = map_frequency_settings(settings)?;
|
||||||
|
let cksel_reg = match input {
|
||||||
|
Input::Ckin1 => 0b00,
|
||||||
|
Input::Ckin2 => 0b01,
|
||||||
|
};
|
||||||
|
|
||||||
|
init(i2c)?;
|
||||||
|
if settings.crystal_ref {
|
||||||
|
rmw(i2c, 0, |v| v | 0x40)?; // FREE_RUN=1
|
||||||
|
}
|
||||||
|
rmw(i2c, 2, |v| (v & 0x0f) | (s.bwsel << 4))?;
|
||||||
|
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
|
||||||
|
rmw(i2c, 3, |v| (v & 0x2f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1
|
||||||
|
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
|
||||||
|
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
|
||||||
|
write(i2c, 25, (s.n1_hs << 5 ) as u8)?;
|
||||||
|
write(i2c, 31, (s.nc1_ls >> 16) as u8)?;
|
||||||
|
write(i2c, 32, (s.nc1_ls >> 8 ) as u8)?;
|
||||||
|
write(i2c, 33, (s.nc1_ls) as u8)?;
|
||||||
|
write(i2c, 34, (s.nc1_ls >> 16) as u8)?; // write to NC2_LS as well
|
||||||
|
write(i2c, 35, (s.nc1_ls >> 8 ) as u8)?;
|
||||||
|
write(i2c, 36, (s.nc1_ls) as u8)?;
|
||||||
|
write(i2c, 40, (s.n2_hs << 5 ) as u8 | (s.n2_ls >> 16) as u8)?;
|
||||||
|
write(i2c, 41, (s.n2_ls >> 8 ) as u8)?;
|
||||||
|
write(i2c, 42, (s.n2_ls) as u8)?;
|
||||||
|
write(i2c, 43, (s.n31 >> 16) as u8)?;
|
||||||
|
write(i2c, 44, (s.n31 >> 8) as u8)?;
|
||||||
|
write(i2c, 45, (s.n31) as u8)?;
|
||||||
|
write(i2c, 46, (s.n32 >> 16) as u8)?;
|
||||||
|
write(i2c, 47, (s.n32 >> 8) as u8)?;
|
||||||
|
write(i2c, 48, (s.n32) as u8)?;
|
||||||
|
rmw(i2c, 137, |v| v | 0x01)?; // FASTLOCK=1
|
||||||
|
rmw(i2c, 136, |v| v | 0x40)?; // ICAL=1
|
||||||
|
|
||||||
|
if !has_xtal(i2c)? {
|
||||||
|
return Err("Si5324 misses XA/XB signal");
|
||||||
|
}
|
||||||
|
if !has_ckin(i2c, input)? {
|
||||||
|
return Err("Si5324 misses clock input signal");
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor_lock(i2c)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_input(i2c: &mut I2c, input: Input) -> Result<()> {
|
||||||
|
let cksel_reg = match input {
|
||||||
|
Input::Ckin1 => 0b00,
|
||||||
|
Input::Ckin2 => 0b01,
|
||||||
|
};
|
||||||
|
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?;
|
||||||
|
if !has_ckin(i2c, input)? {
|
||||||
|
return Err("Si5324 misses clock input signal");
|
||||||
|
}
|
||||||
|
monitor_lock(i2c)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -14,10 +14,5 @@ build_misoc = { path = "../libbuild_misoc" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = { version = "0.4", default-features = false }
|
log = { version = "0.4", default-features = false }
|
||||||
libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git", features = ["ipv6"]}
|
board_misoc = { path = "../libboard_misoc", features = ["uart_console", "log"] }
|
||||||
libsupport_zynq = { default-features = false, features = ["alloc_core"], git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" }
|
board_artiq = { path = "../libboard_artiq" }
|
||||||
libcortex_a9 = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" }
|
|
||||||
libasync = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" }
|
|
||||||
libregister = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" }
|
|
||||||
libconfig = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git", features = ["ipv6"] }
|
|
||||||
libboard_artiq = { path = "../libboard_artiq" }
|
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
pub mod jesd {
|
||||||
|
use libboard_artiqzynq::pl::csr;
|
||||||
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
|
|
||||||
|
pub fn reset(reset: bool) {
|
||||||
|
unsafe {
|
||||||
|
csr::jesd_crg::jreset_write(if reset {1} else {0});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable(dacno: u8, en: bool) {
|
||||||
|
unsafe {
|
||||||
|
(csr::JDCG[dacno as usize].jesd_control_enable_write)(if en {1} else {0})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn phy_done(dacno: u8) -> bool {
|
||||||
|
unsafe {
|
||||||
|
(csr::JDCG[dacno as usize].jesd_control_phy_done_read)() != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ready(dacno: u8) -> bool {
|
||||||
|
unsafe {
|
||||||
|
(csr::JDCG[dacno as usize].jesd_control_ready_read)() != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prbs(dacno: u8, en: bool, timer: GlobalTimer) {
|
||||||
|
unsafe {
|
||||||
|
(csr::JDCG[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00})
|
||||||
|
}
|
||||||
|
timer.delay_us(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stpl(dacno: u8, en: bool, timer: GlobalTimer) {
|
||||||
|
unsafe {
|
||||||
|
(csr::JDCG[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0})
|
||||||
|
}
|
||||||
|
timer.delay_us(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jsync(dacno: u8) -> bool {
|
||||||
|
unsafe {
|
||||||
|
(csr::JDCG[dacno as usize].jesd_control_jsync_read)() != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod jdac {
|
||||||
|
use libboard_artiqzynq::{pl::csr, drtioaux};
|
||||||
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
|
|
||||||
|
use super::jesd;
|
||||||
|
use super::super::jdac_common;
|
||||||
|
|
||||||
|
pub fn basic_request(dacno: u8, reqno: u8, param: u8) -> Result<u8, &'static str> {
|
||||||
|
if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacBasicRequest {
|
||||||
|
destination: 0,
|
||||||
|
dacno: dacno,
|
||||||
|
reqno: reqno,
|
||||||
|
param: param
|
||||||
|
}) {
|
||||||
|
error!("aux packet error ({})", e);
|
||||||
|
return Err("aux packet error while sending for JESD DAC basic request");
|
||||||
|
}
|
||||||
|
match drtioaux::recv_timeout(1, Some(1000)) {
|
||||||
|
Ok(drtioaux::Packet::JdacBasicReply { succeeded, retval }) => {
|
||||||
|
if succeeded {
|
||||||
|
Ok(retval)
|
||||||
|
} else {
|
||||||
|
error!("JESD DAC basic request failed (dacno={}, reqno={})", dacno, reqno);
|
||||||
|
Err("remote error status to JESD DAC basic request")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ok(packet) => {
|
||||||
|
error!("received unexpected aux packet: {:?}", packet);
|
||||||
|
Err("unexpected aux packet in reply to JESD DAC basic request")
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
error!("aux packet error ({})", e);
|
||||||
|
Err("aux packet error while waiting for JESD DAC basic reply")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(timer: GlobalTimer) -> Result<(), &'static str> {
|
||||||
|
for dacno in 0..csr::JDCG.len() {
|
||||||
|
let dacno = dacno as u8;
|
||||||
|
info!("DAC-{} initializing...", dacno);
|
||||||
|
|
||||||
|
jesd::enable(dacno, true);
|
||||||
|
timer.delay_us(10_000);
|
||||||
|
if !jesd::phy_done(dacno) {
|
||||||
|
error!("JESD core PHY not done");
|
||||||
|
return Err("JESD core PHY not done");
|
||||||
|
}
|
||||||
|
|
||||||
|
basic_request(dacno, jdac_common::INIT, 0)?;
|
||||||
|
|
||||||
|
// JESD ready depends on JSYNC being valid, so DAC init needs to happen first
|
||||||
|
if !jesd::ready(dacno) {
|
||||||
|
error!("JESD core reported not ready, sending DAC status print request");
|
||||||
|
basic_request(dacno, jdac_common::PRINT_STATUS, 0)?;
|
||||||
|
return Err("JESD core reported not ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
jesd::prbs(dacno, true);
|
||||||
|
basic_request(dacno, jdac_common::PRBS, 0)?;
|
||||||
|
jesd::prbs(dacno, false);
|
||||||
|
|
||||||
|
basic_request(dacno, jdac_common::INIT, 0)?;
|
||||||
|
timer.delay_us(5000);
|
||||||
|
|
||||||
|
if !jesd::jsync(dacno) {
|
||||||
|
error!("JESD core reported bad SYNC");
|
||||||
|
return Err("JESD core reported bad SYNC");
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(" ...done initializing");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stpl(timer: GlobalTimer) -> Result<(), &'static str> {
|
||||||
|
for dacno in 0..csr::JDCG.len() {
|
||||||
|
let dacno = dacno as u8;
|
||||||
|
|
||||||
|
info!("Running STPL test on DAC-{}...", dacno);
|
||||||
|
|
||||||
|
jesd::stpl(dacno, true, timer);
|
||||||
|
basic_request(dacno, jdac_common::STPL, 0)?;
|
||||||
|
jesd::stpl(dacno, false, timer);
|
||||||
|
|
||||||
|
info!(" ...done STPL test");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,14 +5,20 @@
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use board_misoc::{csr, irq, ident, i2c}; // <- port, use libboard_zynq
|
use board_misoc::{csr, irq, ident, clock, i2c}; // <- port, use libboard_zynq
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
use libboard_artiq::si5324;
|
use libboard_artiqzynq::si5324;
|
||||||
|
#[cfg(has_wrpll)]
|
||||||
|
use board_artiq::wrpll; // <- port
|
||||||
use board_artiq::spi; // <- port?, use libboard_zynq (if spi available/necessary)
|
use board_artiq::spi; // <- port?, use libboard_zynq (if spi available/necessary)
|
||||||
use libboard_artiq::{drtio_routing, drtioaux, logger};
|
use libboard_artiqzynq::{drtio_routing drtioaux};
|
||||||
|
use libboard_artiqzynq::logger;
|
||||||
|
|
||||||
mod repeater;
|
mod repeater;
|
||||||
|
#[cfg(has_jdcg)]
|
||||||
|
mod jdcg;
|
||||||
|
#[cfg(has_jdcg)]
|
||||||
|
pub mod jdac_common;
|
||||||
|
|
||||||
fn drtiosat_reset(reset: bool) {
|
fn drtiosat_reset(reset: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -357,11 +363,11 @@ fn drtiosat_process_errors() {
|
||||||
|
|
||||||
|
|
||||||
#[cfg(has_rtio_crg)]
|
#[cfg(has_rtio_crg)]
|
||||||
fn init_rtio_crg(timer: GlobalTimer) {
|
fn init_rtio_crg() {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio_crg::pll_reset_write(0);
|
csr::rtio_crg::pll_reset_write(0);
|
||||||
}
|
}
|
||||||
timer.delay_us(150);
|
clock::spin_us(150);
|
||||||
let locked = unsafe { csr::rtio_crg::pll_locked_read() != 0 };
|
let locked = unsafe { csr::rtio_crg::pll_locked_read() != 0 };
|
||||||
if !locked {
|
if !locked {
|
||||||
error!("RTIO clock failed");
|
error!("RTIO clock failed");
|
||||||
|
@ -369,11 +375,13 @@ fn init_rtio_crg(timer: GlobalTimer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(has_rtio_crg))]
|
#[cfg(not(has_rtio_crg))]
|
||||||
fn init_rtio_crg(timer: GlobalTimer) { }
|
fn init_rtio_crg() { }
|
||||||
|
|
||||||
fn hardware_tick(ts: &mut u64, timer: GlobalTimer) {
|
fn hardware_tick(ts: &mut u64) {
|
||||||
let now = timer.get_time();
|
let now = clock::get_ms();
|
||||||
if now > *ts {
|
if now > *ts {
|
||||||
|
#[cfg(has_grabber)]
|
||||||
|
board_artiq::grabber::tick();
|
||||||
*ts = now + 200;
|
*ts = now + 200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,7 +414,7 @@ const SI5324_SETTINGS: si5324::FrequencySettings
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn main() -> i32 {
|
pub extern fn main() -> i32 {
|
||||||
let mut timer = GlobalTimer::start();
|
clock::init();
|
||||||
|
|
||||||
let buffer_logger = unsafe {
|
let buffer_logger = unsafe {
|
||||||
logger::BufferLogger::new(&mut LOG_BUFFER[..])
|
logger::BufferLogger::new(&mut LOG_BUFFER[..])
|
||||||
|
@ -419,8 +427,7 @@ pub extern fn main() -> i32 {
|
||||||
info!("gateware ident {}", ident::read(&mut [0; 64]));
|
info!("gateware ident {}", ident::read(&mut [0; 64]));
|
||||||
|
|
||||||
#[cfg(has_i2c)]
|
#[cfg(has_i2c)]
|
||||||
i2c::init().expect("I2C initialization failed"); // port
|
i2c::init().expect("I2C initialization failed");
|
||||||
//see if below is applicable (probably not - not kasli)
|
|
||||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||||
let (mut io_expander0, mut io_expander1);
|
let (mut io_expander0, mut io_expander1);
|
||||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||||
|
@ -429,6 +436,17 @@ pub extern fn main() -> i32 {
|
||||||
io_expander1 = board_misoc::io_expander::IoExpander::new(1);
|
io_expander1 = board_misoc::io_expander::IoExpander::new(1);
|
||||||
io_expander0.init().expect("I2C I/O expander #0 initialization failed");
|
io_expander0.init().expect("I2C I/O expander #0 initialization failed");
|
||||||
io_expander1.init().expect("I2C I/O expander #1 initialization failed");
|
io_expander1.init().expect("I2C I/O expander #1 initialization failed");
|
||||||
|
#[cfg(has_wrpll)]
|
||||||
|
{
|
||||||
|
io_expander0.set_oe(1, 1 << 7).unwrap();
|
||||||
|
io_expander0.set(1, 7, true);
|
||||||
|
io_expander0.service().unwrap();
|
||||||
|
io_expander1.set_oe(0, 1 << 7).unwrap();
|
||||||
|
io_expander1.set_oe(1, 1 << 7).unwrap();
|
||||||
|
io_expander1.set(0, 7, true);
|
||||||
|
io_expander1.set(1, 7, true);
|
||||||
|
io_expander1.service().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// Actively drive TX_DISABLE to false on SFP0..3
|
// Actively drive TX_DISABLE to false on SFP0..3
|
||||||
io_expander0.set_oe(0, 1 << 1).unwrap();
|
io_expander0.set_oe(0, 1 << 1).unwrap();
|
||||||
|
@ -443,19 +461,21 @@ pub extern fn main() -> i32 {
|
||||||
io_expander1.service().unwrap();
|
io_expander1.service().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
//this part was commented in runtime
|
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
||||||
|
#[cfg(has_wrpll)]
|
||||||
|
wrpll::init();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::drtio_transceiver::stable_clkin_write(1);
|
csr::drtio_transceiver::stable_clkin_write(1);
|
||||||
}
|
}
|
||||||
timer.delay_us(1500); // wait for CPLL/QPLL lock
|
clock::spin_us(1500); // wait for CPLL/QPLL lock
|
||||||
|
#[cfg(not(has_jdcg))]
|
||||||
// #[cfg(not(has_jdcg))]
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
|
csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
|
||||||
}
|
}
|
||||||
|
#[cfg(has_wrpll)]
|
||||||
|
wrpll::diagnostics();
|
||||||
init_rtio_crg();
|
init_rtio_crg();
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
|
@ -471,10 +491,15 @@ pub extern fn main() -> i32 {
|
||||||
let mut hardware_tick_ts = 0;
|
let mut hardware_tick_ts = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
#[cfg(has_jdcg)]
|
||||||
|
unsafe {
|
||||||
|
// Hide from uplink until RTM is ready
|
||||||
|
csr::drtio_transceiver::txenable_write(0xfffffffeu32 as _);
|
||||||
|
}
|
||||||
while !drtiosat_link_rx_up() {
|
while !drtiosat_link_rx_up() {
|
||||||
drtiosat_process_errors();
|
drtiosat_process_errors();
|
||||||
for mut rep in repeaters.iter_mut() {
|
for mut rep in repeaters.iter_mut() {
|
||||||
rep.service(&routing_table, rank, timer);
|
rep.service(&routing_table, rank);
|
||||||
}
|
}
|
||||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||||
{
|
{
|
||||||
|
@ -490,11 +515,15 @@ pub extern fn main() -> i32 {
|
||||||
si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks");
|
si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks");
|
||||||
si5324::siphaser::calibrate_skew().expect("failed to calibrate skew");
|
si5324::siphaser::calibrate_skew().expect("failed to calibrate skew");
|
||||||
}
|
}
|
||||||
|
#[cfg(has_wrpll)]
|
||||||
|
wrpll::select_recovered_clock(true);
|
||||||
|
|
||||||
drtioaux::reset(0);
|
drtioaux::reset(0);
|
||||||
drtiosat_reset(false);
|
drtiosat_reset(false);
|
||||||
drtiosat_reset_phy(false);
|
drtiosat_reset_phy(false);
|
||||||
|
|
||||||
|
#[cfg(has_jdcg)]
|
||||||
|
let mut was_up = false;
|
||||||
while drtiosat_link_rx_up() {
|
while drtiosat_link_rx_up() {
|
||||||
drtiosat_process_errors();
|
drtiosat_process_errors();
|
||||||
process_aux_packets(&mut repeaters, &mut routing_table, &mut rank);
|
process_aux_packets(&mut repeaters, &mut routing_table, &mut rank);
|
||||||
|
@ -506,11 +535,23 @@ pub extern fn main() -> i32 {
|
||||||
io_expander0.service().expect("I2C I/O expander #0 service failed");
|
io_expander0.service().expect("I2C I/O expander #0 service failed");
|
||||||
io_expander1.service().expect("I2C I/O expander #1 service failed");
|
io_expander1.service().expect("I2C I/O expander #1 service failed");
|
||||||
}
|
}
|
||||||
hardware_tick(&mut hardware_tick_ts, timer);
|
hardware_tick(&mut hardware_tick_ts);
|
||||||
if drtiosat_tsc_loaded() {
|
if drtiosat_tsc_loaded() {
|
||||||
info!("TSC loaded from uplink");
|
info!("TSC loaded from uplink");
|
||||||
|
#[cfg(has_jdcg)]
|
||||||
|
{
|
||||||
|
// We assume that the RTM on repeater0 is up.
|
||||||
|
// Uplink should not send a TSC load command unless the link is
|
||||||
|
// up, and we are hiding when the RTM is down.
|
||||||
|
if let Err(e) = jdcg::jesd204sync::sysref_rtio_align() {
|
||||||
|
error!("failed to align SYSREF with TSC ({})", e);
|
||||||
|
}
|
||||||
|
if let Err(e) = jdcg::jesd204sync::resync_dacs() {
|
||||||
|
error!("DAC resync failed after SYSREF/TSC realignment ({})", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
for rep in repeaters.iter() {
|
for rep in repeaters.iter() {
|
||||||
if let Err(e) = rep.sync_tsc(timer) {
|
if let Err(e) = rep.sync_tsc() {
|
||||||
error!("failed to sync TSC ({})", e);
|
error!("failed to sync TSC ({})", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,7 +559,37 @@ pub extern fn main() -> i32 {
|
||||||
error!("aux packet error: {}", e);
|
error!("aux packet error: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(has_jdcg)]
|
||||||
|
{
|
||||||
|
let is_up = repeaters[0].is_up();
|
||||||
|
if is_up && !was_up {
|
||||||
|
/*
|
||||||
|
* One side of the JESD204 elastic buffer is clocked by the jitter filter
|
||||||
|
* (Si5324 or WRPLL), the other by the RTM.
|
||||||
|
* The elastic buffer can operate only when those two clocks are derived from
|
||||||
|
* the same oscillator.
|
||||||
|
* This is the case when either of those conditions is true:
|
||||||
|
* (1) The DRTIO master and the RTM are clocked directly from a common external
|
||||||
|
* source, *and* the jitter filter has locked to the recovered clock.
|
||||||
|
* This clocking scheme may provide less noise and phase drift at the DACs.
|
||||||
|
* (2) The RTM clock is connected to the jitter filter output.
|
||||||
|
* To handle those cases, we simply keep the JESD204 core in reset unless the
|
||||||
|
* jitter filter is locked to the recovered clock.
|
||||||
|
*/
|
||||||
|
jdcg::jesd::reset(false);
|
||||||
|
let _ = jdcg::jdac::init();
|
||||||
|
jdcg::jesd204sync::sysref_auto_align();
|
||||||
|
jdcg::jdac::stpl();
|
||||||
|
unsafe {
|
||||||
|
csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); // unhide
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
was_up = is_up;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(has_jdcg)]
|
||||||
|
jdcg::jesd::reset(true);
|
||||||
|
|
||||||
drtiosat_reset_phy(true);
|
drtiosat_reset_phy(true);
|
||||||
drtiosat_reset(true);
|
drtiosat_reset(true);
|
||||||
|
@ -526,6 +597,8 @@ pub extern fn main() -> i32 {
|
||||||
info!("uplink is down, switching to local oscillator clock");
|
info!("uplink is down, switching to local oscillator clock");
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks");
|
si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks");
|
||||||
|
#[cfg(has_wrpll)]
|
||||||
|
wrpll::select_recovered_clock(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use libboard_artiq::{drtioaux, drtio_routing};
|
use board_artiqzynq::{drtioaux, drtio_routing};
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
use libboard_artiq::{pl::csr};
|
use board_artiqzynq::{pl::csr, clock};
|
||||||
#[cfg(has_drtio_routing)]
|
|
||||||
use libboard_zynq::timer::{GlobalTimer, Milliseconds};
|
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
fn rep_link_rx_up(repno: u8) -> bool {
|
fn rep_link_rx_up(repno: u8) -> bool {
|
||||||
|
@ -50,8 +48,7 @@ impl Repeater {
|
||||||
self.state == RepeaterState::Up
|
self.state == RepeaterState::Up
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8,
|
pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8) {
|
||||||
timer: GlobalTimer) {
|
|
||||||
self.process_local_errors();
|
self.process_local_errors();
|
||||||
|
|
||||||
match self.state {
|
match self.state {
|
||||||
|
@ -66,7 +63,7 @@ impl Repeater {
|
||||||
drtioaux::send(self.auxno, &drtioaux::Packet::EchoRequest).unwrap();
|
drtioaux::send(self.auxno, &drtioaux::Packet::EchoRequest).unwrap();
|
||||||
self.state = RepeaterState::WaitPingReply {
|
self.state = RepeaterState::WaitPingReply {
|
||||||
ping_count: ping_count + 1,
|
ping_count: ping_count + 1,
|
||||||
timeout: timer.get_time() + Milliseconds(100)
|
timeout: clock::get_ms() + 100
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!("[REP#{}] link RX went down during ping", self.repno);
|
error!("[REP#{}] link RX went down during ping", self.repno);
|
||||||
|
@ -94,7 +91,7 @@ impl Repeater {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if timer.get_time() > timeout {
|
if clock::get_ms() > timeout {
|
||||||
if ping_count > 200 {
|
if ping_count > 200 {
|
||||||
error!("[REP#{}] ping failed", self.repno);
|
error!("[REP#{}] ping failed", self.repno);
|
||||||
self.state = RepeaterState::Failed;
|
self.state = RepeaterState::Failed;
|
||||||
|
@ -165,13 +162,13 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv_aux_timeout(&self, timeout: u32, timer: GlobalTimer) -> Result<drtioaux::Packet, drtioaux::Error<!>> {
|
fn recv_aux_timeout(&self, timeout: u32) -> Result<drtioaux::Packet, drtioaux::Error<!>> {
|
||||||
let max_time = timer.get_time() + timeout as u64;
|
let max_time = clock::get_ms() + timeout as u64;
|
||||||
loop {
|
loop {
|
||||||
if !rep_link_rx_up(self.repno) {
|
if !rep_link_rx_up(self.repno) {
|
||||||
return Err(drtioaux::Error::LinkDown);
|
return Err(drtioaux::Error::LinkDown);
|
||||||
}
|
}
|
||||||
if timer.get_time() > max_time {
|
if clock::get_ms() > max_time {
|
||||||
return Err(drtioaux::Error::TimedOut);
|
return Err(drtioaux::Error::TimedOut);
|
||||||
}
|
}
|
||||||
match drtioaux::recv(self.auxno) {
|
match drtioaux::recv(self.auxno) {
|
||||||
|
@ -182,17 +179,17 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aux_forward(&self, request: &drtioaux::Packet, timer: GlobalTimer) -> Result<(), drtioaux::Error<!>> {
|
pub fn aux_forward(&self, request: &drtioaux::Packet) -> Result<(), drtioaux::Error<!>> {
|
||||||
if self.state != RepeaterState::Up {
|
if self.state != RepeaterState::Up {
|
||||||
return Err(drtioaux::Error::LinkDown);
|
return Err(drtioaux::Error::LinkDown);
|
||||||
}
|
}
|
||||||
drtioaux::send(self.auxno, request).unwrap();
|
drtioaux::send(self.auxno, request).unwrap();
|
||||||
let reply = self.recv_aux_timeout(200, timer)?;
|
let reply = self.recv_aux_timeout(200)?;
|
||||||
drtioaux::send(0, &reply).unwrap();
|
drtioaux::send(0, &reply).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sync_tsc(&self, timer: GlobalTimer) -> Result<(), drtioaux::Error<!>> {
|
pub fn sync_tsc(&self) -> Result<(), drtioaux::Error<!>> {
|
||||||
if self.state != RepeaterState::Up {
|
if self.state != RepeaterState::Up {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -205,7 +202,7 @@ impl Repeater {
|
||||||
|
|
||||||
// TSCAck is the only aux packet that is sent spontaneously
|
// TSCAck is the only aux packet that is sent spontaneously
|
||||||
// by the satellite, in response to a TSC set on the RT link.
|
// by the satellite, in response to a TSC set on the RT link.
|
||||||
let reply = self.recv_aux_timeout(10000, timer)?;
|
let reply = self.recv_aux_timeout(10000)?;
|
||||||
if reply == drtioaux::Packet::TSCAck {
|
if reply == drtioaux::Packet::TSCAck {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
|
@ -213,7 +210,7 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_path(&self, destination: u8, hops: &[u8; drtio_routing::MAX_HOPS], timer: GlobalTimer) -> Result<(), drtioaux::Error<!>> {
|
pub fn set_path(&self, destination: u8, hops: &[u8; drtio_routing::MAX_HOPS]) -> Result<(), drtioaux::Error<!>> {
|
||||||
if self.state != RepeaterState::Up {
|
if self.state != RepeaterState::Up {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -222,7 +219,7 @@ impl Repeater {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
hops: *hops
|
hops: *hops
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
let reply = self.recv_aux_timeout(200, timer)?;
|
let reply = self.recv_aux_timeout(200)?;
|
||||||
if reply != drtioaux::Packet::RoutingAck {
|
if reply != drtioaux::Packet::RoutingAck {
|
||||||
return Err(drtioaux::Error::UnexpectedReply);
|
return Err(drtioaux::Error::UnexpectedReply);
|
||||||
}
|
}
|
||||||
|
@ -236,24 +233,24 @@ impl Repeater {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_rank(&self, rank: u8, timer: GlobalTimer) -> Result<(), drtioaux::Error<!>> {
|
pub fn set_rank(&self, rank: u8) -> Result<(), drtioaux::Error<!>> {
|
||||||
if self.state != RepeaterState::Up {
|
if self.state != RepeaterState::Up {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetRank {
|
drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetRank {
|
||||||
rank: rank
|
rank: rank
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
let reply = self.recv_aux_timeout(200, timer)?;
|
let reply = self.recv_aux_timeout(200)?;
|
||||||
if reply != drtioaux::Packet::RoutingAck {
|
if reply != drtioaux::Packet::RoutingAck {
|
||||||
return Err(drtioaux::Error::UnexpectedReply);
|
return Err(drtioaux::Error::UnexpectedReply);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rtio_reset(&self, timer: GlobalTimer) -> Result<(), drtioaux::Error<!>> {
|
pub fn rtio_reset(&self) -> Result<(), drtioaux::Error<!>> {
|
||||||
let repno = self.repno as usize;
|
let repno = self.repno as usize;
|
||||||
unsafe { (csr::DRTIOREP[repno].reset_write)(1); }
|
unsafe { (csr::DRTIOREP[repno].reset_write)(1); }
|
||||||
timer.delay_us(100);
|
clock::spin_us(100);
|
||||||
unsafe { (csr::DRTIOREP[repno].reset_write)(0); }
|
unsafe { (csr::DRTIOREP[repno].reset_write)(0); }
|
||||||
|
|
||||||
if self.state != RepeaterState::Up {
|
if self.state != RepeaterState::Up {
|
||||||
|
@ -261,7 +258,7 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
|
|
||||||
drtioaux::send(self.auxno, &drtioaux::Packet::ResetRequest).unwrap();
|
drtioaux::send(self.auxno, &drtioaux::Packet::ResetRequest).unwrap();
|
||||||
let reply = self.recv_aux_timeout(200, timer)?;
|
let reply = self.recv_aux_timeout(200)?;
|
||||||
if reply != drtioaux::Packet::ResetAck {
|
if reply != drtioaux::Packet::ResetAck {
|
||||||
return Err(drtioaux::Error::UnexpectedReply);
|
return Err(drtioaux::Error::UnexpectedReply);
|
||||||
}
|
}
|
||||||
|
@ -278,9 +275,9 @@ pub struct Repeater {
|
||||||
impl Repeater {
|
impl Repeater {
|
||||||
pub fn new(_repno: u8) -> Repeater { Repeater::default() }
|
pub fn new(_repno: u8) -> Repeater { Repeater::default() }
|
||||||
|
|
||||||
pub fn service(&self, _routing_table: &drtio_routing::RoutingTable, _rank: u8, timer: GlobalTimer) { }
|
pub fn service(&self, _routing_table: &drtio_routing::RoutingTable, _rank: u8) { }
|
||||||
|
|
||||||
pub fn sync_tsc(&self) -> Result<(), drtioaux::Error<!>> { Ok(()) }
|
pub fn sync_tsc(&self) -> Result<(), drtioaux::Error<!>> { Ok(()) }
|
||||||
|
|
||||||
pub fn rtio_reset(&self, timer: GlobalTimer) -> Result<(), drtioaux::Error<!>> { Ok(()) }
|
pub fn rtio_reset(&self) -> Result<(), drtioaux::Error<!>> { Ok(()) }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue