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