2020-03-25 20:02:01 +08:00
|
|
|
use crate::slcr;
|
2020-06-15 16:07:31 +08:00
|
|
|
use libregister::*;
|
|
|
|
use log::debug;
|
2020-01-20 19:26:29 +08:00
|
|
|
mod regs;
|
|
|
|
|
|
|
|
pub struct DevC {
|
|
|
|
regs: &'static mut regs::RegisterBlock,
|
|
|
|
}
|
|
|
|
|
2020-06-15 16:07:31 +08:00
|
|
|
/// DMA transfer type for PCAP
|
|
|
|
/// All insecure, we do not implement encrypted transfer
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
pub enum TransferType {
|
|
|
|
PcapWrite,
|
|
|
|
PcapReadback,
|
|
|
|
ConcurrentReadWrite,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const INVALID_ADDR: u32 = 0xFFFFFFFF;
|
|
|
|
|
2020-01-20 19:26:29 +08:00
|
|
|
impl DevC {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
DevC {
|
|
|
|
regs: regs::RegisterBlock::devc(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn enable(&mut self) {
|
2020-06-15 16:07:31 +08:00
|
|
|
unsafe {
|
|
|
|
// unlock register with magic pattern
|
|
|
|
self.regs.unlock.write(0x757BDF0D);
|
|
|
|
}
|
|
|
|
self.regs
|
|
|
|
.control
|
|
|
|
.modify(|_, w| w.pcap_mode(true).pcap_pr(true));
|
|
|
|
self.regs
|
|
|
|
.int_mask
|
|
|
|
.write(self::regs::int_mask::Write { inner: 0xFFFFFFFF });
|
|
|
|
self.clear_interrupts();
|
2020-01-20 19:26:29 +08:00
|
|
|
}
|
|
|
|
pub fn disable(&mut self) {
|
2020-06-15 16:07:31 +08:00
|
|
|
self.regs
|
|
|
|
.control
|
|
|
|
.modify(|_, w| w.pcap_mode(false).pcap_pr(false))
|
2020-01-20 19:26:29 +08:00
|
|
|
}
|
2020-03-25 20:02:01 +08:00
|
|
|
|
2020-05-04 22:16:53 +08:00
|
|
|
pub fn is_done(&self) -> bool {
|
|
|
|
// Note: contrary to what the TRM says, this appears to be simply
|
|
|
|
// the state of the DONE signal.
|
|
|
|
self.regs.int_sts.read().ixr_pcfg_done()
|
|
|
|
}
|
|
|
|
|
2020-06-15 16:07:31 +08:00
|
|
|
pub fn program(&mut self, src_addr: u32, len: u32) {
|
|
|
|
debug!("Init preload FPGA");
|
2020-03-25 20:02:01 +08:00
|
|
|
slcr::RegisterBlock::unlocked(|slcr| {
|
|
|
|
slcr.init_preload_fpga();
|
|
|
|
});
|
2020-06-15 16:07:31 +08:00
|
|
|
debug!("Toggling PROG_B");
|
|
|
|
// set PCFG_PROG_B to high low high
|
|
|
|
self.regs.control.modify(|_, w| w.pcfg_prog_b(true));
|
|
|
|
self.regs.control.modify(|_, w| w.pcfg_prog_b(false));
|
|
|
|
while self.regs.status.read().pcfg_init() {}
|
|
|
|
self.regs.control.modify(|_, w| w.pcfg_prog_b(true));
|
|
|
|
while !self.regs.status.read().pcfg_init() {}
|
|
|
|
self.regs.int_sts.write(
|
|
|
|
self::regs::IntSts::zeroed()
|
|
|
|
.pss_cfg_reset_b_int(true)
|
|
|
|
.ixr_pcfg_cfg_rst(true),
|
|
|
|
);
|
|
|
|
|
|
|
|
debug!("ADDR: {:0X}", src_addr);
|
|
|
|
self.dma_transfer(
|
|
|
|
src_addr | 0x1,
|
|
|
|
INVALID_ADDR | 0x1,
|
|
|
|
len,
|
|
|
|
len,
|
|
|
|
TransferType::PcapWrite,
|
|
|
|
);
|
2020-03-25 20:02:01 +08:00
|
|
|
|
2020-06-15 16:07:31 +08:00
|
|
|
self.wait_dma_transfer_complete();
|
|
|
|
debug!("INT_STS: {:0X}", self.regs.int_sts.read().inner);
|
|
|
|
debug!("STATUS: {:0X}", self.regs.status.read().inner);
|
|
|
|
|
|
|
|
debug!("Waiting for done");
|
2020-05-04 22:16:53 +08:00
|
|
|
while !self.is_done() {}
|
2020-03-25 20:02:01 +08:00
|
|
|
|
2020-06-15 16:07:31 +08:00
|
|
|
debug!("INT_STS: {:0X}", self.regs.int_sts.read().inner);
|
|
|
|
|
|
|
|
debug!("Init postload FPGA");
|
2020-03-25 20:02:01 +08:00
|
|
|
slcr::RegisterBlock::unlocked(|slcr| {
|
|
|
|
slcr.init_postload_fpga();
|
|
|
|
});
|
|
|
|
}
|
2020-06-15 16:07:31 +08:00
|
|
|
|
|
|
|
/// Initiate DMA transaction, all lengths are in words.
|
|
|
|
/// > This function is not meant to be used directly.
|
|
|
|
fn initiate_dma(&mut self, src_addr: u32, dest_addr: u32, src_len: u32, dest_len: u32) {
|
|
|
|
self.regs.dma_src_addr.modify(|_, w| w.src_addr(src_addr));
|
|
|
|
self.regs
|
|
|
|
.dma_dest_addr
|
|
|
|
.modify(|_, w| w.dest_addr(dest_addr));
|
|
|
|
self.regs.dma_src_len.modify(|_, w| w.dma_len(src_len));
|
|
|
|
self.regs.dma_dest_len.modify(|_, w| w.dma_len(dest_len));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// DMA transfer, all lengths are in words.
|
|
|
|
pub fn dma_transfer(
|
|
|
|
&mut self,
|
|
|
|
src_addr: u32,
|
|
|
|
dest_addr: u32,
|
|
|
|
src_len: u32,
|
|
|
|
dest_len: u32,
|
|
|
|
transfer_type: TransferType,
|
|
|
|
) -> Result<(), &str> {
|
|
|
|
if self.regs.status.read().dma_cmd_q_f() {
|
|
|
|
return Err("DMA busy");
|
|
|
|
}
|
|
|
|
|
|
|
|
if transfer_type != TransferType::ConcurrentReadWrite
|
|
|
|
&& !self.regs.status.read().pcfg_init()
|
|
|
|
{
|
|
|
|
return Err("Fabric not initialized");
|
|
|
|
}
|
|
|
|
match &transfer_type {
|
|
|
|
TransferType::PcapReadback => {
|
|
|
|
// clear internal PCAP loopback
|
|
|
|
self.regs.mctrl.modify(|_, w| w.pcap_lpbk(false));
|
|
|
|
// send READ frame command
|
|
|
|
self.initiate_dma(src_addr, INVALID_ADDR, src_len, 0);
|
|
|
|
// wait until DMA done
|
|
|
|
while !self.regs.int_sts.read().ixr_d_p_done() {}
|
|
|
|
// initiate the DMA write
|
|
|
|
self.initiate_dma(INVALID_ADDR, dest_addr, 0, dest_len);
|
|
|
|
}
|
|
|
|
TransferType::PcapWrite | TransferType::ConcurrentReadWrite => {
|
|
|
|
self.regs
|
|
|
|
.mctrl
|
|
|
|
.modify(|_, w| w.pcap_lpbk(transfer_type == TransferType::ConcurrentReadWrite));
|
|
|
|
// PCAP data transmitted every clock
|
|
|
|
self.regs.control.modify(|_, w| w.pcap_rate_en(false));
|
|
|
|
|
|
|
|
self.initiate_dma(src_addr, dest_addr, src_len, dest_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn wait_dma_transfer_complete(&mut self) {
|
|
|
|
debug!("Wait for DMA done");
|
|
|
|
while !self.regs.int_sts.read().ixr_dma_done() {}
|
|
|
|
self.regs
|
|
|
|
.int_sts
|
|
|
|
.write(self::regs::IntSts::zeroed().ixr_dma_done(true));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn dump_registers(&self) {
|
|
|
|
debug!("Control: 0x{:0X}", self.regs.control.read().inner);
|
|
|
|
debug!("Status: 0x{:0X}", self.regs.status.read().inner);
|
|
|
|
debug!("INT STS: 0x{:0X}", self.regs.int_sts.read().inner);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn clear_interrupts(&mut self) {
|
|
|
|
self.regs.int_sts.modify(|_, w| {
|
|
|
|
w.pss_gts_usr_b_int(true)
|
|
|
|
.pss_fst_cfg_b_int(true)
|
|
|
|
.pss_gpwrdwn_b_int(true)
|
|
|
|
.pss_gts_cfg_b_int(true)
|
|
|
|
.pss_cfg_reset_b_int(true)
|
|
|
|
.ixr_axi_wto(true)
|
|
|
|
.ixr_axi_werr(true)
|
|
|
|
.ixr_axi_rto(true)
|
|
|
|
.ixr_axi_rerr(true)
|
|
|
|
.ixr_rx_fifo_ov(true)
|
|
|
|
.ixr_wr_fifo_lvl(true)
|
|
|
|
.ixr_rd_fifo_lvl(true)
|
|
|
|
.ixr_dma_cmd_err(true)
|
|
|
|
.ixr_dma_q_ov(true)
|
|
|
|
.ixr_dma_done(true)
|
|
|
|
.ixr_d_p_done(true)
|
|
|
|
.ixr_p2d_len_err(true)
|
|
|
|
.ixr_pcfg_hmac_err(true)
|
|
|
|
.ixr_pcfg_seu_err(true)
|
|
|
|
.ixr_pcfg_por_b(true)
|
|
|
|
.ixr_pcfg_cfg_rst(true)
|
|
|
|
.ixr_pcfg_done(true)
|
|
|
|
.ixr_pcfg_init_pe(true)
|
|
|
|
.ixr_pcfg_init_ne(true)
|
|
|
|
})
|
|
|
|
}
|
2020-01-20 19:26:29 +08:00
|
|
|
}
|