diff --git a/axdriver_block/Cargo.toml b/axdriver_block/Cargo.toml index 6eecd3823..bb4fefd0c 100644 --- a/axdriver_block/Cargo.toml +++ b/axdriver_block/Cargo.toml @@ -13,9 +13,11 @@ categories.workspace = true [features] bcm2835-sdhci = ["dep:bcm2835-sdhci"] +cvsd = ["dep:sg200x-bsp"] ramdisk = [] [dependencies] axdriver_base = { workspace = true } bcm2835-sdhci = { version = "0.1.1", optional = true } +sg200x-bsp = { version = "0.4.0", optional = true } log = { workspace = true } diff --git a/axdriver_block/src/cvsd.rs b/axdriver_block/src/cvsd.rs new file mode 100644 index 000000000..cf14a3765 --- /dev/null +++ b/axdriver_block/src/cvsd.rs @@ -0,0 +1,81 @@ +//! A SD Card driver for cv181x-sd device + +use axdriver_base::{BaseDriverOps, DevError, DevResult, DeviceType}; +use sg200x_bsp::sdmmc::Sdmmc; + +use crate::BlockDriverOps; + +const BLOCK_SIZE: usize = 512; + +/// CVSD driver based on SG200x BSP SD/MMC. +pub struct CvsdDriver(Sdmmc); + +unsafe impl Send for CvsdDriver {} +unsafe impl Sync for CvsdDriver {} + +impl CvsdDriver { + /// Initializes SD/MMC and creates a new [`CvsdDriver`]. + pub fn new(sdmmc: usize, syscon: usize) -> DevResult { + let sdmmc = unsafe { Sdmmc::from_base_addresses(sdmmc, syscon) }; + sdmmc.init().map_err(|_| DevError::Io)?; + sdmmc.clk_en(true); + Ok(Self(sdmmc)) + } +} + +impl BaseDriverOps for CvsdDriver { + fn device_type(&self) -> DeviceType { + DeviceType::Block + } + + fn device_name(&self) -> &str { + "cvsd" + } +} + +impl BlockDriverOps for CvsdDriver { + fn num_blocks(&self) -> u64 { + // Capacity info is not exposed by sg200x-bsp sdmmc yet. + 67108864 // Fake capacity info: 32G + } + + fn block_size(&self) -> usize { + BLOCK_SIZE + } + + fn read_block(&mut self, block_id: u64, buf: &mut [u8]) -> DevResult { + let (blocks, remainder) = buf.as_chunks_mut::<{ BLOCK_SIZE }>(); + + if !remainder.is_empty() { + return Err(DevError::InvalidParam); + } + + for (i, block) in blocks.iter_mut().enumerate() { + self.0 + .read_block(block_id as u32 + i as u32, block) + .map_err(|_| DevError::Io)?; + } + + Ok(()) + } + + fn write_block(&mut self, block_id: u64, buf: &[u8]) -> DevResult { + let (blocks, remainder) = buf.as_chunks::<{ BLOCK_SIZE }>(); + + if !remainder.is_empty() { + return Err(DevError::InvalidParam); + } + + for (i, block) in blocks.iter().enumerate() { + self.0 + .write_block(block_id as u32 + i as u32, block) + .map_err(|_| DevError::Io)?; + } + + Ok(()) + } + + fn flush(&mut self) -> DevResult { + Ok(()) + } +} diff --git a/axdriver_block/src/lib.rs b/axdriver_block/src/lib.rs index a1906c1ed..49d7d5241 100644 --- a/axdriver_block/src/lib.rs +++ b/axdriver_block/src/lib.rs @@ -6,6 +6,9 @@ #[cfg(feature = "bcm2835-sdhci")] pub mod bcm2835sdhci; +#[cfg(feature = "cvsd")] +pub mod cvsd; + #[cfg(feature = "ramdisk")] pub mod ramdisk;