use super::{AxiError, HlCommsInterface};
use crate::{arc_msg::TypedArcMsg, ArcMsg, ChipImpl};
pub struct Spi {
gpio2_pad_trien_cntl: u64,
gpio2_pad_drv_cntl: u64,
gpio2_pad_rxen_cntl: u64,
spi_cntl: u64,
spi_ctrlr0: u64,
spi_ctrlr1: u64,
spi_ssienr: u64,
spi_ser: u64,
spi_sr: u64,
spi_dr: u64,
spi_baudr: u64,
}
const RX_BUFFER_DEPTH: u32 = 8;
const TX_BUFFER_DEPTH: u32 = 8;
const PAGE_SIZE: u32 = 256;
const SECTOR_SIZE: u32 = 4 * 1024;
const SPI_CNTL_CLK_DISABLE: u32 = 0x1 << 8;
const SPI_CNTL_SPI_DISABLE: u32 = 0x0 << 0;
const SPI_CNTL_SPI_ENABLE: u32 = 0x1 << 0;
const SPI_SSIENR_ENABLE: u32 = 0x1;
const SPI_SSIENR_DISABLE: u32 = 0x0;
const SPI_WR_EN_CMD: u8 = 0x06;
const SPI_WR_ER_CMD: u8 = 0x20;
const SPI_RD_CMD: u8 = 0x03;
const SPI_WR_CMD: u8 = 0x02;
const SPI_RD_STATUS_CMD: u8 = 0x05;
const SPI_WR_STATUS_CMD: u8 = 0x01;
const SPI_CHIP_ERASE_CMD: u8 = 0xC7;
fn spi_ctrl0_spi_scph(scph: u32) -> u32 {
(scph << 6) & 0x1
}
const SPI_CTRL0_TMOD_TRANSMIT_ONLY: u32 = 0x1 << 8;
const SPI_CTRL0_TMOD_EEPROM_READ: u32 = 0x3 << 8;
const SPI_CTRL0_SPI_FRF_STANDARD: u32 = 0x0 << 21;
const SPI_CTRL0_DFS32_FRAME_08BITS: u32 = 0x7 << 16;
fn spi_ctrl1_ndf(frame_count: u32) -> u32 {
(frame_count << 0) & 0xffff
}
const SPI_SR_RFNE: u32 = 0x1 << 3;
const SPI_SR_TFE: u32 = 0x1 << 2;
const SPI_SR_BUSY: u32 = 0x1 << 0;
const SPI_PAGE_ERASE_SIZE: u32 = 0x1000;
const SPI_ROM_SIZE: u32 = 1 << 24;
const ARC_SPI_CHUNK_SIZE: u32 = SPI_PAGE_ERASE_SIZE;
fn spi_ser_slave_disable(slave_id: u32) -> u32 {
0x0 << slave_id
}
fn spi_ser_slave_enable(slave_id: u32) -> u32 {
0x1 << slave_id
}
fn spi_baudr_sckdv(ssi_clk_div: u32) -> u32 {
(ssi_clk_div << 0) & 0xffff
}
impl Spi {
pub fn new(chip: &impl ChipImpl) -> Result<Self, AxiError> {
Ok(Spi {
gpio2_pad_trien_cntl: chip.axi_translate("ARC_RESET.GPIO2_PAD_TRIEN_CNTL")?.addr,
gpio2_pad_drv_cntl: chip.axi_translate("ARC_RESET.GPIO2_PAD_DRV_CNTL")?.addr,
gpio2_pad_rxen_cntl: chip.axi_translate("ARC_RESET.GPIO2_PAD_RXEN_CNTL")?.addr,
spi_ctrlr0: chip.axi_translate("ARC_SPI.SPI_CTRLR0")?.addr,
spi_ctrlr1: chip.axi_translate("ARC_SPI.SPI_CTRLR1")?.addr,
spi_ssienr: chip.axi_translate("ARC_SPI.SPI_SSIENR")?.addr,
spi_ser: chip.axi_translate("ARC_SPI.SPI_SER")?.addr,
spi_sr: chip.axi_translate("ARC_SPI.SPI_SR")?.addr,
spi_dr: chip.axi_translate("ARC_SPI.SPI_DR")?.addr,
spi_baudr: chip.axi_translate("ARC_SPI.SPI_BAUDR")?.addr,
spi_cntl: chip.axi_translate("ARC_RESET.SPI_CNTL")?.addr,
})
}
fn init(&self, chip: &impl ChipImpl, clock_div: u32) -> Result<(), Box<dyn std::error::Error>> {
let mut reg = chip.axi_read32(self.gpio2_pad_trien_cntl)?;
reg |= 1 << 2; reg &= !(1 << 5); reg &= !(1 << 6); chip.axi_write32(self.gpio2_pad_trien_cntl, reg)?;
chip.axi_write32(self.gpio2_pad_drv_cntl, 0xffffffff)?;
let mut reg = chip.axi_read32(self.gpio2_pad_rxen_cntl)?;
reg |= 0x3f << 1; chip.axi_write32(self.gpio2_pad_rxen_cntl, reg)?;
chip.axi_write32(self.spi_cntl, SPI_CNTL_SPI_ENABLE)?;
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_DISABLE)?;
chip.axi_write32(
self.spi_ctrlr0,
SPI_CTRL0_TMOD_EEPROM_READ
| SPI_CTRL0_SPI_FRF_STANDARD
| SPI_CTRL0_DFS32_FRAME_08BITS
| spi_ctrl0_spi_scph(0x1),
)?;
chip.axi_write32(self.spi_ser, 0)?;
chip.axi_write32(self.spi_baudr, spi_baudr_sckdv(clock_div))?;
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_ENABLE)?;
Ok(())
}
fn disable(&self, chip: &impl ChipImpl) -> Result<(), Box<dyn std::error::Error>> {
chip.axi_write32(self.spi_cntl, SPI_CNTL_CLK_DISABLE | SPI_CNTL_SPI_DISABLE)?;
Ok(())
}
pub fn read_status(
&self,
chip: &impl ChipImpl,
register: u8,
) -> Result<u8, Box<dyn std::error::Error>> {
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_DISABLE)?;
chip.axi_write32(
self.spi_ctrlr0,
SPI_CTRL0_TMOD_EEPROM_READ
| SPI_CTRL0_SPI_FRF_STANDARD
| SPI_CTRL0_DFS32_FRAME_08BITS
| spi_ctrl0_spi_scph(0x1),
)?;
chip.axi_write32(self.spi_ctrlr1, spi_ctrl1_ndf(0))?;
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_ENABLE)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
chip.axi_write32(self.spi_dr, register as u32)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_enable(0))?;
loop {
if (chip.axi_read32(self.spi_sr)? & SPI_SR_RFNE) != 0 {
break;
}
}
let read_buf = (chip.axi_read32(self.spi_dr)? & 0xff) as u8;
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
Ok(read_buf)
}
pub fn unlock(&self, chip: &impl ChipImpl) -> Result<(), Box<dyn std::error::Error>> {
self.lock(chip, 0)
}
pub fn lock(
&self,
chip: &impl ChipImpl,
sections: u8,
) -> Result<(), Box<dyn std::error::Error>> {
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_DISABLE)?;
chip.axi_write32(
self.spi_ctrlr0,
SPI_CTRL0_TMOD_TRANSMIT_ONLY
| SPI_CTRL0_SPI_FRF_STANDARD
| SPI_CTRL0_DFS32_FRAME_08BITS
| spi_ctrl0_spi_scph(0x1),
)?;
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_ENABLE)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
chip.axi_write32(self.spi_dr, SPI_WR_EN_CMD as u32)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_enable(0))?;
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_TFE == SPI_SR_TFE {
break;
}
}
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_BUSY != SPI_SR_BUSY {
break;
}
}
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
chip.axi_write32(self.spi_dr, SPI_WR_STATUS_CMD as u32)?;
if sections < 5 {
chip.axi_write32(self.spi_dr, 0x3 << 5 | (sections as u32) << 2)?;
} else {
chip.axi_write32(self.spi_dr, 0x1 << 5 | (sections as u32 - 5) << 2)?;
}
chip.axi_write32(self.spi_ser, spi_ser_slave_enable(0))?;
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_TFE == SPI_SR_TFE {
break;
}
}
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_BUSY != SPI_SR_BUSY {
break;
}
}
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
loop {
let busy = self.read_status(chip, SPI_RD_STATUS_CMD)? & 0x1;
if busy != 0x1 {
break;
}
}
Ok(())
}
pub fn read(
&self,
chip: &impl ChipImpl,
mut addr: u32,
read: &mut [u8],
) -> Result<(), Box<dyn std::error::Error>> {
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_DISABLE)?;
chip.axi_write32(
self.spi_ctrlr0,
SPI_CTRL0_TMOD_EEPROM_READ
| SPI_CTRL0_SPI_FRF_STANDARD
| SPI_CTRL0_DFS32_FRAME_08BITS
| spi_ctrl0_spi_scph(0x1),
)?;
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_ENABLE)?;
let mut frame_index = 0;
while frame_index < read.len() {
let frames = RX_BUFFER_DEPTH.min((read.len() - frame_index) as u32);
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_DISABLE)?;
chip.axi_write32(self.spi_ctrlr1, spi_ctrl1_ndf(frames - 1))?;
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_ENABLE)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
chip.axi_write32(self.spi_dr, SPI_RD_CMD as u32)?;
chip.axi_write32(self.spi_dr, (addr >> 16) & 0xff)?;
chip.axi_write32(self.spi_dr, (addr >> 8) & 0xff)?;
chip.axi_write32(self.spi_dr, (addr >> 0) & 0xff)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_enable(0))?;
for _ in 0..frames {
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_RFNE != 0 {
break;
}
}
read[frame_index] = (chip.axi_read32(self.spi_dr)? & 0xff) as u8;
frame_index += 1;
}
addr += frames;
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
}
Ok(())
}
fn raw_write(
&self,
chip: &impl ChipImpl,
mut addr: u32,
write: &[u8],
) -> Result<(), Box<dyn std::error::Error>> {
let mut frame_index = 0;
while frame_index < write.len() {
let frames = (TX_BUFFER_DEPTH - 4)
.min((write.len() - frame_index) as u32)
.min(PAGE_SIZE - (addr % PAGE_SIZE));
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_DISABLE)?;
chip.axi_write32(
self.spi_ctrlr0,
SPI_CTRL0_TMOD_TRANSMIT_ONLY
| SPI_CTRL0_SPI_FRF_STANDARD
| SPI_CTRL0_DFS32_FRAME_08BITS
| spi_ctrl0_spi_scph(0x1),
)?;
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_ENABLE)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
chip.axi_write32(self.spi_dr, SPI_WR_EN_CMD as u32)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_enable(0))?;
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_TFE == SPI_SR_TFE {
break;
}
}
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_BUSY != SPI_SR_BUSY {
break;
}
}
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
chip.axi_write32(self.spi_dr, SPI_WR_CMD as u32)?;
chip.axi_write32(self.spi_dr, (addr >> 16) & 0xff)?;
chip.axi_write32(self.spi_dr, (addr >> 8) & 0xff)?;
chip.axi_write32(self.spi_dr, (addr >> 0) & 0xff)?;
for _ in 0..frames {
chip.axi_write32(self.spi_dr, write[frame_index] as u32)?;
frame_index += 1;
}
chip.axi_write32(self.spi_ser, spi_ser_slave_enable(0))?;
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_TFE == SPI_SR_TFE {
break;
}
}
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_BUSY != SPI_SR_BUSY {
break;
}
}
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
addr += frames;
loop {
let busy = self.read_status(chip, SPI_RD_STATUS_CMD)? & 0x1;
if busy != 0x1 {
break;
}
}
}
Ok(())
}
fn erase(&self, chip: &impl ChipImpl, addr: u32) -> Result<(), Box<dyn std::error::Error>> {
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_DISABLE)?;
chip.axi_write32(
self.spi_ctrlr0,
SPI_CTRL0_TMOD_TRANSMIT_ONLY
| SPI_CTRL0_SPI_FRF_STANDARD
| SPI_CTRL0_DFS32_FRAME_08BITS
| spi_ctrl0_spi_scph(0x1),
)?;
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_ENABLE)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
chip.axi_write32(self.spi_dr, SPI_WR_EN_CMD as u32)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_enable(0))?;
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_TFE == SPI_SR_TFE {
break;
}
}
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_BUSY != SPI_SR_BUSY {
break;
}
}
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
chip.axi_write32(self.spi_dr, SPI_WR_ER_CMD as u32)?;
chip.axi_write32(self.spi_dr, ((addr >> 16) & 0xff) as u32)?;
chip.axi_write32(self.spi_dr, ((addr >> 8) & 0xff) as u32)?;
chip.axi_write32(self.spi_dr, ((addr >> 0) & 0xff) as u32)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_enable(0))?;
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_TFE == SPI_SR_TFE {
break;
}
}
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_BUSY != SPI_SR_BUSY {
break;
}
}
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
loop {
let busy = self.read_status(chip, SPI_RD_STATUS_CMD)? & 0x1;
if busy != 0x1 {
break;
}
}
Ok(())
}
#[allow(dead_code)]
fn full_erase(&self, chip: &impl ChipImpl) -> Result<(), Box<dyn std::error::Error>> {
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_DISABLE)?;
chip.axi_write32(
self.spi_ctrlr0,
SPI_CTRL0_TMOD_TRANSMIT_ONLY
| SPI_CTRL0_SPI_FRF_STANDARD
| SPI_CTRL0_DFS32_FRAME_08BITS
| spi_ctrl0_spi_scph(0x1),
)?;
chip.axi_write32(self.spi_ssienr, SPI_SSIENR_ENABLE)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
chip.axi_write32(self.spi_dr, SPI_WR_EN_CMD as u32)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_enable(0))?;
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_TFE == SPI_SR_TFE {
break;
}
}
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_BUSY != SPI_SR_BUSY {
break;
}
}
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
chip.axi_write32(self.spi_dr, SPI_CHIP_ERASE_CMD as u32)?;
chip.axi_write32(self.spi_ser, spi_ser_slave_enable(0))?;
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_TFE == SPI_SR_TFE {
break;
}
}
loop {
let spi_status = chip.axi_read32(self.spi_sr)?;
if spi_status & SPI_SR_BUSY != SPI_SR_BUSY {
break;
}
}
chip.axi_write32(self.spi_ser, spi_ser_slave_disable(0))?;
loop {
let busy = self.read_status(chip, SPI_RD_STATUS_CMD)? & 0x1;
if busy != 0x1 {
break;
}
}
Ok(())
}
pub fn write(
&self,
chip: &impl ChipImpl,
addr: u32,
data: &[u8],
) -> Result<(), Box<dyn std::error::Error>> {
let mut existing = vec![0; data.len()];
self.read(chip, addr, &mut existing)?;
if existing.iter().copied().all(|v| v == 0xff) {
self.raw_write(chip, addr, data)?;
} else if existing
.iter()
.copied()
.zip(data.iter().copied())
.any(|(a, b)| a != b)
{
let sector_start = addr / SECTOR_SIZE;
let num_sectors =
(addr + data.len() as u32 + SECTOR_SIZE - 1) / SECTOR_SIZE - sector_start;
existing.resize((num_sectors * SECTOR_SIZE) as usize, 0);
self.read(chip, sector_start * SECTOR_SIZE, &mut existing)?;
let existing_offset = addr - (sector_start * SECTOR_SIZE);
for (i, o) in existing[existing_offset as usize..][..data.len()]
.iter_mut()
.zip(data.iter().copied())
{
*i = o;
}
for i in 0..num_sectors {
let sector_address = (sector_start + i) * SECTOR_SIZE;
let sector_offset = i * SECTOR_SIZE;
self.erase(chip, sector_address)?;
self.raw_write(
chip,
sector_address,
&existing[sector_offset as usize..][..SECTOR_SIZE as usize],
)?;
}
}
Ok(())
}
}
pub struct ActiveSpi {
spi: Spi,
use_arc: bool,
}
impl ActiveSpi {
pub fn new(chip: &impl ChipImpl, use_arc: bool) -> Result<Self, Box<dyn std::error::Error>> {
let spi = Spi::new(chip)?;
Ok(ActiveSpi { spi, use_arc })
}
fn spi_arc_read_chunk(
chip: &impl ChipImpl,
spi_dump_addr: u64,
addr: u32,
) -> Result<[u8; ARC_SPI_CHUNK_SIZE as usize], Box<dyn std::error::Error>> {
chip.arc_msg(super::ArcMsgOptions {
msg: ArcMsg::Typed(TypedArcMsg::SpiRead { addr }),
..Default::default()
})?;
let mut data = [0; ARC_SPI_CHUNK_SIZE as usize];
chip.axi_read(spi_dump_addr, &mut data)?;
Ok(data)
}
fn spi_arc_write_chunk(
chip: &impl ChipImpl,
spi_dump_addr: u64,
data: [u8; ARC_SPI_CHUNK_SIZE as usize],
) -> Result<(), Box<dyn std::error::Error>> {
chip.axi_write(spi_dump_addr, &data)?;
chip.arc_msg(super::ArcMsgOptions {
msg: ArcMsg::Typed(TypedArcMsg::SpiWrite),
..Default::default()
})?;
Ok(())
}
fn get_aligned_params(addr: u32, size: u32) -> Result<(u32, u32, u32), String> {
if addr + size > SPI_ROM_SIZE {
return Err("Requested size exceeds SPI ROM.".to_string());
}
let start_addr = (addr / ARC_SPI_CHUNK_SIZE) * ARC_SPI_CHUNK_SIZE; let end_addr =
((addr + size + ARC_SPI_CHUNK_SIZE - 1) / ARC_SPI_CHUNK_SIZE) * ARC_SPI_CHUNK_SIZE;
let num_chunks = (end_addr - start_addr) / ARC_SPI_CHUNK_SIZE;
let start_offset = addr - start_addr;
Ok((start_addr, num_chunks, start_offset))
}
fn get_spi_dump_address(
chip: &impl ChipImpl,
) -> Result<Option<u64>, Box<dyn std::error::Error>> {
let dump_addr = if let Ok(result) = chip.arc_msg(super::ArcMsgOptions {
msg: ArcMsg::Typed(TypedArcMsg::GetSpiDumpAddr),
..Default::default()
}) {
match result {
crate::ArcMsgOk::Ok { rc: _, arg } => Some(arg),
crate::ArcMsgOk::OkNoWait => None,
}
} else {
None
};
let csm_offset = chip.axi_translate("ARC_CSM.DATA[0]")?.addr - 0x10000000 as u64;
if let Some(dump_addr) = dump_addr {
Ok(Some(csm_offset + (dump_addr as u64)))
} else {
Ok(None)
}
}
fn spi_arc_read(
&self,
chip: &impl ChipImpl,
spi_dump_addr: u64,
addr: u32,
data: &mut [u8],
) -> Result<(), Box<dyn std::error::Error>> {
let (start_addr, num_chunks, start_offset) =
Self::get_aligned_params(addr, data.len() as u32)?;
for chunk in 0..num_chunks {
let offset = chunk * ARC_SPI_CHUNK_SIZE;
let addr = start_addr + offset;
let read_data = Self::spi_arc_read_chunk(chip, spi_dump_addr, addr)?;
if offset < start_offset {
for (a, b) in data[offset as usize..]
.iter_mut()
.zip(read_data[(start_offset - offset) as usize..].into_iter())
{
*a = *b;
}
} else {
for (a, b) in data[(offset - start_offset) as usize..]
.iter_mut()
.zip(read_data.into_iter())
{
*a = b;
}
};
}
Ok(())
}
fn spi_arc_write(
&self,
chip: &impl ChipImpl,
spi_dump_addr: u64,
addr: u32,
data: &[u8],
) -> Result<(), Box<dyn std::error::Error>> {
let (start_addr, num_chunks, start_offset) =
Self::get_aligned_params(addr, data.len() as u32)?;
for chunk in 0..num_chunks {
let offset = chunk * ARC_SPI_CHUNK_SIZE;
let addr = start_addr + offset;
let mut read_data = Self::spi_arc_read_chunk(chip, spi_dump_addr, addr)?;
let orig_data = read_data.clone();
if offset < start_offset {
for (a, b) in data[offset as usize..]
.iter()
.zip(read_data[(start_offset - offset) as usize..].iter_mut())
{
*b = *a;
}
} else {
for (a, b) in data[(offset - start_offset) as usize..]
.iter()
.zip(read_data.iter_mut())
{
*b = *a;
}
};
if read_data != orig_data {
Self::spi_arc_write_chunk(chip, spi_dump_addr, read_data)?;
}
}
Ok(())
}
fn get_clock(&self, chip: &impl ChipImpl) -> Result<u32, Box<dyn std::error::Error>> {
let arcclk = if let Ok(telemetry) = chip.get_telemetry() {
telemetry.smbus_tx_arcclk
} else {
540
};
let mut clock_div = (arcclk as f32 / 20.0).ceil() as u32;
clock_div += clock_div % 2;
Ok(clock_div)
}
pub fn write(
&self,
chip: &impl ChipImpl,
addr: u32,
write: &[u8],
) -> Result<(), Box<dyn std::error::Error>> {
let clock_div = self.get_clock(chip)?;
self.spi.init(chip, clock_div)?;
self.spi.unlock(chip)?;
self.spi.disable(chip)?;
let write_result: Result<(), Box<dyn std::error::Error>> = (|| {
if let (true, Some(spi_addr)) = (self.use_arc, Self::get_spi_dump_address(chip)?) {
self.spi_arc_write(chip, spi_addr, addr, write)?;
} else {
self.spi.init(chip, clock_div)?;
self.spi.write(chip, addr, write)?;
self.spi.disable(chip)?;
}
Ok(())
})();
let lock_result = (|| {
self.spi.init(chip, clock_div)?;
self.spi.lock(chip, 8)?;
self.spi.disable(chip)?;
Ok(())
})();
if let Err(err) = write_result {
return Err(err);
}
lock_result
}
pub fn read(
&self,
chip: &impl ChipImpl,
addr: u32,
read: &mut [u8],
) -> Result<(), Box<dyn std::error::Error>> {
if let (true, Some(spi_addr)) = (self.use_arc, Self::get_spi_dump_address(chip)?) {
self.spi_arc_read(chip, spi_addr, addr, read)?;
} else {
let clock_div = self.get_clock(chip)?;
self.spi.init(chip, clock_div)?;
self.spi.read(chip, addr, read)?;
self.spi.disable(chip)?;
}
Ok(())
}
}