diff --git a/Cargo.lock b/Cargo.lock index ea23f02..1623fe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,6 +69,7 @@ dependencies = [ "embedded-hal 1.0.0-alpha.1", "embedded-io", "fugit", + "heapless", "hex-literal", "panic-halt", "paste", @@ -111,6 +112,12 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "clap" version = "4.5.40" @@ -247,12 +254,31 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.5.0" @@ -430,6 +456,12 @@ dependencies = [ "serde", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.1" diff --git a/Cargo.toml b/Cargo.toml index 0b117f2..9d1a57e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ test-hmac = [] test-hash = [] spi_dma = [] spi_dma_write = [] +spi_dma_irq = [] spi_monitor = [] [dependencies] @@ -33,6 +34,7 @@ embedded-io = "0.6.1" fugit = "0.3.7" proposed-traits = { git = "https://github.com/rusty1968/proposed_traits.git", package = "proposed-traits", rev = "85641310df5a5276c67f81621b104322cff0286c" } hex-literal = "0.4" +heapless = "0.8.0" paste = "1.0" cortex-m = { version = "0.7.5" } diff --git a/src/common.rs b/src/common.rs index bf5909d..14d2037 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,5 +1,9 @@ // Licensed under the Apache-2.0 license +use crate::uart::UartController; +use core::ops::{Index, IndexMut}; +use embedded_io::Write; + pub struct DummyDelay; impl embedded_hal::delay::DelayNs for DummyDelay { @@ -10,6 +14,15 @@ impl embedded_hal::delay::DelayNs for DummyDelay { } } +pub fn fill_random(buf: &mut [u8], seed: &mut u32) { + for b in buf.iter_mut() { + *seed ^= *seed << 13; + *seed ^= *seed >> 17; + *seed ^= *seed << 5; + *b = (*seed & 0xFF) as u8; + } +} + #[repr(align(32))] pub struct DmaBuffer { pub buf: [u8; N], @@ -38,18 +51,18 @@ impl DmaBuffer { } #[must_use] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { N } #[must_use] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { N == 0 } #[must_use] - pub fn as_slice(&self) -> &[u8] { - &self.buf + pub fn as_slice(&self, start: usize, end: usize) -> &[u8] { + &self.buf[start..end] } pub fn as_mut_slice(&mut self, start: usize, end: usize) -> &mut [u8] { @@ -57,8 +70,6 @@ impl DmaBuffer { } } -use core::ops::{Index, IndexMut}; - impl Index for DmaBuffer { type Output = u8; fn index(&self, idx: usize) -> &Self::Output { @@ -71,3 +82,37 @@ impl IndexMut for DmaBuffer { &mut self.buf[idx] } } + +pub trait Logger { + fn debug(&mut self, msg: &str); + fn error(&mut self, msg: &str); +} + +// No-op implementation for production builds +pub struct NoOpLogger; +impl Logger for NoOpLogger { + fn debug(&mut self, _msg: &str) {} + fn error(&mut self, _msg: &str) {} +} + +// UART logger adapter (separate concern) +pub struct UartLogger<'a> { + uart: &'a mut UartController<'a>, +} + +impl<'a> UartLogger<'a> { + pub fn new(uart: &'a mut UartController<'a>) -> Self { + UartLogger { uart } + } +} + +impl<'a> Logger for UartLogger<'a> { + fn debug(&mut self, msg: &str) { + writeln!(self.uart, "{msg}").ok(); + write!(self.uart, "\r").ok(); + } + fn error(&mut self, msg: &str) { + writeln!(self.uart, "ERROR: {msg}").ok(); + write!(self.uart, "\r").ok(); + } +} diff --git a/src/main.rs b/src/main.rs index def120d..c70aaab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,10 +18,10 @@ use aspeed_ddk::syscon::{ClockId, ResetId, SysCon}; use fugit::MillisDurationU32 as MilliSeconds; use aspeed_ddk::tests::functional::ecdsa_test::run_ecdsa_tests; -use aspeed_ddk::tests::functional::gpio_test; use aspeed_ddk::tests::functional::hash_test::run_hash_tests; use aspeed_ddk::tests::functional::hmac_test::run_hmac_tests; use aspeed_ddk::tests::functional::rsa_test::run_rsa_tests; +use aspeed_ddk::tests::functional::{gpio_test, spim_test}; use panic_halt as _; use proposed_traits::system_control::ResetControl; @@ -142,6 +142,7 @@ fn main() -> ! { writeln!(uart_controller, "\r\nHello, world!!\r\n").unwrap(); let delay = DummyDelay; + let mut syscon = SysCon::new(delay.clone(), scu); // Enable HACE (Hash and Crypto Engine) @@ -167,12 +168,28 @@ fn main() -> ! { test_wdt(&mut uart_controller); let test_spicontroller = false; + let test_irq = true; if test_spicontroller { - spi::spitest::test_fmc(&mut uart_controller); - spi::spitest::test_spi(&mut uart_controller); - + if test_irq { + writeln!(uart_controller, "\r\nTEST SPI IRQ!!\r\n").unwrap(); + + spi::spidmairqtest::test_fmc_dma_irq(&mut uart_controller); + spi::spidmairqtest::test_spi_dma_irq(&mut uart_controller); + } else { + spi::spitest::test_fmc(&mut uart_controller); + spi::spitest::test_spi(&mut uart_controller); + //gpio_test::test_gpio_flash_power(&mut uart_controller); + // spi::spitest::test_spi2(&mut uart_controller); + } + let mut delay1 = DummyDelay; + delay1.delay_ns(10_000_000); + } + let spim_test = false; + if spim_test { + // use to release ast2600 + spim_test::test_spim0(&mut uart_controller); gpio_test::test_gpio_flash_power(&mut uart_controller); - spi::spitest::test_spi2(&mut uart_controller); + gpio_test::test_gpio_bmc_reset(&mut uart_controller); } // Initialize the peripherals here if needed loop { diff --git a/src/spi/device.rs b/src/spi/device.rs index aebe83f..b4dc57e 100644 --- a/src/spi/device.rs +++ b/src/spi/device.rs @@ -1,40 +1,45 @@ // Licensed under the Apache-2.0 license +use crate::spimonitor::SpiMonitorNum; + use super::SpiBusWithCs; use super::SpiError; -use crate::spimonitor::{SpiMonitor, SpipfInstance}; use embedded_hal::spi::{ErrorType, Operation, SpiDevice}; #[derive(Debug)] -pub struct ChipSelectDevice<'a, B, SPIPF> +pub struct ChipSelectDevice<'a, B> where B: SpiBusWithCs, - SPIPF: SpipfInstance, { pub bus: &'a mut B, pub cs: usize, - pub spi_monitor: Option<&'a mut SpiMonitor>, + pub spim: Option, } -impl<'a, B, SPIPF> ErrorType for ChipSelectDevice<'a, B, SPIPF> +impl<'a, B> ErrorType for ChipSelectDevice<'a, B> where B: SpiBusWithCs, - SPIPF: SpipfInstance, { type Error = B::Error; } -impl<'a, B, SPIPF> SpiDevice for ChipSelectDevice<'a, B, SPIPF> +impl From for u32 { + #[inline] + fn from(v: SpiMonitorNum) -> u32 { + v as u32 + } +} + +impl<'a, B> SpiDevice for ChipSelectDevice<'a, B> where B: SpiBusWithCs, - SPIPF: SpipfInstance, { fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), SpiError> { self.bus.select_cs(self.cs)?; - if let Some(spim) = self.spi_monitor.as_mut() { + if let Some(spim) = self.spim { if self.bus.get_master_id() != 0 { - spim.spim_scu_ctrl_set(0x8, 0x8); - spim.spim_scu_ctrl_set(0x7, 1 + SPIPF::FILTER_ID as u32); + super::spim_scu_ctrl_set(0x8, 0x8); + super::spim_scu_ctrl_set(0x7, 1 + u32::from(spim)); } super::spim_proprietary_pre_config(); } @@ -48,14 +53,12 @@ where Operation::DelayNs(_) => todo!(), }; } - - super::spim_proprietary_post_config(); - if let Some(spim) = self.spi_monitor.as_mut() { + if let Some(_spim) = self.spim { + super::spim_proprietary_post_config(); if self.bus.get_master_id() != 0 { - spim.spim_scu_ctrl_clear(0xf); + super::spim_scu_ctrl_clear(0xf); } } - self.bus.deselect_cs(self.cs)?; Ok(()) } diff --git a/src/spi/fmccontroller.rs b/src/spi/fmccontroller.rs index 5e92e33..cdc2657 100644 --- a/src/spi/fmccontroller.rs +++ b/src/spi/fmccontroller.rs @@ -480,6 +480,7 @@ impl<'a> FmcController<'a> { checksum } + fn spi_nor_transceive_user(&mut self, op_info: &mut SpiNorData) { let cs: usize = self.current_cs; let dummy = [0u8; 12]; @@ -490,7 +491,7 @@ impl<'a> FmcController<'a> { u32::try_from(cs).unwrap(), self.spi_data.decode_addr[cs].start ); - + self.activate_user(); // Send command let cmd_mode = self.spi_data.cmd_mode[cs].user | super::spi_io_mode_user(u32::from(super::get_cmd_buswidth(op_info.mode as u32))); @@ -529,6 +530,7 @@ impl<'a> FmcController<'a> { } else { unsafe { spi_write_data(start_ptr, op_info.tx_buf) }; } + self.deactivate_user(); } // Helper wrappers would be defined for spi_write_data, spi_read_data, io_mode_user, etc. @@ -590,7 +592,8 @@ impl<'a> FmcController<'a> { } } - fn dma_disable(&mut self) { + pub fn dma_disable(&mut self) { + dbg!(self, "dma disable"); self.regs.fmc080().write(|w| unsafe { w.bits(0x0) }); self.regs @@ -598,42 +601,67 @@ impl<'a> FmcController<'a> { .write(|w| unsafe { w.bits(SPI_DMA_DISCARD_REQ_MAGIC) }); } - fn wait_for_dma_completion(&mut self, timeout: u32) -> Result<(), SpiError> { + pub fn wait_for_dma_completion(&mut self, timeout: u32) -> Result<(), SpiError> { let mut delay = DummyDelay {}; let mut to = timeout; //wait for_dma done - while !self.regs.fmc008().read().dmastatus().is_dma_finish() { - delay.delay_ns(500); - to -= 1; - - if to == 0 { - self.dma_disable(); - return Err(SpiError::DmaTimeout); + #[cfg(not(feature = "spi_dma_irq"))] + { + dbg!(self, "wait_for_dma_completion"); + while !self.regs.fmc008().read().dmastatus().is_dma_finish() { + delay.delay_ns(500); + to -= 1; + + if to == 0 { + self.dma_disable(); + return Err(SpiError::DmaTimeout); + } } + self.dma_disable(); } - self.dma_disable(); Ok(()) } - /* + fn dma_irq_disable(&mut self) { - // Enable the DMA interrupt bit (bit 3) + // disable the DMA interrupt bit (bit 3) + dbg!(self, "dma_irq_disable"); self.regs.fmc008().modify(|_, w| w.dmaintenbl().clear_bit()); } - + #[allow(dead_code)] fn dma_irq_enable(&mut self) { // Enable the DMA interrupt bit (bit 3) + dbg!(self, "dma_irq_enable"); self.regs.fmc008().modify(|_, w| w.dmaintenbl().set_bit()); } + #[allow(dead_code)] fn dbg_fmc_dma(&mut self) { + dbg!(self, "reg 0x14: {:14x}", self.regs.fmc014().read().bits()); dbg!(self, "reg 0x80: {:08x}", self.regs.fmc080().read().bits()); dbg!(self, "reg 0x84: {:08x}", self.regs.fmc084().read().bits()); dbg!(self, "reg 0x88: {:08x}", self.regs.fmc088().read().bits()); dbg!(self, "reg 0x8c: {:08x}", self.regs.fmc08c().read().bits()); } - */ + + pub fn handle_interrupt(&mut self) -> Result<(), SpiError> { + dbg!(self, "handle interrupt"); + if !self.regs.fmc008().read().dmastatus().is_dma_finish() { + return Err(SpiError::Other("irq error")); + } + /* disable IRQ */ + self.dma_irq_disable(); + + /* disable DMA */ + self.dma_disable(); + + // Set it to normal read again + let cs = self.current_cs; + cs_ctrlreg_w!(self, cs, self.spi_data.cmd_mode[cs].normal_read); + Ok(()) + } + pub fn read_dma(&mut self, op: &mut SpiNorData) -> Result<(), SpiError> { let cs = self.current_cs; - dbg!(self, "##### read dma ####"); + dbg!(self, "##### fmc read dma ####"); dbg!(self, "device size: 0x{:08x} dv start: 0x{:08x}, read len: 0x{:08x}, rx_buf:0x{:08x} op addr: 0x{:08x}", self.spi_data.decode_addr[cs].len, self.spi_data.decode_addr[cs].start, @@ -687,16 +715,20 @@ impl<'a> FmcController<'a> { .write(|w| unsafe { w.bits(u32::try_from(read_length).unwrap()) }); // Enable IRQ - //self.dma_irq_enable(); + #[cfg(feature = "spi_dma_irq")] + { + self.dma_irq_enable(); + } + //self.dbg_fmc_dma(); // Start DMA + dbg!(self, "start dma"); self.regs.fmc080().modify(|_, w| { w.dmaenbl().enable_dma_operation(); w.dmadirection() .read_flash_move_from_flash_to_external_memory() }); - dbg!(self, "start wait for dma"); self.wait_for_dma_completion(SPI_DMA_TIMEOUT) } @@ -704,6 +736,13 @@ impl<'a> FmcController<'a> { fn write_dma(&mut self, op: &mut SpiNorData) -> Result<(), SpiError> { let cs = self.current_cs; dbg!(self, "##### write_dma ####"); + dbg!(self, "device size: 0x{:08x} dv start: 0x{:08x}, read len: 0x{:08x}, tx_buf:0x{:08x} op addr: 0x{:08x}", + self.spi_data.decode_addr[cs].len, + self.spi_data.decode_addr[cs].start, + op.tx_buf.len(), + (op.tx_buf.as_ptr() as u32), + op.addr); + //self.dbg_fmc_dma(); // Check alignment and bounds if op.addr % 4 != 0 || (op.tx_buf.as_ptr() as usize) % 4 != 0 { return Err(SpiError::AddressNotAligned(op.addr)); @@ -740,36 +779,67 @@ impl<'a> FmcController<'a> { self.regs .fmc08c() .write(|w| unsafe { w.bits(u32::try_from(op.tx_buf.len()).unwrap() - 1) }); + //self.dbg_fmc_dma(); // Enable DMA IRQ if needed - // self.enable_dma_irq(); // implement if necessary + #[cfg(feature = "spi_dma_irq")] + { + self.dma_irq_enable(); + } + // Start DMA with write direction self.regs.fmc080().modify(|_, w| { w.dmaenbl().enable_dma_operation(); w.dmadirection() .write_flash_move_from_external_memory_to_flash() }); - self.wait_for_dma_completion(SPI_DMA_TIMEOUT) } + + fn activate_user(&mut self) { + let cs = self.current_cs; + let user_reg = self.spi_data.cmd_mode[cs].user; + cs_ctrlreg_w!(self, cs, user_reg | ASPEED_SPI_USER_INACTIVE); + cs_ctrlreg_w!(self, cs, user_reg); + dbg!(self, "activate cs:{}", u32::try_from(cs).unwrap()); + } + + fn deactivate_user(&mut self) { + let cs = self.current_cs; + let user_reg = self.spi_data.cmd_mode[cs].user; + + cs_ctrlreg_w!(self, cs, user_reg | ASPEED_SPI_USER_INACTIVE); + cs_ctrlreg_w!(self, cs, self.spi_data.cmd_mode[cs].normal_read); + dbg!(self, "deactivate cs:{}", u32::try_from(cs).unwrap()); + dbg!( + self, + "normal read:{:08x}", + self.spi_data.cmd_mode[cs].normal_read + ); + } } impl<'a> SpiBus for FmcController<'a> { // we only use mmap for all transaction fn read(&mut self, buffer: &mut [u8]) -> Result<(), SpiError> { let ahb_addr = self.spi_data.decode_addr[self.current_cs].start as usize as *const u32; + self.activate_user(); unsafe { spi_read_data(ahb_addr, buffer) }; + self.deactivate_user(); Ok(()) } fn write(&mut self, buffer: &[u8]) -> Result<(), SpiError> { let ahb_addr = self.spi_data.decode_addr[self.current_cs].start as usize as *mut u32; + self.activate_user(); unsafe { spi_write_data(ahb_addr, buffer) }; + self.deactivate_user(); Ok(()) } fn transfer(&mut self, rd_buffer: &mut [u8], wr_buffer: &[u8]) -> Result<(), SpiError> { let cs = self.current_cs; + self.activate_user(); if !wr_buffer.is_empty() { let ahb_addr = self.spi_data.decode_addr[cs].start as usize as *mut u32; unsafe { spi_write_data(ahb_addr, wr_buffer) }; @@ -780,6 +850,7 @@ impl<'a> SpiBus for FmcController<'a> { // Read RX buffer unsafe { super::spi_read_data(ahb_addr, rd_buffer) }; } + self.deactivate_user(); Ok(()) } @@ -794,30 +865,10 @@ impl<'a> SpiBus for FmcController<'a> { impl<'a> SpiBusWithCs for FmcController<'a> { fn select_cs(&mut self, cs: usize) -> Result<(), SpiError> { - let user_reg = self.spi_data.cmd_mode[cs].user; if cs > self.spi_config.max_cs { return Err(SpiError::CsSelectFailed(cs)); } self.current_cs = cs; - cs_ctrlreg_w!(self, cs, user_reg | ASPEED_SPI_USER_INACTIVE); - cs_ctrlreg_w!(self, cs, user_reg); - dbg!(self, "activate cs:{}", u32::try_from(cs).unwrap()); - Ok(()) - } - - fn deselect_cs(&mut self, cs: usize) -> Result<(), SpiError> { - let user_reg = self.spi_data.cmd_mode[cs].user; - if cs > self.spi_config.max_cs { - return Err(SpiError::CsSelectFailed(cs)); - } - cs_ctrlreg_w!(self, cs, user_reg | ASPEED_SPI_USER_INACTIVE); - cs_ctrlreg_w!(self, cs, self.spi_data.cmd_mode[cs].normal_read); - dbg!(self, "deactivate cs:{}", u32::try_from(cs).unwrap()); - dbg!( - self, - "normal read:{:08x}", - self.spi_data.cmd_mode[cs].normal_read - ); Ok(()) } diff --git a/src/spi/mod.rs b/src/spi/mod.rs index c5730ce..df6ce1e 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -15,6 +15,7 @@ pub mod fmccontroller; pub mod norflash; pub mod norflashblockdevice; pub mod spicontroller; +pub mod spidmairqtest; pub mod spitest; #[derive(Debug)] @@ -50,7 +51,6 @@ impl spi::Error for SpiError { pub trait SpiBusWithCs: SpiBus + ErrorType { fn select_cs(&mut self, cs: usize) -> Result<(), SpiError>; - fn deselect_cs(&mut self, cs: usize) -> Result<(), SpiError>; fn nor_transfer(&mut self, op_info: &mut SpiNorData) -> Result<(), SpiError>; fn nor_read_init(&mut self, cs: usize, op_info: &SpiNorData); fn nor_write_init(&mut self, cs: usize, op_info: &SpiNorData); @@ -82,7 +82,6 @@ const SPI_CALIB_LEN: usize = 0x400; #[cfg(feature = "spi_dma")] const SPI_DMA_TRIGGER_LEN: u32 = 128; -//const SPI_DMA_STS: u32 = 1 << 11; //const SPI_DMA_IRQ_EN: u32 = 1 << 3; #[cfg(feature = "spi_dma")] const SPI_DMA_WRITE: u32 = 1 << 1; @@ -396,6 +395,21 @@ const PIN_SPIM1_CLK_OUT_BIT: u32 = 21; const PIN_SPIM2_CLK_OUT_BIT: u32 = 3; const PIN_SPIM3_CLK_OUT_BIT: u32 = 17; +pub fn spim_scu_ctrl_set(mask: u32, val: u32) { + let scu = unsafe { &*ast1060_pac::Scu::ptr() }; + let mut reg_val = scu.scu0f0().read().bits(); + reg_val &= !mask; + reg_val |= val; + scu.scu0f0().write(|w| unsafe { w.bits(reg_val) }); +} + +pub fn spim_scu_ctrl_clear(clear_bits: u32) { + let scu = unsafe { &*ast1060_pac::Scu::ptr() }; + let mut reg_val = scu.scu0f0().read().bits(); + reg_val &= !clear_bits; + scu.scu0f0().write(|w| unsafe { w.bits(reg_val) }); +} + pub fn spim_proprietary_pre_config() { let scu = unsafe { &*ast1060_pac::Scu::ptr() }; let gpio = unsafe { &*ast1060_pac::Gpio::ptr() }; diff --git a/src/spi/norflash.rs b/src/spi/norflash.rs index f953d0c..2f991b5 100644 --- a/src/spi/norflash.rs +++ b/src/spi/norflash.rs @@ -4,7 +4,6 @@ use super::device::ChipSelectDevice; use super::SpiBusWithCs; use super::{norflash, SpiError, SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; use crate::common::DummyDelay; -use crate::spimonitor::SpipfInstance; use embedded_hal::delay::DelayNs; /* Flash opcodes */ @@ -124,33 +123,31 @@ macro_rules! start_transfer { let _ = (|| -> Result<(), SpiError> { $this.bus.select_cs($this.cs)?; // SPIM config - if let Some(spim) = $this.spi_monitor.as_mut() { + if let Some(spim) = $this.spim { if $this.bus.get_master_id() != 0 { - spim.spim_scu_ctrl_set(0x8, 0x8); - spim.spim_scu_ctrl_set(0x7, 1 + SPIPF::FILTER_ID as u32); + super::spim_scu_ctrl_set(0x8, 0x8); + super::spim_scu_ctrl_set(0x7, 1 + u32::from(spim)); } super::spim_proprietary_pre_config(); } - $this.bus.nor_transfer($data)?; - $this.bus.deselect_cs($this.cs)?; //SPIM deconfig - super::spim_proprietary_post_config(); - if let Some(spim) = $this.spi_monitor.as_mut() { + if let Some(_spim) = $this.spim { + super::spim_proprietary_post_config(); if $this.bus.get_master_id() != 0 { - spim.spim_scu_ctrl_clear(0xf); + super::spim_scu_ctrl_clear(0xf); } } + Ok(()) })(); }}; } //TODO: add 4byte address mode support -impl<'a, B, SPIPF> SpiNorDevice for ChipSelectDevice<'a, B, SPIPF> +impl<'a, B> SpiNorDevice for ChipSelectDevice<'a, B> where B: SpiBusWithCs, - SPIPF: SpipfInstance, { type Error = B::Error; @@ -239,7 +236,6 @@ where data_direct: SPI_NOR_DATA_DIRECT_WRITE, }; start_transfer!(self, &mut nor_data); - self.nor_wait_until_ready(); Ok(()) } @@ -257,7 +253,6 @@ where data_direct: SPI_NOR_DATA_DIRECT_WRITE, }; start_transfer!(self, &mut nor_data); - self.nor_wait_until_ready(); Ok(()) } @@ -274,7 +269,6 @@ where data_direct: SPI_NOR_DATA_DIRECT_READ, }; start_transfer!(self, &mut nor_data); - Ok(()) } @@ -308,7 +302,6 @@ where data_direct: SPI_NOR_DATA_DIRECT_WRITE, }; start_transfer!(self, &mut nor_data); - Ok(()) } @@ -330,20 +323,20 @@ where } fn nor_read_init(&mut self, nor_data: &SpiNorData) -> Result<(), Self::Error> { - if let Some(spim) = self.spi_monitor.as_mut() { + if let Some(spim) = self.spim { if self.bus.get_master_id() != 0 { - spim.spim_scu_ctrl_set(0x8, 0x8); - spim.spim_scu_ctrl_set(0x7, 1 + SPIPF::FILTER_ID as u32); + super::spim_scu_ctrl_set(0x8, 0x8); + super::spim_scu_ctrl_set(0x7, 1 + u32::from(spim)); } super::spim_proprietary_pre_config(); } self.bus.nor_read_init(self.cs, nor_data); - super::spim_proprietary_post_config(); - if let Some(spim) = self.spi_monitor.as_mut() { + if let Some(_spim) = self.spim { + super::spim_proprietary_post_config(); if self.bus.get_master_id() != 0 { - spim.spim_scu_ctrl_clear(0xf); + super::spim_scu_ctrl_clear(0xf); } } Ok(()) diff --git a/src/spi/norflashblockdevice.rs b/src/spi/norflashblockdevice.rs index dd58266..e429fc0 100644 --- a/src/spi/norflashblockdevice.rs +++ b/src/spi/norflashblockdevice.rs @@ -172,12 +172,12 @@ where self.device .nor_page_program(u32::try_from(write_addr).unwrap(), chunk) }; - + self.device.nor_wait_until_ready(); + delay.delay_ns(2_000_000); if result.is_err() { return Err(BlockError::ProgramError); } offset += program_block; - delay.delay_ns(2_000_000); } Ok(()) diff --git a/src/spi/spicontroller.rs b/src/spi/spicontroller.rs index 2883040..91512eb 100644 --- a/src/spi/spicontroller.rs +++ b/src/spi/spicontroller.rs @@ -520,7 +520,7 @@ impl<'a> SpiController<'a> { u32::try_from(cs).unwrap(), self.spi_data.decode_addr[cs].start ); - + self.activate_user(); // Send command let cmd_mode = self.spi_data.cmd_mode[cs].user | super::spi_io_mode_user(u32::from(super::get_cmd_buswidth(op_info.mode as u32))); @@ -559,6 +559,7 @@ impl<'a> SpiController<'a> { } else { unsafe { spi_write_data(start_ptr, op_info.tx_buf) }; } + self.deactivate_user(); } // Helper wrappers would be defined for spi_write_data, spi_read_data, io_mode_user, etc. @@ -648,29 +649,55 @@ impl<'a> SpiController<'a> { let mut delay = DummyDelay {}; let mut to = timeout; //wait for_dma done - while !self.regs.spi008().read().dmastatus().is_dma_finish() { - delay.delay_ns(500); - to -= 1; + #[cfg(not(feature = "spi_dma_irq"))] + { + while !self.regs.spi008().read().dmastatus().is_dma_finish() { + delay.delay_ns(500); + to -= 1; - if to == 0 { - self.dma_disable(); - return Err(SpiError::DmaTimeout); + if to == 0 { + self.dma_disable(); + return Err(SpiError::DmaTimeout); + } } + self.dma_disable(); } - self.dma_disable(); Ok(()) } - /* + fn dma_irq_disable(&mut self) { // Enable the DMA interrupt bit (bit 3) self.regs.spi008().modify(|_, w| w.dmaintenbl().clear_bit()); } - + #[allow(dead_code)] fn dma_irq_enable(&mut self) { // Enable the DMA interrupt bit (bit 3) self.regs.spi008().modify(|_, w| w.dmaintenbl().set_bit()); } - */ + #[allow(dead_code)] + fn dbg_spi_dma(&mut self) { + dbg!(self, "reg 0x80: {:08x}", self.regs.spi080().read().bits()); + dbg!(self, "reg 0x84: {:08x}", self.regs.spi084().read().bits()); + dbg!(self, "reg 0x88: {:08x}", self.regs.spi088().read().bits()); + dbg!(self, "reg 0x8c: {:08x}", self.regs.spi08c().read().bits()); + } + pub fn handle_interrupt(&mut self) -> Result<(), SpiError> { + dbg!(self, "spi handle_interrupt"); + if !self.regs.spi008().read().dmastatus().is_dma_finish() { + return Err(SpiError::Other("dma not finished")); + } + /* disable IRQ */ + self.dma_irq_disable(); + + /* disable DMA */ + self.dma_disable(); + + let cs = self.current_cs; + cs_ctrlreg_w!(self, cs, self.spi_data.cmd_mode[cs].normal_read); + Ok(()) + //spi_context_complete(ctx, dev, 0); + } + pub fn read_dma(&mut self, op: &mut SpiNorData) -> Result<(), SpiError> { let cs = self.current_cs; dbg!(self, "##### read dma ####"); @@ -705,7 +732,6 @@ impl<'a> SpiController<'a> { // Write to CSx control cs_ctrlreg_w!(self, cs, ctrl); - self.regs .spi080() .write(|w| unsafe { w.bits(SPI_DMA_GET_REQ_MAGIC) }); @@ -732,24 +758,25 @@ impl<'a> SpiController<'a> { .write(|w| unsafe { w.bits(u32::try_from(read_length).unwrap()) }); // Enable IRQ - //self.dma_irq_enable(); + #[cfg(feature = "spi_dma_irq")] + { + self.dma_irq_enable(); + } // Start DMA - // self.regs.spi080().write(|w| unsafe { w.bits(SPI_DMA_ENABLE) }); self.regs.spi080().modify(|_, w| { w.dmaenbl().enable_dma_operation(); w.dmadirection() .read_flash_move_from_flash_to_external_memory() }); - dbg!(self, "start wait for dma"); self.wait_for_dma_completion(SPI_DMA_TIMEOUT) } #[allow(dead_code)] fn write_dma(&mut self, op: &mut SpiNorData) -> Result<(), SpiError> { let cs = self.current_cs; - dbg!(self, "##### write_dma ####"); + //dbg!(self, "##### write_dma ####"); // Check alignment and bounds if op.addr % 4 != 0 || (op.tx_buf.as_ptr() as usize) % 4 != 0 { @@ -794,7 +821,10 @@ impl<'a> SpiController<'a> { .write(|w| unsafe { w.bits(u32::try_from(op.tx_buf.len()).unwrap() - 1) }); // Enable DMA IRQ if needed - // self.enable_dma_irq(); // implement if necessary + #[cfg(feature = "spi_dma_irq")] + { + self.dma_irq_enable(); + } // Start DMA with write direction self.regs.spi080().modify(|_, w| { @@ -805,24 +835,51 @@ impl<'a> SpiController<'a> { self.wait_for_dma_completion(SPI_DMA_TIMEOUT) } + + fn activate_user(&mut self) { + let cs = self.current_cs; + let user_reg = self.spi_data.cmd_mode[cs].user; + cs_ctrlreg_w!(self, cs, user_reg | ASPEED_SPI_USER_INACTIVE); + cs_ctrlreg_w!(self, cs, user_reg); + dbg!(self, "activate cs:{}", u32::try_from(cs).unwrap()); + } + + fn deactivate_user(&mut self) { + let cs = self.current_cs; + let user_reg = self.spi_data.cmd_mode[cs].user; + + cs_ctrlreg_w!(self, cs, user_reg | ASPEED_SPI_USER_INACTIVE); + cs_ctrlreg_w!(self, cs, self.spi_data.cmd_mode[cs].normal_read); + dbg!(self, "deactivate cs:{}", u32::try_from(cs).unwrap()); + dbg!( + self, + "normal read:{:08x}", + self.spi_data.cmd_mode[cs].normal_read + ); + } } impl<'a> SpiBus for SpiController<'a> { // we only use mmap for all transaction fn read(&mut self, buffer: &mut [u8]) -> Result<(), SpiError> { let ahb_addr = self.spi_data.decode_addr[self.current_cs].start as usize as *const u32; + self.activate_user(); unsafe { spi_read_data(ahb_addr, buffer) }; + self.deactivate_user(); Ok(()) } fn write(&mut self, buffer: &[u8]) -> Result<(), SpiError> { let ahb_addr = self.spi_data.decode_addr[self.current_cs].start as usize as *mut u32; + self.activate_user(); unsafe { spi_write_data(ahb_addr, buffer) }; + self.deactivate_user(); Ok(()) } fn transfer(&mut self, rd_buffer: &mut [u8], wr_buffer: &[u8]) -> Result<(), SpiError> { let cs = self.current_cs; + self.activate_user(); if !wr_buffer.is_empty() { let ahb_addr = self.spi_data.decode_addr[cs].start as usize as *mut u32; unsafe { spi_write_data(ahb_addr, wr_buffer) }; @@ -833,6 +890,7 @@ impl<'a> SpiBus for SpiController<'a> { // Read RX buffer unsafe { super::spi_read_data(ahb_addr, rd_buffer) }; } + self.deactivate_user(); Ok(()) } @@ -852,30 +910,10 @@ impl<'a> SpiBus for SpiController<'a> { impl<'a> SpiBusWithCs for SpiController<'a> { fn select_cs(&mut self, cs: usize) -> Result<(), SpiError> { - let user_reg = self.spi_data.cmd_mode[cs].user; if cs > self.spi_config.max_cs { return Err(SpiError::CsSelectFailed(cs)); } self.current_cs = cs; - cs_ctrlreg_w!(self, cs, user_reg | ASPEED_SPI_USER_INACTIVE); - cs_ctrlreg_w!(self, cs, user_reg); - dbg!(self, "activate cs:{}", u32::try_from(cs).unwrap()); - Ok(()) - } - - fn deselect_cs(&mut self, cs: usize) -> Result<(), SpiError> { - let user_reg = self.spi_data.cmd_mode[cs].user; - if cs > self.spi_config.max_cs { - return Err(SpiError::CsSelectFailed(cs)); - } - cs_ctrlreg_w!(self, cs, user_reg | ASPEED_SPI_USER_INACTIVE); - cs_ctrlreg_w!(self, cs, self.spi_data.cmd_mode[cs].normal_read); - dbg!(self, "deactivate cs:{}", u32::try_from(cs).unwrap()); - dbg!( - self, - "normal read:{:08x}", - self.spi_data.cmd_mode[cs].normal_read - ); Ok(()) } diff --git a/src/spi/spidmairqtest.rs b/src/spi/spidmairqtest.rs new file mode 100644 index 0000000..3a0a9f6 --- /dev/null +++ b/src/spi/spidmairqtest.rs @@ -0,0 +1,512 @@ +// Licensed under the Apache-2.0 license + +//! spidmairqtest.rs - DMA irq read/write test harness using static buffers and chainable callbacks + +use super::fmccontroller::FmcController; +use crate::common::{self, DmaBuffer, DummyDelay}; +use crate::spi::device::ChipSelectDevice; +use crate::spi::norflash::{SpiNorData, SpiNorDevice}; +use crate::spi::spicontroller::SpiController; +use crate::spi::spitest::{self, DeviceId, FMC_CONFIG}; +use crate::spi::SpiData; +use crate::spimonitor::SpiMonitorNum; +use crate::uart::UartController; +use crate::{astdebug, pinctrl}; +use core::ptr; +use cortex_m::peripheral::NVIC; +use embedded_hal::delay::DelayNs; +use embedded_io::Write; +use heapless::Deque; + +static mut UART_PTR: Option<&'static mut UartController<'static>> = None; +static mut FMC_CONTROLLER: Option> = None; +static mut SPI_CONTROLLER: Option> = None; +//static mut SPI1_CONTROLLER: Option> = None; + +static mut FMC_DEVICE0: Option>> = None; +static mut FMC_DEV0_PTR: *mut ChipSelectDevice<'_, FmcController<'_>> = core::ptr::null_mut(); +static mut FMC_DEVICE1: Option>> = None; +static mut FMC_DEV1_PTR: *mut ChipSelectDevice<'_, FmcController<'_>> = core::ptr::null_mut(); + +static mut SPI_DEVICE0: Option>> = None; +static mut SPI_DEV0_PTR: *mut ChipSelectDevice<'_, SpiController<'_>> = core::ptr::null_mut(); + +static mut REQUST_ALLDONE: bool = true; +// DMA operation type selector +#[derive(Debug, Copy, Clone)] +pub enum DmaOp { + Read, + ReadFast, + Program, + ProgramFast, +} + +// DMA request struct with callback +#[derive(Debug)] +pub struct DmaRequest { + pub src_addr: usize, + pub dst_buf: &'static mut [u8], + pub len: usize, + pub op: DmaOp, + pub verify: bool, // for test + pub buf_idx: usize, // for test + pub on_complete: fn(bool, usize, &[u8]), +} + +// Configuration +const MAX_DMA_CHAIN: usize = 4; +const DMA_BUF_SIZE: usize = 256; +// Static state for current DMA and queue +// use as FIFO + +#[link_section = ".ram_nc"] +static mut READ_BUFFERS: [DmaBuffer; MAX_DMA_CHAIN] = + [const { DmaBuffer::new() }; MAX_DMA_CHAIN]; +#[link_section = ".ram_nc"] +static mut WRITE_BUFFERS: [DmaBuffer; MAX_DMA_CHAIN] = + [const { DmaBuffer::new() }; MAX_DMA_CHAIN]; + +static mut CURRENT_DMA: Option = None; +static mut DMA_QUEUE: Deque = Deque::new(); +static mut CURRENT_DEVID: DeviceId = DeviceId::FmcCs0Idx; + +#[no_mangle] +pub extern "C" fn fmc() { + unsafe { + let fmc = FMC_CONTROLLER.as_mut().unwrap(); + let uart = UART_PTR.as_mut().unwrap(); + let dev = match CURRENT_DEVID { + DeviceId::FmcCs0Idx => FMC_DEV0_PTR.as_mut().unwrap(), + DeviceId::FmcCs1Idx => FMC_DEV1_PTR.as_mut().unwrap(), + _ => todo!(), + }; + if let Err(e) = fmc.handle_interrupt() { + // test done!. irq error + writeln!(uart, "Failed: {e:?}").ok(); + } else { + writeln!(uart, "fmc()").ok(); + if let Some(req) = CURRENT_DMA.take() { + writeln!(uart, "completed").ok(); + if matches!(req.op, DmaOp::Program | DmaOp::ProgramFast) { + writeln!(uart, "wait").ok(); + dev.nor_wait_until_ready(); + } + + (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); + } else { + writeln!(uart, "Error... no CURRENT fmc DMA").ok(); + } + start_next_dma(); + } + } +} + +#[no_mangle] +pub extern "C" fn spi() { + unsafe { + let spi = SPI_CONTROLLER.as_mut().unwrap(); + let uart = UART_PTR.as_mut().unwrap(); + + if let Err(e) = spi.handle_interrupt() { + // test done!. irq error + writeln!(uart, "Failed: {e:?}").ok(); + } else { + if let Some(req) = CURRENT_DMA.take() { + writeln!(uart, "completed").ok(); + (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); + } else { + writeln!(uart, "Error... no CURRENT spi DMA").ok(); + } + + start_next_dma(); + } + } +} + +#[macro_export] +macro_rules! log_uart { + ($($arg:tt)*) => {{ + if let Some(uart) = $crate::spi::spidmairqtest::UART_PTR.as_mut() { + writeln!(uart, $($arg)*).ok(); + write!(uart, "\r").ok(); + } + }}; +} + +unsafe fn show_mmap_reg() { + let (_reg_base, mmap_addr, _cs_capacity) = spitest::device_info(CURRENT_DEVID); + + let uart = UART_PTR.as_mut().unwrap(); + unsafe { + log_uart!("[{:08x}]", mmap_addr); + } + astdebug::print_reg_u8(uart, mmap_addr, 0x400); +} +unsafe fn start_next_dma() { + if DMA_QUEUE.is_empty() { + REQUST_ALLDONE = true; + unsafe { + log_uart!("DMA queue is empty. All transfers are completed!!"); + } + show_mmap_reg(); + return; + } + + if let Some(req) = DMA_QUEUE.pop_front() { + CURRENT_DMA = Some(req); + match CURRENT_DEVID { + DeviceId::FmcCs0Idx | DeviceId::FmcCs1Idx => { + if let Err(e) = start_dma_fmc_transfer(CURRENT_DMA.as_mut().unwrap()) { + unsafe { + log_uart!("Failed to start DMA transfer: {:?}", e); + } + } + } + DeviceId::Spi0Cs0Idx + | DeviceId::Spi1Cs0Idx + | DeviceId::Spi1Cs1Idx + | DeviceId::Spi0Cs1Idx => { + if let Err(e) = start_dma_spi_transfer(CURRENT_DMA.as_mut().unwrap()) { + unsafe { + log_uart!("Failed to start DMA transfer: {:?}", e); + } + } + } + } + } +} + +pub fn on_complete_dma(verify: bool, idx: usize, _buf: &[u8]) { + if verify { + if verify_dma_buffer_match(idx) { + unsafe { + log_uart!("DMA test passed!!"); + } + } else { + unsafe { + log_uart!("DMA test failed!!"); + } + } + } //else if let Some(uart) = unsafe { UART_PTR.as_mut() } { + // astdebug::print_array_u8(uart, buf); + //} +} + +// Start DMA transfer using the device +fn start_dma_spi_transfer(req: &mut DmaRequest) -> Result<(), ()> { + unsafe { + log_uart!("spi start_dma_transfer"); + let dev = match CURRENT_DEVID { + DeviceId::Spi0Cs0Idx => SPI_DEV0_PTR.as_mut().unwrap(), + _ => todo!(), + }; + + let result = match req.op { + DmaOp::Read => dev.nor_read_data(u32::try_from(req.src_addr).unwrap(), req.dst_buf), + DmaOp::ReadFast => { + dev.nor_read_fast_4b_data(u32::try_from(req.src_addr).unwrap(), req.dst_buf) + } + DmaOp::Program => { + dev.nor_page_program(u32::try_from(req.src_addr).unwrap(), req.dst_buf) + } + DmaOp::ProgramFast => { + dev.nor_page_program_4b(u32::try_from(req.src_addr).unwrap(), req.dst_buf) + } + }; + + result.map_err(|e| { + log_uart!("start_dma_transfer failed at {:#x}: {:?}", req.src_addr, e); + }) + } +} + +// Start DMA transfer using the device +fn start_dma_fmc_transfer(req: &mut DmaRequest) -> Result<(), ()> { + unsafe { + log_uart!("fmc start_dma_transfer"); + let dev = match CURRENT_DEVID { + DeviceId::FmcCs0Idx => FMC_DEV0_PTR.as_mut().unwrap(), + DeviceId::FmcCs1Idx => FMC_DEV1_PTR.as_mut().unwrap(), + _ => todo!(), + }; + + let result = match req.op { + DmaOp::Read => dev.nor_read_data(u32::try_from(req.src_addr).unwrap(), req.dst_buf), + DmaOp::ReadFast => { + dev.nor_read_fast_4b_data(u32::try_from(req.src_addr).unwrap(), req.dst_buf) + } + DmaOp::Program => { + dev.nor_page_program(u32::try_from(req.src_addr).unwrap(), req.dst_buf) + } + DmaOp::ProgramFast => { + dev.nor_page_program_4b(u32::try_from(req.src_addr).unwrap(), req.dst_buf) + } + }; + + result.map_err(|e| { + log_uart!("start_dma_transfer failed at {:#x}: {:?}", req.src_addr, e); + }) + } +} + +#[must_use] +pub fn verify_dma_buffer_match(i: usize) -> bool { + unsafe { + let read = READ_BUFFERS[i].as_mut_slice(0, DMA_BUF_SIZE); + let write = WRITE_BUFFERS[i].as_mut_slice(0, DMA_BUF_SIZE); + + if read != write { + // Fast path failed. now scan for first mismatch for debug + for (j, (&r, &w)) in read.iter().zip(write.iter()).enumerate() { + if r != w { + log_uart!( + "Mismatch at buffer {}, index {}: read={:02x}, expected={:02x}", + i, + j, + r, + w + ); + break; + } + } + if let Some(uart) = UART_PTR.as_mut() { + astdebug::print_array_u8(uart, read); + astdebug::print_array_u8(uart, write); + } + return false; + } + } + true +} + +pub fn fill_dma_buffer(op_req: DmaOp, random: bool) { + let mut seed = 0xDEAD_FBEE; + + unsafe { + for i in 0..MAX_DMA_CHAIN { + let buf: &'static mut [u8] = match op_req { + DmaOp::Read | DmaOp::ReadFast => READ_BUFFERS[i].as_mut_slice(0, DMA_BUF_SIZE), + DmaOp::Program | DmaOp::ProgramFast => { + WRITE_BUFFERS[i].as_mut_slice(0, DMA_BUF_SIZE) + } + }; + + buf.fill(0x0); + + if random { + common::fill_random(buf, &mut seed); + } + } + } +} +// Example use +#[allow(clippy::missing_safety_doc)] +pub unsafe fn dma_irq_chain_test(start_addrs: &[u32], op_req: DmaOp, verify: bool) { + DMA_QUEUE.clear(); + REQUST_ALLDONE = false; + + for (i, &addr) in start_addrs.iter().enumerate() { + if i >= MAX_DMA_CHAIN { + unsafe { + log_uart!("Too many DMA addresses; max is {}", MAX_DMA_CHAIN); + } + break; + } + + // Select buffer based on operation type + let buf: &'static mut [u8] = match op_req { + DmaOp::Read | DmaOp::ReadFast => READ_BUFFERS[i].as_mut_slice(0, DMA_BUF_SIZE), + DmaOp::Program | DmaOp::ProgramFast => WRITE_BUFFERS[i].as_mut_slice(0, DMA_BUF_SIZE), + }; + let request = DmaRequest { + src_addr: addr as usize, + dst_buf: buf, + len: DMA_BUF_SIZE, + op: op_req, + buf_idx: i, + verify, + on_complete: on_complete_dma, + }; + DMA_QUEUE.push_back(request).unwrap(); + unsafe { + log_uart!("chaining {}", i); + } + } //for + start_next_dma(); +} + +pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { + let fmc_spi = unsafe { &*ast1060_pac::Fmc::ptr() }; + let mut delay = DummyDelay {}; + + pinctrl::Pinctrl::apply_pinctrl_group(pinctrl::PINCTRL_FMC_QUAD); + let fmc_data = SpiData::new(); + + unsafe { + // register interrupt + /* irq init */ + UART_PTR = Some(core::mem::transmute::< + &mut UartController<'_>, + &'static mut UartController<'static>, + >(uart)); + NVIC::unmask(ast1060_pac::Interrupt::fmc); + + FMC_CONTROLLER = Some(FmcController::new( + fmc_spi, + 0, + FMC_CONFIG, + fmc_data, + Some(UART_PTR.as_mut().unwrap()), + )); + + log_uart!("==== FMC DEV0 DMA read Test===="); + let controller = FMC_CONTROLLER.as_mut().unwrap(); + let _ = controller.init(); + + // You can now pass `fmc_ptr` into ChipSelectDevice or use it directly + let nor_read_data: SpiNorData<'_> = + spitest::nor_device_read_data(spitest::FMC_CS0_CAPACITY); + let nor_write_data = spitest::nor_device_write_data(spitest::FMC_CS0_CAPACITY); + + let flash_device0 = ChipSelectDevice { + bus: controller, + cs: 0, + spim: None, + }; + FMC_DEVICE0 = Some(flash_device0); + + let dev0 = FMC_DEVICE0.as_mut().unwrap(); + //FMC_DEV0_PTR = dev0 as *mut _; + FMC_DEV0_PTR = ptr::from_mut(dev0); + + // Wrap controller in a CS device (CS0) + let _ = dev0.nor_read_init(&nor_read_data); + let _ = dev0.nor_write_init(&nor_write_data); + let start_addrs = [0x0000_0000, 0x0000_0100, 0x0000_0200, 0x0000_0300]; + + CURRENT_DEVID = DeviceId::FmcCs0Idx; + fill_dma_buffer(DmaOp::Read, true); + delay.delay_ns(8_000_000); + dma_irq_chain_test(&start_addrs, DmaOp::Read, false); + + delay.delay_ns(8_000_000); + + log_uart!("==== FMC DEV1 DMA read & write Test===="); + let controller1 = FMC_CONTROLLER.as_mut().unwrap(); + let flash_device1 = ChipSelectDevice { + bus: controller1, // reuse same ref + cs: 1, + spim: None, + }; + + FMC_DEVICE1 = Some(flash_device1); + + let dev1 = FMC_DEVICE1.as_mut().unwrap(); + let _ = dev1.nor_read_init(&nor_read_data); + let _ = dev1.nor_write_init(&nor_write_data); + + FMC_DEV1_PTR = ptr::from_mut(dev1); + + //let start_addrs = [0x0000_0000, 0x0000_0100, 0x0000_0200, 0x0000_0300]; + //let start_addrs = [0x0000_0100]; + let read_only = false; + CURRENT_DEVID = DeviceId::FmcCs1Idx; + if read_only { + fill_dma_buffer(DmaOp::Read, false); + dma_irq_chain_test(&start_addrs, DmaOp::Read, false); + } else { + fill_dma_buffer(DmaOp::Program, true); + let _ = dev1.nor_sector_erase(0x0000_0000); + delay.delay_ns(8_000_000); + // NOTE: DMA write has an issue in AST2600-Errata-11 + // DMA write ends before finish transfering data + // work-around: add delay + dma_irq_chain_test(&start_addrs, DmaOp::Program, false); + delay.delay_ns(8_000_000); + if !REQUST_ALLDONE { + log_uart!("=ERROR: Programming race condition!!!!="); + } + dma_irq_chain_test(&start_addrs, DmaOp::Read, true); + } + } //unsafe + + delay.delay_ns(8_000_000); +} + +pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { + let spi0 = unsafe { &*ast1060_pac::Spi::ptr() }; + //let base = core::ptr::from_ref(spi0) as usize; + let current_cs = 0; + let mut delay = DummyDelay {}; + + pinctrl::Pinctrl::apply_pinctrl_group(pinctrl::PINCTRL_SPIM0_QUAD_DEFAULT); + pinctrl::Pinctrl::apply_pinctrl_group(pinctrl::PINCTRL_SPI1_QUAD); + let scu_qspi_mux: &mut [u32] = + unsafe { core::slice::from_raw_parts_mut((spitest::SCU_BASE + 0xf0) as *mut u32, 4) }; + scu_qspi_mux[0] = 0x0000_fff0; + + let spi_data = SpiData::new(); + + unsafe { + // register interrupt + // irq init + UART_PTR = Some(core::mem::transmute::< + &mut UartController<'_>, + &'static mut UartController<'static>, + >(uart)); + NVIC::unmask(ast1060_pac::Interrupt::spi); + + SPI_CONTROLLER = Some(SpiController::new( + spi0, + current_cs, + spitest::SPI0_CONFIG, + spi_data, + Some(UART_PTR.as_mut().unwrap()), + )); + + let controller = SPI_CONTROLLER.as_mut().unwrap(); + let _ = controller.init(); + log_uart!("==== SPI0 DEV0 DMA read Test===="); + // You can now pass `fmc_ptr` into ChipSelectDevice or use it directly + let nor_read_data: SpiNorData<'_> = + spitest::nor_device_read_4b_data(spitest::SPI_CS0_CAPACITY); + let nor_write_data = spitest::nor_device_write_4b_data(spitest::SPI_CS0_CAPACITY); + + let flash_device0 = ChipSelectDevice { + bus: controller, + cs: 0, + spim: Some(SpiMonitorNum::SPIM0), + }; + + SPI_DEVICE0 = Some(flash_device0); + let dev0 = SPI_DEVICE0.as_mut().unwrap(); + SPI_DEV0_PTR = ptr::from_mut(dev0); + + // Wrap controller in a CS device (CS0) + let _ = dev0.nor_read_init(&nor_read_data); + let _ = dev0.nor_write_init(&nor_write_data); + + let start_addrs = [0x0000_0000, 0x0000_0100, 0x0000_0200, 0x0000_0300]; + //let start_addrs = [0x0000_0100]; + CURRENT_DEVID = DeviceId::Spi0Cs0Idx; + + let read_only = true; + if read_only { + fill_dma_buffer(DmaOp::ReadFast, false); + dma_irq_chain_test(&start_addrs, DmaOp::ReadFast, false); + } else { + fill_dma_buffer(DmaOp::Program, true); + let _ = dev0.nor_sector_erase(0x0000_0000); + delay.delay_ns(8_000_000); + dma_irq_chain_test(&start_addrs, DmaOp::ProgramFast, false); + delay.delay_ns(8_000_000); + if !REQUST_ALLDONE { + log_uart!("=ERROR: Programming race condition!!!!="); + } + dma_irq_chain_test(&start_addrs, DmaOp::ReadFast, true); + } + log_uart!("==== End SPI0 DEV0 DMA read Test===="); + } //unsafe + + scu_qspi_mux[0] = 0x0000_0000; +} diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index 7c94b72..5554cc8 100644 --- a/src/spi/spitest.rs +++ b/src/spi/spitest.rs @@ -1,4 +1,7 @@ // Licensed under the Apache-2.0 license +//! spitest.rs +//! - genric test for FMC, Spi0 and Spi1: get pid, read/write w/wo read dma, no write dma +//! - irq is not being handled in this test use super::device::ChipSelectDevice; use super::fmccontroller::FmcController; @@ -9,15 +12,15 @@ use super::{ norflash, CommandMode, CtrlType, SpiConfig, SpiData, SpiDecodeAddress, SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE, }; -use crate::common::{DmaBuffer, DummyDelay}; +use crate::common::{self, DmaBuffer, DummyDelay}; use crate::spi::norflashblockdevice; use crate::spi::norflashblockdevice::{BlockAddrUsize, NorFlashBlockDevice}; use crate::spi::spicontroller::SpiController; -use crate::spimonitor::{RegionInfo, SpiMonitor, SpimExtMuxSel}; +use crate::spimonitor::SpiMonitorNum; use crate::uart; use crate::uart::{Config, UartController}; use crate::{astdebug, pinctrl}; -use ast1060_pac::{Peripherals, Spipf, Spipf1, Spipf2, Spipf3}; +use ast1060_pac::Peripherals; use embedded_hal::delay::DelayNs; use embedded_hal::spi::SpiDevice; use embedded_io::Write; @@ -31,7 +34,7 @@ pub const SPI0_MMAP_BASE: usize = 0x9000_0000; pub const SPI1_CTRL_BASE: usize = 0x7e64_0000; pub const SPI1_MMAP_BASE: usize = 0xb000_0000; -const SCU_BASE: usize = 0x7E6E_2000; +pub const SCU_BASE: usize = 0x7E6E_2000; pub const CTRL_REG_SIZE: usize = 0xc4; pub const SPIPF1_BASE: usize = 0x7e79_1000; @@ -41,7 +44,7 @@ pub const SPIPF4_BASE: usize = 0x7e79_4000; pub const GPIO_BASE: usize = 0x7e78_0000; -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] #[deny(dead_code)] pub enum DeviceId { FmcCs0Idx, @@ -255,6 +258,7 @@ pub fn test_cs, E>( let _ = dev.nor_page_program_4b(addr, wbuf); } } + dev.nor_wait_until_ready(); delay1.delay_ns(8_000_000); } // when data size is bigger than 128. use read dma @@ -304,6 +308,7 @@ pub fn test_cs, E>( // len > DMA_MIN_LENGTH { test_log!(uart, "Test FIFO read...buf len: 0x20"); let _ = dev.nor_read_data(addr, &mut rbuf[0..0x20]); + delay1.delay_ns(8_000_000); astdebug::print_array_u8(uart, &rbuf[0..0x20]); } } @@ -321,7 +326,7 @@ pub fn test_fmc(uart: &mut UartController<'_>) { let peripherals = unsafe { Peripherals::steal() }; let fmc_uart = peripherals.uart; let mut delay = DummyDelay {}; - let mut fmc_uart_controller = UartController::new(fmc_uart, &mut delay); + let fmc_uart_controller = UartController::new(fmc_uart, &mut delay); unsafe { fmc_uart_controller.init(&Config { baud_rate: 115_200, @@ -333,11 +338,8 @@ pub fn test_fmc(uart: &mut UartController<'_>) { } let mut controller = FmcController::new( - fmc_spi, - current_cs, - FMC_CONFIG, - fmc_data, - Some(&mut fmc_uart_controller), + fmc_spi, current_cs, FMC_CONFIG, fmc_data, //Some(&mut fmc_uart_controller), + None, ); test_log!(uart, "FMC controller init"); @@ -348,10 +350,10 @@ pub fn test_fmc(uart: &mut UartController<'_>) { let nor_write_data = nor_device_write_data(FMC_CS0_CAPACITY); // Wrap controller in a CS device (CS0) - let mut flash_device0: ChipSelectDevice<'_, FmcController<'_>, Spipf> = ChipSelectDevice { + let mut flash_device0: ChipSelectDevice<'_, FmcController<'_>> = ChipSelectDevice { bus: &mut controller, cs: 0, - spi_monitor: None, + spim: None, }; test_read_jedec(uart, &mut flash_device0); let _ = flash_device0.nor_read_init(&nor_read_data); @@ -360,10 +362,10 @@ pub fn test_fmc(uart: &mut UartController<'_>) { //astdebug::print_reg_u32(uart, FMC_MMAP_BASE, 0x80); // Wrap controller in a CS device (CS1) - let mut flash_device1: ChipSelectDevice<'_, FmcController<'_>, Spipf> = ChipSelectDevice { + let mut flash_device1: ChipSelectDevice<'_, FmcController<'_>> = ChipSelectDevice { bus: &mut controller, cs: 1, - spi_monitor: None, + spim: None, }; test_read_jedec(uart, &mut flash_device1); let _ = flash_device1.nor_read_init(&nor_read_data); @@ -385,6 +387,7 @@ pub fn test_fmc(uart: &mut UartController<'_>) { TEST_DATA_SIZE, true, ); + test_log!(uart, "################# FMC test done ! ###############"); } @@ -431,16 +434,16 @@ pub fn test_spi(uart: &mut UartController<'_>) { let _result = spi_controller.init(); //astdebug::print_reg_u32(uart, SPI0_CTRL_BASE, 0xb0); - let mut spi_monitor0 = start_spim0(); // Wrap controller in a CS device (CS0) let mut flash_device = ChipSelectDevice { bus: &mut spi_controller, cs: 0, - spi_monitor: Some(&mut spi_monitor0), + spim: Some(SpiMonitorNum::SPIM0), }; let nor_read_data: SpiNorData<'_> = nor_device_read_4b_data(SPI_CS0_CAPACITY); let nor_write_data = nor_device_write_4b_data(SPI_CS0_CAPACITY); + let _ = flash_device.nor_read_init(&nor_read_data); let _ = flash_device.nor_write_init(&nor_write_data); @@ -538,7 +541,7 @@ pub fn test_block_device(blockdev: &mut NorFlashBlockDevice) let uart = peripherals.uart; let mut delay = DummyDelay {}; let mut uartc = UartController::new(uart, &mut delay); - let addr = 0x0; + let addr = 0x1000; unsafe { uartc.init(&Config { @@ -552,9 +555,11 @@ pub fn test_block_device(blockdev: &mut NorFlashBlockDevice) let testsize = 0x400; let wbuf: &mut [u8] = unsafe { SPI_NC_BUFFER[WRITE_IDX].as_mut_slice(0, testsize) }; - let rbuf: &mut [u8] = unsafe { SPI_NC_BUFFER[READ_IDX].as_mut_slice(0, testsize) }; + let mut seed = 0x179a_4e87; + common::fill_random(wbuf, &mut seed); + test_log!( uartc, "###########################page size: {} sector size: {} capacity:{:08X}", @@ -580,14 +585,10 @@ pub fn test_block_device(blockdev: &mut NorFlashBlockDevice) let mut delay = DummyDelay {}; test_log!(uartc, "########## start erase "); let _ = blockdev.erase(range); - - for (i, value) in wbuf.iter_mut().take(testsize).enumerate() { - *value = u8::try_from(i % 255).unwrap(); - } delay.delay_ns(2_000_000); test_log!( uartc, - "########## start block programming size: {:08x} ", + "########## start block programming size: 0x{:08x} ", testsize ); match blockdev.program(norflashblockdevice::BlockAddrUsize(addr), wbuf) { @@ -596,7 +597,7 @@ pub fn test_block_device(blockdev: &mut NorFlashBlockDevice) } let _ = blockdev.read(norflashblockdevice::BlockAddrUsize(addr), rbuf); - + delay.delay_ns(8_000_000); let result: bool; unsafe { result = core::slice::from_raw_parts(ptr_write, testsize) @@ -610,8 +611,8 @@ pub fn test_block_device(blockdev: &mut NorFlashBlockDevice) astdebug::print_array_u8(&mut uartc, wbuf); test_log!(uartc, "read buffer:"); astdebug::print_array_u8(&mut uartc, rbuf); - test_log!(uartc, "Mmap buffer: {:08x}", SPI0_MMAP_BASE + addr); - astdebug::print_reg_u8(&mut uartc, SPI0_MMAP_BASE + addr, testsize); + //test_log!(uartc, "Mmap buffer: {:08x}", SPI0_MMAP_BASE + addr); + //astdebug::print_reg_u8(&mut uartc, SPI0_MMAP_BASE + addr, testsize); } } @@ -640,7 +641,9 @@ pub fn test_spi2(uart: &mut UartController<'_>) { pinctrl::Pinctrl::apply_pinctrl_group(pinctrl::PINCTRL_SPI2_QUAD); test_log!(uart, "SPI1 set pinctrl"); - test_log!(uart, " SCU:: 0x{:08x}", SCU_BASE); + let scu_qspi_mux: &mut [u32] = + unsafe { core::slice::from_raw_parts_mut((SCU_BASE + 0xf0) as *mut u32, 4) }; + scu_qspi_mux[0] = 0x0000_fff0; let peripherals = unsafe { Peripherals::steal() }; let spi_uart = peripherals.uart; @@ -668,19 +671,17 @@ pub fn test_spi2(uart: &mut UartController<'_>) { let _result = spi_controller.init(); astdebug::print_reg_u32(uart, SPI1_CTRL_BASE, 0xb0); let nor_read_data: SpiNorData<'_> = nor_device_read_4b_data(SPI_CS0_CAPACITY); - let nor_write_data = nor_device_read_4b_data(SPI_CS0_CAPACITY); - - if true { - let mut spi_monitor2 = start_spim2(); - // Wrap controller in a CS device (CS0) - let mut flash_device = ChipSelectDevice { - bus: &mut spi_controller, - cs: 0, - spi_monitor: Some(&mut spi_monitor2), - }; + let nor_write_data = nor_device_write_4b_data(SPI_CS0_CAPACITY); - test_read_jedec(uart, &mut flash_device); + // Wrap controller in a CS device (CS0) + let mut flash_device = ChipSelectDevice { + bus: &mut spi_controller, + cs: 0, + spim: Some(SpiMonitorNum::SPIM2), + }; + test_read_jedec(uart, &mut flash_device); + if true { let mut delay1 = DummyDelay {}; if read_id { @@ -688,7 +689,7 @@ pub fn test_spi2(uart: &mut UartController<'_>) { let mut read_buf: [u8; 0x3] = [0u8; 3]; let write_buf: [u8; 1] = [0x9f]; let _ = flash_device.transfer(&mut read_buf, &write_buf); - delay1.delay_ns(2_000_000); + delay1.delay_ns(8_000_000); astdebug::print_array_u8(uart, &read_buf[..3]); } @@ -724,15 +725,14 @@ pub fn test_spi2(uart: &mut UartController<'_>) { true, ); } - { + if true { test_log!(uart, "####### SPI 2@1#######"); //NOTE: When SPI2 controller accesses the SPI flash through SPIM3/4 output pins by configuring SCU0F0[3:0], // only CS0 decoding address area can be used within this scenario. Thus, CS is fixed to 0. - let mut spi_monitor3 = start_spim3(); let mut flash_device2 = ChipSelectDevice { bus: &mut spi_controller, cs: 0, - spi_monitor: Some(&mut spi_monitor3), + spim: Some(SpiMonitorNum::SPIM3), }; let _ = flash_device2.nor_read_init(&nor_read_data); @@ -757,146 +757,3 @@ pub fn test_spi2(uart: &mut UartController<'_>) { } test_log!(uart, "################# SPI 2 TEST done ! ###############"); } - -#[must_use] -pub fn start_spim0() -> SpiMonitor { - let allow_cmds: [u8; 27] = [ - 0x03, 0x13, 0x0b, 0x0c, 0x6b, 0x6c, 0x01, 0x05, 0x35, 0x06, 0x04, 0x20, 0x21, 0x9f, 0x5a, - 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x15, 0x31, 0x3b, 0x3c, - ]; - - let read_blocked_regions = [RegionInfo { - /*pfm*/ - start: 0x0400_0000, - length: 0x0002_0000, - }]; - - let write_blocked_regions = [RegionInfo { - start: 0x0000_0000, - length: 0x0800_0000, - }]; - let mut spi_monitor0 = SpiMonitor::::new( - true, - SpimExtMuxSel::SpimExtMuxSel1, - &allow_cmds, - u8::try_from(allow_cmds.len()).unwrap(), - &read_blocked_regions, - u8::try_from(read_blocked_regions.len()).unwrap(), - &write_blocked_regions, - u8::try_from(write_blocked_regions.len()).unwrap(), - ); - spi_monitor0.spim_sw_rst(); - spi_monitor0.aspeed_spi_monitor_init(); - - //TODO: when do we disable the mux? - //spi_monitor0.spim_ext_mux_config(SpimExtMuxSel::SpimExtMuxSel0); - spi_monitor0 - // print spim pointer value -} - -#[must_use] -pub fn start_spim1() -> SpiMonitor { - let allow_cmds: [u8; 27] = [ - 0x03, 0x13, 0x0b, 0x0c, 0x6b, 0x6c, 0x01, 0x05, 0x35, 0x06, 0x04, 0x20, 0x21, 0x9f, 0x5a, - 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x15, 0x31, 0x3b, 0x3c, - ]; - - let write_blocked_regions = [RegionInfo { - start: 0x0000_0000, - length: 0x0800_0000, - }]; - let mut spi_monitor1 = SpiMonitor::::new( - true, - SpimExtMuxSel::SpimExtMuxSel1, - &allow_cmds, - u8::try_from(allow_cmds.len()).unwrap(), - &[], - 0, - &write_blocked_regions, - u8::try_from(write_blocked_regions.len()).unwrap(), - ); - spi_monitor1.spim_sw_rst(); - spi_monitor1.aspeed_spi_monitor_init(); - //spi_monitor1.spim_ext_mux_config(SpimExtMuxSel::SpimExtMuxSel0); - - spi_monitor1 -} - -#[must_use] -pub fn start_spim2() -> SpiMonitor { - let allow_cmds: [u8; 27] = [ - 0x03, 0x13, 0x0b, 0x0c, 0x6b, 0x6c, 0x01, 0x05, 0x35, 0x06, 0x04, 0x20, 0x21, 0x9f, 0x5a, - 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x15, 0x31, 0x3b, 0x3c, - ]; - - let write_blocked_regions = [RegionInfo { - start: 0x0000_0000, - length: 0x0800_0000, - }]; - let mut spi_monitor2 = SpiMonitor::::new( - true, - SpimExtMuxSel::SpimExtMuxSel1, - &allow_cmds, - u8::try_from(allow_cmds.len()).unwrap(), - &[], - 0, - &write_blocked_regions, - u8::try_from(write_blocked_regions.len()).unwrap(), - ); - spi_monitor2.spim_sw_rst(); - spi_monitor2.aspeed_spi_monitor_init(); - //spi_monitor2.spim_ext_mux_config(SpimExtMuxSel::SpimExtMuxSel0); - - spi_monitor2 -} - -#[must_use] -pub fn start_spim3() -> SpiMonitor { - let allow_cmds: [u8; 27] = [ - 0x03, 0x13, 0x0b, 0x0c, 0x6b, 0x6c, 0x01, 0x05, 0x35, 0x06, 0x04, 0x20, 0x21, 0x9f, 0x5a, - 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x15, 0x31, 0x3b, 0x3c, - ]; - let read_blocked_regions: [RegionInfo; 3] = [ - RegionInfo { - start: 0x0000_0000, - length: 0x0001_0000, - }, - RegionInfo { - start: 0x0027_4000, - length: 0x0000_4000, - }, - RegionInfo { - start: 0x01E0_0000, - length: 0x0008_0000, - }, - ]; - let write_blocked_regions: [RegionInfo; 3] = [ - RegionInfo { - start: 0x0000_0000, - length: 0x0001_0000, - }, - RegionInfo { - start: 0x013F_C000, - length: 0x0002_8000, - }, - RegionInfo { - start: 0x0FFF_8000, - length: 0x0000_8000, - }, - ]; - let mut spi_monitor3 = SpiMonitor::::new( - true, - SpimExtMuxSel::SpimExtMuxSel1, - &allow_cmds, - u8::try_from(allow_cmds.len()).unwrap(), - &read_blocked_regions, - u8::try_from(read_blocked_regions.len()).unwrap(), - &write_blocked_regions, - u8::try_from(write_blocked_regions.len()).unwrap(), - ); - spi_monitor3.spim_sw_rst(); - spi_monitor3.aspeed_spi_monitor_init(); - //spi_monitor3.spim_ext_mux_config(SpimExtMuxSel::SpimExtMuxSel0); - - spi_monitor3 -} diff --git a/src/spimonitor.rs b/src/spimonitor/hardware.rs similarity index 86% rename from src/spimonitor.rs rename to src/spimonitor/hardware.rs index 693606d..d6dc78f 100644 --- a/src/spimonitor.rs +++ b/src/spimonitor/hardware.rs @@ -2,126 +2,13 @@ use ast1060_pac::Scu; use core::cmp::min; -use core::fmt; -use core::marker::PhantomData; -//use core::ops::bit; -//use embedded_hal::delay::DelayNs; - -#[derive(Debug)] -#[repr(u8)] -pub enum SpiMonitorNum { - SPIM0 = 0, - SPIM1 = 1, - SPIM2 = 2, - SPIM3 = 3, -} - -//abstracts register base access for different instances -pub trait SpipfInstance { - fn ptr() -> *const ast1060_pac::spipf::RegisterBlock; - const FILTER_ID: SpiMonitorNum; -} - -macro_rules! macro_spif { - ($Spipfx: ident, $x: path) => { - impl SpipfInstance for ast1060_pac::$Spipfx { - fn ptr() -> *const ast1060_pac::spipf::RegisterBlock { - ast1060_pac::$Spipfx::ptr() - } - const FILTER_ID: SpiMonitorNum = $x; - } - }; -} -macro_spif!(Spipf, SpiMonitorNum::SPIM0); -macro_spif!(Spipf1, SpiMonitorNum::SPIM1); -macro_spif!(Spipf2, SpiMonitorNum::SPIM2); -macro_spif!(Spipf3, SpiMonitorNum::SPIM3); - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u8)] -pub enum SpimSpiMaster { - SPI1 = 0, - SPI2 = 1, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum SpimPassthroughMode { - SinglePassthrough = 0, - MultiPassthrough = 1, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u8)] -pub enum SpimExtMuxSel { - SpimExtMuxSel0 = 0, - SpimExtMuxSel1 = 1, -} -impl SpimExtMuxSel { - #[must_use] - pub fn to_bool(self) -> bool { - self as u8 != 0 - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u8)] -pub enum SpimBlockMode { - SpimDeassertCsEearly = 0, - SpimBlockExtraClk = 1, -} -//address privilege table control -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u8)] -pub enum AddrPrivRWSel { - AddrPrivReadSel, - AddrPrivWriteSel, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u8)] -pub enum AddrPriOp { - FlagAddrPrivEnable, - FlagAddrPrivDisable, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u8)] -pub enum SpiMonitorError { - CommandNotFound(u8), - NoAllowCmdSlotAvail(u32), - InvalidCmdSlotIndex(u32), - AllowCmdSlotLocked(u32), - AllowCmdSlotInvalid(u32), - AddressInvalid(u32), - LengthInvalid(u32), - AddrTblRegsLocked(u32), -} -//Allow command table information -pub const SPIM_CMD_TABLE_NUM: usize = 32; -pub const MAX_CMD_INDEX: usize = 31; -pub const BLOCK_REGION_NUM: usize = 32; -//generic type -pub struct SpiMonitor { - pub spi_monitor: &'static ast1060_pac::spipf::RegisterBlock, - pub scu: &'static ast1060_pac::scu::RegisterBlock, - pub extra_clk_en: bool, - pub force_rel_flash_rst: bool, - pub ext_mux_sel: SpimExtMuxSel, - pub allow_cmd_list: [u8; SPIM_CMD_TABLE_NUM], - pub allow_cmd_num: u8, - pub read_blocked_regions: [RegionInfo; BLOCK_REGION_NUM], - pub read_blocked_region_num: u8, - pub write_blocked_regions: [RegionInfo; BLOCK_REGION_NUM], - pub write_blocked_region_num: u8, - _marker: PhantomData, -} - -impl fmt::Debug for SpiMonitor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("SpiMonitor") - } -} +use crate::spimonitor::{ + AddrPriOp, AddrPrivRWSel, RegionInfo, SpiMonitor, SpiMonitorError, SpiMonitorNum, + SpimBlockMode, SpimExtMuxSel, SpimPassthroughMode, SpimSpiMaster, SpipfInstance, + BLOCK_REGION_NUM, MAX_CMD_INDEX, SPIM_CMD_TABLE_NUM, +}; +use core::marker::PhantomData; //Address table selection majic value pub const SEL_READ_TBL_MAJIC: u32 = 0x52 << 24; @@ -208,12 +95,6 @@ pub struct CmdTableInfo { cmd_table_val: u32, } -#[derive(Debug, Clone, Copy)] -pub struct RegionInfo { - pub start: u32, - pub length: u32, -} - //#[derive(Debug, Clone, Copy)] //pub struct GpioInfo { @@ -245,7 +126,7 @@ pub const fn cmd_table_value( | cmd } -pub fn spim_get_cmd_table_val(cmd: u8) -> Result { +fn spim_get_cmd_table_val(cmd: u8) -> Result { for entry in CMDS_ARRAY { if entry.cmd == cmd { return Ok(entry.cmd_table_val); @@ -482,25 +363,13 @@ impl SpiMonitor { _marker: PhantomData, } } - pub fn spim_scu_ctrl_set(&mut self, mask: u32, val: u32) { - let mut reg_val = self.scu.scu0f0().read().bits(); - reg_val &= !mask; - reg_val |= val; - self.scu.scu0f0().write(|w| unsafe { w.bits(reg_val) }); - } - - pub fn spim_scu_ctrl_clear(&mut self, clear_bits: u32) { - let mut reg_val = self.scu.scu0f0().read().bits(); - reg_val &= !clear_bits; - self.scu.scu0f0().write(|w| unsafe { w.bits(reg_val) }); - } //SPI_M1: GPIOA6, SCU610[6], SPI master CS output //SPI_M2: GPIOC4, SCU610[20] //SPI_M3: GPIOE2, SCU614[2] (dummy, cannot be disabled) //SPI_M4: GPIOG0, SCU614[16] //disable chip select internal pull down - pub fn spim_disable_cs_internal_pd(&mut self) { + pub(crate) fn spim_disable_cs_internal_pd(&mut self) { //SPIPF::FILTER_ID match SPIPF::FILTER_ID { SpiMonitorNum::SPIM0 => { @@ -522,7 +391,8 @@ impl SpiMonitor { } } //Enable MISO - pub fn spim_miso_multi_func_adjust(&mut self, enable: bool) { + #[allow(dead_code)] + pub(crate) fn spim_miso_multi_func_adjust(&mut self, enable: bool) { match SPIPF::FILTER_ID { SpiMonitorNum::SPIM0 => { self.scu @@ -548,7 +418,7 @@ impl SpiMonitor { } //enable/disable pass through - pub fn spim_scu_passthrough_mode(&mut self, passthrough_en: bool) { + pub(crate) fn spim_scu_passthrough_mode(&mut self, passthrough_en: bool) { self.scu.scu0f0().modify(|_, w| match SPIPF::FILTER_ID { SpiMonitorNum::SPIM0 => w.enbl_passthrough_of_spipf1().bit(passthrough_en), SpiMonitorNum::SPIM1 => w.enbl_passthrough_of_spipf2().bit(passthrough_en), @@ -558,7 +428,7 @@ impl SpiMonitor { } //set passthrough mode - pub fn spim_passthrough_mode_set(&mut self, mode: SpimPassthroughMode) { + pub(crate) fn spim_passthrough_mode_set(&mut self, mode: SpimPassthroughMode) { match mode { SpimPassthroughMode::SinglePassthrough => { self.spi_monitor @@ -578,7 +448,7 @@ impl SpiMonitor { //Internal SPI master selection //Select internal SPI master connection - pub fn spim_spi_ctrl_detour_enable(&mut self, spi_master: SpimSpiMaster, enable: bool) { + pub(crate) fn spim_spi_ctrl_detour_enable(&mut self, spi_master: SpimSpiMaster, enable: bool) { if enable { self.scu.scu0f0().modify(|_, w| unsafe { w.select_int_spimaster_connection() @@ -592,11 +462,18 @@ impl SpiMonitor { .scu0f0() .modify(|_, w| w.int_spimaster_sel().bit(bit_val)); } else { - self.spim_scu_ctrl_clear(0xF); + //self.spim_scu_ctrl_clear(0xF); + let mut reg_val = self.scu.scu0f0().read().bits(); + reg_val &= !0xF; + self.scu.scu0f0().write(|w| unsafe { w.bits(reg_val) }); } } - pub fn spim_passthrough_config(&mut self, passthrough_en: bool, mode: SpimPassthroughMode) { + pub(crate) fn spim_passthrough_config( + &mut self, + passthrough_en: bool, + mode: SpimPassthroughMode, + ) { // self.spim_scu_passthrough_enable(passthrough_en); if passthrough_en { self.spim_passthrough_mode_set(mode); @@ -610,7 +487,7 @@ impl SpiMonitor { } } //External Mux Selection Signal - pub fn spim_ext_mux_config(&mut self, mux_sel: SpimExtMuxSel) { + pub(crate) fn spim_ext_mux_config(&mut self, mux_sel: SpimExtMuxSel) { assert!(mux_sel as u32 <= SpimExtMuxSel::SpimExtMuxSel1 as u32); let bit_val = mux_sel.to_bool(); match SPIPF::FILTER_ID { @@ -639,7 +516,7 @@ impl SpiMonitor { // //Block Mode: Block a command by one extra CLK //Block a command by deasserting CS early - pub fn spim_block_mode_config(&mut self, block_mode: SpimBlockMode) { + pub(crate) fn spim_block_mode_config(&mut self, block_mode: SpimBlockMode) { if block_mode == SpimBlockMode::SpimBlockExtraClk { self.spi_monitor .spipf000() @@ -651,7 +528,11 @@ impl SpiMonitor { } } - pub fn spim_write_fixed_loc_in_allow_cmd_table(&mut self, cmd: u8, reg_val: u32) -> usize { + pub(crate) fn spim_write_fixed_loc_in_allow_cmd_table( + &mut self, + cmd: u8, + reg_val: u32, + ) -> usize { match cmd { CMD_EN4B => { self.spi_monitor @@ -676,7 +557,7 @@ impl SpiMonitor { } //init allow commands table registers //0, 1 and 31 are reserved for the particular commands - pub fn spim_allow_cmd_table_init(&mut self, cmd_list: &[u8], cmd_num: u8, flag: u32) { + pub(crate) fn spim_allow_cmd_table_init(&mut self, cmd_list: &[u8], cmd_num: u8, flag: u32) { let mut index = 1; let list_size = min(cmd_num as usize, cmd_list.len()); for &cmd in cmd_list.iter().take(list_size) { @@ -707,7 +588,8 @@ impl SpiMonitor { } } - pub fn spim_get_empty_allow_cmd_slot(&mut self) -> Result { + #[allow(dead_code)] + pub(crate) fn spim_get_empty_allow_cmd_slot(&mut self) -> Result { for index in 2..SPIM_CMD_TABLE_NUM { let reg_val = self.spi_monitor.spipfwt(index).read().bits(); if reg_val == 0 { @@ -719,7 +601,7 @@ impl SpiMonitor { )) } - pub fn spim_get_allow_cmd_slot( + pub(crate) fn spim_get_allow_cmd_slot( &mut self, cmd: u8, start_offset: u32, @@ -738,7 +620,12 @@ impl SpiMonitor { Err(SpiMonitorError::CommandNotFound(cmd)) } - pub fn spim_add_new_command(&mut self, cmd: u8, flag: u32) -> Result { + #[allow(dead_code)] + pub(crate) fn spim_add_new_command( + &mut self, + cmd: u8, + flag: u32, + ) -> Result { // Retrieve the command table value let Ok(mut reg_val) = spim_get_cmd_table_val(cmd) else { return Err(SpiMonitorError::CommandNotFound(cmd)); @@ -772,7 +659,12 @@ impl SpiMonitor { // If the command doesn't exist in allow command table, an // empty slot will be found and the command info will be // filled into. - pub fn spim_add_allow_command(&mut self, cmd: u8, flag: u32) -> Result { + #[allow(dead_code)] + pub(crate) fn spim_add_allow_command( + &mut self, + cmd: u8, + flag: u32, + ) -> Result { //check if the command is already in allow command Table let mut offset: u32 = 0; @@ -808,7 +700,8 @@ impl SpiMonitor { } //All command table slots where command is equal to "cmd", valid and not locked //will be removed - pub fn spim_remove_allow_command(&mut self, cmd: u8) -> Result { + #[allow(dead_code)] + pub(crate) fn spim_remove_allow_command(&mut self, cmd: u8) -> Result { //check if the command is already in allow command Table let mut offset: u32 = 0; let mut count: u32 = 0; @@ -847,7 +740,7 @@ impl SpiMonitor { //- All command table slot which command is equal to "cmd" // parameter will be locked. // - pub fn spim_lock_allow_command_table( + pub(crate) fn spim_lock_allow_command_table( &mut self, cmd: u8, flag: u32, @@ -888,7 +781,7 @@ impl SpiMonitor { Ok(count) } } - pub fn spim_is_pri_regs_locked(&mut self, rw_select: AddrPrivRWSel) -> bool { + pub(crate) fn spim_is_pri_regs_locked(&mut self, rw_select: AddrPrivRWSel) -> bool { match rw_select { AddrPrivRWSel::AddrPrivWriteSel => { if self.spi_monitor.spipf07c().read().wr_dis_of_spipfwa().bit() { @@ -903,7 +796,7 @@ impl SpiMonitor { } false } - pub fn spim_addr_priv_access_enable(&mut self, priv_sel: AddrPrivRWSel) { + pub(crate) fn spim_addr_priv_access_enable(&mut self, priv_sel: AddrPrivRWSel) { let mut reg_val = self.spi_monitor.spipf000().read().bits(); //mask out the upper 8 bits reg_val &= 0x00FF_FFFF; @@ -918,7 +811,8 @@ impl SpiMonitor { } //get aligned length - pub fn spim_get_adjusted_addr_len(&mut self, addr: u32, len: u32) -> (u32, u32) { + #[allow(clippy::unused_self)] + pub(crate) fn spim_get_adjusted_addr_len(&mut self, addr: u32, len: u32) -> (u32, u32) { if len == 0 { return (addr, 0); } @@ -937,12 +831,13 @@ impl SpiMonitor { //Each bit defines permission of one 16KB block //Calculate numbers of 16KB blocks //Start address may cross two different 16KB blocks - pub fn spim_get_total_block_num(&mut self, addr: u32, len: u32) -> u32 { + #[allow(dead_code)] + pub(crate) fn spim_get_total_block_num(&mut self, addr: u32, len: u32) -> u32 { let (_aligned_addr, adjusted_len) = self.spim_get_adjusted_addr_len(addr, len); adjusted_len / ACCESS_BLOCK_UNIT } - pub fn spim_address_privilege_config( + pub(crate) fn spim_address_privilege_config( &mut self, rw_select: AddrPrivRWSel, priv_op: AddrPriOp, @@ -1009,7 +904,7 @@ impl SpiMonitor { Ok(total_blocks) } //lock all SPIPFWA/RA for writing - pub fn spim_lock_rw_priv_table(&mut self, rw_select: AddrPrivRWSel) { + pub(crate) fn spim_lock_rw_priv_table(&mut self, rw_select: AddrPrivRWSel) { if rw_select == AddrPrivRWSel::AddrPrivWriteSel { self.spi_monitor .spipf07c() @@ -1022,7 +917,7 @@ impl SpiMonitor { } } // - pub fn spim_lock_common(&mut self) { + pub(crate) fn spim_lock_common(&mut self) { self.spim_lock_rw_priv_table(AddrPrivRWSel::AddrPrivReadSel); self.spim_lock_rw_priv_table(AddrPrivRWSel::AddrPrivWriteSel); let _ = self.spim_lock_allow_command_table(0, FLAG_CMD_TABLE_LOCK_ALL); @@ -1045,7 +940,8 @@ impl SpiMonitor { .bit(true) }); } - pub fn spim_set_read_blocked_regions( + #[allow(dead_code)] + pub(crate) fn spim_set_read_blocked_regions( &mut self, read_blocked_regions: &[RegionInfo], read_blocked_region_num: u8, @@ -1055,7 +951,8 @@ impl SpiMonitor { self.read_blocked_region_num = read_blocked_region_num; } - pub fn spim_set_write_blocked_regions( + #[allow(dead_code)] + pub(crate) fn spim_set_write_blocked_regions( &mut self, write_blocked_regions: &[RegionInfo], write_blocked_region_num: u8, @@ -1066,17 +963,19 @@ impl SpiMonitor { } // supported command list - pub fn spim_set_cmd_table(&mut self, allow_cmd_list: &[u8], allow_cmd_num: u8) { + #[allow(dead_code)] + pub(crate) fn spim_set_cmd_table(&mut self, allow_cmd_list: &[u8], allow_cmd_num: u8) { self.allow_cmd_list[..allow_cmd_num as usize] .copy_from_slice(&allow_cmd_list[..allow_cmd_num as usize]); self.allow_cmd_num = allow_cmd_num; } - - pub fn spim_dump_read_blocked_regions(&mut self) {} - pub fn spim_dump_write_blocked_regions(&mut self) {} + #[allow(clippy::unused_self, dead_code)] + pub(crate) fn spim_dump_read_blocked_regions(&mut self) {} + #[allow(clippy::unused_self, dead_code)] + pub(crate) fn spim_dump_write_blocked_regions(&mut self) {} //Block read and write to regions - pub fn spim_rw_perm_init(&mut self) { + pub(crate) fn spim_rw_perm_init(&mut self) { //Enable previliege control for 256MB area let _ = self.spim_address_privilege_config( AddrPrivRWSel::AddrPrivReadSel, @@ -1110,7 +1009,7 @@ impl SpiMonitor { } } //Enable/disable SPI monitor from SCU - pub fn spim_scu_monitor_config(&mut self, enable: bool) { + pub(crate) fn spim_scu_monitor_config(&mut self, enable: bool) { match SPIPF::FILTER_ID { SpiMonitorNum::SPIM0 => { self.scu @@ -1135,20 +1034,20 @@ impl SpiMonitor { } } //Enable/disable SPI monitor/filter function - pub fn spim_ctrl_monitor_config(&mut self, enable: bool) { + pub(crate) fn spim_ctrl_monitor_config(&mut self, enable: bool) { self.spi_monitor .spipf000() .modify(|_, w| w.enbl_filter_fn().bit(enable)); } - pub fn spim_monitor_enable(&mut self, enable: bool) { + pub(crate) fn spim_enable(&mut self, enable: bool) { self.spim_ctrl_monitor_config(enable); // self.spim_miso_multi_func_adjust(enable); self.spim_passthrough_config(enable, SpimPassthroughMode::SinglePassthrough); } //Use SCU0F0 to enable flash rst - pub fn spim_release_flash_rst(&mut self) { + pub(crate) fn spim_release_flash_rst(&mut self) { //SCU0F0[23:20]: Reset source selection //SCU0F0[27:24]: Enable reset signal output match SPIPF::FILTER_ID { @@ -1214,7 +1113,7 @@ impl SpiMonitor { } //Enable push pull mode - pub fn spim_push_pull_mode_config(&mut self) { + pub(crate) fn spim_push_pull_mode_config(&mut self) { self.spi_monitor .spipf004() .modify(|_, w| w.enbl_push_pull_mode().bit(true)); @@ -1225,7 +1124,7 @@ impl SpiMonitor { self.spim_scu_monitor_config(true); } - pub fn spim_irq_enable(&mut self) { + pub(crate) fn spim_irq_enable(&mut self) { self.spi_monitor.spipf004().modify(|_, w| { w.enbl_intof_cmd_block() .bit(true) @@ -1235,8 +1134,9 @@ impl SpiMonitor { .bit(true) }); } - pub fn spim_abnormal_log_init(&mut self) {} - pub fn spim_sw_rst(&mut self) { + #[allow(clippy::unused_self, dead_code)] + pub(crate) fn spim_abnormal_log_init(&mut self) {} + pub(crate) fn spim_sw_rst(&mut self) { self.spi_monitor .spipf000() .modify(|_, w| w.sweng_rst().bit(true)); @@ -1252,7 +1152,7 @@ impl SpiMonitor { //SCU410, SCU414[27:0], SCU4B4 must keep at value 0x0 //SPIM0 pin ctrl //SCU410/4B0/690[13:0], rstin: SCU414/4B4/694[24] - pub fn spim_enbl_spim0_pin_ctrl(&mut self) { + pub(crate) fn spim_enbl_spim0_pin_ctrl(&mut self) { // Clear SCU4B0[13:0] let mut reg_val = self.scu.scu4b0().read().bits(); reg_val &= !0x3FFF; @@ -1269,7 +1169,7 @@ impl SpiMonitor { //SCU410, SCU41C[7:0], SCU4B4, 4BC[24:0] must keep at value 0x0 //SPIM1 pin ctrl //SCU410/4B0/690[27:14], rstin:41C/4BC/69C[9] - pub fn spim_enbl_spim1_pin_ctrl(&mut self) { + pub(crate) fn spim_enbl_spim1_pin_ctrl(&mut self) { // Clear SCU4B0[14:27] let mut reg_val = self.scu.scu4b0().read().bits(); reg_val &= !(0x3FFF << 14); @@ -1292,7 +1192,7 @@ impl SpiMonitor { //SPIM2 pin ctrl //SCU410/4B0/690[31:28], SCU414/4B4/694[9:0] //rstin SCU414/4B4/694[25] - pub fn spim_enbl_spim2_pin_ctrl(&mut self) { + pub(crate) fn spim_enbl_spim2_pin_ctrl(&mut self) { //Clear SCU4B0[31:28] let mut reg_val = self.scu.scu4b0().read().bits(); reg_val &= !(0xF << 28); @@ -1312,7 +1212,7 @@ impl SpiMonitor { } //SCU410, SCU41C[7:0], SCU4B4, 4BC[24:0] must keep at value 0x0 //SCU414/4B4/694[23:10]:SPIM3 pin ctrl rstin,41C/4BC/69C[11] - pub fn spim_enbl_spim3_pin_ctrl(&mut self) { + pub(crate) fn spim_enbl_spim3_pin_ctrl(&mut self) { //Set SCU694[23:10] let mut reg_val = self.scu.scu694().read().bits(); reg_val |= 0x3FFF << 10; @@ -1325,7 +1225,7 @@ impl SpiMonitor { .modify(|_, w| w.enbl_qspimonitor4rstin_fn_pin().bit(true)); } //SCU410,SCU414[27:0],SCU41C[7:0],SCU4B4,4BC[24:0], must be kept as 0x0 - pub fn spim_pin_ctrl_config(&mut self) { + pub(crate) fn spim_pin_ctrl_config(&mut self) { match SPIPF::FILTER_ID { SpiMonitorNum::SPIM0 => { self.spim_enbl_spim0_pin_ctrl(); @@ -1341,7 +1241,7 @@ impl SpiMonitor { } } } - pub fn aspeed_spi_monitor_init(&mut self) { + pub(crate) fn aspeed_spi_monitor_init(&mut self) { let allow_cmd_list = self.allow_cmd_list; let allow_cmd_num = self.allow_cmd_num; @@ -1359,7 +1259,7 @@ impl SpiMonitor { } self.spim_allow_cmd_table_init(&allow_cmd_list, allow_cmd_num, 0); self.spim_rw_perm_init(); - self.spim_monitor_enable(true); + self.spim_enable(true); //log info init //self.spim_abnormal_log_init(); diff --git a/src/spimonitor/mod.rs b/src/spimonitor/mod.rs new file mode 100644 index 0000000..fe5a5a8 --- /dev/null +++ b/src/spimonitor/mod.rs @@ -0,0 +1,256 @@ +// Licensed under the Apache-2.0 license + +use core::fmt; +use core::marker::PhantomData; +pub mod hardware; + +#[derive(Debug, Copy, Clone)] +#[repr(u8)] +pub enum SpiMonitorNum { + SPIM0 = 0, + SPIM1 = 1, + SPIM2 = 2, + SPIM3 = 3, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum SpimSpiMaster { + SPI1 = 0, + SPI2 = 1, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum SpimPassthroughMode { + SinglePassthrough = 0, + MultiPassthrough = 1, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum SpimExtMuxSel { + SpimExtMuxSel0 = 0, + SpimExtMuxSel1 = 1, +} +impl SpimExtMuxSel { + #[must_use] + pub fn to_bool(self) -> bool { + self as u8 != 0 + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum SpimBlockMode { + SpimDeassertCsEearly = 0, + SpimBlockExtraClk = 1, +} + +//address privilege table control +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum AddrPrivRWSel { + AddrPrivReadSel, + AddrPrivWriteSel, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum AddrPriOp { + FlagAddrPrivEnable, + FlagAddrPrivDisable, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum SpiMonitorError { + CommandNotFound(u8), + NoAllowCmdSlotAvail(u32), + InvalidCmdSlotIndex(u32), + AllowCmdSlotLocked(u32), + AllowCmdSlotInvalid(u32), + AddressInvalid(u32), + LengthInvalid(u32), + AddrTblRegsLocked(u32), +} + +//abstracts register base access for different instances +pub trait SpipfInstance { + fn ptr() -> *const ast1060_pac::spipf::RegisterBlock; + const FILTER_ID: SpiMonitorNum; +} + +macro_rules! macro_spif { + ($Spipfx: ident, $x: path) => { + impl SpipfInstance for ast1060_pac::$Spipfx { + fn ptr() -> *const ast1060_pac::spipf::RegisterBlock { + ast1060_pac::$Spipfx::ptr() + } + const FILTER_ID: SpiMonitorNum = $x; + } + }; +} +macro_spif!(Spipf, SpiMonitorNum::SPIM0); +macro_spif!(Spipf1, SpiMonitorNum::SPIM1); +macro_spif!(Spipf2, SpiMonitorNum::SPIM2); +macro_spif!(Spipf3, SpiMonitorNum::SPIM3); + +#[derive(Debug, Clone, Copy)] +pub struct RegionInfo { + pub start: u32, + pub length: u32, +} + +//Allow command table information +pub const SPIM_CMD_TABLE_NUM: usize = 32; +pub const MAX_CMD_INDEX: usize = 31; +pub const BLOCK_REGION_NUM: usize = 32; +//generic type +pub struct SpiMonitor { + pub spi_monitor: &'static ast1060_pac::spipf::RegisterBlock, + pub scu: &'static ast1060_pac::scu::RegisterBlock, + pub extra_clk_en: bool, + pub force_rel_flash_rst: bool, + pub ext_mux_sel: SpimExtMuxSel, + pub allow_cmd_list: [u8; SPIM_CMD_TABLE_NUM], + pub allow_cmd_num: u8, + pub read_blocked_regions: [RegionInfo; BLOCK_REGION_NUM], + pub read_blocked_region_num: u8, + pub write_blocked_regions: [RegionInfo; BLOCK_REGION_NUM], + pub write_blocked_region_num: u8, + _marker: PhantomData, +} + +impl fmt::Debug for SpiMonitor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("SpiMonitor") + } +} + +// public traits for spimonitor +// Keep these traits tiny and object-safe (no generics, no Self returns). +pub trait SpiMonitorInit { + fn init(&mut self); + fn sw_reset(&mut self); + fn ext_mux_config(&mut self, mux_sel: SpimExtMuxSel); +} + +pub trait SpiMonitorOps { + fn enable(&mut self); + fn diable(&mut self); + fn passthrough_config(&mut self, passthrough_en: bool, mode: SpimPassthroughMode); + fn spi_ctrl_detour_enable(&mut self, spi_master: SpimSpiMaster, enable: bool); + fn block_mode_config(&mut self, block_mode: SpimBlockMode); + fn lock_common(&mut self); +} + +pub trait PrivilegeCtrl { + fn addr_priv_enable(&mut self, rw: AddrPrivRWSel); + fn address_privilege_config(&mut self, rw: AddrPrivRWSel, op: AddrPriOp, addr: u32, len: u32); + fn lock_rw_privilege_table(&mut self, rw: AddrPrivRWSel); +} + +pub trait AllowCmdCtrl { + fn get_cmd_table_val(&mut self, cmd: u8) -> Result; + fn set_cmd_table(&mut self, cmd_list: &[u8], cmd_num: u8); + fn init_allow_cmd_table(&mut self, cmd_list: &[u8], cmd_num: u8, flags: u32); + fn first_empty_slot(&mut self) -> Result; + fn find_allow_cmd_slot(&mut self, cmd: u8, start_offset: u32) -> Result; + fn add_allow_cmd(&mut self, cmd: u8, flags: u32) -> Result; + fn remove_allow_cmd(&mut self, cmd: u8) -> Result; + fn lock_allow_cmd(&mut self, cmd: u8, flags: u32) -> Result; +} + +// calling the functions within the same crate, so use inline +impl SpiMonitorInit for SpiMonitor { + #[inline] + fn init(&mut self) { + self.aspeed_spi_monitor_init(); + } + #[inline] + fn sw_reset(&mut self) { + self.spim_sw_rst(); + } + #[inline] + fn ext_mux_config(&mut self, mux_sel: SpimExtMuxSel) { + self.spim_ext_mux_config(mux_sel); + } +} + +impl SpiMonitorOps for SpiMonitor { + #[inline] + fn passthrough_config(&mut self, passthrough_en: bool, mode: SpimPassthroughMode) { + self.spim_passthrough_config(passthrough_en, mode); + } + #[inline] + fn spi_ctrl_detour_enable(&mut self, spi_master: SpimSpiMaster, enable: bool) { + self.spim_spi_ctrl_detour_enable(spi_master, enable); + } + #[inline] + fn block_mode_config(&mut self, block_mode: SpimBlockMode) { + self.spim_block_mode_config(block_mode); + } + #[inline] + fn enable(&mut self) { + self.spim_enable(true); + } + #[inline] + fn diable(&mut self) { + self.spim_enable(false); + } + #[inline] + fn lock_common(&mut self) { + self.spim_lock_common(); + } +} +/* +impl AllowCmdCtrl for SpiMonitor { + #[inline] + fn get_cmd_table_val(&mut self, cmd: u8) -> Result { + self.spim_get_cmd_table_val(cmd) + } + #[inline] + fn set_cmd_table(&mut self, list: &[u8], num: u8) { + self.spim_set_cmd_table(list, num) + } + #[inline] + fn init_allow_cmd_table(&mut self, list: &[u8], num: u8, flags: u32) { + self.spim_allow_cmd_table_init(list, num, flags) + } + #[inline] + fn first_empty_slot(&mut self) -> Result { + self.spim_get_empty_allow_cmd_slot() + } + #[inline] + fn find_allow_cmd_slot(&mut self, cmd: u8, start: u32) -> Result { + self.spim_get_allow_cmd_slot(cmd, start) + } + #[inline] + fn add_allow_cmd(&mut self, cmd: u8, flags: u32) -> Result { + self.spim_add_allow_command(cmd, flags) + } + #[inline] + fn remove_allow_cmd(&mut self, cmd: u8) -> Result { + self.spim_remove_allow_command(cmd) + } + #[inline] + fn lock_allow_cmd(&mut self, cmd: u8, flags: u32) -> Result { + self.spim_lock_allow_command_table(cmd, flags) + } +} + +impl PrivilegeCtrl for SpiMonitor { + #[inline] + fn addr_priv_enable(&mut self, rw: AddrPrivRWSel) { + self.spim_addr_priv_access_enable(rw); + } + #[inline] + fn address_privilege_config(&mut self, rw: AddrPrivRWSel, op: AddrPriOp, addr: u32, len: u32) { + self.spim_address_privilege_config(rw, op, addr, len); + } + #[inline] + fn lock_rw_privilege_table(&mut self, rw: AddrPrivRWSel) { + self.spim_lock_rw_priv_table(rw); + } +} +*/ diff --git a/src/tests/functional/mod.rs b/src/tests/functional/mod.rs index 3206b64..170efd8 100644 --- a/src/tests/functional/mod.rs +++ b/src/tests/functional/mod.rs @@ -6,3 +6,4 @@ pub mod hash_test; pub mod hmac_test; pub mod rsa_test; pub mod rsa_test_vec; +pub mod spim_test; diff --git a/src/tests/functional/spim_test.rs b/src/tests/functional/spim_test.rs new file mode 100644 index 0000000..815368c --- /dev/null +++ b/src/tests/functional/spim_test.rs @@ -0,0 +1,167 @@ +// Licensed under the Apache-2.0 license + +use ast1060_pac::{Spipf, Spipf1, Spipf2, Spipf3}; + +use crate::astdebug; +use crate::spimonitor::{RegionInfo, SpiMonitor, SpiMonitorInit, SpimExtMuxSel}; +use crate::uart::UartController; +use embedded_io::Write; + +pub const SPIM1_BASE: usize = 0x7e79_1000; +pub const SPIM2_BASE: usize = 0x7e79_2000; +pub const SPIM3_BASE: usize = 0x7e79_3000; +pub const SPIM4_BASE: usize = 0x7e79_4000; + +//follow DTS configuration examples +pub fn test_spim0(uart: &mut UartController<'_>) { + uart.write_all(b"\r\n####### SPIM0 setup #######\r\n") + .unwrap(); + let allow_cmds: [u8; 27] = [ + 0x03, 0x13, 0x0b, 0x0c, 0x6b, 0x6c, 0x01, 0x05, 0x35, 0x06, 0x04, 0x20, 0x21, 0x9f, 0x5a, + 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x15, 0x31, 0x3b, 0x3c, + ]; + + let read_blocked_regions = [RegionInfo { + /*pfm*/ + start: 0x0300_0000, + length: 0x0004_0000, + }]; + + let write_blocked_regions = [RegionInfo { + start: 0x0000_0000, + length: 0x0020_0000, + }]; + let mut spi_monitor0 = SpiMonitor::::new( + true, + SpimExtMuxSel::SpimExtMuxSel1, + &allow_cmds, + u8::try_from(allow_cmds.len()).unwrap(), + &read_blocked_regions, + u8::try_from(read_blocked_regions.len()).unwrap(), + &write_blocked_regions, + u8::try_from(write_blocked_regions.len()).unwrap(), + ); + spi_monitor0.sw_reset(); + spi_monitor0.init(); + spi_monitor0.ext_mux_config(SpimExtMuxSel::SpimExtMuxSel0); + if false { + astdebug::print_reg_u32(uart, SPIM1_BASE, 0x80); + astdebug::print_reg_u32(uart, SPIM1_BASE + 0x70, 0x80); + astdebug::print_reg_u32(uart, SPIM1_BASE + 0x100, 0x80); + astdebug::print_reg_u32(uart, SPIM1_BASE + 0x300, 0x100); + astdebug::print_reg_u32(uart, SPIM1_BASE + 0x400, 0x80); + } + + let scu_qspi_mux: &mut [u32] = + unsafe { core::slice::from_raw_parts_mut((SPIM1_BASE) as *mut u32, 4) }; + scu_qspi_mux[0] = 0x5200_0004; + if false { + astdebug::print_reg_u32(uart, SPIM1_BASE, 0x80); + astdebug::print_reg_u32(uart, SPIM1_BASE + 0x70, 0x80); + astdebug::print_reg_u32(uart, SPIM1_BASE + 0x100, 0x80); + astdebug::print_reg_u32(uart, SPIM1_BASE + 0x200, 0x100); + astdebug::print_reg_u32(uart, SPIM1_BASE + 0x300, 0x100); + } + + // print spim pointer value +} + +pub fn test_spim1() { + let allow_cmds: [u8; 27] = [ + 0x03, 0x13, 0x0b, 0x0c, 0x6b, 0x6c, 0x01, 0x05, 0x35, 0x06, 0x04, 0x20, 0x21, 0x9f, 0x5a, + 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x15, 0x31, 0x3b, 0x3c, + ]; + + let write_blocked_regions = [RegionInfo { + start: 0x0000_0000, + length: 0x0800_0000, + }]; + let mut spi_monitor1 = SpiMonitor::::new( + true, + SpimExtMuxSel::SpimExtMuxSel1, + &allow_cmds, + u8::try_from(allow_cmds.len()).unwrap(), + &[], + 0, + &write_blocked_regions, + u8::try_from(write_blocked_regions.len()).unwrap(), + ); + spi_monitor1.sw_reset(); + spi_monitor1.init(); + spi_monitor1.ext_mux_config(SpimExtMuxSel::SpimExtMuxSel0); +} + +pub fn test_spim2() { + let allow_cmds: [u8; 27] = [ + 0x03, 0x13, 0x0b, 0x0c, 0x6b, 0x6c, 0x01, 0x05, 0x35, 0x06, 0x04, 0x20, 0x21, 0x9f, 0x5a, + 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x15, 0x31, 0x3b, 0x3c, + ]; + + let write_blocked_regions = [RegionInfo { + start: 0x0000_0000, + length: 0x0800_0000, + }]; + let mut spi_monitor2 = SpiMonitor::::new( + true, + SpimExtMuxSel::SpimExtMuxSel1, + &allow_cmds, + u8::try_from(allow_cmds.len()).unwrap(), + &[], + 0, + &write_blocked_regions, + u8::try_from(write_blocked_regions.len()).unwrap(), + ); + spi_monitor2.sw_reset(); + spi_monitor2.init(); + spi_monitor2.ext_mux_config(SpimExtMuxSel::SpimExtMuxSel0); +} + +pub fn test_spim3(uart: &mut UartController<'_>) { + uart.write_all(b"\r\n####### SPIM3 setup #######\r\n") + .unwrap(); + let allow_cmds: [u8; 27] = [ + 0x03, 0x13, 0x0b, 0x0c, 0x6b, 0x6c, 0x01, 0x05, 0x35, 0x06, 0x04, 0x20, 0x21, 0x9f, 0x5a, + 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x15, 0x31, 0x3b, 0x3c, + ]; + let read_blocked_regions: [RegionInfo; 3] = [ + RegionInfo { + start: 0x0000_0000, + length: 0x0001_0000, + }, + RegionInfo { + start: 0x0027_4000, + length: 0x0000_4000, + }, + RegionInfo { + start: 0x01E0_0000, + length: 0x0008_0000, + }, + ]; + let write_blocked_regions: [RegionInfo; 3] = [ + RegionInfo { + start: 0x0000_0000, + length: 0x0001_0000, + }, + RegionInfo { + start: 0x013F_C000, + length: 0x0002_8000, + }, + RegionInfo { + start: 0x0FFF_8000, + length: 0x0000_8000, + }, + ]; + let mut spi_monitor3 = SpiMonitor::::new( + true, + SpimExtMuxSel::SpimExtMuxSel1, + &allow_cmds, + u8::try_from(allow_cmds.len()).unwrap(), + &read_blocked_regions, + u8::try_from(read_blocked_regions.len()).unwrap(), + &write_blocked_regions, + u8::try_from(write_blocked_regions.len()).unwrap(), + ); + spi_monitor3.sw_reset(); + spi_monitor3.init(); + spi_monitor3.ext_mux_config(SpimExtMuxSel::SpimExtMuxSel0); +}