forked from M-Labs/artiq-zynq
Refactor i2c and io_expander to make them shared
Signed-off-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
parent
dcc5cc7555
commit
e51a5728e0
83
src/libboard_artiq/src/i2c.rs
Normal file
83
src/libboard_artiq/src/i2c.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use libboard_zynq;
|
||||
|
||||
pub static mut I2C_BUS: Option<libboard_zynq::i2c::I2c> = None;
|
||||
|
||||
pub fn start() -> Result<(), &'static str> {
|
||||
unsafe {
|
||||
if (&mut I2C_BUS).as_mut().unwrap().start().is_err() {
|
||||
Err("I2C start failed")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn restart() -> Result<(), &'static str> {
|
||||
unsafe {
|
||||
if (&mut I2C_BUS).as_mut().unwrap().restart().is_err() {
|
||||
Err("I2C restart failed")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop() -> Result<(), &'static str> {
|
||||
unsafe {
|
||||
if (&mut I2C_BUS).as_mut().unwrap().stop().is_err() {
|
||||
Err("I2C stop failed")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(data: i32) -> Result<bool, &'static str> {
|
||||
unsafe {
|
||||
match (&mut I2C_BUS).as_mut().unwrap().write(data as u8) {
|
||||
Ok(r) =>Ok(r),
|
||||
Err(_) => Err("I2C write failed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(ack: bool) -> Result<i32, &'static str> {
|
||||
unsafe {
|
||||
match (&mut I2C_BUS).as_mut().unwrap().read(ack) {
|
||||
Ok(r) => Ok(r as i32),
|
||||
Err(_) => Err("I2C read failed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pca954x_select(address: i32, channel: Option<u8>) -> Result<(), &'static str> {
|
||||
unsafe {
|
||||
if (&mut I2C_BUS).as_mut().unwrap().pca954x_select(address as u8, channel).is_err() {
|
||||
Err("switch select failed")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn switch_select(address: i32, mask: i32) -> Result<(), &'static str> {
|
||||
let ch = match mask { //decode from mainline, PCA9548-centric API
|
||||
0x00 => None,
|
||||
0x01 => Some(0),
|
||||
0x02 => Some(1),
|
||||
0x04 => Some(2),
|
||||
0x08 => Some(3),
|
||||
0x10 => Some(4),
|
||||
0x20 => Some(5),
|
||||
0x40 => Some(6),
|
||||
0x80 => Some(7),
|
||||
_ => return Err("switch select supports only one channel")
|
||||
};
|
||||
pca954x_select(address, ch)
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let mut i2c = libboard_zynq::i2c::I2c::i2c0();
|
||||
i2c.init().expect("I2C bus initialization failed");
|
||||
unsafe { I2C_BUS = Some(i2c) };
|
||||
}
|
@ -11,7 +11,6 @@ struct Registers {
|
||||
}
|
||||
|
||||
pub struct IoExpander {
|
||||
busno: i32,
|
||||
port: u8,
|
||||
address: i32,
|
||||
iodir: [u8; 2],
|
||||
@ -27,7 +26,6 @@ impl IoExpander {
|
||||
// Both expanders on SHARED I2C bus
|
||||
let mut io_expander = match index {
|
||||
0 => IoExpander {
|
||||
busno: 0,
|
||||
port: 11,
|
||||
address: 0x40,
|
||||
iodir: [0xff; 2],
|
||||
@ -41,7 +39,6 @@ impl IoExpander {
|
||||
},
|
||||
},
|
||||
1 => IoExpander {
|
||||
busno: 0,
|
||||
port: 11,
|
||||
address: 0x42,
|
||||
iodir: [0xff; 2],
|
||||
@ -77,26 +74,26 @@ impl IoExpander {
|
||||
|
||||
fn select(&self) -> Result<(), &'static str> {
|
||||
let mask: u16 = 1 << self.port;
|
||||
i2c::switch_select(self.busno, 0x70, mask as u8 as i32);
|
||||
i2c::switch_select(self.busno, 0x71, (mask >> 8) as u8 as i32);
|
||||
i2c::switch_select(0x70, mask as u8 as i32)?;
|
||||
i2c::switch_select(0x71, (mask >> 8) as u8 as i32)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&self, addr: u8, value: u8) -> Result<(), &'static str> {
|
||||
i2c::start(self.busno);
|
||||
i2c::write(self.busno, self.address as i32);
|
||||
i2c::write(self.busno, addr as i32);
|
||||
i2c::write(self.busno, value as i32);
|
||||
i2c::stop(self.busno);
|
||||
i2c::start()?;
|
||||
i2c::write(self.address as i32)?;
|
||||
i2c::write(addr as i32)?;
|
||||
i2c::write(value as i32)?;
|
||||
i2c::stop()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_ack(&self) -> Result<bool, &'static str> {
|
||||
// Check for ack from io expander
|
||||
self.select()?;
|
||||
i2c::start(self.busno);
|
||||
let ack = i2c::write(self.busno, self.address);
|
||||
i2c::stop(self.busno);
|
||||
i2c::start()?;
|
||||
let ack = i2c::write(self.address)?;
|
||||
i2c::stop()?;
|
||||
Ok(ack)
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ pub mod drtioaux_async;
|
||||
#[cfg(has_drtio)]
|
||||
#[path = "../../../build/mem.rs"]
|
||||
pub mod mem;
|
||||
pub mod i2c;
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
pub mod io_expander;
|
||||
|
||||
use core::{cmp, str};
|
||||
|
||||
|
@ -1,90 +0,0 @@
|
||||
use libboard_zynq;
|
||||
use crate::artiq_raise;
|
||||
|
||||
pub static mut I2C_BUS: Option<libboard_zynq::i2c::I2c> = None;
|
||||
|
||||
pub extern fn start(busno: i32) {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
unsafe {
|
||||
if (&mut I2C_BUS).as_mut().unwrap().start().is_err() {
|
||||
artiq_raise!("I2CError", "I2C start failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn restart(busno: i32) {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
unsafe {
|
||||
if (&mut I2C_BUS).as_mut().unwrap().restart().is_err() {
|
||||
artiq_raise!("I2CError", "I2C restart failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn stop(busno: i32) {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
unsafe {
|
||||
if (&mut I2C_BUS).as_mut().unwrap().stop().is_err() {
|
||||
artiq_raise!("I2CError", "I2C stop failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn write(busno: i32, data: i32) -> bool {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
unsafe {
|
||||
match (&mut I2C_BUS).as_mut().unwrap().write(data as u8) {
|
||||
Ok(r) => r,
|
||||
Err(_) => artiq_raise!("I2CError", "I2C write failed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn read(busno: i32, ack: bool) -> i32 {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
unsafe {
|
||||
match (&mut I2C_BUS).as_mut().unwrap().read(ack) {
|
||||
Ok(r) => r as i32,
|
||||
Err(_) => artiq_raise!("I2CError", "I2C read failed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn switch_select(busno: i32, address: i32, mask: i32) {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
let ch = match mask { //decode from mainline, PCA9548-centric API
|
||||
0x00 => None,
|
||||
0x01 => Some(0),
|
||||
0x02 => Some(1),
|
||||
0x04 => Some(2),
|
||||
0x08 => Some(3),
|
||||
0x10 => Some(4),
|
||||
0x20 => Some(5),
|
||||
0x40 => Some(6),
|
||||
0x80 => Some(7),
|
||||
_ => artiq_raise!("I2CError", "switch select supports only one channel")
|
||||
};
|
||||
unsafe {
|
||||
if (&mut I2C_BUS).as_mut().unwrap().pca954x_select(address as u8, ch).is_err() {
|
||||
artiq_raise!("I2CError", "switch select failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let mut i2c = libboard_zynq::i2c::I2c::i2c0();
|
||||
i2c.init().expect("I2C bus initialization failed");
|
||||
unsafe { I2C_BUS = Some(i2c) };
|
||||
}
|
@ -21,7 +21,7 @@ use nb;
|
||||
use void::Void;
|
||||
use libconfig::Config;
|
||||
use libcortex_a9::l2c::enable_l2_cache;
|
||||
use libboard_artiq::{logger, identifier_read, pl};
|
||||
use libboard_artiq::{logger, identifier_read, pl, i2c, io_expander};
|
||||
|
||||
const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
|
||||
const ASYNC_ERROR_BUSY: u8 = 1 << 1;
|
||||
@ -45,9 +45,6 @@ mod panic;
|
||||
mod mgmt;
|
||||
mod analyzer;
|
||||
mod irq;
|
||||
mod i2c;
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
mod io_expander;
|
||||
|
||||
static mut SEEN_ASYNC_ERRORS: u8 = 0;
|
||||
|
||||
@ -141,7 +138,7 @@ pub fn main_core0() {
|
||||
Config::new_dummy()
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
rtio_clocking::init(&mut timer, &cfg);
|
||||
|
||||
task::spawn(report_async_rtio_errors());
|
||||
|
@ -18,11 +18,12 @@ extern crate unwind;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds, print, println, mpcore, gic, stdio};
|
||||
use libboard_zynq::{timer::GlobalTimer, time::Milliseconds, print, println, mpcore, gic, stdio};
|
||||
use libsupport_zynq::ram;
|
||||
#[cfg(has_si5324)]
|
||||
use libboard_artiq::si5324;
|
||||
use libboard_artiq::{pl::csr, drtio_routing, drtioaux, logger, identifier_read};
|
||||
use libboard_artiq::{pl::csr, drtio_routing, drtioaux, logger,
|
||||
identifier_read, i2c, io_expander};
|
||||
use libcortex_a9::{spin_lock_yield, interrupt_handler, regs::{MPIDR, SP}, notify_spin_lock, asm, l2c::enable_l2_cache};
|
||||
use libregister::{RegisterW, RegisterR};
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
@ -84,7 +85,7 @@ macro_rules! forward {
|
||||
|
||||
fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
|
||||
_routing_table: &mut drtio_routing::RoutingTable, _rank: &mut u8,
|
||||
packet: drtioaux::Packet, timer: &mut GlobalTimer, i2c: &mut I2c) -> Result<(), drtioaux::Error> {
|
||||
packet: drtioaux::Packet, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
|
||||
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
||||
// and u16 otherwise; hence the `as _` conversion.
|
||||
match packet {
|
||||
@ -253,22 +254,22 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
|
||||
|
||||
drtioaux::Packet::I2cStartRequest { destination: _destination, busno: _busno } => {
|
||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||
let succeeded = i2c.start().is_ok();
|
||||
let succeeded = i2c::start().is_ok();
|
||||
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||
}
|
||||
drtioaux::Packet::I2cRestartRequest { destination: _destination, busno: _busno } => {
|
||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||
let succeeded = i2c.restart().is_ok();
|
||||
let succeeded = i2c::restart().is_ok();
|
||||
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||
}
|
||||
drtioaux::Packet::I2cStopRequest { destination: _destination, busno: _busno } => {
|
||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||
let succeeded = i2c.stop().is_ok();
|
||||
let succeeded = i2c::stop().is_ok();
|
||||
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||
}
|
||||
drtioaux::Packet::I2cWriteRequest { destination: _destination, busno: _busno, data } => {
|
||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||
match i2c.write(data) {
|
||||
match i2c::write(data as i32) {
|
||||
Ok(ack) => drtioaux::send(0,
|
||||
&drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }),
|
||||
Err(_) => drtioaux::send(0,
|
||||
@ -277,9 +278,9 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
|
||||
}
|
||||
drtioaux::Packet::I2cReadRequest { destination: _destination, busno: _busno, ack } => {
|
||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||
match i2c.read(ack) {
|
||||
match i2c::read(ack) {
|
||||
Ok(data) => drtioaux::send(0,
|
||||
&drtioaux::Packet::I2cReadReply { succeeded: true, data: data }),
|
||||
&drtioaux::Packet::I2cReadReply { succeeded: true, data: data as u8 }),
|
||||
Err(_) => drtioaux::send(0,
|
||||
&drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff })
|
||||
}
|
||||
@ -298,7 +299,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
|
||||
0x80 => Some(7),
|
||||
_ => { return drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: false }); }
|
||||
};
|
||||
let succeeded = i2c.pca954x_select(address, ch).is_ok();
|
||||
let succeeded = i2c::pca954x_select(address as i32, ch).is_ok();
|
||||
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||
}
|
||||
|
||||
@ -339,11 +340,11 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
|
||||
|
||||
fn process_aux_packets(repeaters: &mut [repeater::Repeater],
|
||||
routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8,
|
||||
timer: &mut GlobalTimer, i2c: &mut I2c) {
|
||||
timer: &mut GlobalTimer) {
|
||||
let result =
|
||||
drtioaux::recv(0).and_then(|packet| {
|
||||
if let Some(packet) = packet {
|
||||
process_aux_packet(repeaters, routing_table, rank, packet, timer, i2c)
|
||||
process_aux_packet(repeaters, routing_table, rank, packet, timer)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@ -447,11 +448,32 @@ pub extern fn main_core0() -> i32 {
|
||||
|
||||
ram::init_alloc_core0();
|
||||
|
||||
let mut i2c = I2c::i2c0();
|
||||
i2c.init().expect("I2C initialization failed");
|
||||
i2c::init();
|
||||
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
{
|
||||
let (mut io_expander0, mut io_expander1) = (io_expander::IoExpander::new(0).unwrap(), io_expander::IoExpander::new(1).unwrap());
|
||||
io_expander0.init().expect("I2C I/O expander #0 initialization failed");
|
||||
io_expander1.init().expect("I2C I/O expander #1 initialization failed");
|
||||
|
||||
// Actively drive TX_DISABLE to false on SFP0..3
|
||||
io_expander0.set_oe(0, 1 << 1).unwrap();
|
||||
io_expander0.set_oe(1, 1 << 1).unwrap();
|
||||
io_expander1.set_oe(0, 1 << 1).unwrap();
|
||||
io_expander1.set_oe(1, 1 << 1).unwrap();
|
||||
io_expander0.set(0, 1, false);
|
||||
io_expander0.set(1, 1, false);
|
||||
io_expander1.set(0, 1, false);
|
||||
io_expander1.set(1, 1, false);
|
||||
io_expander0.service().unwrap();
|
||||
io_expander1.service().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(has_si5324)]
|
||||
si5324::setup(&mut i2c, &SI5324_SETTINGS, si5324::Input::Ckin1, &mut timer).expect("cannot initialize Si5324");
|
||||
{
|
||||
let mut i2c = unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() };
|
||||
si5324::setup(&mut i2c, &SI5324_SETTINGS, si5324::Input::Ckin1, &mut timer).expect("cannot initialize Si5324");
|
||||
}
|
||||
|
||||
timer.delay_us(100_000);
|
||||
info!("Switching SYS clocks...");
|
||||
@ -495,6 +517,7 @@ pub extern fn main_core0() -> i32 {
|
||||
info!("uplink is up, switching to recovered clock");
|
||||
#[cfg(has_siphaser)]
|
||||
{
|
||||
let mut i2c = unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() };
|
||||
si5324::siphaser::select_recovered_clock(&mut i2c, true, &mut timer).expect("failed to switch clocks");
|
||||
si5324::siphaser::calibrate_skew(&mut timer).expect("failed to calibrate skew");
|
||||
}
|
||||
@ -505,7 +528,7 @@ pub extern fn main_core0() -> i32 {
|
||||
|
||||
while drtiosat_link_rx_up() {
|
||||
drtiosat_process_errors();
|
||||
process_aux_packets(&mut repeaters, &mut routing_table, &mut rank, &mut timer, &mut i2c);
|
||||
process_aux_packets(&mut repeaters, &mut routing_table, &mut rank, &mut timer);
|
||||
#[allow(unused_mut)]
|
||||
for mut rep in repeaters.iter_mut() {
|
||||
rep.service(&routing_table, rank, &mut timer);
|
||||
@ -529,7 +552,10 @@ pub extern fn main_core0() -> i32 {
|
||||
drtiosat_tsc_loaded();
|
||||
info!("uplink is down, switching to local oscillator clock");
|
||||
#[cfg(has_siphaser)]
|
||||
si5324::siphaser::select_recovered_clock(&mut i2c, false, &mut timer).expect("failed to switch clocks");
|
||||
{
|
||||
let mut i2c = unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() };
|
||||
si5324::siphaser::select_recovered_clock(&mut i2c, false, &mut timer).expect("failed to switch clocks");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user