forked from M-Labs/zynq-rs
devc working!
This commit is contained in:
parent
82ec1ba7a7
commit
e0f26871db
|
@ -1,11 +1,23 @@
|
|||
use libregister::*;
|
||||
use crate::slcr;
|
||||
use libregister::*;
|
||||
use log::debug;
|
||||
mod regs;
|
||||
|
||||
pub struct DevC {
|
||||
regs: &'static mut regs::RegisterBlock,
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
||||
impl DevC {
|
||||
pub fn new() -> Self {
|
||||
DevC {
|
||||
|
@ -14,16 +26,22 @@ impl DevC {
|
|||
}
|
||||
|
||||
pub fn enable(&mut self) {
|
||||
self.regs.control.modify(|_, w| {
|
||||
w.pcap_mode(true)
|
||||
.pcap_pr(true)
|
||||
})
|
||||
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();
|
||||
}
|
||||
pub fn disable(&mut self) {
|
||||
self.regs.control.modify(|_, w| {
|
||||
w.pcap_mode(false)
|
||||
.pcap_pr(false)
|
||||
})
|
||||
self.regs
|
||||
.control
|
||||
.modify(|_, w| w.pcap_mode(false).pcap_pr(false))
|
||||
}
|
||||
|
||||
pub fn is_done(&self) -> bool {
|
||||
|
@ -32,15 +50,141 @@ impl DevC {
|
|||
self.regs.int_sts.read().ixr_pcfg_done()
|
||||
}
|
||||
|
||||
pub fn program(&mut self) {
|
||||
pub fn program(&mut self, src_addr: u32, len: u32) {
|
||||
debug!("Init preload FPGA");
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
slcr.init_preload_fpga();
|
||||
});
|
||||
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,
|
||||
);
|
||||
|
||||
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");
|
||||
while !self.is_done() {}
|
||||
|
||||
debug!("INT_STS: {:0X}", self.regs.int_sts.read().inner);
|
||||
|
||||
debug!("Init postload FPGA");
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
slcr.init_postload_fpga();
|
||||
});
|
||||
}
|
||||
|
||||
/// 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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@ use libregister::{
|
|||
register, register_at,
|
||||
register_bit, register_bits, register_bits_typed,
|
||||
};
|
||||
use volatile_register::WO;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
pub control: Control,
|
||||
pub cfg: Cfg,
|
||||
pub lock: Lock,
|
||||
pub cfg: Cfg,
|
||||
pub int_sts: IntSts,
|
||||
pub int_mask: IntMask,
|
||||
pub status: Status,
|
||||
|
@ -15,9 +16,13 @@ pub struct RegisterBlock {
|
|||
pub dma_dest_addr: DmaDestAddr,
|
||||
pub dma_src_len: DmaSrcLen,
|
||||
pub dma_dest_len: DmaDestLen,
|
||||
unused0: u32,
|
||||
pub multiboot_addr: MultibootAddr,
|
||||
pub unlock: Unlock,
|
||||
unused1: u32,
|
||||
pub unlock: WO<u32>,
|
||||
unused2: [u32; 18],
|
||||
pub mctrl: MCtrl,
|
||||
unused3: [u32; 31],
|
||||
pub xadcif_cfg: XADCIfCfg,
|
||||
pub xadcif_int_sts: XADCIfIntSts,
|
||||
pub xadcif_int_mask: XADCIfIntMask,
|
||||
|
@ -71,18 +76,18 @@ pub enum WFifoTh {
|
|||
ThreeFourthEmpty = 0b10, // Three fourth empty for write
|
||||
Empty = 0b11, // Empty for write
|
||||
}
|
||||
register_bits_typed!(cfg, wfifo_th, u8, WFifoTh, 10, 11);
|
||||
register_bits_typed!(cfg, wfifo_th, u8, WFifoTh, 8, 9);
|
||||
register_bit!(cfg, rclk_edge, 7);
|
||||
register_bit!(cfg, wclk_edge, 6);
|
||||
register_bit!(cfg, disable_src_inc, 5);
|
||||
register_bit!(cfg, disable_dst_inc, 4);
|
||||
|
||||
register!(int_sts, IntSts, RW, u32);
|
||||
register_bit!(int_sts, pps_gts_usr_b_int, 31);
|
||||
register_bit!(int_sts, pps_fst_cfg_b_int, 30);
|
||||
register_bit!(int_sts, pps_gpwrdwn_b_int, 29);
|
||||
register_bit!(int_sts, pps_gts_cfg_b_int, 27);
|
||||
register_bit!(int_sts, pps_cfg_reset_b_int, 26);
|
||||
register_bit!(int_sts, pss_gts_usr_b_int, 31);
|
||||
register_bit!(int_sts, pss_fst_cfg_b_int, 30);
|
||||
register_bit!(int_sts, pss_gpwrdwn_b_int, 29);
|
||||
register_bit!(int_sts, pss_gts_cfg_b_int, 28);
|
||||
register_bit!(int_sts, pss_cfg_reset_b_int, 27);
|
||||
register_bit!(int_sts, ixr_axi_wto, 23);
|
||||
register_bit!(int_sts, ixr_axi_werr, 22);
|
||||
register_bit!(int_sts, ixr_axi_rto, 21);
|
||||
|
@ -148,23 +153,20 @@ register_bit!(status, efuse_sec_en, 2);
|
|||
register_bit!(status, efuse_jtag_dis, 1);
|
||||
|
||||
register!(dma_src_addr, DmaSrcAddr, RW, u32);
|
||||
register_bits!(dma_src_addr, src_addr, u8, 0, 31);
|
||||
register_bits!(dma_src_addr, src_addr, u32, 0, 31);
|
||||
|
||||
register!(dma_dest_addr, DmaDestAddr, RW, u32);
|
||||
register_bits!(dma_dest_addr, dest_addr, u8, 0, 31);
|
||||
register_bits!(dma_dest_addr, dest_addr, u32, 0, 31);
|
||||
|
||||
register!(dma_src_len, DmaSrcLen, RW, u32);
|
||||
register_bits!(dma_src_len, dma_len, u8, 0, 26);
|
||||
register_bits!(dma_src_len, dma_len, u32, 0, 26);
|
||||
|
||||
register!(dma_dest_len, DmaDestLen, RW, u32);
|
||||
register_bits!(dma_dest_len, dma_len, u8, 0, 26);
|
||||
register_bits!(dma_dest_len, dma_len, u32, 0, 26);
|
||||
|
||||
register!(multiboot_addr, MultibootAddr, RW, u32);
|
||||
register_bits!(multiboot_addr, multiboot_addr, u8, 0, 12);
|
||||
|
||||
register!(unlock, Unlock, RW, u32);
|
||||
register_bits!(unlock, unlock, u8, 0, 31);
|
||||
|
||||
register!(mctrl, MCtrl, RW, u32);
|
||||
register_bits!(mctrl, ps_version, u8, 28, 31);
|
||||
register_bit!(mctrl, pcfg_por_b, 8);
|
||||
|
|
Loading…
Reference in New Issue