From 7bad45ca4f5c3e23e388e5debe421d814aa7e009 Mon Sep 17 00:00:00 2001 From: hailin wu Date: Mon, 4 Aug 2025 15:58:00 -0700 Subject: [PATCH 01/10] add spi dma irq support --- Cargo.lock | 32 ++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 18 +++++++---- src/spi/fmccontroller.rs | 65 +++++++++++++++++++++++++++++++--------- src/spi/mod.rs | 3 +- src/spi/spicontroller.rs | 48 +++++++++++++++++++++-------- src/spi/spitest.rs | 18 ++++++----- 7 files changed, 146 insertions(+), 39 deletions(-) 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..393ce24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,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/main.rs b/src/main.rs index def120d..49145f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -166,13 +166,21 @@ fn main() -> ! { gpio_test::test_gpioa(&mut uart_controller); test_wdt(&mut uart_controller); - let test_spicontroller = false; + let test_spicontroller = true; + 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(); - gpio_test::test_gpio_flash_power(&mut uart_controller); - spi::spitest::test_spi2(&mut uart_controller); + 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); + } } // Initialize the peripherals here if needed loop { diff --git a/src/spi/fmccontroller.rs b/src/spi/fmccontroller.rs index 5e92e33..50dd9e4 100644 --- a/src/spi/fmccontroller.rs +++ b/src/spi/fmccontroller.rs @@ -8,7 +8,7 @@ use super::{ ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_DISCARD_REQ_MAGIC, SPI_DMA_ENABLE, SPI_DMA_FLASH_MAP_BASE, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, SPI_DMA_RAM_MAP_BASE, - SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, + SPI_DMA_REQUEST, SPI_DMA_STATUS, }; #[cfg(feature = "spi_dma")] @@ -18,7 +18,7 @@ use crate::dbg; use crate::spi::{ SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, SPI_CTRL_CEX_SPI_CMD_MASK, SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_MASK, - SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, SPI_DMA_DELAY_SHIFT, + SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, SPI_DMA_DELAY_SHIFT, SPI_DMA_STS, }; use crate::{common::DummyDelay, spi::norflash::SpiNorData, uart::UartController}; use embedded_hal::{ @@ -590,7 +590,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,10 +599,11 @@ 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 + dbg!(self, "wait_for_dma_completion"); while !self.regs.fmc008().read().dmastatus().is_dma_finish() { delay.delay_ns(500); to -= 1; @@ -614,14 +616,16 @@ impl<'a> FmcController<'a> { self.dma_disable(); Ok(()) } - /* + fn dma_irq_disable(&mut self) { // Enable the DMA interrupt bit (bit 3) + dbg!(self, "dma_irq_disable"); self.regs.fmc008().modify(|_, w| w.dmaintenbl().clear_bit()); } 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()); } fn dbg_fmc_dma(&mut self) { @@ -630,10 +634,28 @@ impl<'a> FmcController<'a> { 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(); + + // TODO: 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,23 +709,33 @@ impl<'a> FmcController<'a> { .write(|w| unsafe { w.bits(u32::try_from(read_length).unwrap()) }); // Enable IRQ - //self.dma_irq_enable(); - + + 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) + let mut delay = DummyDelay {}; + delay.delay_ns(1_000_000); + //self.wait_for_dma_completion(SPI_DMA_TIMEOUT) + Ok(()) } #[allow(dead_code)] 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); // Check alignment and bounds if op.addr % 4 != 0 || (op.tx_buf.as_ptr() as usize) % 4 != 0 { return Err(SpiError::AddressNotAligned(op.addr)); @@ -742,7 +774,10 @@ impl<'a> FmcController<'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 + self.dma_irq_enable(); + //self.dbg_fmc_dma(); + let mut delay = DummyDelay {}; + delay.delay_ns(8_000_000); // Start DMA with write direction self.regs.fmc080().modify(|_, w| { w.dmaenbl().enable_dma_operation(); @@ -750,7 +785,9 @@ impl<'a> FmcController<'a> { .write_flash_move_from_external_memory_to_flash() }); - self.wait_for_dma_completion(SPI_DMA_TIMEOUT) + delay.delay_ns(8_000_000); + // self.wait_for_dma_completion(SPI_DMA_TIMEOUT) + Ok(()) } } diff --git a/src/spi/mod.rs b/src/spi/mod.rs index c5730ce..3e88252 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)] @@ -82,7 +83,7 @@ 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_STS: u32 = 1 << 11; //const SPI_DMA_IRQ_EN: u32 = 1 << 3; #[cfg(feature = "spi_dma")] const SPI_DMA_WRITE: u32 = 1 << 1; diff --git a/src/spi/spicontroller.rs b/src/spi/spicontroller.rs index 2883040..407824d 100644 --- a/src/spi/spicontroller.rs +++ b/src/spi/spicontroller.rs @@ -8,7 +8,7 @@ use super::{ ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_DISCARD_REQ_MAGIC, SPI_DMA_ENABLE, SPI_DMA_FLASH_MAP_BASE, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, SPI_DMA_RAM_MAP_BASE, - SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, + SPI_DMA_REQUEST, SPI_DMA_STATUS, }; #[cfg(feature = "spi_dma")] @@ -18,7 +18,7 @@ use crate::dbg; use crate::spi::{ SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, SPI_CTRL_CEX_SPI_CMD_MASK, SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_MASK, - SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, SPI_DMA_DELAY_SHIFT, + SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, SPI_DMA_DELAY_SHIFT, SPI_DMA_STS, }; use crate::{common::DummyDelay, spi::norflash::SpiNorData, uart::UartController}; @@ -660,7 +660,7 @@ impl<'a> SpiController<'a> { 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()); @@ -670,7 +670,30 @@ impl<'a> SpiController<'a> { // Enable the DMA interrupt bit (bit 3) self.regs.spi008().modify(|_, w| w.dmaintenbl().set_bit()); } - */ + 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 +728,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,18 +754,19 @@ impl<'a> SpiController<'a> { .write(|w| unsafe { w.bits(u32::try_from(read_length).unwrap()) }); // Enable IRQ - //self.dma_irq_enable(); + 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) + let mut delay = DummyDelay {}; + delay.delay_ns(1_000_000); + //dbg!(self, "start wait for dma"); + //self.wait_for_dma_completion(SPI_DMA_TIMEOUT) + Ok(()) } #[allow(dead_code)] @@ -794,7 +817,7 @@ 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 + self.dma_irq_enable(); // Start DMA with write direction self.regs.spi080().modify(|_, w| { @@ -803,7 +826,8 @@ impl<'a> SpiController<'a> { .write_flash_move_from_external_memory_to_flash() }); - self.wait_for_dma_completion(SPI_DMA_TIMEOUT) + //self.wait_for_dma_completion(SPI_DMA_TIMEOUT) + Ok(()) } } diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index 7c94b72..a38b084 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; @@ -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, @@ -273,7 +276,7 @@ pub fn test_cs, E>( let _ = dev.nor_read_fast_4b_data(addr, rbuf); } } - delay1.delay_ns(2_000_000); + delay1.delay_ns(8_000_000); if test_write { let result: bool; @@ -304,6 +307,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]); } } @@ -584,7 +588,7 @@ pub fn test_block_device(blockdev: &mut NorFlashBlockDevice) for (i, value) in wbuf.iter_mut().take(testsize).enumerate() { *value = u8::try_from(i % 255).unwrap(); } - delay.delay_ns(2_000_000); + delay.delay_ns(8_000_000); test_log!( uartc, "########## start block programming size: {:08x} ", @@ -596,7 +600,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) @@ -668,7 +672,7 @@ 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); + let nor_write_data = nor_device_write_4b_data(SPI_CS0_CAPACITY); if true { let mut spi_monitor2 = start_spim2(); @@ -688,7 +692,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]); } From ffa08b60b3f00640a8b5dd10d443089b96321207 Mon Sep 17 00:00:00 2001 From: hailin wu Date: Mon, 4 Aug 2025 16:56:47 -0700 Subject: [PATCH 02/10] add spi dma irq test code. fixed precommit errors --- src/main.rs | 3 +- src/spi/fmccontroller.rs | 20 +- src/spi/mod.rs | 5 +- src/spi/spicontroller.rs | 16 +- src/spi/spidmairqtest.rs | 523 +++++++++++++++++++++++++++++++++++++++ src/spi/spitest.rs | 4 +- 6 files changed, 548 insertions(+), 23 deletions(-) create mode 100644 src/spi/spidmairqtest.rs diff --git a/src/main.rs b/src/main.rs index 49145f8..20d47b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -174,8 +174,7 @@ fn main() -> ! { spi::spidmairqtest::test_fmc_dma_irq(&mut uart_controller); spi::spidmairqtest::test_spi_dma_irq(&mut uart_controller); - } - else { + } else { spi::spitest::test_fmc(&mut uart_controller); spi::spitest::test_spi(&mut uart_controller); //gpio_test::test_gpio_flash_power(&mut uart_controller); diff --git a/src/spi/fmccontroller.rs b/src/spi/fmccontroller.rs index 50dd9e4..2dc570c 100644 --- a/src/spi/fmccontroller.rs +++ b/src/spi/fmccontroller.rs @@ -18,7 +18,7 @@ use crate::dbg; use crate::spi::{ SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, SPI_CTRL_CEX_SPI_CMD_MASK, SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_MASK, - SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, SPI_DMA_DELAY_SHIFT, SPI_DMA_STS, + SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, SPI_DMA_DELAY_SHIFT, }; use crate::{common::DummyDelay, spi::norflash::SpiNorData, uart::UartController}; use embedded_hal::{ @@ -599,6 +599,7 @@ impl<'a> FmcController<'a> { .write(|w| unsafe { w.bits(SPI_DMA_DISCARD_REQ_MAGIC) }); } + #[allow(dead_code)] pub fn wait_for_dma_completion(&mut self, timeout: u32) -> Result<(), SpiError> { let mut delay = DummyDelay {}; let mut to = timeout; @@ -628,6 +629,8 @@ impl<'a> FmcController<'a> { 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 0x80: {:08x}", self.regs.fmc080().read().bits()); dbg!(self, "reg 0x84: {:08x}", self.regs.fmc084().read().bits()); @@ -635,12 +638,11 @@ impl<'a> FmcController<'a> { dbg!(self, "reg 0x8c: {:08x}", self.regs.fmc08c().read().bits()); } - pub fn handle_interrupt(&mut self) -> Result<(), SpiError> - { + pub fn handle_interrupt(&mut self) -> Result<(), SpiError> { dbg!(self, "handle interrupt"); - if !self.regs.fmc008().read().dmastatus().is_dma_finish() { + if !self.regs.fmc008().read().dmastatus().is_dma_finish() { return Err(SpiError::Other("irq error")); - } + } /* disable IRQ */ self.dma_irq_disable(); @@ -709,10 +711,10 @@ impl<'a> FmcController<'a> { .write(|w| unsafe { w.bits(u32::try_from(read_length).unwrap()) }); // Enable IRQ - + self.dma_irq_enable(); //self.dbg_fmc_dma(); - + // Start DMA dbg!(self, "start dma"); self.regs.fmc080().modify(|_, w| { @@ -774,7 +776,7 @@ impl<'a> FmcController<'a> { .write(|w| unsafe { w.bits(u32::try_from(op.tx_buf.len()).unwrap() - 1) }); // Enable DMA IRQ if needed - self.dma_irq_enable(); + self.dma_irq_enable(); //self.dbg_fmc_dma(); let mut delay = DummyDelay {}; delay.delay_ns(8_000_000); @@ -786,7 +788,7 @@ impl<'a> FmcController<'a> { }); delay.delay_ns(8_000_000); - // self.wait_for_dma_completion(SPI_DMA_TIMEOUT) + // self.wait_for_dma_completion(SPI_DMA_TIMEOUT) Ok(()) } } diff --git a/src/spi/mod.rs b/src/spi/mod.rs index 3e88252..303120f 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -83,7 +83,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; @@ -110,8 +109,8 @@ const HPLL_FREQ: u32 = 1_000_000_000; //const HCLK_DIV_SEL_MASK: u32 = 0b111 << 28; //const SPI_NOR_MAX_ID_LEN: u32 = 3; - -const SPI_DMA_TIMEOUT: u32 = 0x10000; +#[allow(dead_code)] +const SPI_DMA_TIMEOUT: u32 = 0x1_0000; const SPI_NOR_DATA_DIRECT_READ: u32 = 0x0000_0001; const SPI_NOR_DATA_DIRECT_WRITE: u32 = 0x0000_0002; diff --git a/src/spi/spicontroller.rs b/src/spi/spicontroller.rs index 407824d..f21f48d 100644 --- a/src/spi/spicontroller.rs +++ b/src/spi/spicontroller.rs @@ -18,7 +18,7 @@ use crate::dbg; use crate::spi::{ SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, SPI_CTRL_CEX_SPI_CMD_MASK, SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_MASK, - SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, SPI_DMA_DELAY_SHIFT, SPI_DMA_STS, + SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, SPI_DMA_DELAY_SHIFT, }; use crate::{common::DummyDelay, spi::norflash::SpiNorData, uart::UartController}; @@ -644,6 +644,7 @@ impl<'a> SpiController<'a> { .write(|w| unsafe { w.bits(SPI_DMA_DISCARD_REQ_MAGIC) }); } + #[allow(dead_code)] fn wait_for_dma_completion(&mut self, timeout: u32) -> Result<(), SpiError> { let mut delay = DummyDelay {}; let mut to = timeout; @@ -660,7 +661,7 @@ impl<'a> SpiController<'a> { 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()); @@ -670,18 +671,19 @@ impl<'a> SpiController<'a> { // 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> - { + 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(); @@ -691,7 +693,7 @@ impl<'a> SpiController<'a> { 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); + //spi_context_complete(ctx, dev, 0); } pub fn read_dma(&mut self, op: &mut SpiNorData) -> Result<(), SpiError> { @@ -766,7 +768,7 @@ impl<'a> SpiController<'a> { delay.delay_ns(1_000_000); //dbg!(self, "start wait for dma"); //self.wait_for_dma_completion(SPI_DMA_TIMEOUT) - Ok(()) + Ok(()) } #[allow(dead_code)] diff --git a/src/spi/spidmairqtest.rs b/src/spi/spidmairqtest.rs new file mode 100644 index 0000000..48d930f --- /dev/null +++ b/src/spi/spidmairqtest.rs @@ -0,0 +1,523 @@ +// 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::{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::{RegionInfo, SpiMonitor, SpimExtMuxSel}; +use crate::uart::UartController; +use crate::{astdebug, pinctrl}; +use ast1060_pac::Spipf; +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, Spipf>> = None; +static mut FMC_DEV0_PTR: *mut ChipSelectDevice<'_, FmcController<'_>, Spipf> = + core::ptr::null_mut(); +static mut FMC_DEVICE1: Option, Spipf>> = None; +static mut FMC_DEV1_PTR: *mut ChipSelectDevice<'_, FmcController<'_>, Spipf> = + core::ptr::null_mut(); + +static mut SPI_DEVICE0: Option, Spipf>> = None; +static mut SPI_DEV0_PTR: *mut ChipSelectDevice<'_, SpiController<'_>, Spipf> = + core::ptr::null_mut(); + +static mut SPI_MONITOR0: Option> = None; + +// 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(); + + 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(); + (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 (_, mmap_addr, _) = spitest::device_info(CURRENT_DEVID); + + let uart = UART_PTR.as_mut().unwrap(); + log_uart!("[{:08x}]", mmap_addr); + astdebug::print_reg_u8(uart, mmap_addr, 0x400); +} +unsafe fn start_next_dma() { + unsafe { + log_uart!("start_next_dma()"); + if DMA_QUEUE.is_empty() { + 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()) { + 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()) { + log_uart!("Failed to start DMA transfer: {:?}", e); + } + } + } + } +} + +pub fn on_complete_dma(verify: bool, idx: usize, buf: &[u8]) { + unsafe { + log_uart!("on_complete_dma"); + if verify { + if verify_dma_buffer_match(idx) { + log_uart!("DMA test passed!!"); + } else { + log_uart!("DMA test failed!!"); + } + } else if let Some(uart) = 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; + } + } + + unsafe { + log_uart!("All DMA buffers matched successfully!"); + } + true +} + +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; + } +} + +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 { + 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(); + + log_uart!("irq_chain_test"); + for (i, &addr) in start_addrs.iter().enumerate() { + if i >= MAX_DMA_CHAIN { + 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(); + 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, + spi_monitor: 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); + 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, + spi_monitor: 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 = true; + 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); + 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 current_cs = 0; + + 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 spi_monitor0 = start_static_spim0(); + + let flash_device0 = ChipSelectDevice { + bus: controller, + cs: 0, + spi_monitor: Some(spi_monitor0), + }; + + 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; + fill_dma_buffer(DmaOp::ReadFast, false); + dma_irq_chain_test(&start_addrs, DmaOp::ReadFast, false); + } //unsafe +} + +static 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, +]; + +static READ_BLOCKED_REGIONS: [RegionInfo; 1] = [RegionInfo { + start: 0x0400_0000, + length: 0x0002_0000, +}]; + +static WRITE_BLOCKED_REGIONS: [RegionInfo; 1] = [RegionInfo { + start: 0x0000_0000, + length: 0x0800_0000, +}]; + +pub fn start_static_spim0() -> &'static mut SpiMonitor { + unsafe { + SPI_MONITOR0 = Some(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(), + )); + + let monitor = SPI_MONITOR0.as_mut().unwrap(); + monitor.spim_sw_rst(); + monitor.aspeed_spi_monitor_init(); + + monitor + } +} diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index a38b084..5c3c364 100644 --- a/src/spi/spitest.rs +++ b/src/spi/spitest.rs @@ -1,6 +1,6 @@ // 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 +//! 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; From b270671222051d9e760f578bd950cb805fdab86e Mon Sep 17 00:00:00 2001 From: hailin wu Date: Tue, 12 Aug 2025 11:48:54 -0700 Subject: [PATCH 03/10] fixed synchronization issue. --- Cargo.toml | 1 + src/common.rs | 57 +++++++++++++++-- src/spi/device.rs | 1 - src/spi/fmccontroller.rs | 110 +++++++++++++++++--------------- src/spi/mod.rs | 5 +- src/spi/norflash.rs | 5 -- src/spi/norflashblockdevice.rs | 4 +- src/spi/spicontroller.rs | 96 +++++++++++++++------------- src/spi/spidmairqtest.rs | 112 +++++++++++++++++++++------------ src/spi/spitest.rs | 34 +++++----- 10 files changed, 259 insertions(+), 166 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 393ce24..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] 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/spi/device.rs b/src/spi/device.rs index aebe83f..db38483 100644 --- a/src/spi/device.rs +++ b/src/spi/device.rs @@ -55,7 +55,6 @@ where spim.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 2dc570c..cdc2657 100644 --- a/src/spi/fmccontroller.rs +++ b/src/spi/fmccontroller.rs @@ -8,7 +8,7 @@ use super::{ ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_DISCARD_REQ_MAGIC, SPI_DMA_ENABLE, SPI_DMA_FLASH_MAP_BASE, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, SPI_DMA_RAM_MAP_BASE, - SPI_DMA_REQUEST, SPI_DMA_STATUS, + SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, }; #[cfg(feature = "spi_dma")] @@ -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. @@ -599,39 +601,41 @@ impl<'a> FmcController<'a> { .write(|w| unsafe { w.bits(SPI_DMA_DISCARD_REQ_MAGIC) }); } - #[allow(dead_code)] pub fn wait_for_dma_completion(&mut self, timeout: u32) -> Result<(), SpiError> { let mut delay = DummyDelay {}; let mut to = timeout; //wait for_dma done - 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); + #[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()); @@ -649,7 +653,7 @@ impl<'a> FmcController<'a> { /* disable DMA */ self.dma_disable(); - // TODO: set it to normal read again + // 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(()) @@ -711,8 +715,10 @@ 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 @@ -722,10 +728,8 @@ impl<'a> FmcController<'a> { w.dmadirection() .read_flash_move_from_flash_to_external_memory() }); - let mut delay = DummyDelay {}; - delay.delay_ns(1_000_000); - //self.wait_for_dma_completion(SPI_DMA_TIMEOUT) - Ok(()) + + self.wait_for_dma_completion(SPI_DMA_TIMEOUT) } #[allow(dead_code)] @@ -738,6 +742,7 @@ impl<'a> FmcController<'a> { 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)); @@ -774,22 +779,43 @@ 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.dma_irq_enable(); - //self.dbg_fmc_dma(); - let mut delay = DummyDelay {}; - delay.delay_ns(8_000_000); + #[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) + } - delay.delay_ns(8_000_000); - // self.wait_for_dma_completion(SPI_DMA_TIMEOUT) - Ok(()) + 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 + ); } } @@ -797,18 +823,23 @@ 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) }; @@ -819,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(()) } @@ -833,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 303120f..ba06bdc 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -51,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); @@ -109,8 +108,8 @@ const HPLL_FREQ: u32 = 1_000_000_000; //const HCLK_DIV_SEL_MASK: u32 = 0b111 << 28; //const SPI_NOR_MAX_ID_LEN: u32 = 3; -#[allow(dead_code)] -const SPI_DMA_TIMEOUT: u32 = 0x1_0000; + +const SPI_DMA_TIMEOUT: u32 = 0x10000; const SPI_NOR_DATA_DIRECT_READ: u32 = 0x0000_0001; const SPI_NOR_DATA_DIRECT_WRITE: u32 = 0x0000_0002; diff --git a/src/spi/norflash.rs b/src/spi/norflash.rs index f953d0c..c983fdf 100644 --- a/src/spi/norflash.rs +++ b/src/spi/norflash.rs @@ -133,7 +133,6 @@ macro_rules! start_transfer { } $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() { @@ -239,7 +238,6 @@ where data_direct: SPI_NOR_DATA_DIRECT_WRITE, }; start_transfer!(self, &mut nor_data); - self.nor_wait_until_ready(); Ok(()) } @@ -257,7 +255,6 @@ where data_direct: SPI_NOR_DATA_DIRECT_WRITE, }; start_transfer!(self, &mut nor_data); - self.nor_wait_until_ready(); Ok(()) } @@ -274,7 +271,6 @@ where data_direct: SPI_NOR_DATA_DIRECT_READ, }; start_transfer!(self, &mut nor_data); - Ok(()) } @@ -308,7 +304,6 @@ where data_direct: SPI_NOR_DATA_DIRECT_WRITE, }; start_transfer!(self, &mut nor_data); - 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 f21f48d..91512eb 100644 --- a/src/spi/spicontroller.rs +++ b/src/spi/spicontroller.rs @@ -8,7 +8,7 @@ use super::{ ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_DISCARD_REQ_MAGIC, SPI_DMA_ENABLE, SPI_DMA_FLASH_MAP_BASE, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, SPI_DMA_RAM_MAP_BASE, - SPI_DMA_REQUEST, SPI_DMA_STATUS, + SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, }; #[cfg(feature = "spi_dma")] @@ -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. @@ -644,21 +645,23 @@ impl<'a> SpiController<'a> { .write(|w| unsafe { w.bits(SPI_DMA_DISCARD_REQ_MAGIC) }); } - #[allow(dead_code)] 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.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(()) } @@ -666,12 +669,11 @@ impl<'a> SpiController<'a> { // 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()); @@ -756,7 +758,10 @@ 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().modify(|_, w| { @@ -764,17 +769,14 @@ impl<'a> SpiController<'a> { w.dmadirection() .read_flash_move_from_flash_to_external_memory() }); - let mut delay = DummyDelay {}; - delay.delay_ns(1_000_000); - //dbg!(self, "start wait for dma"); - //self.wait_for_dma_completion(SPI_DMA_TIMEOUT) - Ok(()) + + 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 { @@ -819,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.dma_irq_enable(); + #[cfg(feature = "spi_dma_irq")] + { + self.dma_irq_enable(); + } // Start DMA with write direction self.regs.spi080().modify(|_, w| { @@ -828,8 +833,29 @@ impl<'a> SpiController<'a> { .write_flash_move_from_external_memory_to_flash() }); - //self.wait_for_dma_completion(SPI_DMA_TIMEOUT) - Ok(()) + 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 + ); } } @@ -837,18 +863,23 @@ 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) }; @@ -859,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(()) } @@ -878,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 index 48d930f..e3b3feb 100644 --- a/src/spi/spidmairqtest.rs +++ b/src/spi/spidmairqtest.rs @@ -3,7 +3,7 @@ //! spidmairqtest.rs - DMA irq read/write test harness using static buffers and chainable callbacks use super::fmccontroller::FmcController; -use crate::common::{DmaBuffer, DummyDelay}; +use crate::common::{self, DmaBuffer, DummyDelay}; use crate::spi::device::ChipSelectDevice; use crate::spi::norflash::{SpiNorData, SpiNorDevice}; use crate::spi::spicontroller::SpiController; @@ -37,6 +37,7 @@ static mut SPI_DEV0_PTR: *mut ChipSelectDevice<'_, SpiController<'_>, Spipf> = static mut SPI_MONITOR0: Option> = None; +static mut REQUST_ALLDONE: bool = true; // DMA operation type selector #[derive(Debug, Copy, Clone)] pub enum DmaOp { @@ -80,7 +81,11 @@ 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(); @@ -88,6 +93,11 @@ pub extern "C" fn fmc() { 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(); @@ -130,20 +140,22 @@ macro_rules! log_uart { } unsafe fn show_mmap_reg() { - let (_, mmap_addr, _) = spitest::device_info(CURRENT_DEVID); + let (_reg_base, mmap_addr, _cs_capacity) = spitest::device_info(CURRENT_DEVID); let uart = UART_PTR.as_mut().unwrap(); - log_uart!("[{:08x}]", mmap_addr); + unsafe { + log_uart!("[{:08x}]", mmap_addr); + } astdebug::print_reg_u8(uart, mmap_addr, 0x400); } unsafe fn start_next_dma() { - unsafe { - log_uart!("start_next_dma()"); - if DMA_QUEUE.is_empty() { + if DMA_QUEUE.is_empty() { + REQUST_ALLDONE = true; + unsafe { log_uart!("DMA queue is empty. All transfers are completed!!"); - show_mmap_reg(); - return; } + show_mmap_reg(); + return; } if let Some(req) = DMA_QUEUE.pop_front() { @@ -151,7 +163,9 @@ unsafe fn start_next_dma() { match CURRENT_DEVID { DeviceId::FmcCs0Idx | DeviceId::FmcCs1Idx => { if let Err(e) = start_dma_fmc_transfer(CURRENT_DMA.as_mut().unwrap()) { - log_uart!("Failed to start DMA transfer: {:?}", e); + unsafe { + log_uart!("Failed to start DMA transfer: {:?}", e); + } } } DeviceId::Spi0Cs0Idx @@ -159,26 +173,29 @@ unsafe fn start_next_dma() { | DeviceId::Spi1Cs1Idx | DeviceId::Spi0Cs1Idx => { if let Err(e) = start_dma_spi_transfer(CURRENT_DMA.as_mut().unwrap()) { - log_uart!("Failed to start DMA transfer: {:?}", e); + unsafe { + log_uart!("Failed to start DMA transfer: {:?}", e); + } } } } } } -pub fn on_complete_dma(verify: bool, idx: usize, buf: &[u8]) { - unsafe { - log_uart!("on_complete_dma"); - if verify { - if verify_dma_buffer_match(idx) { +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 { + } + } else { + unsafe { log_uart!("DMA test failed!!"); } - } else if let Some(uart) = UART_PTR.as_mut() { - astdebug::print_array_u8(uart, buf); } - } + } //else if let Some(uart) = unsafe { UART_PTR.as_mut() } { + // astdebug::print_array_u8(uart, buf); + //} } // Start DMA transfer using the device @@ -265,22 +282,9 @@ pub fn verify_dma_buffer_match(i: usize) -> bool { return false; } } - - unsafe { - log_uart!("All DMA buffers matched successfully!"); - } true } -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; - } -} - pub fn fill_dma_buffer(op_req: DmaOp, random: bool) { let mut seed = 0xDEAD_FBEE; @@ -296,7 +300,7 @@ pub fn fill_dma_buffer(op_req: DmaOp, random: bool) { buf.fill(0x0); if random { - fill_random(buf, &mut seed); + common::fill_random(buf, &mut seed); } } } @@ -305,11 +309,13 @@ pub fn fill_dma_buffer(op_req: DmaOp, random: bool) { #[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; - log_uart!("irq_chain_test"); for (i, &addr) in start_addrs.iter().enumerate() { if i >= MAX_DMA_CHAIN { - log_uart!("Too many DMA addresses; max is {}", MAX_DMA_CHAIN); + unsafe { + log_uart!("Too many DMA addresses; max is {}", MAX_DMA_CHAIN); + } break; } @@ -328,7 +334,9 @@ pub unsafe fn dma_irq_chain_test(start_addrs: &[u32], op_req: DmaOp, verify: boo on_complete: on_complete_dma, }; DMA_QUEUE.push_back(request).unwrap(); - log_uart!("chaining {}", i); + unsafe { + log_uart!("chaining {}", i); + } } //for start_next_dma(); } @@ -384,6 +392,7 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { 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); @@ -406,7 +415,7 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { //let start_addrs = [0x0000_0000, 0x0000_0100, 0x0000_0200, 0x0000_0300]; //let start_addrs = [0x0000_0100]; - let read_only = true; + let read_only = false; CURRENT_DEVID = DeviceId::FmcCs1Idx; if read_only { fill_dma_buffer(DmaOp::Read, false); @@ -419,6 +428,10 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { // 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 @@ -428,7 +441,9 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { 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); @@ -481,9 +496,26 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { let start_addrs = [0x0000_0000, 0x0000_0100, 0x0000_0200, 0x0000_0300]; //let start_addrs = [0x0000_0100]; CURRENT_DEVID = DeviceId::Spi0Cs0Idx; - fill_dma_buffer(DmaOp::ReadFast, false); - dma_irq_chain_test(&start_addrs, DmaOp::ReadFast, false); + + 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; } static ALLOW_CMDS: [u8; 27] = [ diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index 5c3c364..280b415 100644 --- a/src/spi/spitest.rs +++ b/src/spi/spitest.rs @@ -12,7 +12,7 @@ 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; @@ -258,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 @@ -276,7 +277,7 @@ pub fn test_cs, E>( let _ = dev.nor_read_fast_4b_data(addr, rbuf); } } - delay1.delay_ns(8_000_000); + delay1.delay_ns(2_000_000); if test_write { let result: bool; @@ -325,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, @@ -337,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"); @@ -389,6 +387,7 @@ pub fn test_fmc(uart: &mut UartController<'_>) { TEST_DATA_SIZE, true, ); + test_log!(uart, "################# FMC test done ! ###############"); } @@ -445,6 +444,7 @@ pub fn test_spi(uart: &mut UartController<'_>) { 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); @@ -542,7 +542,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 { @@ -556,9 +556,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}", @@ -584,14 +586,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(8_000_000); + 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) { @@ -614,8 +612,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); } } From 22f573cee1ce30418c913aaf1f4aa750a53ae52e Mon Sep 17 00:00:00 2001 From: hailin wu Date: Thu, 14 Aug 2025 16:27:57 -0700 Subject: [PATCH 04/10] removed spimonitor from spi controller. Add traits for spimonitor for public access --- src/main.rs | 14 +- src/spi/device.rs | 34 ++- src/spi/mod.rs | 15 + src/spi/norflash.rs | 30 +- src/spi/spidmairqtest.rs | 63 +--- src/spi/spitest.rs | 185 ++---------- src/{spimonitor.rs => spimonitor/hardware.rs} | 268 ++++++------------ src/spimonitor/mod.rs | 256 +++++++++++++++++ src/tests/functional/mod.rs | 1 + src/tests/functional/spim_test.rs | 167 +++++++++++ 10 files changed, 598 insertions(+), 435 deletions(-) rename src/{spimonitor.rs => spimonitor/hardware.rs} (86%) create mode 100644 src/spimonitor/mod.rs create mode 100644 src/tests/functional/spim_test.rs diff --git a/src/main.rs b/src/main.rs index 20d47b1..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) @@ -166,7 +167,7 @@ fn main() -> ! { gpio_test::test_gpioa(&mut uart_controller); test_wdt(&mut uart_controller); - let test_spicontroller = true; + let test_spicontroller = false; let test_irq = true; if test_spicontroller { if test_irq { @@ -180,6 +181,15 @@ fn main() -> ! { //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); + 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 db38483..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,11 +53,10 @@ 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); } } Ok(()) diff --git a/src/spi/mod.rs b/src/spi/mod.rs index ba06bdc..df6ce1e 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -395,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 c983fdf..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,32 +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)?; //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; @@ -325,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/spidmairqtest.rs b/src/spi/spidmairqtest.rs index e3b3feb..3a0a9f6 100644 --- a/src/spi/spidmairqtest.rs +++ b/src/spi/spidmairqtest.rs @@ -9,10 +9,9 @@ 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::{RegionInfo, SpiMonitor, SpimExtMuxSel}; +use crate::spimonitor::SpiMonitorNum; use crate::uart::UartController; use crate::{astdebug, pinctrl}; -use ast1060_pac::Spipf; use core::ptr; use cortex_m::peripheral::NVIC; use embedded_hal::delay::DelayNs; @@ -24,18 +23,13 @@ static mut FMC_CONTROLLER: Option> = None; static mut SPI_CONTROLLER: Option> = None; //static mut SPI1_CONTROLLER: Option> = None; -static mut FMC_DEVICE0: Option, Spipf>> = None; -static mut FMC_DEV0_PTR: *mut ChipSelectDevice<'_, FmcController<'_>, Spipf> = - core::ptr::null_mut(); -static mut FMC_DEVICE1: Option, Spipf>> = None; -static mut FMC_DEV1_PTR: *mut ChipSelectDevice<'_, FmcController<'_>, Spipf> = - core::ptr::null_mut(); +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, Spipf>> = None; -static mut SPI_DEV0_PTR: *mut ChipSelectDevice<'_, SpiController<'_>, Spipf> = - core::ptr::null_mut(); - -static mut SPI_MONITOR0: Option> = None; +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 @@ -377,7 +371,7 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { let flash_device0 = ChipSelectDevice { bus: controller, cs: 0, - spi_monitor: None, + spim: None, }; FMC_DEVICE0 = Some(flash_device0); @@ -402,7 +396,7 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { let flash_device1 = ChipSelectDevice { bus: controller1, // reuse same ref cs: 1, - spi_monitor: None, + spim: None, }; FMC_DEVICE1 = Some(flash_device1); @@ -477,12 +471,11 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { 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 spi_monitor0 = start_static_spim0(); let flash_device0 = ChipSelectDevice { bus: controller, cs: 0, - spi_monitor: Some(spi_monitor0), + spim: Some(SpiMonitorNum::SPIM0), }; SPI_DEVICE0 = Some(flash_device0); @@ -517,39 +510,3 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { scu_qspi_mux[0] = 0x0000_0000; } - -static 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, -]; - -static READ_BLOCKED_REGIONS: [RegionInfo; 1] = [RegionInfo { - start: 0x0400_0000, - length: 0x0002_0000, -}]; - -static WRITE_BLOCKED_REGIONS: [RegionInfo; 1] = [RegionInfo { - start: 0x0000_0000, - length: 0x0800_0000, -}]; - -pub fn start_static_spim0() -> &'static mut SpiMonitor { - unsafe { - SPI_MONITOR0 = Some(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(), - )); - - let monitor = SPI_MONITOR0.as_mut().unwrap(); - monitor.spim_sw_rst(); - monitor.aspeed_spi_monitor_init(); - - monitor - } -} diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index 280b415..5554cc8 100644 --- a/src/spi/spitest.rs +++ b/src/spi/spitest.rs @@ -16,11 +16,11 @@ 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; @@ -350,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); @@ -362,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); @@ -434,12 +434,11 @@ 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); @@ -642,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; @@ -672,17 +673,15 @@ pub fn test_spi2(uart: &mut UartController<'_>) { 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); - 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), - }; - - 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 { @@ -726,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); @@ -759,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); +} From f3f7cc6b49bfed43c18327546677eb7c17479259 Mon Sep 17 00:00:00 2001 From: hailin wu Date: Wed, 11 Feb 2026 15:54:26 -0800 Subject: [PATCH 05/10] 1. divided spi/mod.rs into different files. 2. make sure GPIO_ORI_VA is safe with mutex 3. updated transfer_in_place() and flush() to return error code to avoid unexpected panic --- Cargo.lock | 8 + Cargo.toml | 4 +- src/main.rs | 12 +- src/spi/consts.rs | 59 +++++ src/spi/error.rs | 33 +++ src/spi/fmccontroller.rs | 48 ++-- src/spi/mod.rs | 520 ++------------------------------------- src/spi/norflash.rs | 3 +- src/spi/spicontroller.rs | 49 ++-- src/spi/spidmairqtest.rs | 21 +- src/spi/spim.rs | 141 +++++++++++ src/spi/spitest.rs | 7 +- src/spi/traits.rs | 17 ++ src/spi/types.rs | 88 +++++++ src/spi/util.rs | 220 +++++++++++++++++ 15 files changed, 657 insertions(+), 573 deletions(-) create mode 100644 src/spi/consts.rs create mode 100644 src/spi/error.rs create mode 100644 src/spi/spim.rs create mode 100644 src/spi/traits.rs create mode 100644 src/spi/types.rs create mode 100644 src/spi/util.rs diff --git a/Cargo.lock b/Cargo.lock index 1623fe3..b6281fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,6 +65,7 @@ dependencies = [ "ast1060-pac", "cortex-m", "cortex-m-rt", + "critical-section", "embedded-hal 1.0.0", "embedded-hal 1.0.0-alpha.1", "embedded-io", @@ -172,6 +173,7 @@ checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" dependencies = [ "bare-metal", "bitfield", + "critical-section", "embedded-hal 0.2.7", "volatile-register", ] @@ -197,6 +199,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "embedded-hal" version = "0.2.7" diff --git a/Cargo.toml b/Cargo.toml index 9d1a57e..049a88c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,8 +36,8 @@ proposed-traits = { git = "https://github.com/rusty1968/proposed_traits.git", pa hex-literal = "0.4" heapless = "0.8.0" paste = "1.0" - -cortex-m = { version = "0.7.5" } +critical-section = "1.2" +cortex-m = { version = "0.7.5", features = ["critical-section-single-core"] } cortex-m-rt = { version = "0.6.5", features = ["device"] } panic-halt = "1.0.0" diff --git a/src/main.rs b/src/main.rs index c70aaab..5750c69 100644 --- a/src/main.rs +++ b/src/main.rs @@ -160,14 +160,14 @@ fn main() -> ! { let _ = syscon.enable_clock(ClockId::ClkRSACLK as u8); let mut ecdsa = AspeedEcdsa::new(&secure, delay.clone()); - run_ecdsa_tests(&mut uart_controller, &mut ecdsa); + // run_ecdsa_tests(&mut uart_controller, &mut ecdsa); - let mut rsa = AspeedRsa::new(&secure, delay); - run_rsa_tests(&mut uart_controller, &mut rsa); - gpio_test::test_gpioa(&mut uart_controller); - test_wdt(&mut uart_controller); + //let mut rsa = AspeedRsa::new(&secure, delay); + //run_rsa_tests(&mut uart_controller, &mut rsa); + //gpio_test::test_gpioa(&mut uart_controller); + //test_wdt(&mut uart_controller); - let test_spicontroller = false; + let test_spicontroller = true; let test_irq = true; if test_spicontroller { if test_irq { diff --git a/src/spi/consts.rs b/src/spi/consts.rs new file mode 100644 index 0000000..3617275 --- /dev/null +++ b/src/spi/consts.rs @@ -0,0 +1,59 @@ +// Licensed under the Apache-2.0 license + +// Constants (unchanged) +pub(crate) const SPI_CONF_CE0_ENABLE_WRITE_SHIFT: u32 = 16; + +pub(crate) const SPI_CTRL_FREQ_MASK: u32 = 0x0F00_0F00; +pub(crate) const SPI_CTRL_CEX_SPI_CMD_SHIFT: u32 = 16; +pub(crate) const SPI_CTRL_CEX_SPI_CMD_MASK: u32 = 0xff; +pub(crate) const SPI_CTRL_CEX_DUMMY_SHIFT: u32 = 6; +pub(crate) const SPI_CTRL_CEX_4BYTE_MODE_SET: u32 = 0x11; // bit0: 4byte mode, bit4: 4byte mode cmd + +pub(crate) const SPI_DMA_DELAY_SHIFT: u32 = 8; +pub(crate) const SPI_DMA_DELAY_MASK: u32 = 0xff; +pub(crate) const SPI_DMA_CLK_FREQ_SHIFT: u32 = 16; +pub(crate) const SPI_DMA_CLK_FREQ_MASK: u32 = 0xf; + +pub(crate) const SPI_DMA_GET_REQ_MAGIC: u32 = 0xaeed_0000; +pub(crate) const SPI_DMA_DISCARD_REQ_MAGIC: u32 = 0xdeea_0000; +pub(crate) const SPI_DMA_RAM_MAP_BASE: u32 = 0x8000_0000; +pub(crate) const SPI_DMA_FLASH_MAP_BASE: u32 = 0x6000_0000; + +pub(crate) const SPI_CALIB_LEN: usize = 0x400; + +#[cfg(feature = "spi_dma")] +pub(crate) const SPI_DMA_TRIGGER_LEN: u32 = 128; + +#[cfg(feature = "spi_dma")] +pub(crate) const SPI_DMA_WRITE: u32 = 1 << 1; + +pub(crate) const SPI_DMA_REQUEST: u32 = 1 << 31; +pub(crate) const SPI_DMA_GRANT: u32 = 1 << 30; +pub(crate) const SPI_DMA_CALIB_MODE: u32 = 1 << 3; +pub(crate) const SPI_DMA_CALC_CKSUM: u32 = 1 << 2; + +pub(crate) const SPI_DMA_ENABLE: u32 = 1 << 0; +pub(crate) const SPI_DMA_STATUS: u32 = 1 << 11; + +pub(crate) const ASPEED_MAX_CS: usize = 5; // Must be usize for array indexing + +pub(crate) const ASPEED_SPI_NORMAL_READ: u32 = 0x1; +pub(crate) const ASPEED_SPI_NORMAL_WRITE: u32 = 0x2; +pub(crate) const ASPEED_SPI_USER: u32 = 0x3; +pub(crate) const ASPEED_SPI_USER_INACTIVE: u32 = 0x4; + +pub(crate) const ASPEED_SPI_SZ_2M: u32 = 0x0020_0000; +pub(crate) const ASPEED_SPI_SZ_256M: u32 = 0x1000_0000; + +pub(crate) const HPLL_FREQ: u32 = 1_000_000_000; + +pub(crate) const SPI_DMA_TIMEOUT: u32 = 0x10000; + +// SPIM clock output pin bits +pub(crate) const PIN_SPIM0_CLK_OUT_BIT: u32 = 7; +pub(crate) const PIN_SPIM1_CLK_OUT_BIT: u32 = 21; +pub(crate) const PIN_SPIM2_CLK_OUT_BIT: u32 = 3; +pub(crate) const PIN_SPIM3_CLK_OUT_BIT: u32 = 17; + +pub const SPI_NOR_DATA_DIRECT_READ: u32 = 0x0000_0001; +pub const SPI_NOR_DATA_DIRECT_WRITE: u32 = 0x0000_0002; diff --git a/src/spi/error.rs b/src/spi/error.rs new file mode 100644 index 0000000..6fcd761 --- /dev/null +++ b/src/spi/error.rs @@ -0,0 +1,33 @@ +// Licensed under the Apache-2.0 license + +use embedded_hal::spi; + +#[derive(Debug)] +pub enum SpiError { + BusError, + DmaTimeout, + CsSelectFailed(usize), + LengthMismatch, + CapacityOutOfRange, + UnsupportedDevice(u8), + AddressNotAligned(u32), + InvalidCommand(u8), + Other(&'static str), +} + +/// Required by embedded-hal 1.0 +impl spi::Error for SpiError { + fn kind(&self) -> spi::ErrorKind { + match self { + SpiError::BusError + | SpiError::DmaTimeout + | SpiError::CsSelectFailed(_) + | SpiError::LengthMismatch + | SpiError::CapacityOutOfRange + | SpiError::UnsupportedDevice(_) + | SpiError::InvalidCommand(_) + | SpiError::AddressNotAligned(_) + | SpiError::Other(_) => spi::ErrorKind::Other, + } + } +} diff --git a/src/spi/fmccontroller.rs b/src/spi/fmccontroller.rs index cdc2657..de7cd83 100644 --- a/src/spi/fmccontroller.rs +++ b/src/spi/fmccontroller.rs @@ -3,23 +3,25 @@ use super::{ aspeed_get_spi_freq_div, get_addr_buswidth, get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, spi_io_mode, spi_io_mode_user, spi_read_data, - spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, Write, ASPEED_MAX_CS, - ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, ASPEED_SPI_SZ_2M, - ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, SPI_CTRL_FREQ_MASK, - SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_DISCARD_REQ_MAGIC, SPI_DMA_ENABLE, - SPI_DMA_FLASH_MAP_BASE, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, SPI_DMA_RAM_MAP_BASE, - SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, + spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, get_cmd_buswidth, + get_data_buswidth }; +use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, + ASPEED_SPI_SZ_2M, ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, + SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_DISCARD_REQ_MAGIC, + SPI_DMA_ENABLE, SPI_DMA_FLASH_MAP_BASE, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, + SPI_DMA_RAM_MAP_BASE, SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, + SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, SPI_CTRL_CEX_SPI_CMD_MASK, + SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_CLK_FREQ_MASK, SPI_DMA_DELAY_MASK, + SPI_DMA_DELAY_SHIFT, SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; + +use embedded_io::Write; #[cfg(feature = "spi_dma")] -use super::{SPI_DMA_TRIGGER_LEN, SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; +use super::consts::{SPI_DMA_TRIGGER_LEN}; use crate::dbg; -use crate::spi::{ - SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, - SPI_CTRL_CEX_SPI_CMD_MASK, SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_MASK, - SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, SPI_DMA_DELAY_SHIFT, -}; + use crate::{common::DummyDelay, spi::norflash::SpiNorData, uart::UartController}; use embedded_hal::{ delay::DelayNs, @@ -494,14 +496,14 @@ impl<'a> FmcController<'a> { 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))); + | spi_io_mode_user(u32::from(get_cmd_buswidth(op_info.mode as u32))); cs_ctrlreg_w!(self, cs, cmd_mode); dbg!(self, "write opcode/cmd: 0x{:08x}", op_info.opcode); - unsafe { super::spi_write_data(start_ptr, &[op_info.opcode.try_into().unwrap()]) }; + unsafe { spi_write_data(start_ptr, &[op_info.opcode.try_into().unwrap()]) }; // Send address let addr_mode = self.spi_data.cmd_mode[cs].user - | super::spi_io_mode_user(u32::from(super::get_addr_buswidth(op_info.mode as u32))); + | spi_io_mode_user(u32::from(get_addr_buswidth(op_info.mode as u32))); cs_ctrlreg_w!(self, cs, addr_mode); let mut addr = op_info.addr; @@ -510,22 +512,22 @@ impl<'a> FmcController<'a> { } let addr_bytes = addr.to_be_bytes(); - unsafe { super::spi_write_data(start_ptr, &addr_bytes[..op_info.addr_len as usize]) }; + unsafe { spi_write_data(start_ptr, &addr_bytes[..op_info.addr_len as usize]) }; // Dummy cycles - let bus_width: u8 = super::get_addr_buswidth(op_info.mode as u32); + let bus_width: u8 = get_addr_buswidth(op_info.mode as u32); let dummy_len: u8 = (op_info.dummy_cycle / (8 / u32::from(bus_width))) .try_into() .unwrap(); dbg!(self, "write dummy len: 0x{:08x}", dummy_len); - unsafe { super::spi_write_data(start_ptr, &dummy[..dummy_len as usize]) }; + unsafe { spi_write_data(start_ptr, &dummy[..dummy_len as usize]) }; // Data transfer let data_mode = self.spi_data.cmd_mode[cs].user - | spi_io_mode_user(u32::from(super::get_data_buswidth(op_info.mode as u32))); + | spi_io_mode_user(u32::from(get_data_buswidth(op_info.mode as u32))); cs_ctrlreg_w!(self, cs, data_mode); - if op_info.data_direct == super::SPI_NOR_DATA_DIRECT_READ { + if op_info.data_direct == SPI_NOR_DATA_DIRECT_READ { unsafe { spi_read_data(start_ptr, op_info.rx_buf) }; } else { unsafe { spi_write_data(start_ptr, op_info.tx_buf) }; @@ -848,18 +850,18 @@ impl<'a> SpiBus for FmcController<'a> { if !rd_buffer.is_empty() { let ahb_addr = self.spi_data.decode_addr[cs].start as usize as *const u32; // Read RX buffer - unsafe { super::spi_read_data(ahb_addr, rd_buffer) }; + unsafe { spi_read_data(ahb_addr, rd_buffer) }; } self.deactivate_user(); Ok(()) } fn transfer_in_place(&mut self, _buffer: &mut [u8]) -> Result<(), SpiError> { - todo!() + Err(SpiError::Other("transfer_in_place not supported")) } fn flush(&mut self) -> Result<(), SpiError> { - todo!() + Err(SpiError::Other("flush not supported")) } } diff --git a/src/spi/mod.rs b/src/spi/mod.rs index df6ce1e..f828790 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -1,14 +1,6 @@ // Licensed under the Apache-2.0 license -use crate::{ - modify_reg, - spi::norflash::{Jesd216Mode, SpiNorData}, -}; -use ast1060_pac::Scu; -use embedded_hal::spi; -use embedded_hal::spi::ErrorType; -use embedded_hal::spi::SpiBus; -use embedded_io::Write; +//! Aspeed SPI HAL module pub mod device; pub mod fmccontroller; @@ -18,502 +10,22 @@ pub mod spicontroller; pub mod spidmairqtest; pub mod spitest; -#[derive(Debug)] +pub(crate) mod consts; -pub enum SpiError { - BusError, - DmaTimeout, - CsSelectFailed(usize), - LengthMismatch, - CapacityOutOfRange, - UnsupportedDevice(u8), - AddressNotAligned(u32), - InvalidCommand(u8), - Other(&'static str), -} +pub mod util; +pub mod error; +pub mod traits; +pub mod types; -/// Required by embedded-hal 1.0 -impl spi::Error for SpiError { - fn kind(&self) -> spi::ErrorKind { - match self { - SpiError::BusError - | SpiError::DmaTimeout - | SpiError::CsSelectFailed(_) - | SpiError::LengthMismatch - | SpiError::CapacityOutOfRange - | SpiError::UnsupportedDevice(_) - | SpiError::InvalidCommand(_) - | SpiError::AddressNotAligned(_) - | SpiError::Other(_) => spi::ErrorKind::Other, - } - } -} +pub mod spim; -pub trait SpiBusWithCs: SpiBus + ErrorType { - fn select_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); +pub use error::SpiError; +pub use traits::SpiBusWithCs; +pub use types::{CommandMode, CtrlType, DataDirection, SpiConfig, SpiDecodeAddress, SpiData, + FlashAddress, AddressWidth}; +pub use norflash::{Jesd216Mode, SpiNorData, SpiNorDevice}; - fn get_device_info(&mut self, cs: usize) -> (u32, u32); - fn get_master_id(&mut self) -> u32; -} - -// Constants (unchanged) -const SPI_CONF_CE0_ENABLE_WRITE_SHIFT: u32 = 16; - -const SPI_CTRL_FREQ_MASK: u32 = 0x0F00_0F00; -const SPI_CTRL_CEX_SPI_CMD_SHIFT: u32 = 16; -const SPI_CTRL_CEX_SPI_CMD_MASK: u32 = 0xff; -const SPI_CTRL_CEX_DUMMY_SHIFT: u32 = 6; -const SPI_CTRL_CEX_4BYTE_MODE_SET: u32 = 0x11; // bit0: 4byte mode, bit4: 4byte mode cmd - -const SPI_DMA_DELAY_SHIFT: u32 = 8; -const SPI_DMA_DELAY_MASK: u32 = 0xff; -const SPI_DMA_CLK_FREQ_SHIFT: u32 = 16; -const SPI_DMA_CLK_FREQ_MASK: u32 = 0xf; - -const SPI_DMA_GET_REQ_MAGIC: u32 = 0xaeed_0000; -const SPI_DMA_DISCARD_REQ_MAGIC: u32 = 0xdeea_0000; -const SPI_DMA_RAM_MAP_BASE: u32 = 0x8000_0000; -const SPI_DMA_FLASH_MAP_BASE: u32 = 0x6000_0000; - -const SPI_CALIB_LEN: usize = 0x400; - -#[cfg(feature = "spi_dma")] -const SPI_DMA_TRIGGER_LEN: u32 = 128; -//const SPI_DMA_IRQ_EN: u32 = 1 << 3; -#[cfg(feature = "spi_dma")] -const SPI_DMA_WRITE: u32 = 1 << 1; - -const SPI_DMA_REQUEST: u32 = 1 << 31; -const SPI_DMA_GRANT: u32 = 1 << 30; -const SPI_DMA_CALIB_MODE: u32 = 1 << 3; -const SPI_DMA_CALC_CKSUM: u32 = 1 << 2; - -const SPI_DMA_ENABLE: u32 = 1 << 0; -const SPI_DMA_STATUS: u32 = 1 << 11; - -const ASPEED_MAX_CS: usize = 5; // Must be usize for array indexing - -const ASPEED_SPI_NORMAL_READ: u32 = 0x1; -const ASPEED_SPI_NORMAL_WRITE: u32 = 0x2; -const ASPEED_SPI_USER: u32 = 0x3; -const ASPEED_SPI_USER_INACTIVE: u32 = 0x4; - -const ASPEED_SPI_SZ_2M: u32 = 0x0020_0000; -const ASPEED_SPI_SZ_256M: u32 = 0x1000_0000; - -const HPLL_FREQ: u32 = 1_000_000_000; -//const HCLK_DIV_SEL_MASK: u32 = 0b111 << 28; - -//const SPI_NOR_MAX_ID_LEN: u32 = 3; - -const SPI_DMA_TIMEOUT: u32 = 0x10000; -const SPI_NOR_DATA_DIRECT_READ: u32 = 0x0000_0001; -const SPI_NOR_DATA_DIRECT_WRITE: u32 = 0x0000_0002; - -#[derive(Clone, Copy)] -pub enum CtrlType { - BootSpi, - HostSpi, - NormalSpi, -} - -#[derive(Clone, Copy)] -pub struct CommandMode { - pub normal_read: u32, - pub normal_write: u32, - pub user: u32, -} - -#[derive(Default, Clone, Copy)] -pub struct SpiDecodeAddress { - pub start: u32, - pub len: u32, -} - -//Static spi controller configuration information -pub struct SpiConfig { - pub mmap_base: u32, - pub max_cs: usize, - pub write_block_size: u32, - pub ctrl_type: CtrlType, - pub timing_cali_start_off: u32, - pub master_idx: u32, - pub pure_spi_mode_only: bool, - pub frequency: u32, - pub timing_calibration_start_off: u32, - pub timing_calibration_disabled: bool, -} - -// Struct holding segment behavior as trait object -// controller state structure -pub struct SpiData { - pub decode_addr: [SpiDecodeAddress; ASPEED_MAX_CS], - pub cmd_mode: [CommandMode; ASPEED_MAX_CS], - pub hclk: u32, - pub spim_proprietary_pre_config: u32, -} - -impl Default for SpiData { - fn default() -> Self { - Self::new() - } -} - -impl SpiData { - #[must_use] - pub const fn new() -> Self { - const ZERO_ADDR: SpiDecodeAddress = SpiDecodeAddress { start: 0, len: 0 }; - const ZERO_CMD: CommandMode = CommandMode { - normal_read: 0, - normal_write: 0, - user: 0, - }; - - Self { - decode_addr: [ZERO_ADDR; ASPEED_MAX_CS], - cmd_mode: [ZERO_CMD; ASPEED_MAX_CS], - hclk: 0, - spim_proprietary_pre_config: 0, - } - } -} - -#[macro_export] -macro_rules! dbg { - ($self:expr, $($arg:tt)*) => {{ - if let Some(ref mut uart) = $self.dbg_uart { - writeln!(uart, $($arg)*).unwrap(); - write!(uart, "\r").unwrap(); - } - }}; -} - -#[inline] -fn hclk_div_reg_to_val(x: u32) -> u32 { - if x == 0 { - 2 - } else { - x + 1 - } -} - -#[must_use] -pub fn get_hclock_rate() -> u32 { - let scu_reg = unsafe { &*Scu::ptr() }; - let raw_div = scu_reg.scu314().read().hclkdivider_sel().bits(); - let clk_div = hclk_div_reg_to_val(u32::from(raw_div)); - - HPLL_FREQ / clk_div -} - -#[must_use] -pub fn spi_io_mode(mode: Jesd216Mode) -> u32 { - match mode { - //Jesd216Mode::Mode111 | Jesd216Mode::Mode111Fast => 0x0000_0000, - Jesd216Mode::Mode112 => 0x2000_0000, - Jesd216Mode::Mode122 => 0x3000_0000, - Jesd216Mode::Mode114 => 0x4000_0000, - Jesd216Mode::Mode144 => 0x5000_0000, - _ => 0, - } -} -#[must_use] -pub fn spi_io_mode_user(bus_width: u32) -> u32 { - match bus_width { - 4 => 0x4000_0000, - 2 => 0x2000_0000, - _ => 0x0000_0000, - } -} -#[must_use] -pub fn spi_cal_dummy_cycle(bus_width: u32, dummy_cycle: u32) -> u32 { - let dummy_byte = dummy_cycle / (8 / bus_width); - ((dummy_byte & 0x3) << 6) | (((dummy_byte & 0x4) >> 2) << 14) -} - -const fn get_cmd_buswidth(v: u32) -> u8 { - ((v & 0x0000_0F00) >> 8) as u8 -} -const fn get_addr_buswidth(v: u32) -> u8 { - ((v & 0x0000_00F0) >> 4) as u8 -} -const fn get_data_buswidth(v: u32) -> u8 { - (v & 0x0000_000F) as u8 -} - -/// Calculate the SPI frequency division setting based on bus clock and max frequency. -/// -/// # Arguments -/// * `bus_clk` - The bus clock frequency in Hz. -/// * `max_freq` - The maximum desired SPI frequency in Hz. -/// -/// # Returns -/// A 32-bit value encoding the frequency divider, -/// or 0 if no valid divider found. - -#[must_use] -pub fn aspeed_get_spi_freq_div(bus_clk: u32, max_freq: u32) -> u32 { - // Division mapping array matching C div_arr - let div_arr = [15, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0]; - - for i in 0..0x0f { - for (j, div_val) in div_arr.iter().copied().enumerate() { - if i == 0 && j == 0 { - continue; - } - let divisor = j + 1 + (i * 16); - let freq = bus_clk / u32::try_from(divisor).unwrap(); - - if max_freq >= freq { - #[allow(clippy::cast_sign_loss)] - return ((i << 24) | ((div_val as u32) << 8) as usize) - .try_into() - .unwrap(); - } - } - } - // If not found, log error and return 0 (adjust logging as needed) - //log eprintln!("aspeed_get_spi_freq_div: cannot get correct frequency division."); - 0 -} - -/// Finds the midpoint of the longest consecutive sequence of 1's in a buffer. -/// -/// Returns the midpoint index if the longest run is at least length 4, -/// otherwise returns -1. -/// -/// # Arguments -/// * `buf` - slice of bytes (each should be 0 or 1). -#[must_use] -pub fn get_mid_point_of_longest_one(buf: &[u8]) -> i32 { - let mut start = 0; - let mut mid_point = 0; - let mut max_cnt = 0; - let mut cnt = 0; - - for (i, &val) in buf.iter().enumerate() { - if val == 1 { - cnt += 1; - } else { - cnt = 0; - start = i; - } - - if cnt > max_cnt { - max_cnt = cnt; - mid_point = start + (cnt / 2); - } - } - - if max_cnt < 4 { - -1 - } else { - i32::try_from(mid_point).unwrap() - } -} - -#[must_use] -pub fn spi_calibration_enable(buf: &[u8]) -> bool { - if buf.len() < 4 { - return false; - } - - let mut valid_count = 0; - - // Process 4 bytes at a time - for chunk in buf.chunks_exact(4) { - // Convert 4 bytes to u32 in little-endian order - let word = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]); - - if word != 0 && word != 0xFFFF_FFFF { - valid_count += 1; - } - if valid_count > 100 { - return true; - } - } - - false -} - -#[allow(clippy::missing_safety_doc)] -pub unsafe fn spi_read_data(ahb_addr: *const u32, read_arr: &mut [u8]) { - let len = read_arr.len(); - let mut i = 0; - - // Read full u32 words - while i + 4 <= len { - let word = core::ptr::read_volatile(ahb_addr.add(i / 4)); - read_arr[i..i + 4].copy_from_slice(&word.to_le_bytes()); // adjust for BE if needed - i += 4; - } - - // Remaining bytes - while i < len { - read_arr[i] = core::ptr::read_volatile((ahb_addr.cast::()).add(i)); - i += 1; - } -} - -#[allow(clippy::missing_safety_doc)] -pub unsafe fn spi_write_data(ahb_addr: *mut u32, write_arr: &[u8]) { - if write_arr.is_empty() { - return; - } - - let len = write_arr.len(); - let mut i = 0; - - // Write in u32 words as long as possible - while i + 4 <= len { - let word = u32::from_le_bytes([ - write_arr[i], - write_arr[i + 1], - write_arr[i + 2], - write_arr[i + 3], - ]); - core::ptr::write_volatile(ahb_addr.add(i / 4), word); - i += 4; - } - - // Write remaining bytes (if any) - let ahb_addr_u8 = ahb_addr.cast::(); - while i < len { - core::ptr::write_volatile(ahb_addr_u8.add(i), write_arr[i]); - i += 1; - } -} -pub static mut GPIO_ORI_VAL: [u32; 4] = [0; 4]; -fn get_gpio_ori_val() -> [u32; 4] { - unsafe { GPIO_ORI_VAL } -} -const PIN_SPIM0_CLK_OUT_BIT: u32 = 7; -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() }; - - // If no SPIM in use, return - #[allow(clippy::verbose_bit_mask)] - if scu.scu0f0().read().bits() & 0x7 == 0 { - return; - } - - let spim_idx = (scu.scu0f0().read().bits() & 0x7) - 1; - if spim_idx > 3 { - return; - } - let clear = true; - for (idx, ori_val) in get_gpio_ori_val().iter_mut().enumerate() { - if u32::try_from(idx).unwrap() == spim_idx { - continue; - } - - match idx { - 0 => { - modify_reg!(scu.scu690(), PIN_SPIM0_CLK_OUT_BIT, clear); - *ori_val = gpio.gpio004().read().bits(); - modify_reg!(gpio.gpio004(), PIN_SPIM0_CLK_OUT_BIT, clear); - } - 1 => { - modify_reg!(scu.scu690(), PIN_SPIM1_CLK_OUT_BIT, clear); - *ori_val = gpio.gpio004().read().bits(); - modify_reg!(gpio.gpio004(), PIN_SPIM1_CLK_OUT_BIT, clear); - } - 2 => { - modify_reg!(scu.scu694(), PIN_SPIM2_CLK_OUT_BIT, clear); - *ori_val = gpio.gpio024().read().bits(); - modify_reg!(gpio.gpio024(), PIN_SPIM2_CLK_OUT_BIT, clear); - } - 3 => { - modify_reg!(scu.scu694(), PIN_SPIM3_CLK_OUT_BIT, clear); - *ori_val = gpio.gpio024().read().bits(); - modify_reg!(gpio.gpio024(), PIN_SPIM3_CLK_OUT_BIT, clear); - } - _ => (), - } - } -} - -pub fn spim_proprietary_post_config() { - let scu = unsafe { &*ast1060_pac::Scu::ptr() }; - let gpio = unsafe { &*ast1060_pac::Gpio::ptr() }; - - // If no SPIM in use, return - let bits = scu.scu0f0().read().bits(); - if bits.trailing_zeros() >= 3 { - return; - } - - let spim_idx = (scu.scu0f0().read().bits() & 0x7) - 1; - if spim_idx > 3 { - return; - } - let clear = false; - for (idx, ori_val) in get_gpio_ori_val().iter().copied().enumerate() { - if u32::try_from(idx).unwrap() == spim_idx { - continue; - } - - match idx { - 0 => { - gpio.gpio004().modify(|r, w| unsafe { - let mut current = r.bits(); - current &= !(1 << PIN_SPIM0_CLK_OUT_BIT); - current |= ori_val; - w.bits(current) - }); - modify_reg!(scu.scu690(), PIN_SPIM0_CLK_OUT_BIT, clear); - } - 1 => { - gpio.gpio004().modify(|r, w| unsafe { - let mut current = r.bits(); - current &= !(1 << PIN_SPIM1_CLK_OUT_BIT); - current |= ori_val; - w.bits(current) - }); - modify_reg!(gpio.gpio004(), PIN_SPIM1_CLK_OUT_BIT, clear); - } - 2 => { - gpio.gpio024().modify(|r, w| unsafe { - let mut current = r.bits(); - current &= !(1 << PIN_SPIM2_CLK_OUT_BIT); - current |= ori_val; - w.bits(current) - }); - modify_reg!(scu.scu694(), PIN_SPIM2_CLK_OUT_BIT, clear); - } - 3 => { - gpio.gpio024().modify(|r, w| unsafe { - let mut current = r.bits(); - current &= !(1 << PIN_SPIM3_CLK_OUT_BIT); - current |= ori_val; - w.bits(current) - }); - modify_reg!(scu.scu694(), PIN_SPIM3_CLK_OUT_BIT, clear); - } - _ => (), - } - } -} +pub use util::{spi_read_data, spi_write_data, aspeed_get_spi_freq_div, get_mid_point_of_longest_one, + spi_cal_dummy_cycle, spi_calibration_enable, get_hclock_rate, spi_io_mode, spi_io_mode_user, + get_addr_buswidth, get_cmd_buswidth, get_data_buswidth}; +pub use spim::{spim_proprietary_post_config, spim_proprietary_pre_config, spim_scu_ctrl_clear, spim_scu_ctrl_set}; diff --git a/src/spi/norflash.rs b/src/spi/norflash.rs index 2f991b5..9b1e904 100644 --- a/src/spi/norflash.rs +++ b/src/spi/norflash.rs @@ -2,7 +2,8 @@ use super::device::ChipSelectDevice; use super::SpiBusWithCs; -use super::{norflash, SpiError, SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; +use super::{norflash, SpiError}; +use super::consts::{SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; use crate::common::DummyDelay; use embedded_hal::delay::DelayNs; diff --git a/src/spi/spicontroller.rs b/src/spi/spicontroller.rs index 91512eb..43d7265 100644 --- a/src/spi/spicontroller.rs +++ b/src/spi/spicontroller.rs @@ -3,23 +3,26 @@ use super::{ aspeed_get_spi_freq_div, get_addr_buswidth, get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, spi_io_mode, spi_io_mode_user, spi_read_data, - spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, Write, ASPEED_MAX_CS, - ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, ASPEED_SPI_SZ_2M, - ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, SPI_CTRL_FREQ_MASK, - SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_DISCARD_REQ_MAGIC, SPI_DMA_ENABLE, - SPI_DMA_FLASH_MAP_BASE, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, SPI_DMA_RAM_MAP_BASE, - SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, + spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, get_cmd_buswidth, + get_data_buswidth }; +use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, + ASPEED_SPI_SZ_2M, ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, + SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_DISCARD_REQ_MAGIC, + SPI_DMA_ENABLE, SPI_DMA_FLASH_MAP_BASE, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, + SPI_DMA_RAM_MAP_BASE, SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, + SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, SPI_CTRL_CEX_SPI_CMD_MASK, + SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_CLK_FREQ_MASK, SPI_DMA_DELAY_MASK, + SPI_DMA_DELAY_SHIFT, SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; + +use embedded_io::Write; + #[cfg(feature = "spi_dma")] -use super::{SPI_DMA_TRIGGER_LEN, SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; +use super::consts::{SPI_DMA_TRIGGER_LEN}; use crate::dbg; -use crate::spi::{ - SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, - SPI_CTRL_CEX_SPI_CMD_MASK, SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_MASK, - SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, SPI_DMA_DELAY_SHIFT, -}; + use crate::{common::DummyDelay, spi::norflash::SpiNorData, uart::UartController}; use embedded_hal::{ @@ -523,14 +526,14 @@ impl<'a> SpiController<'a> { 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))); + | spi_io_mode_user(u32::from(get_cmd_buswidth(op_info.mode as u32))); cs_ctrlreg_w!(self, cs, cmd_mode); dbg!(self, "write opcode/cmd: 0x{:08x}", op_info.opcode); - unsafe { super::spi_write_data(start_ptr, &[op_info.opcode.try_into().unwrap()]) }; + unsafe { spi_write_data(start_ptr, &[op_info.opcode.try_into().unwrap()]) }; // Send address let addr_mode = self.spi_data.cmd_mode[cs].user - | super::spi_io_mode_user(u32::from(super::get_addr_buswidth(op_info.mode as u32))); + | spi_io_mode_user(u32::from(get_addr_buswidth(op_info.mode as u32))); cs_ctrlreg_w!(self, cs, addr_mode); let mut addr = op_info.addr; @@ -539,22 +542,22 @@ impl<'a> SpiController<'a> { } //op_info.addr = sys_cpu_to_be32(op_info.addr); let addr_bytes = addr.to_be_bytes(); - unsafe { super::spi_write_data(start_ptr, &addr_bytes[..op_info.addr_len as usize]) }; + unsafe { spi_write_data(start_ptr, &addr_bytes[..op_info.addr_len as usize]) }; // Dummy cycles - let bus_width: u8 = super::get_addr_buswidth(op_info.mode as u32); + let bus_width: u8 = get_addr_buswidth(op_info.mode as u32); let dummy_len: u8 = (op_info.dummy_cycle / (8 / u32::from(bus_width))) .try_into() .unwrap(); dbg!(self, "write dummy len: 0x{:08x}", dummy_len); - unsafe { super::spi_write_data(start_ptr, &dummy[..dummy_len as usize]) }; + unsafe { spi_write_data(start_ptr, &dummy[..dummy_len as usize]) }; // Data transfer let data_mode = self.spi_data.cmd_mode[cs].user - | spi_io_mode_user(u32::from(super::get_data_buswidth(op_info.mode as u32))); + | spi_io_mode_user(u32::from(get_data_buswidth(op_info.mode as u32))); cs_ctrlreg_w!(self, cs, data_mode); - if op_info.data_direct == super::SPI_NOR_DATA_DIRECT_READ { + if op_info.data_direct == SPI_NOR_DATA_DIRECT_READ { unsafe { spi_read_data(start_ptr, op_info.rx_buf) }; } else { unsafe { spi_write_data(start_ptr, op_info.tx_buf) }; @@ -888,7 +891,7 @@ impl<'a> SpiBus for SpiController<'a> { if !rd_buffer.is_empty() { let ahb_addr = self.spi_data.decode_addr[cs].start as usize as *const u32; // Read RX buffer - unsafe { super::spi_read_data(ahb_addr, rd_buffer) }; + unsafe { spi_read_data(ahb_addr, rd_buffer) }; } self.deactivate_user(); Ok(()) @@ -900,11 +903,11 @@ impl<'a> SpiBus for SpiController<'a> { temp[..len].copy_from_slice(buffer); self.transfer(buffer, &temp[..len]) */ - todo!() + Err(SpiError::Other("transfer_in_place not supported")) } fn flush(&mut self) -> Result<(), SpiError> { - todo!() + Err(SpiError::Other("flush not supported")) } } diff --git a/src/spi/spidmairqtest.rs b/src/spi/spidmairqtest.rs index 3a0a9f6..025885f 100644 --- a/src/spi/spidmairqtest.rs +++ b/src/spi/spidmairqtest.rs @@ -279,8 +279,9 @@ pub fn verify_dma_buffer_match(i: usize) -> bool { true } -pub fn fill_dma_buffer(op_req: DmaOp, random: bool) { +pub fn fill_dma_buffer(op_req: DmaOp, random: bool, pattern: u32) { let mut seed = 0xDEAD_FBEE; + seed += pattern; unsafe { for i in 0..MAX_DMA_CHAIN { @@ -385,13 +386,13 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { let start_addrs = [0x0000_0000, 0x0000_0100, 0x0000_0200, 0x0000_0300]; CURRENT_DEVID = DeviceId::FmcCs0Idx; - fill_dma_buffer(DmaOp::Read, true); + fill_dma_buffer(DmaOp::Read, true, 0); 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===="); + log_uart!("==== FMC DEV1 DMA Slow read & write Test===="); let controller1 = FMC_CONTROLLER.as_mut().unwrap(); let flash_device1 = ChipSelectDevice { bus: controller1, // reuse same ref @@ -412,10 +413,10 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { let read_only = false; CURRENT_DEVID = DeviceId::FmcCs1Idx; if read_only { - fill_dma_buffer(DmaOp::Read, false); + fill_dma_buffer(DmaOp::Read, false, 0); dma_irq_chain_test(&start_addrs, DmaOp::Read, false); } else { - fill_dma_buffer(DmaOp::Program, true); + fill_dma_buffer(DmaOp::Program, true, 0x1234); let _ = dev1.nor_sector_erase(0x0000_0000); delay.delay_ns(8_000_000); // NOTE: DMA write has an issue in AST2600-Errata-11 @@ -466,7 +467,7 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { let controller = SPI_CONTROLLER.as_mut().unwrap(); let _ = controller.init(); - log_uart!("==== SPI0 DEV0 DMA read Test===="); + log_uart!("==== SPI0 DEV0 DMA 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); @@ -490,12 +491,12 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { //let start_addrs = [0x0000_0100]; CURRENT_DEVID = DeviceId::Spi0Cs0Idx; - let read_only = true; + let read_only = false; if read_only { - fill_dma_buffer(DmaOp::ReadFast, false); + fill_dma_buffer(DmaOp::ReadFast, false, 0); dma_irq_chain_test(&start_addrs, DmaOp::ReadFast, false); } else { - fill_dma_buffer(DmaOp::Program, true); + fill_dma_buffer(DmaOp::Program, true, 0xabc); let _ = dev0.nor_sector_erase(0x0000_0000); delay.delay_ns(8_000_000); dma_irq_chain_test(&start_addrs, DmaOp::ProgramFast, false); @@ -505,7 +506,7 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { } dma_irq_chain_test(&start_addrs, DmaOp::ReadFast, true); } - log_uart!("==== End SPI0 DEV0 DMA read Test===="); + log_uart!("==== End SPI0 DEV0 DMA Test===="); } //unsafe scu_qspi_mux[0] = 0x0000_0000; diff --git a/src/spi/spim.rs b/src/spi/spim.rs new file mode 100644 index 0000000..ba54f5a --- /dev/null +++ b/src/spi/spim.rs @@ -0,0 +1,141 @@ +// Licensed under the Apache-2.0 license + +use crate::modify_reg; +use core::cell::Cell; +use critical_section::Mutex; + + +use super::consts::{PIN_SPIM0_CLK_OUT_BIT, PIN_SPIM1_CLK_OUT_BIT, PIN_SPIM2_CLK_OUT_BIT, PIN_SPIM3_CLK_OUT_BIT}; + +static GPIO_ORI_VAL: Mutex<[Cell; 4]> = + Mutex::new([const { Cell::new(0) }; 4]); + +pub fn get_gpio_ori_val() -> [u32; 4] { + critical_section::with(|crit| { + let v = GPIO_ORI_VAL.borrow(crit); + [v[0].get(), v[1].get(), v[2].get(), v[3].get()] + }) +} + +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() }; + + // If no SPIM in use, return + #[allow(clippy::verbose_bit_mask)] + if scu.scu0f0().read().bits() & 0x7 == 0 { + return; + } + + let spim_idx = (scu.scu0f0().read().bits() & 0x7) - 1; + if spim_idx > 3 { + return; + } + let clear = true; + for (idx, ori_val) in get_gpio_ori_val().iter_mut().enumerate() { + if u32::try_from(idx).unwrap() == spim_idx { + continue; + } + + match idx { + 0 => { + modify_reg!(scu.scu690(), PIN_SPIM0_CLK_OUT_BIT, clear); + *ori_val = gpio.gpio004().read().bits(); + modify_reg!(gpio.gpio004(), PIN_SPIM0_CLK_OUT_BIT, clear); + } + 1 => { + modify_reg!(scu.scu690(), PIN_SPIM1_CLK_OUT_BIT, clear); + *ori_val = gpio.gpio004().read().bits(); + modify_reg!(gpio.gpio004(), PIN_SPIM1_CLK_OUT_BIT, clear); + } + 2 => { + modify_reg!(scu.scu694(), PIN_SPIM2_CLK_OUT_BIT, clear); + *ori_val = gpio.gpio024().read().bits(); + modify_reg!(gpio.gpio024(), PIN_SPIM2_CLK_OUT_BIT, clear); + } + 3 => { + modify_reg!(scu.scu694(), PIN_SPIM3_CLK_OUT_BIT, clear); + *ori_val = gpio.gpio024().read().bits(); + modify_reg!(gpio.gpio024(), PIN_SPIM3_CLK_OUT_BIT, clear); + } + _ => (), + } + } +} + +pub fn spim_proprietary_post_config() { + let scu = unsafe { &*ast1060_pac::Scu::ptr() }; + let gpio = unsafe { &*ast1060_pac::Gpio::ptr() }; + + // If no SPIM in use, return + let bits = scu.scu0f0().read().bits(); + if bits.trailing_zeros() >= 3 { + return; + } + + let spim_idx = (scu.scu0f0().read().bits() & 0x7) - 1; + if spim_idx > 3 { + return; + } + let clear = false; + for (idx, ori_val) in get_gpio_ori_val().iter().copied().enumerate() { + if u32::try_from(idx).unwrap() == spim_idx { + continue; + } + + match idx { + 0 => { + gpio.gpio004().modify(|r, w| unsafe { + let mut current = r.bits(); + current &= !(1 << PIN_SPIM0_CLK_OUT_BIT); + current |= ori_val; + w.bits(current) + }); + modify_reg!(scu.scu690(), PIN_SPIM0_CLK_OUT_BIT, clear); + } + 1 => { + gpio.gpio004().modify(|r, w| unsafe { + let mut current = r.bits(); + current &= !(1 << PIN_SPIM1_CLK_OUT_BIT); + current |= ori_val; + w.bits(current) + }); + modify_reg!(gpio.gpio004(), PIN_SPIM1_CLK_OUT_BIT, clear); + } + 2 => { + gpio.gpio024().modify(|r, w| unsafe { + let mut current = r.bits(); + current &= !(1 << PIN_SPIM2_CLK_OUT_BIT); + current |= ori_val; + w.bits(current) + }); + modify_reg!(scu.scu694(), PIN_SPIM2_CLK_OUT_BIT, clear); + } + 3 => { + gpio.gpio024().modify(|r, w| unsafe { + let mut current = r.bits(); + current &= !(1 << PIN_SPIM3_CLK_OUT_BIT); + current |= ori_val; + w.bits(current) + }); + modify_reg!(scu.scu694(), PIN_SPIM3_CLK_OUT_BIT, clear); + } + _ => (), + } + } +} diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index 5554cc8..a3cb8ad 100644 --- a/src/spi/spitest.rs +++ b/src/spi/spitest.rs @@ -8,10 +8,9 @@ use super::fmccontroller::FmcController; use super::norflash::{ Jesd216Mode, SpiNorData, SpiNorDevice, SPI_NOR_CMD_QREAD, SPI_NOR_CMD_READ_FAST_4B, }; -use super::{ - norflash, CommandMode, CtrlType, SpiConfig, SpiData, SpiDecodeAddress, - SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE, -}; +use super::{ norflash }; +use super::types::{CommandMode, CtrlType, SpiConfig, SpiData, SpiDecodeAddress}; +use super::consts::{SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; use crate::common::{self, DmaBuffer, DummyDelay}; use crate::spi::norflashblockdevice; use crate::spi::norflashblockdevice::{BlockAddrUsize, NorFlashBlockDevice}; diff --git a/src/spi/traits.rs b/src/spi/traits.rs new file mode 100644 index 0000000..a851183 --- /dev/null +++ b/src/spi/traits.rs @@ -0,0 +1,17 @@ +// Licensed under the Apache-2.0 license + +use embedded_hal::spi::{ErrorType, SpiBus}; + +use crate::spi::norflash::SpiNorData; + +use super::SpiError; + +pub trait SpiBusWithCs: SpiBus + ErrorType { + fn select_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); + + fn get_device_info(&mut self, cs: usize) -> (u32, u32); + fn get_master_id(&mut self) -> u32; +} diff --git a/src/spi/types.rs b/src/spi/types.rs new file mode 100644 index 0000000..cd85097 --- /dev/null +++ b/src/spi/types.rs @@ -0,0 +1,88 @@ +// Licensed under the Apache-2.0 license + +use super::consts::ASPEED_MAX_CS; + +#[derive(Clone, Copy)] +pub enum DataDirection { + Read, + Write, + +} + +pub struct FlashAddress { + pub value: u32, + pub width: AddressWidth, +} + +pub enum AddressWidth { + ThreeByte, + FourByte, +} + +#[derive(Clone, Copy)] +pub enum CtrlType { + BootSpi, + HostSpi, + NormalSpi, +} + +#[derive(Clone, Copy)] +pub struct CommandMode { + pub normal_read: u32, + pub normal_write: u32, + pub user: u32, +} + +#[derive(Default, Clone, Copy)] +pub struct SpiDecodeAddress { + pub start: u32, + pub len: u32, +} + +/// Static SPI controller configuration information +pub struct SpiConfig { + pub mmap_base: u32, + pub max_cs: usize, + pub write_block_size: u32, + pub ctrl_type: CtrlType, + pub timing_cali_start_off: u32, + pub master_idx: u32, + pub pure_spi_mode_only: bool, + pub frequency: u32, + pub timing_calibration_start_off: u32, + pub timing_calibration_disabled: bool, +} + +/// Controller state structure +pub struct SpiData { + pub decode_addr: [SpiDecodeAddress; ASPEED_MAX_CS], + pub cmd_mode: [CommandMode; ASPEED_MAX_CS], + pub hclk: u32, + pub spim_proprietary_pre_config: u32, +} + +impl Default for SpiData { + fn default() -> Self { + Self::new() + } +} + +impl SpiData { + #[must_use] + pub const fn new() -> Self { + const ZERO_ADDR: SpiDecodeAddress = SpiDecodeAddress { start: 0, len: 0 }; + const ZERO_CMD: CommandMode = CommandMode { + normal_read: 0, + normal_write: 0, + user: 0, + }; + + Self { + decode_addr: [ZERO_ADDR; ASPEED_MAX_CS], + cmd_mode: [ZERO_CMD; ASPEED_MAX_CS], + hclk: 0, + spim_proprietary_pre_config: 0, + } + } +} + diff --git a/src/spi/util.rs b/src/spi/util.rs new file mode 100644 index 0000000..6f37d11 --- /dev/null +++ b/src/spi/util.rs @@ -0,0 +1,220 @@ +// Licensed under the Apache-2.0 license + +use crate::{ + spi::norflash::{Jesd216Mode}, +}; +use ast1060_pac::Scu; +use super::consts::HPLL_FREQ; + +#[macro_export] +macro_rules! dbg { + ($self:expr, $($arg:tt)*) => {{ + if let Some(ref mut uart) = $self.dbg_uart { + writeln!(uart, $($arg)*).unwrap(); + write!(uart, "\r").unwrap(); + } + }}; +} + +#[inline] +fn hclk_div_reg_to_val(x: u32) -> u32 { + if x == 0 { + 2 + } else { + x + 1 + } +} + +#[must_use] +pub fn get_hclock_rate() -> u32 { + let scu_reg = unsafe { &*Scu::ptr() }; + let raw_div = scu_reg.scu314().read().hclkdivider_sel().bits(); + let clk_div = hclk_div_reg_to_val(u32::from(raw_div)); + + HPLL_FREQ / clk_div +} + +#[must_use] +pub fn spi_io_mode(mode: Jesd216Mode) -> u32 { + match mode { + //Jesd216Mode::Mode111 | Jesd216Mode::Mode111Fast => 0x0000_0000, + Jesd216Mode::Mode112 => 0x2000_0000, + Jesd216Mode::Mode122 => 0x3000_0000, + Jesd216Mode::Mode114 => 0x4000_0000, + Jesd216Mode::Mode144 => 0x5000_0000, + _ => 0, + } +} +#[must_use] +pub fn spi_io_mode_user(bus_width: u32) -> u32 { + match bus_width { + 4 => 0x4000_0000, + 2 => 0x2000_0000, + _ => 0x0000_0000, + } +} +#[must_use] +pub fn spi_cal_dummy_cycle(bus_width: u32, dummy_cycle: u32) -> u32 { + if bus_width == 0 || bus_width > 8 { + return 0; + } + let bits_per_cycle = 8 / bus_width; + if bits_per_cycle == 0 { + return 0; + } + let dummy_byte = dummy_cycle / bits_per_cycle; + ((dummy_byte & 0x3) << 6) | (((dummy_byte & 0x4) >> 2) << 14) +} + +pub const fn get_cmd_buswidth(v: u32) -> u8 { + ((v & 0x0000_0F00) >> 8) as u8 +} +pub const fn get_addr_buswidth(v: u32) -> u8 { + ((v & 0x0000_00F0) >> 4) as u8 +} +pub const fn get_data_buswidth(v: u32) -> u8 { + (v & 0x0000_000F) as u8 +} + +/// Calculate the SPI frequency division setting based on bus clock and max frequency. +/// +/// # Arguments +/// * `bus_clk` - The bus clock frequency in Hz. +/// * `max_freq` - The maximum desired SPI frequency in Hz. +/// +/// # Returns +/// A 32-bit value encoding the frequency divider, +/// or 0 if no valid divider found. + +#[must_use] +pub fn aspeed_get_spi_freq_div(bus_clk: u32, max_freq: u32) -> u32 { + // Division mapping array matching C div_arr + let div_arr = [15, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0]; + + for i in 0..0x0f { + for (j, div_val) in div_arr.iter().copied().enumerate() { + if i == 0 && j == 0 { + continue; + } + let divisor = j + 1 + (i * 16); + let freq = bus_clk / u32::try_from(divisor).unwrap(); + + if max_freq >= freq { + #[allow(clippy::cast_sign_loss)] + return ((i << 24) | ((div_val as u32) << 8) as usize) + .try_into() + .unwrap(); + } + } + } + // If not found, log error and return 0 (adjust logging as needed) + //log eprintln!("aspeed_get_spi_freq_div: cannot get correct frequency division."); + 0 +} + +/// Finds the midpoint of the longest consecutive sequence of 1's in a buffer. +/// +/// Returns the midpoint index if the longest run is at least length 4, +/// otherwise returns -1. +/// +/// # Arguments +/// * `buf` - slice of bytes (each should be 0 or 1). +#[must_use] +pub fn get_mid_point_of_longest_one(buf: &[u8]) -> i32 { + let mut start = 0; + let mut mid_point = 0; + let mut max_cnt = 0; + let mut cnt = 0; + + for (i, &val) in buf.iter().enumerate() { + if val == 1 { + cnt += 1; + } else { + cnt = 0; + start = i; + } + + if cnt > max_cnt { + max_cnt = cnt; + mid_point = start + (cnt / 2); + } + } + + if max_cnt < 4 { + -1 + } else { + i32::try_from(mid_point).unwrap() + } +} + +#[must_use] +pub fn spi_calibration_enable(buf: &[u8]) -> bool { + if buf.len() < 4 { + return false; + } + + let mut valid_count = 0; + + // Process 4 bytes at a time + for chunk in buf.chunks_exact(4) { + // Convert 4 bytes to u32 in little-endian order + let word = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]); + + if word != 0 && word != 0xFFFF_FFFF { + valid_count += 1; + } + if valid_count > 100 { + return true; + } + } + + false +} + +#[allow(clippy::missing_safety_doc)] +pub unsafe fn spi_read_data(ahb_addr: *const u32, read_arr: &mut [u8]) { + let len = read_arr.len(); + let mut i = 0; + + // Read full u32 words + while i + 4 <= len { + let word = core::ptr::read_volatile(ahb_addr.add(i / 4)); + read_arr[i..i + 4].copy_from_slice(&word.to_le_bytes()); // adjust for BE if needed + i += 4; + } + + // Remaining bytes + while i < len { + read_arr[i] = core::ptr::read_volatile((ahb_addr.cast::()).add(i)); + i += 1; + } +} + +#[allow(clippy::missing_safety_doc)] +pub unsafe fn spi_write_data(ahb_addr: *mut u32, write_arr: &[u8]) { + if write_arr.is_empty() { + return; + } + + let len = write_arr.len(); + let mut i = 0; + + // Write in u32 words as long as possible + while i + 4 <= len { + let word = u32::from_le_bytes([ + write_arr[i], + write_arr[i + 1], + write_arr[i + 2], + write_arr[i + 3], + ]); + core::ptr::write_volatile(ahb_addr.add(i / 4), word); + i += 4; + } + + // Write remaining bytes (if any) + let ahb_addr_u8 = ahb_addr.cast::(); + while i < len { + core::ptr::write_volatile(ahb_addr_u8.add(i), write_arr[i]); + i += 1; + } +} From 41c8fe7dc063f0d13a32c96a714c7b053e493744 Mon Sep 17 00:00:00 2001 From: hailin wu Date: Wed, 11 Feb 2026 16:16:33 -0800 Subject: [PATCH 06/10] update const magic, Datadirection read/write, to enum --- src/spi/consts.rs | 4 +-- src/spi/fmccontroller.rs | 30 ++++++++++---------- src/spi/mod.rs | 2 +- src/spi/norflash.rs | 59 ++++++++++++++++++++-------------------- src/spi/spicontroller.rs | 30 ++++++++++---------- src/spi/spidmairqtest.rs | 10 +++---- src/spi/spitest.rs | 35 ++++++++++++------------ src/spi/traits.rs | 8 +++--- src/spi/types.rs | 5 ++-- 9 files changed, 90 insertions(+), 93 deletions(-) diff --git a/src/spi/consts.rs b/src/spi/consts.rs index 3617275..5a8ae03 100644 --- a/src/spi/consts.rs +++ b/src/spi/consts.rs @@ -55,5 +55,5 @@ pub(crate) const PIN_SPIM1_CLK_OUT_BIT: u32 = 21; pub(crate) const PIN_SPIM2_CLK_OUT_BIT: u32 = 3; pub(crate) const PIN_SPIM3_CLK_OUT_BIT: u32 = 17; -pub const SPI_NOR_DATA_DIRECT_READ: u32 = 0x0000_0001; -pub const SPI_NOR_DATA_DIRECT_WRITE: u32 = 0x0000_0002; +//pub const SPI_NOR_DATA_DIRECT_READ: u32 = 0x0000_0001; +//pub const SPI_NOR_DATA_DIRECT_WRITE: u32 = 0x0000_0002; diff --git a/src/spi/fmccontroller.rs b/src/spi/fmccontroller.rs index de7cd83..2f68a23 100644 --- a/src/spi/fmccontroller.rs +++ b/src/spi/fmccontroller.rs @@ -4,7 +4,7 @@ use super::{ aspeed_get_spi_freq_div, get_addr_buswidth, get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, spi_io_mode, spi_io_mode_user, spi_read_data, spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, get_cmd_buswidth, - get_data_buswidth + get_data_buswidth, DataDirection }; use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, ASPEED_SPI_SZ_2M, ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, @@ -13,7 +13,7 @@ use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRIT SPI_DMA_RAM_MAP_BASE, SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, SPI_CTRL_CEX_SPI_CMD_MASK, SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_CLK_FREQ_MASK, SPI_DMA_DELAY_MASK, - SPI_DMA_DELAY_SHIFT, SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; + SPI_DMA_DELAY_SHIFT, SPI_CONF_CE0_ENABLE_WRITE_SHIFT}; use embedded_io::Write; @@ -22,7 +22,7 @@ use super::consts::{SPI_DMA_TRIGGER_LEN}; use crate::dbg; -use crate::{common::DummyDelay, spi::norflash::SpiNorData, uart::UartController}; +use crate::{common::DummyDelay, spi::norflash::SpiNorCommand, uart::UartController}; use embedded_hal::{ delay::DelayNs, spi::{ErrorType, SpiBus}, @@ -227,7 +227,7 @@ impl<'a> FmcController<'a> { } } - fn spi_nor_read_init(&mut self, cs: usize, op_info: &SpiNorData) { + fn spi_nor_read_init(&mut self, cs: usize, op_info: &SpiNorCommand) { dbg!( self, "spi_nor_read_init() cs:{} master_idx: {}", @@ -280,7 +280,7 @@ impl<'a> FmcController<'a> { self.timing_calibration(cs); } - fn spi_nor_write_init(&mut self, cs: usize, op_info: &SpiNorData) { + fn spi_nor_write_init(&mut self, cs: usize, op_info: &SpiNorCommand) { let io_mode = spi_io_mode(op_info.mode); let dummy = 0; let write_cmd = (io_mode @@ -483,7 +483,7 @@ impl<'a> FmcController<'a> { checksum } - fn spi_nor_transceive_user(&mut self, op_info: &mut SpiNorData) { + fn spi_nor_transceive_user(&mut self, op_info: &mut SpiNorCommand) { let cs: usize = self.current_cs; let dummy = [0u8; 12]; let start_ptr = self.spi_data.decode_addr[cs].start as *mut u32; @@ -527,7 +527,7 @@ impl<'a> FmcController<'a> { | spi_io_mode_user(u32::from(get_data_buswidth(op_info.mode as u32))); cs_ctrlreg_w!(self, cs, data_mode); - if op_info.data_direct == SPI_NOR_DATA_DIRECT_READ { + if matches!(op_info.data_direct, DataDirection::DRead) { unsafe { spi_read_data(start_ptr, op_info.rx_buf) }; } else { unsafe { spi_write_data(start_ptr, op_info.tx_buf) }; @@ -537,7 +537,7 @@ impl<'a> FmcController<'a> { // Helper wrappers would be defined for spi_write_data, spi_read_data, io_mode_user, etc. - pub fn spi_nor_transceive(&mut self, op_info: &mut SpiNorData) -> Result<(), SpiError> { + pub fn spi_nor_transceive(&mut self, op_info: &mut SpiNorCommand) -> Result<(), SpiError> { dbg!(self, "spi_nor_transceive()..."); #[cfg(feature = "spi_dma")] @@ -545,7 +545,7 @@ impl<'a> FmcController<'a> { dbg!(self, "spi dma enabled rx_len:{}", op_info.rx_buf.len()); let addr_aligned = op_info.addr % 4 == 0; - if op_info.data_direct == SPI_NOR_DATA_DIRECT_READ { + if matches!(op_info.data_direct, DataDirection::DRead) { let buf_aligned = (op_info.rx_buf.as_ptr() as usize) % 4 == 0; let use_dma = !self.spi_config.pure_spi_mode_only && op_info.rx_buf.len() > SPI_DMA_TRIGGER_LEN as usize @@ -565,7 +565,7 @@ impl<'a> FmcController<'a> { } else { self.spi_nor_transceive_user(op_info); } - } else if op_info.data_direct == SPI_NOR_DATA_DIRECT_WRITE { + } else if matches!(op_info.data_direct, DataDirection::DWrite) { dbg!(self, "write dma"); #[cfg(feature = "spi_dma_write")] { @@ -661,7 +661,7 @@ impl<'a> FmcController<'a> { Ok(()) } - pub fn read_dma(&mut self, op: &mut SpiNorData) -> Result<(), SpiError> { + pub fn read_dma(&mut self, op: &mut SpiNorCommand) -> Result<(), SpiError> { let cs = self.current_cs; 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}", @@ -735,7 +735,7 @@ impl<'a> FmcController<'a> { } #[allow(dead_code)] - fn write_dma(&mut self, op: &mut SpiNorData) -> Result<(), SpiError> { + fn write_dma(&mut self, op: &mut SpiNorCommand) -> 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}", @@ -874,16 +874,16 @@ impl<'a> SpiBusWithCs for FmcController<'a> { Ok(()) } - fn nor_transfer(&mut self, op_info: &mut SpiNorData) -> Result<(), SpiError> { + fn nor_transfer(&mut self, op_info: &mut SpiNorCommand) -> Result<(), SpiError> { let _ = self.spi_nor_transceive(op_info); Ok(()) } - fn nor_read_init(&mut self, cs: usize, op_info: &SpiNorData) { + fn nor_read_init(&mut self, cs: usize, op_info: &SpiNorCommand) { self.spi_nor_read_init(cs, op_info); } - fn nor_write_init(&mut self, cs: usize, op_info: &SpiNorData) { + fn nor_write_init(&mut self, cs: usize, op_info: &SpiNorCommand) { self.spi_nor_write_init(cs, op_info); } diff --git a/src/spi/mod.rs b/src/spi/mod.rs index f828790..6187b97 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -23,7 +23,7 @@ pub use error::SpiError; pub use traits::SpiBusWithCs; pub use types::{CommandMode, CtrlType, DataDirection, SpiConfig, SpiDecodeAddress, SpiData, FlashAddress, AddressWidth}; -pub use norflash::{Jesd216Mode, SpiNorData, SpiNorDevice}; +pub use norflash::{Jesd216Mode, SpiNorCommand, SpiNorDevice}; pub use util::{spi_read_data, spi_write_data, aspeed_get_spi_freq_div, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, get_hclock_rate, spi_io_mode, spi_io_mode_user, diff --git a/src/spi/norflash.rs b/src/spi/norflash.rs index 9b1e904..d19306b 100644 --- a/src/spi/norflash.rs +++ b/src/spi/norflash.rs @@ -2,8 +2,7 @@ use super::device::ChipSelectDevice; use super::SpiBusWithCs; -use super::{norflash, SpiError}; -use super::consts::{SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; +use super::{norflash, SpiError,DataDirection}; use crate::common::DummyDelay; use embedded_hal::delay::DelayNs; @@ -89,7 +88,7 @@ pub enum Jesd216Mode { Unknown = 0xFFF_FFFF, } -pub struct SpiNorData<'a> { +pub struct SpiNorCommand<'a> { pub mode: Jesd216Mode, pub opcode: u32, pub dummy_cycle: u32, @@ -98,13 +97,13 @@ pub struct SpiNorData<'a> { pub data_len: u32, pub tx_buf: &'a [u8], pub rx_buf: &'a mut [u8], - pub data_direct: u32, + pub data_direct: DataDirection, } pub trait SpiNorDevice { type Error; - fn nor_read_init(&mut self, data: &SpiNorData) -> Result<(), Self::Error>; - fn nor_write_init(&mut self, data: &SpiNorData) -> Result<(), Self::Error>; + fn nor_read_init(&mut self, data: &SpiNorCommand) -> Result<(), Self::Error>; + fn nor_write_init(&mut self, data: &SpiNorCommand) -> Result<(), Self::Error>; fn nor_write_enable(&mut self) -> Result<(), Self::Error>; fn nor_write_disable(&mut self) -> Result<(), Self::Error>; fn nor_read_jedec_id(&mut self) -> Result<[u8; 3], Self::Error>; @@ -153,14 +152,14 @@ where type Error = B::Error; fn nor_write_enable(&mut self) -> Result<(), Self::Error> { - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_WREN, dummy_cycle: 0, addr: 0, addr_len: 0, data_len: 0, - data_direct: SPI_NOR_DATA_DIRECT_WRITE, + data_direct: DataDirection::DWrite, tx_buf: &[], rx_buf: &mut [], }; @@ -169,14 +168,14 @@ where } fn nor_write_disable(&mut self) -> Result<(), Self::Error> { - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_WRDI, dummy_cycle: 0, addr: 0, addr_len: 0, data_len: 0, - data_direct: SPI_NOR_DATA_DIRECT_WRITE, + data_direct: DataDirection::DWrite, tx_buf: &[], rx_buf: &mut [], }; @@ -186,7 +185,7 @@ where fn nor_read_jedec_id(&mut self) -> Result<[u8; 3], Self::Error> { let mut read_buf: [u8; 3] = [0, 0, 0]; - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: 0x9F, dummy_cycle: 0, @@ -195,7 +194,7 @@ where data_len: 0, rx_buf: &mut read_buf, tx_buf: &[], - data_direct: SPI_NOR_DATA_DIRECT_READ, + data_direct: DataDirection::DRead, }; start_transfer!(self, &mut nor_data); Ok([read_buf[0], read_buf[1], read_buf[2]]) @@ -204,7 +203,7 @@ where fn nor_sector_erase(&mut self, address: u32) -> Result<(), Self::Error> { self.nor_write_enable()?; if self.nor_sector_aligned(address) { - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_SE, dummy_cycle: 0, @@ -213,7 +212,7 @@ where data_len: 0, tx_buf: &[], rx_buf: &mut [], - data_direct: SPI_NOR_DATA_DIRECT_WRITE, + data_direct: DataDirection::DWrite, }; start_transfer!(self, &mut nor_data); self.nor_wait_until_ready(); @@ -225,7 +224,7 @@ where fn nor_page_program(&mut self, address: u32, data: &[u8]) -> Result<(), Self::Error> { self.nor_write_enable()?; - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP, dummy_cycle: 0, @@ -234,7 +233,7 @@ where data_len: u32::try_from(data.len()).unwrap(), tx_buf: data, rx_buf: &mut [], - data_direct: SPI_NOR_DATA_DIRECT_WRITE, + data_direct: DataDirection::DWrite, }; start_transfer!(self, &mut nor_data); Ok(()) @@ -242,7 +241,7 @@ where fn nor_page_program_4b(&mut self, address: u32, data: &[u8]) -> Result<(), Self::Error> { self.nor_write_enable()?; - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP_4B, dummy_cycle: 0, @@ -251,14 +250,14 @@ where data_len: u32::try_from(data.len()).unwrap(), tx_buf: data, rx_buf: &mut [], - data_direct: SPI_NOR_DATA_DIRECT_WRITE, + data_direct: DataDirection::DWrite, }; start_transfer!(self, &mut nor_data); Ok(()) } fn nor_read_data(&mut self, address: u32, buf: &mut [u8]) -> Result<(), Self::Error> { - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode114, opcode: SPI_NOR_CMD_QREAD, dummy_cycle: 8, @@ -267,14 +266,14 @@ where data_len: u32::try_from(buf.len()).unwrap(), // it is not in used. tx_buf: &[], rx_buf: buf, - data_direct: SPI_NOR_DATA_DIRECT_READ, + data_direct: DataDirection::DRead, }; start_transfer!(self, &mut nor_data); Ok(()) } fn nor_read_fast_4b_data(&mut self, address: u32, buf: &mut [u8]) -> Result<(), Self::Error> { - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111Fast, opcode: SPI_NOR_CMD_READ_FAST_4B, dummy_cycle: 8, @@ -283,7 +282,7 @@ where data_len: u32::try_from(buf.len()).unwrap(), // it is not in used. tx_buf: &[], rx_buf: buf, - data_direct: SPI_NOR_DATA_DIRECT_READ, + data_direct: DataDirection::DRead, }; start_transfer!(self, &mut nor_data); @@ -291,7 +290,7 @@ where } fn nor_reset_enable(&mut self) -> Result<(), Self::Error> { - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_RESET_EN, dummy_cycle: 0, @@ -300,14 +299,14 @@ where data_len: 0x0, // it is not in used. tx_buf: &[], rx_buf: &mut [], - data_direct: SPI_NOR_DATA_DIRECT_WRITE, + data_direct: DataDirection::DWrite, }; start_transfer!(self, &mut nor_data); Ok(()) } fn nor_reset(&mut self) -> Result<(), Self::Error> { - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_RESET_MEM, dummy_cycle: 0, @@ -316,14 +315,14 @@ where data_len: 0x0, // it is not in used. tx_buf: &[], rx_buf: &mut [], - data_direct: SPI_NOR_DATA_DIRECT_WRITE, + data_direct: DataDirection::DWrite, }; start_transfer!(self, &mut nor_data); Ok(()) } - fn nor_read_init(&mut self, nor_data: &SpiNorData) -> Result<(), Self::Error> { + fn nor_read_init(&mut self, nor_data: &SpiNorCommand) -> Result<(), Self::Error> { if let Some(spim) = self.spim { if self.bus.get_master_id() != 0 { super::spim_scu_ctrl_set(0x8, 0x8); @@ -343,7 +342,7 @@ where Ok(()) } - fn nor_write_init(&mut self, nor_data: &SpiNorData) -> Result<(), Self::Error> { + fn nor_write_init(&mut self, nor_data: &SpiNorCommand) -> Result<(), Self::Error> { self.bus.nor_write_init(self.cs, nor_data); Ok(()) } @@ -359,7 +358,7 @@ where let mut delay = DummyDelay {}; let mut buf: [u8; 1] = [0u8]; - let mut nor_data = SpiNorData { + let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_RDSR, dummy_cycle: 0, @@ -368,7 +367,7 @@ where data_len: 1, // it is not in used. tx_buf: &[], rx_buf: &mut buf, - data_direct: SPI_NOR_DATA_DIRECT_READ, + data_direct: DataDirection::DRead, }; loop { start_transfer!(self, &mut nor_data); diff --git a/src/spi/spicontroller.rs b/src/spi/spicontroller.rs index 43d7265..a6f4515 100644 --- a/src/spi/spicontroller.rs +++ b/src/spi/spicontroller.rs @@ -4,7 +4,7 @@ use super::{ aspeed_get_spi_freq_div, get_addr_buswidth, get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, spi_io_mode, spi_io_mode_user, spi_read_data, spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, get_cmd_buswidth, - get_data_buswidth + get_data_buswidth,DataDirection }; use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, @@ -14,7 +14,7 @@ use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRIT SPI_DMA_RAM_MAP_BASE, SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, SPI_CTRL_CEX_SPI_CMD_MASK, SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_CLK_FREQ_MASK, SPI_DMA_DELAY_MASK, - SPI_DMA_DELAY_SHIFT, SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; + SPI_DMA_DELAY_SHIFT, SPI_CONF_CE0_ENABLE_WRITE_SHIFT}; use embedded_io::Write; @@ -23,7 +23,7 @@ use super::consts::{SPI_DMA_TRIGGER_LEN}; use crate::dbg; -use crate::{common::DummyDelay, spi::norflash::SpiNorData, uart::UartController}; +use crate::{common::DummyDelay, spi::norflash::SpiNorCommand, uart::UartController}; use embedded_hal::{ delay::DelayNs, @@ -233,7 +233,7 @@ impl<'a> SpiController<'a> { } } - fn spi_nor_read_init(&mut self, cs: usize, op_info: &SpiNorData) { + fn spi_nor_read_init(&mut self, cs: usize, op_info: &SpiNorCommand) { dbg!( self, "spi_nor_read_init() cs:{} master_idx: {}", @@ -286,7 +286,7 @@ impl<'a> SpiController<'a> { self.timing_calibration(cs); } - fn spi_nor_write_init(&mut self, cs: usize, op_info: &SpiNorData) { + fn spi_nor_write_init(&mut self, cs: usize, op_info: &SpiNorCommand) { let io_mode = spi_io_mode(op_info.mode); let dummy = 0; let write_cmd = (io_mode @@ -513,7 +513,7 @@ impl<'a> SpiController<'a> { checksum } - fn spi_nor_transceive_user(&mut self, op_info: &mut SpiNorData) { + fn spi_nor_transceive_user(&mut self, op_info: &mut SpiNorCommand) { let cs: usize = self.current_cs; let dummy = [0u8; 12]; let start_ptr = self.spi_data.decode_addr[cs].start as *mut u32; @@ -557,7 +557,7 @@ impl<'a> SpiController<'a> { | spi_io_mode_user(u32::from(get_data_buswidth(op_info.mode as u32))); cs_ctrlreg_w!(self, cs, data_mode); - if op_info.data_direct == SPI_NOR_DATA_DIRECT_READ { + if matches!(op_info.data_direct, DataDirection::DRead) { unsafe { spi_read_data(start_ptr, op_info.rx_buf) }; } else { unsafe { spi_write_data(start_ptr, op_info.tx_buf) }; @@ -567,7 +567,7 @@ impl<'a> SpiController<'a> { // Helper wrappers would be defined for spi_write_data, spi_read_data, io_mode_user, etc. - pub fn spi_nor_transceive(&mut self, op_info: &mut SpiNorData) -> Result<(), SpiError> { + pub fn spi_nor_transceive(&mut self, op_info: &mut SpiNorCommand) -> Result<(), SpiError> { dbg!(self, "spi_nor_transceive()..."); #[cfg(feature = "spi_dma")] @@ -582,7 +582,7 @@ impl<'a> SpiController<'a> { ); let addr_aligned = op_info.addr % 4 == 0; - if op_info.data_direct == SPI_NOR_DATA_DIRECT_READ { + if matches!(op_info.data_direct, DataDirection::DRead) { let buf_aligned = (op_info.rx_buf.as_ptr() as usize) % 4 == 0; let use_dma = !self.spi_config.pure_spi_mode_only && op_info.rx_buf.len() > SPI_DMA_TRIGGER_LEN as usize @@ -602,7 +602,7 @@ impl<'a> SpiController<'a> { } else { self.spi_nor_transceive_user(op_info); } - } else if op_info.data_direct == SPI_NOR_DATA_DIRECT_WRITE { + } else if matches!(op_info.data_direct, DataDirection::DWrite) { dbg!(self, "write dma"); #[cfg(feature = "spi_dma_write")] @@ -701,7 +701,7 @@ impl<'a> SpiController<'a> { //spi_context_complete(ctx, dev, 0); } - pub fn read_dma(&mut self, op: &mut SpiNorData) -> Result<(), SpiError> { + pub fn read_dma(&mut self, op: &mut SpiNorCommand) -> Result<(), SpiError> { let cs = self.current_cs; dbg!(self, "##### read dma ####"); dbg!(self, "device size: 0x{:08x} dv start: 0x{:08x}, read len: 0x{:08x}, rx_buf:0x{:08x} op addr: 0x{:08x}", @@ -777,7 +777,7 @@ impl<'a> SpiController<'a> { } #[allow(dead_code)] - fn write_dma(&mut self, op: &mut SpiNorData) -> Result<(), SpiError> { + fn write_dma(&mut self, op: &mut SpiNorCommand) -> Result<(), SpiError> { let cs = self.current_cs; //dbg!(self, "##### write_dma ####"); @@ -920,16 +920,16 @@ impl<'a> SpiBusWithCs for SpiController<'a> { Ok(()) } - fn nor_transfer(&mut self, op_info: &mut SpiNorData) -> Result<(), SpiError> { + fn nor_transfer(&mut self, op_info: &mut SpiNorCommand) -> Result<(), SpiError> { let _ = self.spi_nor_transceive(op_info); Ok(()) } - fn nor_read_init(&mut self, cs: usize, op_info: &SpiNorData) { + fn nor_read_init(&mut self, cs: usize, op_info: &SpiNorCommand) { self.spi_nor_read_init(cs, op_info); } - fn nor_write_init(&mut self, cs: usize, op_info: &SpiNorData) { + fn nor_write_init(&mut self, cs: usize, op_info: &SpiNorCommand) { self.spi_nor_write_init(cs, op_info); } diff --git a/src/spi/spidmairqtest.rs b/src/spi/spidmairqtest.rs index 025885f..df2cd82 100644 --- a/src/spi/spidmairqtest.rs +++ b/src/spi/spidmairqtest.rs @@ -5,7 +5,7 @@ use super::fmccontroller::FmcController; use crate::common::{self, DmaBuffer, DummyDelay}; use crate::spi::device::ChipSelectDevice; -use crate::spi::norflash::{SpiNorData, SpiNorDevice}; +use crate::spi::norflash::{SpiNorCommand, SpiNorDevice}; use crate::spi::spicontroller::SpiController; use crate::spi::spitest::{self, DeviceId, FMC_CONFIG}; use crate::spi::SpiData; @@ -365,7 +365,7 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { let _ = controller.init(); // You can now pass `fmc_ptr` into ChipSelectDevice or use it directly - let nor_read_data: SpiNorData<'_> = + let nor_read_data: SpiNorCommand<'_> = spitest::nor_device_read_data(spitest::FMC_CS0_CAPACITY); let nor_write_data = spitest::nor_device_write_data(spitest::FMC_CS0_CAPACITY); @@ -416,7 +416,7 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { fill_dma_buffer(DmaOp::Read, false, 0); dma_irq_chain_test(&start_addrs, DmaOp::Read, false); } else { - fill_dma_buffer(DmaOp::Program, true, 0x1234); + fill_dma_buffer(DmaOp::Program, true, 0x456); let _ = dev1.nor_sector_erase(0x0000_0000); delay.delay_ns(8_000_000); // NOTE: DMA write has an issue in AST2600-Errata-11 @@ -469,7 +469,7 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { let _ = controller.init(); log_uart!("==== SPI0 DEV0 DMA Test===="); // You can now pass `fmc_ptr` into ChipSelectDevice or use it directly - let nor_read_data: SpiNorData<'_> = + let nor_read_data: SpiNorCommand<'_> = spitest::nor_device_read_4b_data(spitest::SPI_CS0_CAPACITY); let nor_write_data = spitest::nor_device_write_4b_data(spitest::SPI_CS0_CAPACITY); @@ -496,7 +496,7 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { fill_dma_buffer(DmaOp::ReadFast, false, 0); dma_irq_chain_test(&start_addrs, DmaOp::ReadFast, false); } else { - fill_dma_buffer(DmaOp::Program, true, 0xabc); + fill_dma_buffer(DmaOp::Program, true, 0xdeed); let _ = dev0.nor_sector_erase(0x0000_0000); delay.delay_ns(8_000_000); dma_irq_chain_test(&start_addrs, DmaOp::ProgramFast, false); diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index a3cb8ad..2d7af0c 100644 --- a/src/spi/spitest.rs +++ b/src/spi/spitest.rs @@ -6,11 +6,10 @@ use super::device::ChipSelectDevice; use super::fmccontroller::FmcController; use super::norflash::{ - Jesd216Mode, SpiNorData, SpiNorDevice, SPI_NOR_CMD_QREAD, SPI_NOR_CMD_READ_FAST_4B, + Jesd216Mode, SpiNorCommand, SpiNorDevice, SPI_NOR_CMD_QREAD, SPI_NOR_CMD_READ_FAST_4B, }; use super::{ norflash }; -use super::types::{CommandMode, CtrlType, SpiConfig, SpiData, SpiDecodeAddress}; -use super::consts::{SPI_NOR_DATA_DIRECT_READ, SPI_NOR_DATA_DIRECT_WRITE}; +use super::{CommandMode, CtrlType, SpiConfig, SpiData, SpiDecodeAddress, DataDirection}; use crate::common::{self, DmaBuffer, DummyDelay}; use crate::spi::norflashblockdevice; use crate::spi::norflashblockdevice::{BlockAddrUsize, NorFlashBlockDevice}; @@ -116,8 +115,8 @@ pub const SPI1_CONFIG: SpiConfig = SpiConfig { }; #[must_use] -pub fn nor_device_read_data<'a>(len: usize) -> SpiNorData<'a> { - SpiNorData { +pub fn nor_device_read_data<'a>(len: usize) -> SpiNorCommand<'a> { + SpiNorCommand { mode: Jesd216Mode::Mode114, opcode: SPI_NOR_CMD_QREAD, dummy_cycle: 8, @@ -126,13 +125,13 @@ pub fn nor_device_read_data<'a>(len: usize) -> SpiNorData<'a> { data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], - data_direct: SPI_NOR_DATA_DIRECT_READ, + data_direct: DataDirection::DRead, } } #[must_use] -pub fn nor_device_write_data<'a>(len: usize) -> SpiNorData<'a> { - SpiNorData { +pub fn nor_device_write_data<'a>(len: usize) -> SpiNorCommand<'a> { + SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP, dummy_cycle: 0, @@ -141,13 +140,13 @@ pub fn nor_device_write_data<'a>(len: usize) -> SpiNorData<'a> { data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], - data_direct: SPI_NOR_DATA_DIRECT_WRITE, + data_direct: DataDirection::DWrite, } } #[must_use] -pub fn nor_device_read_4b_data<'a>(len: usize) -> SpiNorData<'a> { - SpiNorData { +pub fn nor_device_read_4b_data<'a>(len: usize) -> SpiNorCommand<'a> { + SpiNorCommand { mode: Jesd216Mode::Mode111Fast, opcode: SPI_NOR_CMD_READ_FAST_4B, dummy_cycle: 8, @@ -156,13 +155,13 @@ pub fn nor_device_read_4b_data<'a>(len: usize) -> SpiNorData<'a> { data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], - data_direct: SPI_NOR_DATA_DIRECT_READ, + data_direct: DataDirection::DRead, } } #[must_use] -pub fn nor_device_write_4b_data<'a>(len: usize) -> SpiNorData<'a> { - SpiNorData { +pub fn nor_device_write_4b_data<'a>(len: usize) -> SpiNorCommand<'a> { + SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP_4B, dummy_cycle: 0, @@ -171,7 +170,7 @@ pub fn nor_device_write_4b_data<'a>(len: usize) -> SpiNorData<'a> { data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], - data_direct: SPI_NOR_DATA_DIRECT_WRITE, + data_direct: DataDirection::DWrite, } } @@ -345,7 +344,7 @@ pub fn test_fmc(uart: &mut UartController<'_>) { let _result = controller.init(); //astdebug::print_reg_u32(uart, FMC_CTRL_BASE, 0xb0); - let nor_read_data: SpiNorData<'_> = nor_device_read_data(FMC_CS0_CAPACITY); + let nor_read_data: SpiNorCommand<'_> = nor_device_read_data(FMC_CS0_CAPACITY); let nor_write_data = nor_device_write_data(FMC_CS0_CAPACITY); // Wrap controller in a CS device (CS0) @@ -440,7 +439,7 @@ pub fn test_spi(uart: &mut UartController<'_>) { spim: Some(SpiMonitorNum::SPIM0), }; - let nor_read_data: SpiNorData<'_> = nor_device_read_4b_data(SPI_CS0_CAPACITY); + let nor_read_data: SpiNorCommand<'_> = 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); @@ -669,7 +668,7 @@ 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_read_data: SpiNorCommand<'_> = nor_device_read_4b_data(SPI_CS0_CAPACITY); let nor_write_data = nor_device_write_4b_data(SPI_CS0_CAPACITY); // Wrap controller in a CS device (CS0) diff --git a/src/spi/traits.rs b/src/spi/traits.rs index a851183..9a10cfe 100644 --- a/src/spi/traits.rs +++ b/src/spi/traits.rs @@ -2,15 +2,15 @@ use embedded_hal::spi::{ErrorType, SpiBus}; -use crate::spi::norflash::SpiNorData; +use crate::spi::norflash::SpiNorCommand; use super::SpiError; pub trait SpiBusWithCs: SpiBus + ErrorType { fn select_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); + fn nor_transfer(&mut self, op_info: &mut SpiNorCommand) -> Result<(), SpiError>; + fn nor_read_init(&mut self, cs: usize, op_info: &SpiNorCommand); + fn nor_write_init(&mut self, cs: usize, op_info: &SpiNorCommand); fn get_device_info(&mut self, cs: usize) -> (u32, u32); fn get_master_id(&mut self) -> u32; diff --git a/src/spi/types.rs b/src/spi/types.rs index cd85097..a95dfe9 100644 --- a/src/spi/types.rs +++ b/src/spi/types.rs @@ -4,9 +4,8 @@ use super::consts::ASPEED_MAX_CS; #[derive(Clone, Copy)] pub enum DataDirection { - Read, - Write, - + DRead, + DWrite, } pub struct FlashAddress { From 1d0b3c05bb450a2b0580147f16339b727e653013 Mon Sep 17 00:00:00 2001 From: hailin wu Date: Thu, 12 Feb 2026 10:12:00 -0800 Subject: [PATCH 07/10] update SpiNorData to SpiNorCommand. use enum instead of magic number . use a address strure --- src/spi/consts.rs | 2 -- src/spi/fmccontroller.rs | 47 ++++++++++++++++------------ src/spi/norflash.rs | 66 ++++++++++++++++------------------------ src/spi/spicontroller.rs | 50 ++++++++++++++++-------------- src/spi/spidmairqtest.rs | 4 +-- src/spi/spitest.rs | 15 ++++----- src/spi/types.rs | 1 + src/spi/util.rs | 2 +- 8 files changed, 92 insertions(+), 95 deletions(-) diff --git a/src/spi/consts.rs b/src/spi/consts.rs index 5a8ae03..bc8612d 100644 --- a/src/spi/consts.rs +++ b/src/spi/consts.rs @@ -55,5 +55,3 @@ pub(crate) const PIN_SPIM1_CLK_OUT_BIT: u32 = 21; pub(crate) const PIN_SPIM2_CLK_OUT_BIT: u32 = 3; pub(crate) const PIN_SPIM3_CLK_OUT_BIT: u32 = 17; -//pub const SPI_NOR_DATA_DIRECT_READ: u32 = 0x0000_0001; -//pub const SPI_NOR_DATA_DIRECT_WRITE: u32 = 0x0000_0002; diff --git a/src/spi/fmccontroller.rs b/src/spi/fmccontroller.rs index 2f68a23..f3fcd77 100644 --- a/src/spi/fmccontroller.rs +++ b/src/spi/fmccontroller.rs @@ -4,7 +4,7 @@ use super::{ aspeed_get_spi_freq_div, get_addr_buswidth, get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, spi_io_mode, spi_io_mode_user, spi_read_data, spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, get_cmd_buswidth, - get_data_buswidth, DataDirection + get_data_buswidth, DataDirection, AddressWidth, FlashAddress }; use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, ASPEED_SPI_SZ_2M, ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, @@ -250,16 +250,18 @@ impl<'a> FmcController<'a> { self.spi_data.cmd_mode[cs].normal_read = read_cmd; dbg!( self, - "cs: {:08x}, io_mode: {:08x}, dummy: {:08x}, op: {:08x}, normal read: {:08x}", + "cs: {:08x}, io_mode: {:08x}, dummy: {:08x}, op: {:08x}, normal read: {:08x}, + address{:08x}", cs, io_mode, dummy, op_info.opcode, - read_cmd + read_cmd, + op_info.address.value ); cs_ctrlreg_w!(self, cs, read_cmd); - if op_info.addr_len == 4 { + if matches!(op_info.address.width, AddressWidth::FourByte) { self.regs.fmc004().modify(|r, w| unsafe { let current = r.bits(); w.bits(current | (SPI_CTRL_CEX_4BYTE_MODE_SET << cs)) @@ -268,7 +270,7 @@ impl<'a> FmcController<'a> { if matches!(self.spi_config.ctrl_type, CtrlType::HostSpi) { self.regs.fmc06c().modify(|r, w| unsafe { let mut current = r.bits(); - if op_info.addr_len == 4 { + if matches!(op_info.address.width, AddressWidth::FourByte){ current = (current & 0xffff_00ff) | (op_info.opcode << 8); } else { current = (current & 0xffff_ff00) | op_info.opcode; @@ -506,13 +508,18 @@ impl<'a> FmcController<'a> { | spi_io_mode_user(u32::from(get_addr_buswidth(op_info.mode as u32))); cs_ctrlreg_w!(self, cs, addr_mode); - let mut addr = op_info.addr; - if op_info.addr_len == 3 { - addr <<= 8; + let be = op_info.address.value.to_be_bytes(); + + let bytes = match op_info.address.width { + AddressWidth::ThreeByte => &be[1..], // last 3 bytes (24-bit) + AddressWidth::FourByte => &be[..], + AddressWidth::None => &[], + }; + + unsafe { + super::spi_write_data(start_ptr, bytes); } - let addr_bytes = addr.to_be_bytes(); - unsafe { spi_write_data(start_ptr, &addr_bytes[..op_info.addr_len as usize]) }; // Dummy cycles let bus_width: u8 = get_addr_buswidth(op_info.mode as u32); @@ -543,7 +550,7 @@ impl<'a> FmcController<'a> { #[cfg(feature = "spi_dma")] { dbg!(self, "spi dma enabled rx_len:{}", op_info.rx_buf.len()); - let addr_aligned = op_info.addr % 4 == 0; + let addr_aligned = op_info.address.value % 4 == 0; if matches!(op_info.data_direct, DataDirection::DRead) { let buf_aligned = (op_info.rx_buf.as_ptr() as usize) % 4 == 0; @@ -669,7 +676,7 @@ impl<'a> FmcController<'a> { self.spi_data.decode_addr[cs].start, op.rx_buf.len(), (op.rx_buf.as_ptr() as u32), - op.addr); + op.address.value); // Length check if op.rx_buf.len() > self.spi_data.decode_addr[cs].len.try_into().unwrap() { @@ -677,8 +684,8 @@ impl<'a> FmcController<'a> { } // Alignment check - if (op.addr % 4 != 0) || ((op.rx_buf.as_ptr() as u32) % 4 != 0) { - return Err(SpiError::AddressNotAligned(op.addr)); + if (op.address.value % 4 != 0) || ((op.rx_buf.as_ptr() as u32) % 4 != 0) { + return Err(SpiError::AddressNotAligned(op.address.value)); } // Construct control value let mut ctrl = self.spi_data.cmd_mode[cs].normal_read & SPI_CTRL_FREQ_MASK; @@ -702,7 +709,7 @@ impl<'a> FmcController<'a> { while self.regs.fmc080().read().bits() & SPI_DMA_GRANT != SPI_DMA_GRANT {} } - let flash_start = self.spi_data.decode_addr[cs].start + op.addr - SPI_DMA_FLASH_MAP_BASE; + let flash_start = self.spi_data.decode_addr[cs].start + op.address.value - SPI_DMA_FLASH_MAP_BASE; dbg!(self, "flash start: 0x{:08x}", flash_start); // DMA flash and RAM address self.regs.fmc084().write(|w| unsafe { w.bits(flash_start) }); @@ -743,11 +750,11 @@ impl<'a> FmcController<'a> { self.spi_data.decode_addr[cs].start, op.tx_buf.len(), (op.tx_buf.as_ptr() as u32), - op.addr); + op.address.value); //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)); + if op.address.value % 4 != 0 || (op.tx_buf.as_ptr() as usize) % 4 != 0 { + return Err(SpiError::AddressNotAligned(op.address.value)); } if op.tx_buf.len() > self.spi_data.decode_addr[cs].len.try_into().unwrap() { return Err(SpiError::Other("Write length exceeds decode region")); @@ -773,7 +780,7 @@ impl<'a> FmcController<'a> { // Program addresses self.regs.fmc084().write(|w| unsafe { - w.bits(self.spi_data.decode_addr[cs].start + op.addr - SPI_DMA_FLASH_MAP_BASE) + w.bits(self.spi_data.decode_addr[cs].start + op.address.value - SPI_DMA_FLASH_MAP_BASE) }); self.regs.fmc088().write(|w| unsafe { w.bits(u32::try_from(op.tx_buf.as_ptr() as usize).unwrap() + SPI_DMA_RAM_MAP_BASE) @@ -867,7 +874,7 @@ impl<'a> SpiBus for FmcController<'a> { impl<'a> SpiBusWithCs for FmcController<'a> { fn select_cs(&mut self, cs: usize) -> Result<(), SpiError> { - if cs > self.spi_config.max_cs { + if cs >= self.spi_config.max_cs { return Err(SpiError::CsSelectFailed(cs)); } self.current_cs = cs; diff --git a/src/spi/norflash.rs b/src/spi/norflash.rs index d19306b..e759078 100644 --- a/src/spi/norflash.rs +++ b/src/spi/norflash.rs @@ -2,7 +2,7 @@ use super::device::ChipSelectDevice; use super::SpiBusWithCs; -use super::{norflash, SpiError,DataDirection}; +use super::{norflash, SpiError,DataDirection, FlashAddress, AddressWidth}; use crate::common::DummyDelay; use embedded_hal::delay::DelayNs; @@ -92,8 +92,7 @@ pub struct SpiNorCommand<'a> { pub mode: Jesd216Mode, pub opcode: u32, pub dummy_cycle: u32, - pub addr_len: u32, - pub addr: u32, + pub address: FlashAddress, pub data_len: u32, pub tx_buf: &'a [u8], pub rx_buf: &'a mut [u8], @@ -156,8 +155,7 @@ where mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_WREN, dummy_cycle: 0, - addr: 0, - addr_len: 0, + address: FlashAddress { value: 0, width: AddressWidth::None }, data_len: 0, data_direct: DataDirection::DWrite, tx_buf: &[], @@ -172,8 +170,7 @@ where mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_WRDI, dummy_cycle: 0, - addr: 0, - addr_len: 0, + address: FlashAddress { value: 0, width: AddressWidth::None }, data_len: 0, data_direct: DataDirection::DWrite, tx_buf: &[], @@ -189,8 +186,7 @@ where mode: Jesd216Mode::Mode111, opcode: 0x9F, dummy_cycle: 0, - addr: 0, - addr_len: 0, + address: FlashAddress { value: 0, width: AddressWidth::None }, data_len: 0, rx_buf: &mut read_buf, tx_buf: &[], @@ -200,15 +196,14 @@ where Ok([read_buf[0], read_buf[1], read_buf[2]]) } - fn nor_sector_erase(&mut self, address: u32) -> Result<(), Self::Error> { + fn nor_sector_erase(&mut self, addr: u32) -> Result<(), Self::Error> { self.nor_write_enable()?; - if self.nor_sector_aligned(address) { + if self.nor_sector_aligned(addr) { let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_SE, dummy_cycle: 0, - addr: address, - addr_len: 3, + address: FlashAddress { value: addr, width: AddressWidth::ThreeByte }, data_len: 0, tx_buf: &[], rx_buf: &mut [], @@ -218,18 +213,17 @@ where self.nor_wait_until_ready(); Ok(()) } else { - Err(SpiError::AddressNotAligned(address)) + Err(SpiError::AddressNotAligned(addr)) } } - fn nor_page_program(&mut self, address: u32, data: &[u8]) -> Result<(), Self::Error> { + fn nor_page_program(&mut self, addr: u32, data: &[u8]) -> Result<(), Self::Error> { self.nor_write_enable()?; let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP, dummy_cycle: 0, - addr: address, - addr_len: 3, + address: FlashAddress { value: addr, width: AddressWidth::ThreeByte }, data_len: u32::try_from(data.len()).unwrap(), tx_buf: data, rx_buf: &mut [], @@ -239,14 +233,13 @@ where Ok(()) } - fn nor_page_program_4b(&mut self, address: u32, data: &[u8]) -> Result<(), Self::Error> { + fn nor_page_program_4b(&mut self, addr: u32, data: &[u8]) -> Result<(), Self::Error> { self.nor_write_enable()?; let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP_4B, dummy_cycle: 0, - addr: address, - addr_len: 4, + address: FlashAddress { value: addr, width: AddressWidth::FourByte }, data_len: u32::try_from(data.len()).unwrap(), tx_buf: data, rx_buf: &mut [], @@ -256,14 +249,13 @@ where Ok(()) } - fn nor_read_data(&mut self, address: u32, buf: &mut [u8]) -> Result<(), Self::Error> { + fn nor_read_data(&mut self, addr: u32, buf: &mut [u8]) -> Result<(), Self::Error> { let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode114, opcode: SPI_NOR_CMD_QREAD, dummy_cycle: 8, - addr: address, - addr_len: 3, - data_len: u32::try_from(buf.len()).unwrap(), // it is not in used. + address: FlashAddress { value: addr, width: AddressWidth::ThreeByte }, + data_len: u32::try_from(buf.len()).unwrap(), tx_buf: &[], rx_buf: buf, data_direct: DataDirection::DRead, @@ -272,14 +264,13 @@ where Ok(()) } - fn nor_read_fast_4b_data(&mut self, address: u32, buf: &mut [u8]) -> Result<(), Self::Error> { + fn nor_read_fast_4b_data(&mut self, addr: u32, buf: &mut [u8]) -> Result<(), Self::Error> { let mut nor_data = SpiNorCommand { mode: Jesd216Mode::Mode111Fast, opcode: SPI_NOR_CMD_READ_FAST_4B, dummy_cycle: 8, - addr: address, - addr_len: 4, - data_len: u32::try_from(buf.len()).unwrap(), // it is not in used. + address: FlashAddress { value: addr, width: AddressWidth::FourByte }, + data_len: u32::try_from(buf.len()).unwrap(), tx_buf: &[], rx_buf: buf, data_direct: DataDirection::DRead, @@ -294,9 +285,8 @@ where mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_RESET_EN, dummy_cycle: 0, - addr: 0x0, - addr_len: 0x0, - data_len: 0x0, // it is not in used. + address: FlashAddress { value: 0x0, width: AddressWidth::None }, + data_len: 0, tx_buf: &[], rx_buf: &mut [], data_direct: DataDirection::DWrite, @@ -310,9 +300,8 @@ where mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_RESET_MEM, dummy_cycle: 0, - addr: 0x0, - addr_len: 0x0, - data_len: 0x0, // it is not in used. + address: FlashAddress { value: 0x0, width: AddressWidth::None }, + data_len: 0x0, tx_buf: &[], rx_buf: &mut [], data_direct: DataDirection::DWrite, @@ -347,11 +336,11 @@ where Ok(()) } - fn nor_sector_aligned(&mut self, address: u32) -> bool { + fn nor_sector_aligned(&mut self, addr: u32) -> bool { //let (flash_sz, sector_sz) = self.bus.get_device_info(self.cs); let bits = 12; let mask = (1 << bits) - 1; - (address & mask) == 0 + (addr & mask) == 0 } fn nor_wait_until_ready(&mut self) { @@ -362,9 +351,8 @@ where mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_RDSR, dummy_cycle: 0, - addr: 0, - addr_len: 0, - data_len: 1, // it is not in used. + address: FlashAddress { value: 0, width: AddressWidth::None }, + data_len: 1, tx_buf: &[], rx_buf: &mut buf, data_direct: DataDirection::DRead, diff --git a/src/spi/spicontroller.rs b/src/spi/spicontroller.rs index a6f4515..10c6b18 100644 --- a/src/spi/spicontroller.rs +++ b/src/spi/spicontroller.rs @@ -4,7 +4,7 @@ use super::{ aspeed_get_spi_freq_div, get_addr_buswidth, get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, spi_io_mode, spi_io_mode_user, spi_read_data, spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, get_cmd_buswidth, - get_data_buswidth,DataDirection + get_data_buswidth, DataDirection, AddressWidth, FlashAddress }; use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, @@ -256,16 +256,18 @@ impl<'a> SpiController<'a> { self.spi_data.cmd_mode[cs].normal_read = read_cmd; dbg!( self, - "cs: {:08x}, io_mode: {:08x}, dummy: {:08x}, op: {:08x}, normal read: {:08x}", + "cs: {:08x}, io_mode: {:08x}, dummy: {:08x}, op: {:08x}, normal read: {:08x}, + address{:08x}", cs, io_mode, dummy, op_info.opcode, - read_cmd + read_cmd, + op_info.address.value ); cs_ctrlreg_w!(self, cs, read_cmd); - if op_info.addr_len == 4 { + if matches!(op_info.address.width, AddressWidth::FourByte) { self.regs.spi004().modify(|r, w| unsafe { let current = r.bits(); w.bits(current | (SPI_CTRL_CEX_4BYTE_MODE_SET << cs)) @@ -274,7 +276,7 @@ impl<'a> SpiController<'a> { if matches!(self.spi_config.ctrl_type, CtrlType::HostSpi) { self.regs.spi06c().modify(|r, w| unsafe { let mut current = r.bits(); - if op_info.addr_len == 4 { + if matches!(op_info.address.width, AddressWidth::FourByte) { current = (current & 0xffff_00ff) | (op_info.opcode << 8); } else { current = (current & 0xffff_ff00) | op_info.opcode; @@ -304,7 +306,7 @@ impl<'a> SpiController<'a> { self.regs.spi074().modify(|r, w| unsafe { let mut current = r.bits(); - if op_info.addr_len == 4 { + if matches!(op_info.address.width, AddressWidth::FourByte) { current = (current & 0xffff_00ff) | (op_info.opcode << 8); } else { current = (current & 0xffff_ff00) | op_info.opcode; @@ -536,13 +538,17 @@ impl<'a> SpiController<'a> { | spi_io_mode_user(u32::from(get_addr_buswidth(op_info.mode as u32))); cs_ctrlreg_w!(self, cs, addr_mode); - let mut addr = op_info.addr; - if op_info.addr_len == 3 { - addr <<= 8; + let be = op_info.address.value.to_be_bytes(); + + let bytes = match op_info.address.width { + AddressWidth::ThreeByte => &be[1..], // last 3 bytes (24-bit) + AddressWidth::FourByte => &be[..], + AddressWidth::None => &[], + }; + + unsafe { + super::spi_write_data(start_ptr, bytes); } - //op_info.addr = sys_cpu_to_be32(op_info.addr); - let addr_bytes = addr.to_be_bytes(); - unsafe { spi_write_data(start_ptr, &addr_bytes[..op_info.addr_len as usize]) }; // Dummy cycles let bus_width: u8 = get_addr_buswidth(op_info.mode as u32); @@ -580,7 +586,7 @@ impl<'a> SpiController<'a> { op_info.tx_buf.as_ptr(), op_info.tx_buf.len() ); - let addr_aligned = op_info.addr % 4 == 0; + let addr_aligned = op_info.address.value % 4 == 0; if matches!(op_info.data_direct, DataDirection::DRead) { let buf_aligned = (op_info.rx_buf.as_ptr() as usize) % 4 == 0; @@ -709,7 +715,7 @@ impl<'a> SpiController<'a> { self.spi_data.decode_addr[cs].start, op.rx_buf.len(), (op.rx_buf.as_ptr() as u32), - op.addr); + op.address.value); // Length check if op.rx_buf.len() > self.spi_data.decode_addr[cs].len.try_into().unwrap() { @@ -717,8 +723,8 @@ impl<'a> SpiController<'a> { } // Alignment check - if (op.addr % 4 != 0) || ((op.rx_buf.as_ptr() as u32) % 4 != 0) { - return Err(SpiError::AddressNotAligned(op.addr)); + if (op.address.value % 4 != 0) || ((op.rx_buf.as_ptr() as u32) % 4 != 0) { + return Err(SpiError::AddressNotAligned(op.address.value)); } dbg!(self, "set ctrl "); @@ -743,7 +749,7 @@ impl<'a> SpiController<'a> { while self.regs.spi080().read().bits() & SPI_DMA_GRANT != SPI_DMA_GRANT {} } - let flash_start = self.spi_data.decode_addr[cs].start + op.addr - SPI_DMA_FLASH_MAP_BASE; + let flash_start = self.spi_data.decode_addr[cs].start + op.address.value - SPI_DMA_FLASH_MAP_BASE; dbg!(self, "flash start: 0x{:08x}", flash_start); // DMA flash and RAM address @@ -782,8 +788,8 @@ impl<'a> SpiController<'a> { //dbg!(self, "##### write_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)); + if op.address.value % 4 != 0 || (op.tx_buf.as_ptr() as usize) % 4 != 0 { + return Err(SpiError::AddressNotAligned(op.address.value)); } if op.tx_buf.len() > self.spi_data.decode_addr[cs].len.try_into().unwrap() { return Err(SpiError::Other("Write length exceeds decode region")); @@ -800,7 +806,7 @@ impl<'a> SpiController<'a> { self, "write opcode: {} , addr/offset: {}", op.opcode, - op.addr + op.address.value ); cs_ctrlreg_w!(self, cs, ctrl_reg); @@ -814,7 +820,7 @@ impl<'a> SpiController<'a> { // Program addresses self.regs.spi084().write(|w| unsafe { - w.bits(self.spi_data.decode_addr[cs].start + op.addr - SPI_DMA_FLASH_MAP_BASE) + w.bits(self.spi_data.decode_addr[cs].start + op.address.value - SPI_DMA_FLASH_MAP_BASE) }); self.regs.spi088().write(|w| unsafe { w.bits(u32::try_from(op.tx_buf.as_ptr() as usize).unwrap() + SPI_DMA_RAM_MAP_BASE) @@ -913,7 +919,7 @@ impl<'a> SpiBus for SpiController<'a> { impl<'a> SpiBusWithCs for SpiController<'a> { fn select_cs(&mut self, cs: usize) -> Result<(), SpiError> { - if cs > self.spi_config.max_cs { + if cs >= self.spi_config.max_cs { return Err(SpiError::CsSelectFailed(cs)); } self.current_cs = cs; diff --git a/src/spi/spidmairqtest.rs b/src/spi/spidmairqtest.rs index df2cd82..3f5c496 100644 --- a/src/spi/spidmairqtest.rs +++ b/src/spi/spidmairqtest.rs @@ -416,7 +416,7 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { fill_dma_buffer(DmaOp::Read, false, 0); dma_irq_chain_test(&start_addrs, DmaOp::Read, false); } else { - fill_dma_buffer(DmaOp::Program, true, 0x456); + fill_dma_buffer(DmaOp::Program, true, 0xfed); let _ = dev1.nor_sector_erase(0x0000_0000); delay.delay_ns(8_000_000); // NOTE: DMA write has an issue in AST2600-Errata-11 @@ -496,7 +496,7 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { fill_dma_buffer(DmaOp::ReadFast, false, 0); dma_irq_chain_test(&start_addrs, DmaOp::ReadFast, false); } else { - fill_dma_buffer(DmaOp::Program, true, 0xdeed); + fill_dma_buffer(DmaOp::Program, true, 0xce12); let _ = dev0.nor_sector_erase(0x0000_0000); delay.delay_ns(8_000_000); dma_irq_chain_test(&start_addrs, DmaOp::ProgramFast, false); diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index 2d7af0c..e72c9b8 100644 --- a/src/spi/spitest.rs +++ b/src/spi/spitest.rs @@ -9,7 +9,8 @@ use super::norflash::{ Jesd216Mode, SpiNorCommand, SpiNorDevice, SPI_NOR_CMD_QREAD, SPI_NOR_CMD_READ_FAST_4B, }; use super::{ norflash }; -use super::{CommandMode, CtrlType, SpiConfig, SpiData, SpiDecodeAddress, DataDirection}; +use super::{CommandMode, CtrlType, SpiConfig, SpiData, SpiDecodeAddress, DataDirection, + AddressWidth, FlashAddress}; use crate::common::{self, DmaBuffer, DummyDelay}; use crate::spi::norflashblockdevice; use crate::spi::norflashblockdevice::{BlockAddrUsize, NorFlashBlockDevice}; @@ -120,8 +121,7 @@ pub fn nor_device_read_data<'a>(len: usize) -> SpiNorCommand<'a> { mode: Jesd216Mode::Mode114, opcode: SPI_NOR_CMD_QREAD, dummy_cycle: 8, - addr: 0, - addr_len: 3, + address: FlashAddress { value: 0x0, width: AddressWidth::ThreeByte }, data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], @@ -135,8 +135,7 @@ pub fn nor_device_write_data<'a>(len: usize) -> SpiNorCommand<'a> { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP, dummy_cycle: 0, - addr: 0, - addr_len: 3, + address: FlashAddress { value: 0x0, width: AddressWidth::ThreeByte }, data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], @@ -150,8 +149,7 @@ pub fn nor_device_read_4b_data<'a>(len: usize) -> SpiNorCommand<'a> { mode: Jesd216Mode::Mode111Fast, opcode: SPI_NOR_CMD_READ_FAST_4B, dummy_cycle: 8, - addr: 0, - addr_len: 4, + address: FlashAddress { value: 0x0, width: AddressWidth::FourByte }, data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], @@ -165,8 +163,7 @@ pub fn nor_device_write_4b_data<'a>(len: usize) -> SpiNorCommand<'a> { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP_4B, dummy_cycle: 0, - addr: 0, - addr_len: 4, + address: FlashAddress { value: 0x0, width: AddressWidth::FourByte }, data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], diff --git a/src/spi/types.rs b/src/spi/types.rs index a95dfe9..0d4706b 100644 --- a/src/spi/types.rs +++ b/src/spi/types.rs @@ -16,6 +16,7 @@ pub struct FlashAddress { pub enum AddressWidth { ThreeByte, FourByte, + None, } #[derive(Clone, Copy)] diff --git a/src/spi/util.rs b/src/spi/util.rs index 6f37d11..1fee0c5 100644 --- a/src/spi/util.rs +++ b/src/spi/util.rs @@ -192,7 +192,7 @@ pub unsafe fn spi_read_data(ahb_addr: *const u32, read_arr: &mut [u8]) { #[allow(clippy::missing_safety_doc)] pub unsafe fn spi_write_data(ahb_addr: *mut u32, write_arr: &[u8]) { - if write_arr.is_empty() { + if write_arr.is_empty() { return; } From 4c9d483a889748fb5655214581a6278afd9f66b8 Mon Sep 17 00:00:00 2001 From: hailin wu Date: Tue, 3 Mar 2026 16:26:53 -0800 Subject: [PATCH 08/10] fixed clippying errors --- src/main.rs | 4 +- src/spi/device.rs | 8 +- src/spi/fmccontroller.rs | 12 +- src/spi/norflash.rs | 2 +- src/spi/spicontroller.rs | 12 +- src/spi/spidmairqtest.rs | 257 +++++++++++++++++---------------------- src/spi/spim.rs | 1 + src/spi/spitest.rs | 5 - src/spi/util.rs | 5 +- 9 files changed, 135 insertions(+), 171 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7f45fca..06fbceb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -373,8 +373,8 @@ fn main() -> ! { test_wdt(&mut uart_controller); run_timer_tests(&mut uart_controller); - let test_spicontroller = false; - let test_irq = false; + let test_spicontroller = true; + let test_irq = true; if test_spicontroller { if test_irq { writeln!(uart_controller, "\r\nTEST SPI IRQ!!\r\n").unwrap(); diff --git a/src/spi/device.rs b/src/spi/device.rs index b4dc57e..9fae7d9 100644 --- a/src/spi/device.rs +++ b/src/spi/device.rs @@ -16,7 +16,7 @@ where pub spim: Option, } -impl<'a, B> ErrorType for ChipSelectDevice<'a, B> +impl ErrorType for ChipSelectDevice<'_, B> where B: SpiBusWithCs, { @@ -30,7 +30,7 @@ impl From for u32 { } } -impl<'a, B> SpiDevice for ChipSelectDevice<'a, B> +impl SpiDevice for ChipSelectDevice<'_, B> where B: SpiBusWithCs, { @@ -50,8 +50,8 @@ where Operation::Write(buf) => self.bus.write(buf)?, Operation::Transfer(read, write) => self.bus.transfer(read, write)?, Operation::TransferInPlace(buf) => self.bus.transfer_in_place(buf)?, - Operation::DelayNs(_) => todo!(), - }; + Operation::DelayNs(_) => {}, // Ignore delay, as the SPI controller will handle timing + } } if let Some(_spim) = self.spim { super::spim_proprietary_post_config(); diff --git a/src/spi/fmccontroller.rs b/src/spi/fmccontroller.rs index b55f4cb..707b410 100644 --- a/src/spi/fmccontroller.rs +++ b/src/spi/fmccontroller.rs @@ -4,7 +4,7 @@ use super::{ aspeed_get_spi_freq_div, get_addr_buswidth, get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, spi_io_mode, spi_io_mode_user, spi_read_data, spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, get_cmd_buswidth, - get_data_buswidth, DataDirection, AddressWidth, FlashAddress + get_data_buswidth, DataDirection, AddressWidth, }; use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, ASPEED_SPI_SZ_2M, ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, @@ -28,7 +28,7 @@ use embedded_hal::{ spi::{ErrorType, SpiBus}, }; -impl<'a> ErrorType for FmcController<'a> { +impl ErrorType for FmcController<'_> { type Error = SpiError; } @@ -684,7 +684,7 @@ impl<'a> FmcController<'a> { } // Alignment check - if (op.address.value % 4 != 0) || ((op.rx_buf.as_ptr() as u32) % 4 != 0) { + if !op.address.value.is_multiple_of(4) || !(op.rx_buf.as_ptr() as u32).is_multiple_of(4) { return Err(SpiError::AddressNotAligned(op.address.value)); } // Construct control value @@ -753,7 +753,7 @@ impl<'a> FmcController<'a> { op.address.value); //self.dbg_fmc_dma(); // Check alignment and bounds - if op.address.value % 4 != 0 || (op.tx_buf.as_ptr() as usize) % 4 != 0 { + if !op.address.value.is_multiple_of(4) || !(op.tx_buf.as_ptr() as usize).is_multiple_of(4) { return Err(SpiError::AddressNotAligned(op.address.value)); } if op.tx_buf.len() > self.spi_data.decode_addr[cs].len.try_into().unwrap() { @@ -828,7 +828,7 @@ impl<'a> FmcController<'a> { } } -impl<'a> SpiBus for FmcController<'a> { +impl SpiBus for FmcController<'_> { // 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; @@ -872,7 +872,7 @@ impl<'a> SpiBus for FmcController<'a> { } } -impl<'a> SpiBusWithCs for FmcController<'a> { +impl SpiBusWithCs for FmcController<'_> { fn select_cs(&mut self, cs: usize) -> Result<(), SpiError> { if cs >= self.spi_config.max_cs { return Err(SpiError::CsSelectFailed(cs)); diff --git a/src/spi/norflash.rs b/src/spi/norflash.rs index e759078..88e6075 100644 --- a/src/spi/norflash.rs +++ b/src/spi/norflash.rs @@ -144,7 +144,7 @@ macro_rules! start_transfer { } //TODO: add 4byte address mode support -impl<'a, B> SpiNorDevice for ChipSelectDevice<'a, B> +impl SpiNorDevice for ChipSelectDevice<'_, B> where B: SpiBusWithCs, { diff --git a/src/spi/spicontroller.rs b/src/spi/spicontroller.rs index e0b201b..43347d6 100644 --- a/src/spi/spicontroller.rs +++ b/src/spi/spicontroller.rs @@ -4,7 +4,7 @@ use super::{ aspeed_get_spi_freq_div, get_addr_buswidth, get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, spi_io_mode, spi_io_mode_user, spi_read_data, spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, get_cmd_buswidth, - get_data_buswidth, DataDirection, AddressWidth, FlashAddress + get_data_buswidth, DataDirection, AddressWidth, }; use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, @@ -29,7 +29,7 @@ use embedded_hal::{ delay::DelayNs, spi::{ErrorType, SpiBus}, }; -impl<'a> ErrorType for SpiController<'a> { +impl ErrorType for SpiController<'_> { type Error = SpiError; } @@ -723,7 +723,7 @@ impl<'a> SpiController<'a> { } // Alignment check - if (op.address.value % 4 != 0) || ((op.rx_buf.as_ptr() as u32) % 4 != 0) { + if !op.address.value.is_multiple_of(4) || !(op.rx_buf.as_ptr() as u32).is_multiple_of(4) { return Err(SpiError::AddressNotAligned(op.address.value)); } @@ -788,7 +788,7 @@ impl<'a> SpiController<'a> { //dbg!(self, "##### write_dma ####"); // Check alignment and bounds - if op.address.value % 4 != 0 || (op.tx_buf.as_ptr() as usize) % 4 != 0 { + if !op.address.value.is_multiple_of(4) || !(op.tx_buf.as_ptr() as usize).is_multiple_of(4) { return Err(SpiError::AddressNotAligned(op.address.value)); } if op.tx_buf.len() > self.spi_data.decode_addr[cs].len.try_into().unwrap() { @@ -868,7 +868,7 @@ impl<'a> SpiController<'a> { } } -impl<'a> SpiBus for SpiController<'a> { +impl SpiBus for SpiController<'_> { // 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; @@ -917,7 +917,7 @@ impl<'a> SpiBus for SpiController<'a> { } } -impl<'a> SpiBusWithCs for SpiController<'a> { +impl SpiBusWithCs for SpiController<'_> { fn select_cs(&mut self, cs: usize) -> Result<(), SpiError> { if cs >= self.spi_config.max_cs { return Err(SpiError::CsSelectFailed(cs)); diff --git a/src/spi/spidmairqtest.rs b/src/spi/spidmairqtest.rs index fbf17d3..377aea2 100644 --- a/src/spi/spidmairqtest.rs +++ b/src/spi/spidmairqtest.rs @@ -8,17 +8,17 @@ use crate::spi::device::ChipSelectDevice; use crate::spi::norflash::{SpiNorCommand, SpiNorDevice}; use crate::spi::spicontroller::SpiController; use crate::spi::spitest::{self, DeviceId, FMC_CONFIG}; -use crate::spi::SpiData; +use crate::spi::{SpiData, SpiError}; use crate::spimonitor::SpiMonitorNum; -use crate::uart_core::UartController; +use crate::uart_core::{UartController, UartConfig}; use crate::{astdebug, pinctrl}; use core::ptr; +use core::result::Result; 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; @@ -70,34 +70,34 @@ static mut CURRENT_DMA: Option = None; static mut DMA_QUEUE: Deque = Deque::new(); static mut CURRENT_DEVID: DeviceId = DeviceId::FmcCs0Idx; +static mut FMC_IRQ_RESULT: Option> = None; +static mut FMC_IRQ_EVENT: bool = false; + +static mut SPI_IRQ_RESULT: Option> = None; +static mut SPI_IRQ_EVENT: bool = false; + #[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(); + let result = fmc.handle_interrupt(); + + FMC_IRQ_RESULT = Some(result); + FMC_IRQ_EVENT = true; + + // Continue minimal DMA handling logic + if let Some(req) = CURRENT_DMA.take() { + if matches!(req.op, DmaOp::Program | DmaOp::ProgramFast) { + let dev = match CURRENT_DEVID { + DeviceId::FmcCs0Idx => &mut *FMC_DEV0_PTR, + DeviceId::FmcCs1Idx => &mut *FMC_DEV1_PTR, + _ => return, + }; + dev.nor_wait_until_ready(); } - start_next_dma(); + (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); } + let _ = start_next_dma(); } } @@ -105,103 +105,88 @@ pub extern "C" fn fmc() { pub extern "C" fn spi() { unsafe { let spi = SPI_CONTROLLER.as_mut().unwrap(); - let uart = UART_PTR.as_mut().unwrap(); + let result = spi.handle_interrupt(); - 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(); - } + SPI_IRQ_RESULT = Some(result); + SPI_IRQ_EVENT = true; - start_next_dma(); - } + if let Some(req) = CURRENT_DMA.take() { + (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); + } + let _ = 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(); - } + ($uart:expr, $($arg:tt)*) => {{ + writeln!($uart, $($arg)*).ok(); + write!($uart, "\r").ok(); }}; } - -unsafe fn show_mmap_reg() { +#[allow(dead_code)] +unsafe fn show_mmap_reg(uart: &mut UartController<'_>) { 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); - } + log_uart!(uart, "[{:08x}]", mmap_addr); astdebug::print_reg_u8(uart, mmap_addr, 0x400); } -unsafe fn start_next_dma() { + +#[allow(clippy::result_unit_err)] +#[allow(clippy::missing_safety_doc)] +pub unsafe fn start_next_dma() -> Result<(), ()> { if DMA_QUEUE.is_empty() { REQUST_ALLDONE = true; - unsafe { - log_uart!("DMA queue is empty. All transfers are completed!!"); - } - show_mmap_reg(); - return; + return Ok(()); } - 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); - } - } - } + let Some(req) = DMA_QUEUE.pop_front() else { + // queue said not empty but pop failed (shouldn't happen) + return Err(()); + }; + + CURRENT_DMA = Some(req); + + match CURRENT_DEVID { + DeviceId::FmcCs0Idx | DeviceId::FmcCs1Idx => { + start_dma_fmc_transfer(CURRENT_DMA.as_mut().unwrap())?; + } + + DeviceId::Spi0Cs0Idx + | DeviceId::Spi1Cs0Idx + | DeviceId::Spi1Cs1Idx + | DeviceId::Spi0Cs1Idx => { + start_dma_spi_transfer(CURRENT_DMA.as_mut().unwrap())?; } } + + Ok(()) } pub fn on_complete_dma(verify: bool, idx: usize, _buf: &[u8]) { + let uart_regs = unsafe { &*ast1060_pac::Uart::ptr() }; + let mut uart_controller = UartController::new(uart_regs); + uart_controller.init(&UartConfig::default()).unwrap(); + if verify { - if verify_dma_buffer_match(idx) { - unsafe { - log_uart!("DMA test passed!!"); - } - } else { - unsafe { - log_uart!("DMA test failed!!"); - } + if verify_dma_buffer_match(&mut uart_controller, idx) { + log_uart!(&mut uart_controller, "DMA test passed!!"); + } else { + log_uart!(&mut uart_controller, "DMA test failed!!"); } - } //else if let Some(uart) = unsafe { UART_PTR.as_mut() } { - // astdebug::print_array_u8(uart, buf); + } //else if { + // astdebug::print_array_u8(&mut uart_controller, buf); //} } // Start DMA transfer using the device -fn start_dma_spi_transfer(req: &mut DmaRequest) -> Result<(), ()> { - unsafe { - log_uart!("spi start_dma_transfer"); +fn start_dma_spi_transfer( req: &mut DmaRequest) -> Result<(), ()> { + unsafe { let dev = match CURRENT_DEVID { DeviceId::Spi0Cs0Idx => SPI_DEV0_PTR.as_mut().unwrap(), - _ => todo!(), + _ => return Err(()), }; - let result = match req.op { + 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) @@ -213,24 +198,20 @@ fn start_dma_spi_transfer(req: &mut DmaRequest) -> Result<(), ()> { 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); - }) + result.map_err(|_| ()) } } // Start DMA transfer using the device -fn start_dma_fmc_transfer(req: &mut DmaRequest) -> Result<(), ()> { +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!(), + _ => return Err(()), }; - let result = match req.op { + 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) @@ -242,15 +223,12 @@ fn start_dma_fmc_transfer(req: &mut DmaRequest) -> Result<(), ()> { 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); - }) + result.map_err(|_| ()) } } #[must_use] -pub fn verify_dma_buffer_match(i: usize) -> bool { +pub fn verify_dma_buffer_match(uart: &mut UartController<'_>, 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); @@ -259,7 +237,7 @@ pub fn verify_dma_buffer_match(i: usize) -> bool { // 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!( + log_uart!(uart, "Mismatch at buffer {}, index {}: read={:02x}, expected={:02x}", i, j, @@ -268,11 +246,10 @@ pub fn verify_dma_buffer_match(i: usize) -> bool { ); break; } - } - if let Some(uart) = UART_PTR.as_mut() { - astdebug::print_array_u8(uart, read); - astdebug::print_array_u8(uart, write); - } + } + astdebug::print_array_u8(uart, read); + astdebug::print_array_u8(uart, write); + return false; } } @@ -302,15 +279,13 @@ pub fn fill_dma_buffer(op_req: DmaOp, random: bool, pattern: u32) { } // Example use #[allow(clippy::missing_safety_doc)] -pub unsafe fn dma_irq_chain_test(start_addrs: &[u32], op_req: DmaOp, verify: bool) { +pub unsafe fn dma_irq_chain_test(uart: &mut UartController<'_>, 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); - } + log_uart!(uart, "Too many DMA addresses; max is {}", MAX_DMA_CHAIN); break; } @@ -329,11 +304,11 @@ pub unsafe fn dma_irq_chain_test(start_addrs: &[u32], op_req: DmaOp, verify: boo on_complete: on_complete_dma, }; DMA_QUEUE.push_back(request).unwrap(); - unsafe { - log_uart!("chaining {}", i); - } + log_uart!(uart, "chaining {}", i); + } //for - start_next_dma(); + let _ = start_next_dma(); + } pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { @@ -342,14 +317,10 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { 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)); + /* irq init */ NVIC::unmask(ast1060_pac::Interrupt::fmc); FMC_CONTROLLER = Some(FmcController::new( @@ -357,10 +328,10 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { 0, FMC_CONFIG, fmc_data, - Some(UART_PTR.as_mut().unwrap()), + None, )); - log_uart!("==== FMC DEV0 DMA read Test===="); + log_uart!(uart, "==== FMC DEV0 DMA read Test===="); let controller = FMC_CONTROLLER.as_mut().unwrap(); let _ = controller.init(); @@ -388,11 +359,11 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { CURRENT_DEVID = DeviceId::FmcCs0Idx; fill_dma_buffer(DmaOp::Read, true, 0); delay.delay_ns(8_000_000); - dma_irq_chain_test(&start_addrs, DmaOp::Read, false); + dma_irq_chain_test(uart, &start_addrs, DmaOp::Read, false); delay.delay_ns(8_000_000); - log_uart!("==== FMC DEV1 DMA Slow read & write Test===="); + log_uart!(uart, "==== FMC DEV1 DMA Slow read & write Test===="); let controller1 = FMC_CONTROLLER.as_mut().unwrap(); let flash_device1 = ChipSelectDevice { bus: controller1, // reuse same ref @@ -414,20 +385,20 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { CURRENT_DEVID = DeviceId::FmcCs1Idx; if read_only { fill_dma_buffer(DmaOp::Read, false, 0); - dma_irq_chain_test(&start_addrs, DmaOp::Read, false); + dma_irq_chain_test(uart, &start_addrs, DmaOp::Read, false); } else { - fill_dma_buffer(DmaOp::Program, true, 0xfed); + fill_dma_buffer(DmaOp::Program, true, 0x3e4d); 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); + dma_irq_chain_test(uart, &start_addrs, DmaOp::Program, false); delay.delay_ns(8_000_000); if !REQUST_ALLDONE { - log_uart!("=ERROR: Programming race condition!!!!="); + log_uart!(uart, "=ERROR: Programming race condition!!!!="); } - dma_irq_chain_test(&start_addrs, DmaOp::Read, true); + dma_irq_chain_test(uart, &start_addrs, DmaOp::Read, true); } } //unsafe @@ -451,10 +422,6 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { 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( @@ -462,12 +429,12 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { current_cs, spitest::SPI0_CONFIG, spi_data, - Some(UART_PTR.as_mut().unwrap()), + None, )); let controller = SPI_CONTROLLER.as_mut().unwrap(); let _ = controller.init(); - log_uart!("==== SPI0 DEV0 DMA Test===="); + log_uart!(uart, "==== SPI0 DEV0 DMA Test===="); // You can now pass `fmc_ptr` into ChipSelectDevice or use it directly let nor_read_data: SpiNorCommand<'_> = spitest::nor_device_read_4b_data(spitest::SPI_CS0_CAPACITY); @@ -494,19 +461,19 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { let read_only = false; if read_only { fill_dma_buffer(DmaOp::ReadFast, false, 0); - dma_irq_chain_test(&start_addrs, DmaOp::ReadFast, false); + dma_irq_chain_test(uart,&start_addrs, DmaOp::ReadFast, false); } else { - fill_dma_buffer(DmaOp::Program, true, 0xce12); + fill_dma_buffer(DmaOp::Program, true, 0xd3e1); let _ = dev0.nor_sector_erase(0x0000_0000); delay.delay_ns(8_000_000); - dma_irq_chain_test(&start_addrs, DmaOp::ProgramFast, false); + dma_irq_chain_test(uart, &start_addrs, DmaOp::ProgramFast, false); delay.delay_ns(8_000_000); if !REQUST_ALLDONE { - log_uart!("=ERROR: Programming race condition!!!!="); + log_uart!(uart, "=ERROR: Programming race condition!!!!="); } - dma_irq_chain_test(&start_addrs, DmaOp::ReadFast, true); + dma_irq_chain_test(uart,&start_addrs, DmaOp::ReadFast, true); } - log_uart!("==== End SPI0 DEV0 DMA Test===="); + log_uart!(uart, "==== End SPI0 DEV0 DMA Test===="); } //unsafe scu_qspi_mux[0] = 0x0000_0000; diff --git a/src/spi/spim.rs b/src/spi/spim.rs index ba54f5a..799a4a9 100644 --- a/src/spi/spim.rs +++ b/src/spi/spim.rs @@ -10,6 +10,7 @@ use super::consts::{PIN_SPIM0_CLK_OUT_BIT, PIN_SPIM1_CLK_OUT_BIT, PIN_SPIM2_CLK_ static GPIO_ORI_VAL: Mutex<[Cell; 4]> = Mutex::new([const { Cell::new(0) }; 4]); +#[must_use] pub fn get_gpio_ori_val() -> [u32; 4] { critical_section::with(|crit| { let v = GPIO_ORI_VAL.borrow(crit); diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index efaa970..24dfae6 100644 --- a/src/spi/spitest.rs +++ b/src/spi/spitest.rs @@ -18,7 +18,6 @@ use crate::spi::spicontroller::SpiController; use crate::spimonitor::SpiMonitorNum; use crate::uart_core::{UartConfig, UartController}; use crate::{astdebug, pinctrl}; -use ast1060_pac::Peripherals; use embedded_hal::delay::DelayNs; use embedded_hal::spi::SpiDevice; use proposed_traits::block_device::{BlockDevice, BlockRange}; @@ -317,7 +316,6 @@ pub fn test_fmc(uart: &mut UartController<'_>) { let current_cs = 0x0; let fmc_data = SpiData::new(); - let peripherals = unsafe { Peripherals::steal() }; let uart_regs = unsafe { &*ast1060_pac::Uart::ptr() }; let mut uart_controller = UartController::new(uart_regs); uart_controller.init(&UartConfig::default()).unwrap(); @@ -394,7 +392,6 @@ pub fn test_spi(uart: &mut UartController<'_>) { //astdebug::print_reg_u32(uart, SCU_BASE + 0x00, 0x100); let spi_data = SpiData::new(); - let peripherals = unsafe { Peripherals::steal() }; let uart_regs = unsafe { &*ast1060_pac::Uart::ptr() }; let mut spi_uart_controller = UartController::new(uart_regs); spi_uart_controller.init(&UartConfig::default()).unwrap(); @@ -514,7 +511,6 @@ pub fn test_spi(uart: &mut UartController<'_>) { } pub fn test_block_device(blockdev: &mut NorFlashBlockDevice) { - let peripherals = unsafe { Peripherals::steal() }; let uart_regs = unsafe { &*ast1060_pac::Uart::ptr() }; let mut uartc = UartController::new(uart_regs); let addr = 0x1000; @@ -613,7 +609,6 @@ pub fn test_spi2(uart: &mut UartController<'_>) { 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 uart_regs = unsafe { &*ast1060_pac::Uart::ptr() }; let mut uart_controller = UartController::new(uart_regs); uart_controller.init(&UartConfig::default()).unwrap(); diff --git a/src/spi/util.rs b/src/spi/util.rs index 1fee0c5..d83248a 100644 --- a/src/spi/util.rs +++ b/src/spi/util.rs @@ -65,13 +65,15 @@ pub fn spi_cal_dummy_cycle(bus_width: u32, dummy_cycle: u32) -> u32 { let dummy_byte = dummy_cycle / bits_per_cycle; ((dummy_byte & 0x3) << 6) | (((dummy_byte & 0x4) >> 2) << 14) } - +#[must_use] pub const fn get_cmd_buswidth(v: u32) -> u8 { ((v & 0x0000_0F00) >> 8) as u8 } +#[must_use] pub const fn get_addr_buswidth(v: u32) -> u8 { ((v & 0x0000_00F0) >> 4) as u8 } +#[must_use] pub const fn get_data_buswidth(v: u32) -> u8 { (v & 0x0000_000F) as u8 } @@ -85,7 +87,6 @@ pub const fn get_data_buswidth(v: u32) -> u8 { /// # Returns /// A 32-bit value encoding the frequency divider, /// or 0 if no valid divider found. - #[must_use] pub fn aspeed_get_spi_freq_div(bus_clk: u32, max_freq: u32) -> u32 { // Division mapping array matching C div_arr From 12328259057a858763e914be6706ca7437c32c9a Mon Sep 17 00:00:00 2001 From: hailin wu Date: Thu, 5 Mar 2026 16:24:09 -0800 Subject: [PATCH 09/10] fixed UART clippy issue in spidmatest --- src/spi/spidmairqtest.rs | 155 +++++++++++++++++---------------------- src/spi/spitest.rs | 12 +++ 2 files changed, 81 insertions(+), 86 deletions(-) diff --git a/src/spi/spidmairqtest.rs b/src/spi/spidmairqtest.rs index 377aea2..89419c6 100644 --- a/src/spi/spidmairqtest.rs +++ b/src/spi/spidmairqtest.rs @@ -8,16 +8,16 @@ use crate::spi::device::ChipSelectDevice; use crate::spi::norflash::{SpiNorCommand, SpiNorDevice}; use crate::spi::spicontroller::SpiController; use crate::spi::spitest::{self, DeviceId, FMC_CONFIG}; -use crate::spi::{SpiData, SpiError}; +use crate::spi::SpiData; use crate::spimonitor::SpiMonitorNum; use crate::uart_core::{UartController, UartConfig}; use crate::{astdebug, pinctrl}; use core::ptr; -use core::result::Result; use cortex_m::peripheral::NVIC; use embedded_hal::delay::DelayNs; use embedded_io::Write; use heapless::Deque; +use core::result::Result; static mut FMC_CONTROLLER: Option> = None; static mut SPI_CONTROLLER: Option> = None; @@ -70,34 +70,28 @@ static mut CURRENT_DMA: Option = None; static mut DMA_QUEUE: Deque = Deque::new(); static mut CURRENT_DEVID: DeviceId = DeviceId::FmcCs0Idx; -static mut FMC_IRQ_RESULT: Option> = None; -static mut FMC_IRQ_EVENT: bool = false; - -static mut SPI_IRQ_RESULT: Option> = None; -static mut SPI_IRQ_EVENT: bool = false; - #[no_mangle] pub extern "C" fn fmc() { unsafe { let fmc = FMC_CONTROLLER.as_mut().unwrap(); - let result = fmc.handle_interrupt(); - - FMC_IRQ_RESULT = Some(result); - FMC_IRQ_EVENT = true; - - // Continue minimal DMA handling logic - if let Some(req) = CURRENT_DMA.take() { - if matches!(req.op, DmaOp::Program | DmaOp::ProgramFast) { - let dev = match CURRENT_DEVID { - DeviceId::FmcCs0Idx => &mut *FMC_DEV0_PTR, - DeviceId::FmcCs1Idx => &mut *FMC_DEV1_PTR, - _ => return, - }; - dev.nor_wait_until_ready(); + + let dev = match CURRENT_DEVID { + DeviceId::FmcCs0Idx => FMC_DEV0_PTR.as_mut().unwrap(), + DeviceId::FmcCs1Idx => FMC_DEV1_PTR.as_mut().unwrap(), + _ => return, + }; + let irq_result = fmc.handle_interrupt(); + + if let Ok(_) = irq_result { + if let Some(req) = CURRENT_DMA.take() { + if matches!(req.op, DmaOp::Program | DmaOp::ProgramFast) { + dev.nor_wait_until_ready(); + } + (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); } - (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); + start_next_dma(); } - let _ = start_next_dma(); + } } @@ -105,15 +99,14 @@ pub extern "C" fn fmc() { pub extern "C" fn spi() { unsafe { let spi = SPI_CONTROLLER.as_mut().unwrap(); - let result = spi.handle_interrupt(); - - SPI_IRQ_RESULT = Some(result); - SPI_IRQ_EVENT = true; - - if let Some(req) = CURRENT_DMA.take() { - (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); - } - let _ = start_next_dma(); + let irq_result = spi.handle_interrupt(); + + if let Ok(_) = irq_result { + if let Some(req) = CURRENT_DMA.take() { + (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); + } + start_next_dma(); + } } } @@ -124,69 +117,59 @@ macro_rules! log_uart { write!($uart, "\r").ok(); }}; } -#[allow(dead_code)] + unsafe fn show_mmap_reg(uart: &mut UartController<'_>) { let (_reg_base, mmap_addr, _cs_capacity) = spitest::device_info(CURRENT_DEVID); log_uart!(uart, "[{:08x}]", mmap_addr); astdebug::print_reg_u8(uart, mmap_addr, 0x400); } - -#[allow(clippy::result_unit_err)] -#[allow(clippy::missing_safety_doc)] -pub unsafe fn start_next_dma() -> Result<(), ()> { +unsafe fn start_next_dma() { if DMA_QUEUE.is_empty() { - REQUST_ALLDONE = true; - return Ok(()); + REQUST_ALLDONE = true; + return; } - let Some(req) = DMA_QUEUE.pop_front() else { - // queue said not empty but pop failed (shouldn't happen) - return Err(()); - }; - - CURRENT_DMA = Some(req); - - match CURRENT_DEVID { - DeviceId::FmcCs0Idx | DeviceId::FmcCs1Idx => { - start_dma_fmc_transfer(CURRENT_DMA.as_mut().unwrap())?; - } - - DeviceId::Spi0Cs0Idx - | DeviceId::Spi1Cs0Idx - | DeviceId::Spi1Cs1Idx - | DeviceId::Spi0Cs1Idx => { - start_dma_spi_transfer(CURRENT_DMA.as_mut().unwrap())?; + if let Some(req) = DMA_QUEUE.pop_front() { + CURRENT_DMA = Some(req); + match CURRENT_DEVID { + DeviceId::FmcCs0Idx | DeviceId::FmcCs1Idx => { + let _= start_dma_fmc_transfer(CURRENT_DMA.as_mut().unwrap()); + } + DeviceId::Spi0Cs0Idx + | DeviceId::Spi1Cs0Idx + | DeviceId::Spi1Cs1Idx + | DeviceId::Spi0Cs1Idx => { + let _= start_dma_spi_transfer(CURRENT_DMA.as_mut().unwrap()); + } } } - - Ok(()) } -pub fn on_complete_dma(verify: bool, idx: usize, _buf: &[u8]) { - let uart_regs = unsafe { &*ast1060_pac::Uart::ptr() }; +pub fn on_complete_dma( verify: bool, idx: usize, _buf: &[u8]) { + let uart_regs = unsafe { &*ast1060_pac::Uart::ptr() }; let mut uart_controller = UartController::new(uart_regs); uart_controller.init(&UartConfig::default()).unwrap(); - if verify { if verify_dma_buffer_match(&mut uart_controller, idx) { - log_uart!(&mut uart_controller, "DMA test passed!!"); - } else { - log_uart!(&mut uart_controller, "DMA test failed!!"); + log_uart!(&mut uart_controller, "DMA test passed!!"); + } else { + log_uart!(&mut uart_controller, "DMA test failed!!"); } - } //else if { - // astdebug::print_array_u8(&mut uart_controller, buf); - //} + } + astdebug::print_array_u8(&mut uart_controller, _buf); } // Start DMA transfer using the device -fn start_dma_spi_transfer( req: &mut DmaRequest) -> Result<(), ()> { - unsafe { - let dev = match CURRENT_DEVID { +fn start_dma_spi_transfer(req: &mut DmaRequest) -> Result<(), ()> { + unsafe { + + let dev = match CURRENT_DEVID { DeviceId::Spi0Cs0Idx => SPI_DEV0_PTR.as_mut().unwrap(), - _ => return Err(()), + _ => return Ok(()), }; + - let result = match req.op { + 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) @@ -199,19 +182,20 @@ fn start_dma_spi_transfer( req: &mut DmaRequest) -> Result<(), ()> { } }; result.map_err(|_| ()) + } } // Start DMA transfer using the device -fn start_dma_fmc_transfer( req: &mut DmaRequest) -> Result<(), ()> { +fn start_dma_fmc_transfer(req: &mut DmaRequest) -> Result<(), ()> { unsafe { let dev = match CURRENT_DEVID { DeviceId::FmcCs0Idx => FMC_DEV0_PTR.as_mut().unwrap(), DeviceId::FmcCs1Idx => FMC_DEV1_PTR.as_mut().unwrap(), - _ => return Err(()), + _ => return Ok(()), }; - let result = match req.op { + 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) @@ -237,7 +221,7 @@ pub fn verify_dma_buffer_match(uart: &mut UartController<'_>, i: usize) -> bool // 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!(uart, + log_uart!(uart, "Mismatch at buffer {}, index {}: read={:02x}, expected={:02x}", i, j, @@ -246,7 +230,7 @@ pub fn verify_dma_buffer_match(uart: &mut UartController<'_>, i: usize) -> bool ); break; } - } + } astdebug::print_array_u8(uart, read); astdebug::print_array_u8(uart, write); @@ -307,8 +291,7 @@ pub unsafe fn dma_irq_chain_test(uart: &mut UartController<'_>, start_addrs: &[u log_uart!(uart, "chaining {}", i); } //for - let _ = start_next_dma(); - + start_next_dma(); } pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { @@ -317,10 +300,11 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { pinctrl::Pinctrl::apply_pinctrl_group(pinctrl::PINCTRL_FMC_QUAD); let fmc_data = SpiData::new(); - + unsafe { // register interrupt - /* irq init */ + /* irq init */ + NVIC::unmask(ast1060_pac::Interrupt::fmc); FMC_CONTROLLER = Some(FmcController::new( @@ -390,9 +374,7 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { fill_dma_buffer(DmaOp::Program, true, 0x3e4d); 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(uart, &start_addrs, DmaOp::Program, false); delay.delay_ns(8_000_000); if !REQUST_ALLDONE { @@ -422,6 +404,7 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { unsafe { // register interrupt // irq init + NVIC::unmask(ast1060_pac::Interrupt::spi); SPI_CONTROLLER = Some(SpiController::new( @@ -463,7 +446,7 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { fill_dma_buffer(DmaOp::ReadFast, false, 0); dma_irq_chain_test(uart,&start_addrs, DmaOp::ReadFast, false); } else { - fill_dma_buffer(DmaOp::Program, true, 0xd3e1); + fill_dma_buffer(DmaOp::Program, true, 0x1e3f); let _ = dev0.nor_sector_erase(0x0000_0000); delay.delay_ns(8_000_000); dma_irq_chain_test(uart, &start_addrs, DmaOp::ProgramFast, false); diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index 24dfae6..a21644a 100644 --- a/src/spi/spitest.rs +++ b/src/spi/spitest.rs @@ -211,6 +211,18 @@ pub fn device_info(dev_idx: DeviceId) -> (usize, usize, usize) { ), } } + +pub fn show_spi_regiters(uart: &mut UartController<'_>) { + test_log!(uart, "SCU registers::"); + astdebug::print_reg_u32(uart, SCU_BASE + 0x00, 0x40); + test_log!(uart, "FMC controller::"); + astdebug::print_reg_u32(uart, FMC_CTRL_BASE, 0x40); + test_log!(uart, "Spi0 controller::"); + astdebug::print_reg_u32(uart, SPI0_CTRL_BASE, 0x40); + test_log!(uart, "Spi1 controller::"); + astdebug::print_reg_u32(uart, SPI1_CTRL_BASE, 0x40); +} + pub fn test_cs, E>( uart: &mut UartController<'_>, dev: &mut D, From 347e3f4b28b369a2b337b84d18a3d9c7c6893850 Mon Sep 17 00:00:00 2001 From: hailin wu Date: Mon, 9 Mar 2026 16:01:22 -0700 Subject: [PATCH 10/10] Fixed clippy issues. in Spidmairqtest, moved all the unsafe global static variables in StaticCell, which enforce global singleton initialization. --- Cargo.lock | 18 +- Cargo.toml | 1 + src/main.rs | 54 ++-- src/spi/consts.rs | 1 - src/spi/device.rs | 2 +- src/spi/fmccontroller.rs | 42 +-- src/spi/mod.rs | 23 +- src/spi/norflash.rs | 57 +++- src/spi/spicontroller.rs | 37 ++- src/spi/spidmairqtest.rs | 613 ++++++++++++++++++++---------------- src/spi/spim.rs | 8 +- src/spi/spitest.rs | 35 +- src/spi/types.rs | 1 - src/spi/util.rs | 8 +- src/tests/functional/mod.rs | 2 +- 15 files changed, 518 insertions(+), 384 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ec95f4..7f52300 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "anstream" @@ -78,6 +78,7 @@ dependencies = [ "panic-halt", "paste", "proposed-traits", + "static_cell", "zerocopy", ] @@ -381,6 +382,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + [[package]] name = "proc-macro2" version = "1.0.106" @@ -500,6 +507,15 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_cell" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0530892bb4fa575ee0da4b86f86c667132a94b74bb72160f58ee5a4afec74c23" +dependencies = [ + "portable-atomic", +] + [[package]] name = "strsim" version = "0.11.1" diff --git a/Cargo.toml b/Cargo.toml index 19a4702..57d5c3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ hex-literal = "0.4" heapless = "0.8.0" nb = "1.1.0" paste = "1.0" +static_cell = "2" openprot-hal-blocking = { git="https://github.com/OpenPRoT/openprot" } zerocopy = { version = "0.8.25", features = ["derive"] } diff --git a/src/main.rs b/src/main.rs index 06fbceb..e1b1e36 100644 --- a/src/main.rs +++ b/src/main.rs @@ -335,6 +335,33 @@ fn main() -> ! { let reset_id = ResetId::RstHACE; let _ = syscon.reset_deassert(&reset_id); + spi::spitest::show_spi_regiters(&mut uart_controller); + let test_spicontroller = false; + let test_irq = false; + if test_spicontroller { + spi::spidmairqtest::init_spidmairq_app_once(); + 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); + gpio_test::test_gpio_bmc_reset(&mut uart_controller); + } + let mut hace_controller = HaceController::new(hace); run_hash_tests(&mut uart_controller, &mut hace_controller); @@ -348,11 +375,12 @@ fn main() -> ! { let _ = syscon.enable_clock(ClockId::ClkRSACLK as u8); let mut ecdsa = AspeedEcdsa::new(&secure, delay.clone()); - // run_ecdsa_tests(&mut uart_controller, &mut ecdsa); + run_ecdsa_tests(&mut uart_controller, &mut ecdsa); let mut rsa = AspeedRsa::new(&secure, delay); run_rsa_tests(&mut uart_controller, &mut rsa); gpio_test::test_gpioa(&mut uart_controller); + i2c_test::test_i2c_master(&mut uart_controller); #[cfg(feature = "i2c_target")] i2c_test::test_i2c_slave(&mut uart_controller); @@ -373,30 +401,6 @@ fn main() -> ! { test_wdt(&mut uart_controller); run_timer_tests(&mut uart_controller); - let test_spicontroller = true; - let test_irq = true; - if test_spicontroller { - 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); - gpio_test::test_gpio_bmc_reset(&mut uart_controller); - } // Initialize the peripherals here if needed loop { cortex_m::asm::wfi(); diff --git a/src/spi/consts.rs b/src/spi/consts.rs index bc8612d..25b51d7 100644 --- a/src/spi/consts.rs +++ b/src/spi/consts.rs @@ -54,4 +54,3 @@ pub(crate) const PIN_SPIM0_CLK_OUT_BIT: u32 = 7; pub(crate) const PIN_SPIM1_CLK_OUT_BIT: u32 = 21; pub(crate) const PIN_SPIM2_CLK_OUT_BIT: u32 = 3; pub(crate) const PIN_SPIM3_CLK_OUT_BIT: u32 = 17; - diff --git a/src/spi/device.rs b/src/spi/device.rs index 9fae7d9..5627038 100644 --- a/src/spi/device.rs +++ b/src/spi/device.rs @@ -50,7 +50,7 @@ where Operation::Write(buf) => self.bus.write(buf)?, Operation::Transfer(read, write) => self.bus.transfer(read, write)?, Operation::TransferInPlace(buf) => self.bus.transfer_in_place(buf)?, - Operation::DelayNs(_) => {}, // Ignore delay, as the SPI controller will handle timing + Operation::DelayNs(_) => {} // Ignore delay, as the SPI controller will handle timing } } if let Some(_spim) = self.spim { diff --git a/src/spi/fmccontroller.rs b/src/spi/fmccontroller.rs index 707b410..464d028 100644 --- a/src/spi/fmccontroller.rs +++ b/src/spi/fmccontroller.rs @@ -1,24 +1,26 @@ // Licensed under the Apache-2.0 license +use super::consts::{ + ASPEED_MAX_CS, ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, + ASPEED_SPI_SZ_2M, ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, + SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, + SPI_CTRL_CEX_SPI_CMD_MASK, SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, + SPI_DMA_CALIB_MODE, SPI_DMA_CLK_FREQ_MASK, SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, + SPI_DMA_DELAY_SHIFT, SPI_DMA_DISCARD_REQ_MAGIC, SPI_DMA_ENABLE, SPI_DMA_FLASH_MAP_BASE, + SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, SPI_DMA_RAM_MAP_BASE, SPI_DMA_REQUEST, SPI_DMA_STATUS, + SPI_DMA_TIMEOUT, +}; use super::{ - aspeed_get_spi_freq_div, get_addr_buswidth, get_hclock_rate, get_mid_point_of_longest_one, - spi_cal_dummy_cycle, spi_calibration_enable, spi_io_mode, spi_io_mode_user, spi_read_data, - spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, get_cmd_buswidth, - get_data_buswidth, DataDirection, AddressWidth, + aspeed_get_spi_freq_div, get_addr_buswidth, get_cmd_buswidth, get_data_buswidth, + get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, + spi_io_mode, spi_io_mode_user, spi_read_data, spi_write_data, AddressWidth, CtrlType, + DataDirection, SpiBusWithCs, SpiConfig, SpiData, SpiError, }; -use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, - ASPEED_SPI_SZ_2M, ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, - SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_DISCARD_REQ_MAGIC, - SPI_DMA_ENABLE, SPI_DMA_FLASH_MAP_BASE, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, - SPI_DMA_RAM_MAP_BASE, SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, - SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, SPI_CTRL_CEX_SPI_CMD_MASK, - SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_CLK_FREQ_MASK, SPI_DMA_DELAY_MASK, - SPI_DMA_DELAY_SHIFT, SPI_CONF_CE0_ENABLE_WRITE_SHIFT}; use embedded_io::Write; #[cfg(feature = "spi_dma")] -use super::consts::{SPI_DMA_TRIGGER_LEN}; +use super::consts::SPI_DMA_TRIGGER_LEN; use crate::dbg; @@ -270,7 +272,7 @@ impl<'a> FmcController<'a> { if matches!(self.spi_config.ctrl_type, CtrlType::HostSpi) { self.regs.fmc06c().modify(|r, w| unsafe { let mut current = r.bits(); - if matches!(op_info.address.width, AddressWidth::FourByte){ + if matches!(op_info.address.width, AddressWidth::FourByte) { current = (current & 0xffff_00ff) | (op_info.opcode << 8); } else { current = (current & 0xffff_ff00) | op_info.opcode; @@ -511,16 +513,15 @@ impl<'a> FmcController<'a> { let be = op_info.address.value.to_be_bytes(); let bytes = match op_info.address.width { - AddressWidth::ThreeByte => &be[1..], // last 3 bytes (24-bit) - AddressWidth::FourByte => &be[..], - AddressWidth::None => &[], - }; + AddressWidth::ThreeByte => &be[1..], // last 3 bytes (24-bit) + AddressWidth::FourByte => &be[..], + AddressWidth::None => &[], + }; unsafe { super::spi_write_data(start_ptr, bytes); } - // Dummy cycles let bus_width: u8 = get_addr_buswidth(op_info.mode as u32); let dummy_len: u8 = (op_info.dummy_cycle / (8 / u32::from(bus_width))) @@ -709,7 +710,8 @@ impl<'a> FmcController<'a> { while self.regs.fmc080().read().bits() & SPI_DMA_GRANT != SPI_DMA_GRANT {} } - let flash_start = self.spi_data.decode_addr[cs].start + op.address.value - SPI_DMA_FLASH_MAP_BASE; + let flash_start = + self.spi_data.decode_addr[cs].start + op.address.value - SPI_DMA_FLASH_MAP_BASE; dbg!(self, "flash start: 0x{:08x}", flash_start); // DMA flash and RAM address self.regs.fmc084().write(|w| unsafe { w.bits(flash_start) }); diff --git a/src/spi/mod.rs b/src/spi/mod.rs index 6187b97..d5609c7 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -12,20 +12,27 @@ pub mod spitest; pub(crate) mod consts; -pub mod util; pub mod error; pub mod traits; pub mod types; +pub mod util; pub mod spim; pub use error::SpiError; -pub use traits::SpiBusWithCs; -pub use types::{CommandMode, CtrlType, DataDirection, SpiConfig, SpiDecodeAddress, SpiData, - FlashAddress, AddressWidth}; pub use norflash::{Jesd216Mode, SpiNorCommand, SpiNorDevice}; +pub use traits::SpiBusWithCs; +pub use types::{ + AddressWidth, CommandMode, CtrlType, DataDirection, FlashAddress, SpiConfig, SpiData, + SpiDecodeAddress, +}; -pub use util::{spi_read_data, spi_write_data, aspeed_get_spi_freq_div, get_mid_point_of_longest_one, - spi_cal_dummy_cycle, spi_calibration_enable, get_hclock_rate, spi_io_mode, spi_io_mode_user, - get_addr_buswidth, get_cmd_buswidth, get_data_buswidth}; -pub use spim::{spim_proprietary_post_config, spim_proprietary_pre_config, spim_scu_ctrl_clear, spim_scu_ctrl_set}; +pub use spim::{ + spim_proprietary_post_config, spim_proprietary_pre_config, spim_scu_ctrl_clear, + spim_scu_ctrl_set, +}; +pub use util::{ + aspeed_get_spi_freq_div, get_addr_buswidth, get_cmd_buswidth, get_data_buswidth, + get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, + spi_io_mode, spi_io_mode_user, spi_read_data, spi_write_data, +}; diff --git a/src/spi/norflash.rs b/src/spi/norflash.rs index 88e6075..2beb73e 100644 --- a/src/spi/norflash.rs +++ b/src/spi/norflash.rs @@ -2,7 +2,7 @@ use super::device::ChipSelectDevice; use super::SpiBusWithCs; -use super::{norflash, SpiError,DataDirection, FlashAddress, AddressWidth}; +use super::{norflash, AddressWidth, DataDirection, FlashAddress, SpiError}; use crate::common::DummyDelay; use embedded_hal::delay::DelayNs; @@ -155,7 +155,10 @@ where mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_WREN, dummy_cycle: 0, - address: FlashAddress { value: 0, width: AddressWidth::None }, + address: FlashAddress { + value: 0, + width: AddressWidth::None, + }, data_len: 0, data_direct: DataDirection::DWrite, tx_buf: &[], @@ -170,7 +173,10 @@ where mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_WRDI, dummy_cycle: 0, - address: FlashAddress { value: 0, width: AddressWidth::None }, + address: FlashAddress { + value: 0, + width: AddressWidth::None, + }, data_len: 0, data_direct: DataDirection::DWrite, tx_buf: &[], @@ -186,7 +192,10 @@ where mode: Jesd216Mode::Mode111, opcode: 0x9F, dummy_cycle: 0, - address: FlashAddress { value: 0, width: AddressWidth::None }, + address: FlashAddress { + value: 0, + width: AddressWidth::None, + }, data_len: 0, rx_buf: &mut read_buf, tx_buf: &[], @@ -203,7 +212,10 @@ where mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_SE, dummy_cycle: 0, - address: FlashAddress { value: addr, width: AddressWidth::ThreeByte }, + address: FlashAddress { + value: addr, + width: AddressWidth::ThreeByte, + }, data_len: 0, tx_buf: &[], rx_buf: &mut [], @@ -223,7 +235,10 @@ where mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP, dummy_cycle: 0, - address: FlashAddress { value: addr, width: AddressWidth::ThreeByte }, + address: FlashAddress { + value: addr, + width: AddressWidth::ThreeByte, + }, data_len: u32::try_from(data.len()).unwrap(), tx_buf: data, rx_buf: &mut [], @@ -239,7 +254,10 @@ where mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP_4B, dummy_cycle: 0, - address: FlashAddress { value: addr, width: AddressWidth::FourByte }, + address: FlashAddress { + value: addr, + width: AddressWidth::FourByte, + }, data_len: u32::try_from(data.len()).unwrap(), tx_buf: data, rx_buf: &mut [], @@ -254,7 +272,10 @@ where mode: Jesd216Mode::Mode114, opcode: SPI_NOR_CMD_QREAD, dummy_cycle: 8, - address: FlashAddress { value: addr, width: AddressWidth::ThreeByte }, + address: FlashAddress { + value: addr, + width: AddressWidth::ThreeByte, + }, data_len: u32::try_from(buf.len()).unwrap(), tx_buf: &[], rx_buf: buf, @@ -269,7 +290,10 @@ where mode: Jesd216Mode::Mode111Fast, opcode: SPI_NOR_CMD_READ_FAST_4B, dummy_cycle: 8, - address: FlashAddress { value: addr, width: AddressWidth::FourByte }, + address: FlashAddress { + value: addr, + width: AddressWidth::FourByte, + }, data_len: u32::try_from(buf.len()).unwrap(), tx_buf: &[], rx_buf: buf, @@ -285,7 +309,10 @@ where mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_RESET_EN, dummy_cycle: 0, - address: FlashAddress { value: 0x0, width: AddressWidth::None }, + address: FlashAddress { + value: 0x0, + width: AddressWidth::None, + }, data_len: 0, tx_buf: &[], rx_buf: &mut [], @@ -300,7 +327,10 @@ where mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_RESET_MEM, dummy_cycle: 0, - address: FlashAddress { value: 0x0, width: AddressWidth::None }, + address: FlashAddress { + value: 0x0, + width: AddressWidth::None, + }, data_len: 0x0, tx_buf: &[], rx_buf: &mut [], @@ -351,7 +381,10 @@ where mode: Jesd216Mode::Mode111, opcode: SPI_NOR_CMD_RDSR, dummy_cycle: 0, - address: FlashAddress { value: 0, width: AddressWidth::None }, + address: FlashAddress { + value: 0, + width: AddressWidth::None, + }, data_len: 1, tx_buf: &[], rx_buf: &mut buf, diff --git a/src/spi/spicontroller.rs b/src/spi/spicontroller.rs index 43347d6..6340a3e 100644 --- a/src/spi/spicontroller.rs +++ b/src/spi/spicontroller.rs @@ -1,25 +1,27 @@ // Licensed under the Apache-2.0 license use super::{ - aspeed_get_spi_freq_div, get_addr_buswidth, get_hclock_rate, get_mid_point_of_longest_one, - spi_cal_dummy_cycle, spi_calibration_enable, spi_io_mode, spi_io_mode_user, spi_read_data, - spi_write_data, CtrlType, SpiBusWithCs, SpiConfig, SpiData, SpiError, get_cmd_buswidth, - get_data_buswidth, DataDirection, AddressWidth, + aspeed_get_spi_freq_div, get_addr_buswidth, get_cmd_buswidth, get_data_buswidth, + get_hclock_rate, get_mid_point_of_longest_one, spi_cal_dummy_cycle, spi_calibration_enable, + spi_io_mode, spi_io_mode_user, spi_read_data, spi_write_data, AddressWidth, CtrlType, + DataDirection, SpiBusWithCs, SpiConfig, SpiData, SpiError, }; -use super::consts::{ASPEED_MAX_CS,ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, - ASPEED_SPI_SZ_2M, ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, - SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_DISCARD_REQ_MAGIC, - SPI_DMA_ENABLE, SPI_DMA_FLASH_MAP_BASE, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, - SPI_DMA_RAM_MAP_BASE, SPI_DMA_REQUEST, SPI_DMA_STATUS, SPI_DMA_TIMEOUT, - SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, SPI_CTRL_CEX_SPI_CMD_MASK, - SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_CLK_FREQ_MASK, SPI_DMA_DELAY_MASK, - SPI_DMA_DELAY_SHIFT, SPI_CONF_CE0_ENABLE_WRITE_SHIFT}; +use super::consts::{ + ASPEED_MAX_CS, ASPEED_SPI_NORMAL_READ, ASPEED_SPI_NORMAL_WRITE, ASPEED_SPI_SZ_256M, + ASPEED_SPI_SZ_2M, ASPEED_SPI_USER, ASPEED_SPI_USER_INACTIVE, SPI_CALIB_LEN, + SPI_CONF_CE0_ENABLE_WRITE_SHIFT, SPI_CTRL_CEX_4BYTE_MODE_SET, SPI_CTRL_CEX_DUMMY_SHIFT, + SPI_CTRL_CEX_SPI_CMD_MASK, SPI_CTRL_CEX_SPI_CMD_SHIFT, SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, + SPI_DMA_CALIB_MODE, SPI_DMA_CLK_FREQ_MASK, SPI_DMA_CLK_FREQ_SHIFT, SPI_DMA_DELAY_MASK, + SPI_DMA_DELAY_SHIFT, SPI_DMA_DISCARD_REQ_MAGIC, SPI_DMA_ENABLE, SPI_DMA_FLASH_MAP_BASE, + SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, SPI_DMA_RAM_MAP_BASE, SPI_DMA_REQUEST, SPI_DMA_STATUS, + SPI_DMA_TIMEOUT, +}; use embedded_io::Write; #[cfg(feature = "spi_dma")] -use super::consts::{SPI_DMA_TRIGGER_LEN}; +use super::consts::SPI_DMA_TRIGGER_LEN; use crate::dbg; @@ -541,9 +543,9 @@ impl<'a> SpiController<'a> { let be = op_info.address.value.to_be_bytes(); let bytes = match op_info.address.width { - AddressWidth::ThreeByte => &be[1..], // last 3 bytes (24-bit) - AddressWidth::FourByte => &be[..], - AddressWidth::None => &[], + AddressWidth::ThreeByte => &be[1..], // last 3 bytes (24-bit) + AddressWidth::FourByte => &be[..], + AddressWidth::None => &[], }; unsafe { @@ -749,7 +751,8 @@ impl<'a> SpiController<'a> { while self.regs.spi080().read().bits() & SPI_DMA_GRANT != SPI_DMA_GRANT {} } - let flash_start = self.spi_data.decode_addr[cs].start + op.address.value - SPI_DMA_FLASH_MAP_BASE; + let flash_start = + self.spi_data.decode_addr[cs].start + op.address.value - SPI_DMA_FLASH_MAP_BASE; dbg!(self, "flash start: 0x{:08x}", flash_start); // DMA flash and RAM address diff --git a/src/spi/spidmairqtest.rs b/src/spi/spidmairqtest.rs index 89419c6..b87994e 100644 --- a/src/spi/spidmairqtest.rs +++ b/src/spi/spidmairqtest.rs @@ -9,29 +9,22 @@ use crate::spi::norflash::{SpiNorCommand, 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_core::{UartController, UartConfig}; +use crate::uart_core::{UartConfig, 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; -use core::result::Result; +use static_cell::StaticCell; -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(); +#[macro_export] +macro_rules! log_uart { + ($uart:expr, $($arg:tt)*) => {{ + writeln!($uart, $($arg)*).ok(); + write!($uart, "\r").ok(); + }}; +} -static mut REQUST_ALLDONE: bool = true; // DMA operation type selector #[derive(Debug, Copy, Clone)] pub enum DmaOp { @@ -56,118 +49,128 @@ pub struct DmaRequest { // 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]; +struct App { + uart: UartController<'static>, + // controllers + fmc_controller: Option>, + spi_controller: Option>, + + // dma state + request_alldone: bool, + current_dma: Option, + dma_queue: Deque, + current_devid: DeviceId, + + // buffers + read_buffers: [DmaBuffer; MAX_DMA_CHAIN], + write_buffers: [DmaBuffer; MAX_DMA_CHAIN], +} -static mut CURRENT_DMA: Option = None; -static mut DMA_QUEUE: Deque = Deque::new(); -static mut CURRENT_DEVID: DeviceId = DeviceId::FmcCs0Idx; +impl App { + fn new() -> Self { + let uart_regs = unsafe { &*ast1060_pac::Uart::ptr() }; + let mut uart = UartController::new(uart_regs); + uart.init(&UartConfig::default()).unwrap(); -#[no_mangle] -pub extern "C" fn fmc() { - unsafe { - let fmc = FMC_CONTROLLER.as_mut().unwrap(); - - let dev = match CURRENT_DEVID { - DeviceId::FmcCs0Idx => FMC_DEV0_PTR.as_mut().unwrap(), - DeviceId::FmcCs1Idx => FMC_DEV1_PTR.as_mut().unwrap(), + Self { + uart, + fmc_controller: None, + spi_controller: None, + + request_alldone: true, + current_dma: None, + dma_queue: Deque::new(), + current_devid: DeviceId::FmcCs0Idx, + + read_buffers: [const { DmaBuffer::new() }; MAX_DMA_CHAIN], + write_buffers: [const { DmaBuffer::new() }; MAX_DMA_CHAIN], + } + } + + unsafe fn fmc_irq(&mut self) { + log_uart!(&mut self.uart, "fmc_irq"); + let Some(fmc) = self.fmc_controller.as_mut() else { + return; + }; + let irq_result = fmc.handle_interrupt(); + + let mut dev = match self.current_devid { + DeviceId::FmcCs0Idx => ChipSelectDevice { + bus: fmc, + cs: 0, + spim: None, + }, + DeviceId::FmcCs1Idx => ChipSelectDevice { + bus: fmc, + cs: 1, + spim: None, + }, _ => return, }; - let irq_result = fmc.handle_interrupt(); - if let Ok(_) = irq_result { - if let Some(req) = CURRENT_DMA.take() { - if matches!(req.op, DmaOp::Program | DmaOp::ProgramFast) { + if irq_result.is_ok() { + log_uart!(&mut self.uart, "ok"); + if let Some(req) = self.current_dma.take() { + if matches!(req.op, DmaOp::Program | DmaOp::ProgramFast) { dev.nor_wait_until_ready(); } + log_uart!(&mut self.uart, "call on complete"); (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); } - start_next_dma(); + self.start_next_dma(); } - } -} -#[no_mangle] -pub extern "C" fn spi() { - unsafe { - let spi = SPI_CONTROLLER.as_mut().unwrap(); - let irq_result = spi.handle_interrupt(); + unsafe fn spi_irq(&mut self) { + log_uart!(&mut self.uart, "spi_irq"); + let Some(spi) = self.spi_controller.as_mut() else { + return; + }; - if let Ok(_) = irq_result { - if let Some(req) = CURRENT_DMA.take() { - (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); - } - start_next_dma(); - } - } -} + let irq_result = spi.handle_interrupt(); -#[macro_export] -macro_rules! log_uart { - ($uart:expr, $($arg:tt)*) => {{ - writeln!($uart, $($arg)*).ok(); - write!($uart, "\r").ok(); - }}; -} - -unsafe fn show_mmap_reg(uart: &mut UartController<'_>) { - let (_reg_base, mmap_addr, _cs_capacity) = spitest::device_info(CURRENT_DEVID); - log_uart!(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; - return; - } - - if let Some(req) = DMA_QUEUE.pop_front() { - CURRENT_DMA = Some(req); - match CURRENT_DEVID { - DeviceId::FmcCs0Idx | DeviceId::FmcCs1Idx => { - let _= start_dma_fmc_transfer(CURRENT_DMA.as_mut().unwrap()); - } - DeviceId::Spi0Cs0Idx - | DeviceId::Spi1Cs0Idx - | DeviceId::Spi1Cs1Idx - | DeviceId::Spi0Cs1Idx => { - let _= start_dma_spi_transfer(CURRENT_DMA.as_mut().unwrap()); + if irq_result.is_ok() { + if let Some(req) = self.current_dma.take() { + (req.on_complete)(req.verify, req.buf_idx, req.dst_buf); } + self.start_next_dma(); } } -} -pub fn on_complete_dma( verify: bool, idx: usize, _buf: &[u8]) { - let uart_regs = unsafe { &*ast1060_pac::Uart::ptr() }; - let mut uart_controller = UartController::new(uart_regs); - uart_controller.init(&UartConfig::default()).unwrap(); - if verify { - if verify_dma_buffer_match(&mut uart_controller, idx) { - log_uart!(&mut uart_controller, "DMA test passed!!"); - } else { - log_uart!(&mut uart_controller, "DMA test failed!!"); + unsafe fn start_next_dma(&mut self) { + if self.dma_queue.is_empty() { + self.request_alldone = true; + return; } - } - astdebug::print_array_u8(&mut uart_controller, _buf); -} - -// Start DMA transfer using the device -fn start_dma_spi_transfer(req: &mut DmaRequest) -> Result<(), ()> { - unsafe { + log_uart!(&mut self.uart, "start_next_dma"); + if let Some(mut req) = self.dma_queue.pop_front() { + match self.current_devid { + DeviceId::FmcCs0Idx | DeviceId::FmcCs1Idx => { + let _ = self.start_dma_fmc_transfer(&mut req); + } + DeviceId::Spi0Cs0Idx + | DeviceId::Spi1Cs0Idx + | DeviceId::Spi1Cs1Idx + | DeviceId::Spi0Cs1Idx => { + let _ = self.start_dma_spi_transfer(&mut req); + } + } + self.current_dma = Some(req); + } + } - let dev = match CURRENT_DEVID { - DeviceId::Spi0Cs0Idx => SPI_DEV0_PTR.as_mut().unwrap(), - _ => return Ok(()), + unsafe fn start_dma_spi_transfer(&mut self, req: &mut DmaRequest) -> Result<(), ()> { + let controller = self.spi_controller.as_mut().unwrap(); + log_uart!(&mut self.uart, "start_dma_spi_transfer"); + let mut dev = match self.current_devid { + DeviceId::Spi0Cs0Idx => ChipSelectDevice { + bus: controller, + cs: 0, + spim: None, + }, + _ => return Ok(()), }; - let result = match req.op { DmaOp::Read => dev.nor_read_data(u32::try_from(req.src_addr).unwrap(), req.dst_buf), @@ -181,17 +184,24 @@ fn start_dma_spi_transfer(req: &mut DmaRequest) -> Result<(), ()> { dev.nor_page_program_4b(u32::try_from(req.src_addr).unwrap(), req.dst_buf) } }; + result.map_err(|_| ()) - } -} -// Start DMA transfer using the device -fn start_dma_fmc_transfer(req: &mut DmaRequest) -> Result<(), ()> { - unsafe { - let dev = match CURRENT_DEVID { - DeviceId::FmcCs0Idx => FMC_DEV0_PTR.as_mut().unwrap(), - DeviceId::FmcCs1Idx => FMC_DEV1_PTR.as_mut().unwrap(), + unsafe fn start_dma_fmc_transfer(&mut self, req: &mut DmaRequest) -> Result<(), ()> { + log_uart!(&mut self.uart, "fmc_irq"); + let controller = self.fmc_controller.as_mut().unwrap(); + let mut dev = match self.current_devid { + DeviceId::FmcCs0Idx => ChipSelectDevice { + bus: controller, + cs: 0, + spim: None, + }, + DeviceId::FmcCs1Idx => ChipSelectDevice { + bus: controller, + cs: 1, + spim: None, + }, _ => return Ok(()), }; @@ -207,77 +217,131 @@ fn start_dma_fmc_transfer(req: &mut DmaRequest) -> Result<(), ()> { dev.nor_page_program_4b(u32::try_from(req.src_addr).unwrap(), req.dst_buf) } }; + result.map_err(|_| ()) } } +// One time globale instance: +static APP: StaticCell = StaticCell::new(); +static mut APP_PTR: *mut App = core::ptr::null_mut(); + +// initialize the APP and return a mutable reference to it +#[allow(clippy::ref_as_ptr)] +pub fn init_spidmairq_app_once() { + let app = APP.init_with(App::new); + unsafe { + APP_PTR = core::ptr::from_mut(app); //app as *mut _; + } +} +#[inline] +fn app_mut() -> &'static mut App { + unsafe { APP_PTR.as_mut().expect("APP not initialized") } +} +#[no_mangle] +pub extern "C" fn fmc() { + unsafe { app_mut().fmc_irq() }; +} + +#[no_mangle] +pub extern "C" fn spi() { + unsafe { app_mut().spi_irq() }; +} + +#[allow(dead_code)] +unsafe fn show_mmap_reg(uart: &mut UartController<'_>) { + let (_reg_base, mmap_addr, _cs_capacity) = spitest::device_info(app_mut().current_devid); + log_uart!(uart, "[{:08x}]", mmap_addr); + astdebug::print_reg_u8(uart, mmap_addr, 0x400); +} #[must_use] pub fn verify_dma_buffer_match(uart: &mut UartController<'_>, 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!(uart, - "Mismatch at buffer {}, index {}: read={:02x}, expected={:02x}", - i, - j, - r, - w - ); - break; - } + let read = app_mut().read_buffers[i].as_mut_slice(0, DMA_BUF_SIZE); + let write = app_mut().write_buffers[i].as_mut_slice(0, DMA_BUF_SIZE); + + if read != write { + for (j, (&r, &w)) in read.iter().zip(write.iter()).enumerate() { + if r != w { + log_uart!( + uart, + "Mismatch at buffer {}, index {}: read={:02x}, expected={:02x}", + i, + j, + r, + w + ); + break; } - astdebug::print_array_u8(uart, read); - astdebug::print_array_u8(uart, write); - - return false; } + astdebug::print_array_u8(uart, read); + astdebug::print_array_u8(uart, write); + return false; } + astdebug::print_array_u8(uart, read); + astdebug::print_array_u8(uart, write); true } +pub fn on_complete_dma(verify: bool, idx: usize, buf: &[u8]) { + let uart_regs = unsafe { &*ast1060_pac::Uart::ptr() }; + let mut uart_controller = UartController::new(uart_regs); + uart_controller.init(&UartConfig::default()).unwrap(); + + if verify { + if verify_dma_buffer_match(&mut uart_controller, idx) { + log_uart!(&mut uart_controller, "DMA test passed!!"); + } else { + log_uart!(&mut uart_controller, "DMA test failed!!"); + } + } else { + astdebug::print_array_u8(&mut uart_controller, buf); + } +} pub fn fill_dma_buffer(op_req: DmaOp, random: bool, pattern: u32) { let mut seed = 0xDEAD_FBEE; seed += pattern; - 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); + for i in 0..MAX_DMA_CHAIN { + let buf: &'static mut [u8] = match op_req { + DmaOp::Read | DmaOp::ReadFast => { + app_mut().read_buffers[i].as_mut_slice(0, DMA_BUF_SIZE) } + DmaOp::Program | DmaOp::ProgramFast => { + app_mut().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(uart: &mut UartController<'_>, start_addrs: &[u32], op_req: DmaOp, verify: bool) { - DMA_QUEUE.clear(); - REQUST_ALLDONE = false; +pub unsafe fn dma_irq_chain_test( + uart: &mut UartController<'_>, + start_addrs: &[u32], + op_req: DmaOp, + verify: bool, +) { + app_mut().dma_queue.clear(); + app_mut().request_alldone = false; for (i, &addr) in start_addrs.iter().enumerate() { if i >= MAX_DMA_CHAIN { - log_uart!(uart, "Too many DMA addresses; max is {}", MAX_DMA_CHAIN); + log_uart!(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), + DmaOp::Read | DmaOp::ReadFast => { + app_mut().read_buffers[i].as_mut_slice(0, DMA_BUF_SIZE) + } + DmaOp::Program | DmaOp::ProgramFast => { + app_mut().write_buffers[i].as_mut_slice(0, DMA_BUF_SIZE) + } }; + let request = DmaRequest { src_addr: addr as usize, dst_buf: buf, @@ -287,11 +351,14 @@ pub unsafe fn dma_irq_chain_test(uart: &mut UartController<'_>, start_addrs: &[u verify, on_complete: on_complete_dma, }; - DMA_QUEUE.push_back(request).unwrap(); + + app_mut().dma_queue.push_back(request).unwrap(); log_uart!(uart, "chaining {}", i); - - } //for - start_next_dma(); + } + + unsafe { + app_mut().start_next_dma(); + } } pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { @@ -302,99 +369,89 @@ pub fn test_fmc_dma_irq(uart: &mut UartController<'_>) { let fmc_data = SpiData::new(); unsafe { - // register interrupt - /* irq init */ - NVIC::unmask(ast1060_pac::Interrupt::fmc); + } - FMC_CONTROLLER = Some(FmcController::new( - fmc_spi, - 0, - FMC_CONFIG, - fmc_data, - None, - )); - - log_uart!(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: SpiNorCommand<'_> = - 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); + app_mut().fmc_controller = Some(FmcController::new(fmc_spi, 0, FMC_CONFIG, fmc_data, None)); - let dev0 = FMC_DEVICE0.as_mut().unwrap(); - //FMC_DEV0_PTR = dev0 as *mut _; - FMC_DEV0_PTR = ptr::from_mut(dev0); + let controller = app_mut().fmc_controller.as_mut().unwrap(); + let _ = controller.init(); - // 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 nor_read_data: SpiNorCommand<'_> = spitest::nor_device_read_data(spitest::FMC_CS0_CAPACITY); + let nor_write_data = spitest::nor_device_write_data(spitest::FMC_CS0_CAPACITY); - CURRENT_DEVID = DeviceId::FmcCs0Idx; - fill_dma_buffer(DmaOp::Read, true, 0); - delay.delay_ns(8_000_000); - dma_irq_chain_test(uart, &start_addrs, DmaOp::Read, false); + let mut dev0 = ChipSelectDevice { + bus: controller, + cs: 0, + spim: None, + }; - delay.delay_ns(8_000_000); + let _ = dev0.nor_read_init(&nor_read_data); + let _ = dev0.nor_write_init(&nor_write_data); - log_uart!(uart, "==== FMC DEV1 DMA Slow read & write Test===="); - let controller1 = FMC_CONTROLLER.as_mut().unwrap(); - let flash_device1 = ChipSelectDevice { - bus: controller1, // reuse same ref - cs: 1, - spim: None, - }; + let mut dev1 = ChipSelectDevice { + bus: controller, + cs: 1, + spim: None, + }; + + let _ = dev1.nor_read_init(&nor_read_data); + let _ = dev1.nor_write_init(&nor_write_data); - FMC_DEVICE1 = Some(flash_device1); + log_uart!(uart, "==== FMC DEV0 DMA Read Test===="); + app_mut().current_devid = DeviceId::FmcCs0Idx; - let dev1 = FMC_DEVICE1.as_mut().unwrap(); - let _ = dev1.nor_read_init(&nor_read_data); - let _ = dev1.nor_write_init(&nor_write_data); + let start_addrs = [0x0000_0000, 0x0000_0100, 0x0000_0200, 0x0000_0300]; + // DEV0 read test + app_mut().current_devid = DeviceId::FmcCs0Idx; + fill_dma_buffer(DmaOp::Read, true, 0); + delay.delay_ns(8_000_000); + unsafe { + dma_irq_chain_test(uart, &start_addrs, DmaOp::Read, false); + } + delay.delay_ns(8_000_000); - FMC_DEV1_PTR = ptr::from_mut(dev1); + log_uart!(uart, "==== FMC DEV1 DMA Read Write Verify Test===="); + // DEV1 program + verify + let read_only = false; + app_mut().current_devid = DeviceId::FmcCs1Idx; - //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, 0); + if read_only { + fill_dma_buffer(DmaOp::Read, false, 0); + unsafe { dma_irq_chain_test(uart, &start_addrs, DmaOp::Read, false); - } else { - fill_dma_buffer(DmaOp::Program, true, 0x3e4d); - let _ = dev1.nor_sector_erase(0x0000_0000); - delay.delay_ns(8_000_000); - - dma_irq_chain_test(uart, &start_addrs, DmaOp::Program, false); - delay.delay_ns(8_000_000); - if !REQUST_ALLDONE { - log_uart!(uart, "=ERROR: Programming race condition!!!!="); - } + } + } else { + fill_dma_buffer(DmaOp::Program, true, 0x3ef1); + + // dev1 erase must be done via APP + let _ = dev1.nor_sector_erase(0x0000_0000); + + delay.delay_ns(8_000_000); + unsafe { dma_irq_chain_test(uart, &start_addrs, DmaOp::Program, false) }; + delay.delay_ns(8_000_000); + + let done = app_mut().request_alldone; + if !done { + log_uart!(uart, "=ERROR: Programming race condition!!!!="); + } + + unsafe { dma_irq_chain_test(uart, &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; @@ -402,62 +459,64 @@ pub fn test_spi_dma_irq(uart: &mut UartController<'_>) { let spi_data = SpiData::new(); unsafe { - // register interrupt - // irq init - NVIC::unmask(ast1060_pac::Interrupt::spi); + } - SPI_CONTROLLER = Some(SpiController::new( - spi0, - current_cs, - spitest::SPI0_CONFIG, - spi_data, - None, - )); - - let controller = SPI_CONTROLLER.as_mut().unwrap(); - let _ = controller.init(); - log_uart!(uart, "==== SPI0 DEV0 DMA Test===="); - // You can now pass `fmc_ptr` into ChipSelectDevice or use it directly - let nor_read_data: SpiNorCommand<'_> = - 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), - }; + // Setup controller + device inside APP - SPI_DEVICE0 = Some(flash_device0); - let dev0 = SPI_DEVICE0.as_mut().unwrap(); - SPI_DEV0_PTR = ptr::from_mut(dev0); + app_mut().spi_controller = Some(SpiController::new( + spi0, + current_cs, + spitest::SPI0_CONFIG, + spi_data, + None, + )); - // Wrap controller in a CS device (CS0) - let _ = dev0.nor_read_init(&nor_read_data); - let _ = dev0.nor_write_init(&nor_write_data); + let controller = app_mut().spi_controller.as_mut().unwrap(); + let _ = controller.init(); - let start_addrs = [0x0000_0000, 0x0000_0100, 0x0000_0200, 0x0000_0300]; - //let start_addrs = [0x0000_0100]; - CURRENT_DEVID = DeviceId::Spi0Cs0Idx; + log_uart!(uart, "==== SPI0 DEV0 DMA Test===="); - let read_only = false; - if read_only { - fill_dma_buffer(DmaOp::ReadFast, false, 0); - dma_irq_chain_test(uart,&start_addrs, DmaOp::ReadFast, false); - } else { - fill_dma_buffer(DmaOp::Program, true, 0x1e3f); - let _ = dev0.nor_sector_erase(0x0000_0000); - delay.delay_ns(8_000_000); - dma_irq_chain_test(uart, &start_addrs, DmaOp::ProgramFast, false); - delay.delay_ns(8_000_000); - if !REQUST_ALLDONE { - log_uart!(uart, "=ERROR: Programming race condition!!!!="); - } - dma_irq_chain_test(uart,&start_addrs, DmaOp::ReadFast, true); + let nor_read_data: SpiNorCommand<'_> = + 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 mut dev0 = ChipSelectDevice { + bus: controller, + cs: 0, + spim: None, + }; + + let _ = dev0.nor_read_init(&nor_read_data); + let _ = dev0.nor_write_init(&nor_write_data); + + app_mut().current_devid = DeviceId::Spi0Cs0Idx; + + let start_addrs = [0x0000_0000, 0x0000_0100, 0x0000_0200, 0x0000_0300]; + let read_only = false; + + if read_only { + fill_dma_buffer(DmaOp::ReadFast, false, 0); + unsafe { dma_irq_chain_test(uart, &start_addrs, DmaOp::ReadFast, false) }; + } else { + fill_dma_buffer(DmaOp::Program, true, 0x8e1); + + let _ = dev0.nor_sector_erase(0x0000_0000); + + delay.delay_ns(8_000_000); + + unsafe { dma_irq_chain_test(uart, &start_addrs, DmaOp::ProgramFast, false) }; + delay.delay_ns(8_000_000); + + let done = app_mut().request_alldone; + if !done { + log_uart!(uart, "=ERROR: Programming race condition!!!!="); } - log_uart!(uart, "==== End SPI0 DEV0 DMA Test===="); - } //unsafe + + unsafe { dma_irq_chain_test(uart, &start_addrs, DmaOp::ReadFast, true) }; + } + + log_uart!(uart, "==== End SPI0 DEV0 DMA Test===="); scu_qspi_mux[0] = 0x0000_0000; } diff --git a/src/spi/spim.rs b/src/spi/spim.rs index 799a4a9..762ca0e 100644 --- a/src/spi/spim.rs +++ b/src/spi/spim.rs @@ -4,11 +4,11 @@ use crate::modify_reg; use core::cell::Cell; use critical_section::Mutex; +use super::consts::{ + PIN_SPIM0_CLK_OUT_BIT, PIN_SPIM1_CLK_OUT_BIT, PIN_SPIM2_CLK_OUT_BIT, PIN_SPIM3_CLK_OUT_BIT, +}; -use super::consts::{PIN_SPIM0_CLK_OUT_BIT, PIN_SPIM1_CLK_OUT_BIT, PIN_SPIM2_CLK_OUT_BIT, PIN_SPIM3_CLK_OUT_BIT}; - -static GPIO_ORI_VAL: Mutex<[Cell; 4]> = - Mutex::new([const { Cell::new(0) }; 4]); +static GPIO_ORI_VAL: Mutex<[Cell; 4]> = Mutex::new([const { Cell::new(0) }; 4]); #[must_use] pub fn get_gpio_ori_val() -> [u32; 4] { diff --git a/src/spi/spitest.rs b/src/spi/spitest.rs index a21644a..af070cf 100644 --- a/src/spi/spitest.rs +++ b/src/spi/spitest.rs @@ -5,12 +5,14 @@ use super::device::ChipSelectDevice; use super::fmccontroller::FmcController; +use super::norflash; use super::norflash::{ Jesd216Mode, SpiNorCommand, SpiNorDevice, SPI_NOR_CMD_QREAD, SPI_NOR_CMD_READ_FAST_4B, }; -use super::{ norflash }; -use super::{CommandMode, CtrlType, SpiConfig, SpiData, SpiDecodeAddress, DataDirection, - AddressWidth, FlashAddress}; +use super::{ + AddressWidth, CommandMode, CtrlType, DataDirection, FlashAddress, SpiConfig, SpiData, + SpiDecodeAddress, +}; use crate::common::{self, DmaBuffer, DummyDelay}; use crate::spi::norflashblockdevice; use crate::spi::norflashblockdevice::{BlockAddrUsize, NorFlashBlockDevice}; @@ -20,8 +22,8 @@ use crate::uart_core::{UartConfig, UartController}; use crate::{astdebug, pinctrl}; use embedded_hal::delay::DelayNs; use embedded_hal::spi::SpiDevice; -use proposed_traits::block_device::{BlockDevice, BlockRange}; use embedded_io::Write; +use proposed_traits::block_device::{BlockDevice, BlockRange}; pub const FMC_CTRL_BASE: usize = 0x7e62_0000; pub const FMC_MMAP_BASE: usize = 0x8000_0000; @@ -119,7 +121,10 @@ pub fn nor_device_read_data<'a>(len: usize) -> SpiNorCommand<'a> { mode: Jesd216Mode::Mode114, opcode: SPI_NOR_CMD_QREAD, dummy_cycle: 8, - address: FlashAddress { value: 0x0, width: AddressWidth::ThreeByte }, + address: FlashAddress { + value: 0x0, + width: AddressWidth::ThreeByte, + }, data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], @@ -133,7 +138,10 @@ pub fn nor_device_write_data<'a>(len: usize) -> SpiNorCommand<'a> { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP, dummy_cycle: 0, - address: FlashAddress { value: 0x0, width: AddressWidth::ThreeByte }, + address: FlashAddress { + value: 0x0, + width: AddressWidth::ThreeByte, + }, data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], @@ -147,7 +155,10 @@ pub fn nor_device_read_4b_data<'a>(len: usize) -> SpiNorCommand<'a> { mode: Jesd216Mode::Mode111Fast, opcode: SPI_NOR_CMD_READ_FAST_4B, dummy_cycle: 8, - address: FlashAddress { value: 0x0, width: AddressWidth::FourByte }, + address: FlashAddress { + value: 0x0, + width: AddressWidth::FourByte, + }, data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], @@ -161,7 +172,10 @@ pub fn nor_device_write_4b_data<'a>(len: usize) -> SpiNorCommand<'a> { mode: Jesd216Mode::Mode111, opcode: norflash::SPI_NOR_CMD_PP_4B, dummy_cycle: 0, - address: FlashAddress { value: 0x0, width: AddressWidth::FourByte }, + address: FlashAddress { + value: 0x0, + width: AddressWidth::FourByte, + }, data_len: u32::try_from(len).unwrap(), tx_buf: &[], rx_buf: &mut [], @@ -214,8 +228,8 @@ pub fn device_info(dev_idx: DeviceId) -> (usize, usize, usize) { pub fn show_spi_regiters(uart: &mut UartController<'_>) { test_log!(uart, "SCU registers::"); - astdebug::print_reg_u32(uart, SCU_BASE + 0x00, 0x40); - test_log!(uart, "FMC controller::"); + astdebug::print_reg_u32(uart, SCU_BASE, 0x40); + test_log!(uart, "FMC controller::"); astdebug::print_reg_u32(uart, FMC_CTRL_BASE, 0x40); test_log!(uart, "Spi0 controller::"); astdebug::print_reg_u32(uart, SPI0_CTRL_BASE, 0x40); @@ -408,7 +422,6 @@ pub fn test_spi(uart: &mut UartController<'_>) { let mut spi_uart_controller = UartController::new(uart_regs); spi_uart_controller.init(&UartConfig::default()).unwrap(); - let mut spi_controller = SpiController::new( spi0, current_cs, diff --git a/src/spi/types.rs b/src/spi/types.rs index 0d4706b..4c4c892 100644 --- a/src/spi/types.rs +++ b/src/spi/types.rs @@ -85,4 +85,3 @@ impl SpiData { } } } - diff --git a/src/spi/util.rs b/src/spi/util.rs index d83248a..a6fc8ea 100644 --- a/src/spi/util.rs +++ b/src/spi/util.rs @@ -1,10 +1,8 @@ // Licensed under the Apache-2.0 license -use crate::{ - spi::norflash::{Jesd216Mode}, -}; -use ast1060_pac::Scu; use super::consts::HPLL_FREQ; +use crate::spi::norflash::Jesd216Mode; +use ast1060_pac::Scu; #[macro_export] macro_rules! dbg { @@ -193,7 +191,7 @@ pub unsafe fn spi_read_data(ahb_addr: *const u32, read_arr: &mut [u8]) { #[allow(clippy::missing_safety_doc)] pub unsafe fn spi_write_data(ahb_addr: *mut u32, write_arr: &[u8]) { - if write_arr.is_empty() { + if write_arr.is_empty() { return; } diff --git a/src/tests/functional/mod.rs b/src/tests/functional/mod.rs index 3790c97..fd006d2 100644 --- a/src/tests/functional/mod.rs +++ b/src/tests/functional/mod.rs @@ -9,5 +9,5 @@ pub mod i2c_master_slave_test; pub mod i2c_test; pub mod rsa_test; pub mod rsa_test_vec; +pub mod spim_test; pub mod timer_test; -pub mod spim_test; \ No newline at end of file