forked from M-Labs/artiq-zynq
CXP FW: camera setup init
cxp FW: add channel discovery cxp FW: add CXP version negotiate cxp FW: add CXP operation linerate setter cxp FW: add ConnectReset, CXP version readout
This commit is contained in:
parent
407b4c9984
commit
55f2cab99a
|
@ -0,0 +1,172 @@
|
|||
use embedded_hal::blocking::delay::DelayMs;
|
||||
use libboard_zynq::timer::GlobalTimer;
|
||||
use log::{info, warn};
|
||||
|
||||
use crate::{cxp_comms,
|
||||
cxp_comms::Error,
|
||||
cxp_phys,
|
||||
pl::{csr, csr::CXP}};
|
||||
|
||||
const STANDARD: u32 = 0x0000;
|
||||
const REVISION: u32 = 0x0004;
|
||||
const CONNECTION_RESET: u32 = 0x4000;
|
||||
const CONTROL_PACKET_SIZE_MAX: u32 = 0x400C;
|
||||
const STREAM_PACKET_SIZE_MAX: u32 = 0x4010;
|
||||
const CONNECTION_CFG: u32 = 0x4014;
|
||||
const CONNECTION_CFG_DEF: u32 = 0x4018;
|
||||
const TESTMODE: u32 = 0x401C;
|
||||
const CAPABILITY_REGISTER: u32 = 0x403C;
|
||||
const VERSION_SUPPORTED: u32 = 0x4044;
|
||||
const VERSION_USED: u32 = 0x4048;
|
||||
|
||||
const MASTER_CHANNEL: u8 = 0;
|
||||
|
||||
pub fn setup(timer: &mut GlobalTimer) {
|
||||
cxp_phys::setup(timer);
|
||||
if let Err(e) = probe_connections(timer) {
|
||||
warn!("CXP init failure {:?} ", e);
|
||||
};
|
||||
}
|
||||
|
||||
fn connection_reset(channel: u8) -> Result<(), Error> {
|
||||
// ConnectionReset
|
||||
// without this, camera will still blind red @ 1Hz (i.e. no connection)
|
||||
// TODO: rename cxp_comms to cxp_ctrl
|
||||
cxp_comms::write_u32_no_ack(channel, CONNECTION_RESET, 1, false)
|
||||
}
|
||||
|
||||
fn scan_channels_status() -> Result<(), Error> {
|
||||
let mut result = Err(Error::LinkDown);
|
||||
for ch in 0..cxp_phys::CXP_CHANNELS {
|
||||
if unsafe { (CXP[ch as usize].downconn_rx_ready_read)() } == 1 {
|
||||
info!("CHANNEL #{} discovered", ch);
|
||||
result = Ok(());
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn discover_channels(timer: &mut GlobalTimer) -> Result<(), Error> {
|
||||
// only the simple topology MASTER:ch0, extension:ch1,2,3 is supported right now
|
||||
// TODO: properly support other topology
|
||||
|
||||
// Section 7.6 (CXP-001-2021)
|
||||
// 1.25Gbps (CXP_1) and 3.125Gbps (CXP_3) are the discovery rate
|
||||
// both linerate need to be checked as camera only support ONE of discovery rate
|
||||
for speed in [cxp_phys::CXP_SPEED::CXP_1, cxp_phys::CXP_SPEED::CXP_3].iter() {
|
||||
// Section 12.1.2 (CXP-001-2021)
|
||||
// reset -> wait 200ms -> scan for active channels
|
||||
connection_reset(MASTER_CHANNEL)?;
|
||||
|
||||
cxp_phys::change_linerate(*speed);
|
||||
timer.delay_ms(200);
|
||||
if scan_channels_status().is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(Error::LinkDown)
|
||||
}
|
||||
|
||||
fn negotiate_cxp_version() -> Result<bool, Error> {
|
||||
let rev = cxp_comms::read_u32(MASTER_CHANNEL, REVISION, false)?;
|
||||
|
||||
let mut major_rev: u32 = rev >> 16;
|
||||
let mut minor_rev: u32 = rev & 0xFF;
|
||||
info!("Camera's CXP revision is {}.{}", major_rev, minor_rev);
|
||||
|
||||
// Section 12.1.4 (CXP-001-2021)
|
||||
// For CXP 2.0 and onward, Host need to check the VersionSupported register to determine
|
||||
// the highest common version that supported by both device & host
|
||||
if major_rev >= 2 {
|
||||
let reg = cxp_comms::read_u32(MASTER_CHANNEL, VERSION_SUPPORTED, false)?;
|
||||
|
||||
if ((reg >> 3) & 1) == 1 {
|
||||
major_rev = 2;
|
||||
minor_rev = 1;
|
||||
} else if ((reg >> 2) & 1) == 1 {
|
||||
major_rev = 2;
|
||||
minor_rev = 0;
|
||||
} else {
|
||||
return Err(Error::UnsupportedVersion);
|
||||
}
|
||||
|
||||
cxp_comms::write_u32(MASTER_CHANNEL, VERSION_USED, major_rev << 16 | minor_rev, false)?;
|
||||
}
|
||||
info!(
|
||||
"Camera supports CXP {}.{}, using CXP {}.{} protcol now",
|
||||
major_rev, minor_rev, major_rev, minor_rev
|
||||
);
|
||||
|
||||
let with_tag = major_rev >= 2;
|
||||
Ok(with_tag)
|
||||
}
|
||||
|
||||
fn negotiate_pak_max_size(with_tag: bool) -> Result<(), Error> {
|
||||
let reg = cxp_comms::read_u32(MASTER_CHANNEL, CONTROL_PACKET_SIZE_MAX, with_tag)?;
|
||||
info!("Max CTRL PAK size = {:#010X}", reg);
|
||||
|
||||
let reg = cxp_comms::read_u32(MASTER_CHANNEL, STREAM_PACKET_SIZE_MAX, with_tag)?;
|
||||
info!("Max STREAM PAK size = {:#010X}", reg);
|
||||
// TODO: set stream packet size
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_standard() -> Result<(), Error> {
|
||||
let reg = cxp_comms::read_u32(MASTER_CHANNEL, STANDARD, true)?;
|
||||
info!("CoaXPress special WORD = {:#010X} !!!", reg);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_optional_features() -> Result<(), Error> {
|
||||
let reg = cxp_comms::read_u32(MASTER_CHANNEL, CAPABILITY_REGISTER, true)?;
|
||||
info!("Camera optional feature = {:#010X}", reg);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decode_cxp_speed(code: u32) -> Option<cxp_phys::CXP_SPEED> {
|
||||
match code {
|
||||
0x28 => Some(cxp_phys::CXP_SPEED::CXP_1),
|
||||
0x30 => Some(cxp_phys::CXP_SPEED::CXP_2),
|
||||
0x38 => Some(cxp_phys::CXP_SPEED::CXP_3),
|
||||
0x40 => Some(cxp_phys::CXP_SPEED::CXP_5),
|
||||
0x48 => Some(cxp_phys::CXP_SPEED::CXP_6),
|
||||
0x50 => Some(cxp_phys::CXP_SPEED::CXP_10),
|
||||
0x58 => Some(cxp_phys::CXP_SPEED::CXP_12),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_operation_linerate(with_tag: bool, timer: &mut GlobalTimer) -> Result<(), Error> {
|
||||
let reg = cxp_comms::read_u32(MASTER_CHANNEL, CONNECTION_CFG, with_tag)?;
|
||||
info!("Current connection cfg = {:#010X}", reg);
|
||||
|
||||
let cfg = cxp_comms::read_u32(MASTER_CHANNEL, CONNECTION_CFG_DEF, with_tag)?;
|
||||
info!("Best connection cfg = {:#010X}", cfg);
|
||||
|
||||
if let Some(speed) = decode_cxp_speed(cfg & 0xFF) {
|
||||
cxp_comms::write_u32(MASTER_CHANNEL, CONNECTION_CFG, cfg, with_tag)?;
|
||||
|
||||
cxp_phys::change_linerate(speed);
|
||||
timer.delay_ms(500);
|
||||
scan_channels_status()
|
||||
} else {
|
||||
Err(Error::UnsupportedSpeed)
|
||||
}
|
||||
}
|
||||
|
||||
fn probe_connections(timer: &mut GlobalTimer) -> Result<(), Error> {
|
||||
discover_channels(timer)?;
|
||||
// TODO: Section 12.1.3 (CXP-001-2021)
|
||||
// TODO: add a topology struct and output master channel??
|
||||
// discover_topology(); // get master_channel here
|
||||
|
||||
let with_tag = negotiate_cxp_version()?;
|
||||
// CXP 2.x ONLY, need TAGS
|
||||
// negotiate_pak_max_size(with_tag)?;
|
||||
set_operation_linerate(with_tag, timer)?;
|
||||
|
||||
// DEBUG: print
|
||||
// check_standard()?;
|
||||
// check_optional_features()?;
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue