From e51a5728e08f2c4ed87f61c945649aa500f41469 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Fri, 17 Feb 2023 12:47:28 +0800 Subject: [PATCH] Refactor i2c and io_expander to make them shared Signed-off-by: Egor Savkin --- src/libboard_artiq/src/i2c.rs | 83 +++++++++++++++++ .../src/io_expander.rs | 23 +++-- src/libboard_artiq/src/lib.rs | 3 + src/runtime/src/i2c.rs | 90 ------------------- src/runtime/src/main.rs | 7 +- src/satman/src/main.rs | 60 +++++++++---- 6 files changed, 141 insertions(+), 125 deletions(-) create mode 100644 src/libboard_artiq/src/i2c.rs rename src/{runtime => libboard_artiq}/src/io_expander.rs (88%) delete mode 100644 src/runtime/src/i2c.rs diff --git a/src/libboard_artiq/src/i2c.rs b/src/libboard_artiq/src/i2c.rs new file mode 100644 index 0000000..c141407 --- /dev/null +++ b/src/libboard_artiq/src/i2c.rs @@ -0,0 +1,83 @@ +use libboard_zynq; + +pub static mut I2C_BUS: Option = 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 { + 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 { + 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) -> 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) }; +} diff --git a/src/runtime/src/io_expander.rs b/src/libboard_artiq/src/io_expander.rs similarity index 88% rename from src/runtime/src/io_expander.rs rename to src/libboard_artiq/src/io_expander.rs index a199f76..cabd032 100644 --- a/src/runtime/src/io_expander.rs +++ b/src/libboard_artiq/src/io_expander.rs @@ -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 { // 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) } diff --git a/src/libboard_artiq/src/lib.rs b/src/libboard_artiq/src/lib.rs index 454a819..f94978d 100644 --- a/src/libboard_artiq/src/lib.rs +++ b/src/libboard_artiq/src/lib.rs @@ -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}; diff --git a/src/runtime/src/i2c.rs b/src/runtime/src/i2c.rs deleted file mode 100644 index de908f3..0000000 --- a/src/runtime/src/i2c.rs +++ /dev/null @@ -1,90 +0,0 @@ -use libboard_zynq; -use crate::artiq_raise; - -pub static mut I2C_BUS: Option = 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) }; -} diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index fe47a04..af7950f 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -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()); diff --git a/src/satman/src/main.rs b/src/satman/src/main.rs index 4cd3213..1c39a35 100644 --- a/src/satman/src/main.rs +++ b/src/satman/src/main.rs @@ -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"); + } } }