phytium_mci/lib.rs
1#![no_std]
2#![deny(warnings, missing_docs)]
3
4//! # phytium-mci
5//!
6//! A `no_std` SD/MMC host controller driver for Phytium E2000 series SoCs.
7//!
8//! ## Overview
9//!
10//! This crate provides a comprehensive driver for SD/MMC cards on Phytium platforms,
11//! supporting both SD and eMMC cards with DMA and PIO transfer modes.
12//!
13//! ## Features
14//!
15//! - **Full SD Specification Support**: SDSC, SDHC, SDXC (versions 1.0-3.0)
16//! - **eMMC Support**: MMC protocol implementation
17//! - **Flexible Transfer Modes**: DMA (high-performance) and PIO (simple)
18//! - **Voltage Support**: 3.3V (default) and 1.8V (UHS-I modes)
19//! - **Bus Widths**: 1-bit, 4-bit, and 8-bit (eMMC) data bus
20//! - **High-Speed Modes**: SDR12, SDR25, SDR50, SDR104, DDR50
21//! - **Clock Speed**: From 400 KHz to 208 MHz
22//! - **Card Detection**: GPIO-based and host-based
23//! - **Interrupt Support**: Command, data, and card detection interrupts
24//!
25//! ## Architecture
26//!
27//! The driver is organized into distinct layers:
28//!
29//! ```text
30//! Application Layer (SdCard, MCIHost - High-level API)
31//! ↓
32//! Protocol Layer (Command/Data transfer, Card initialization)
33//! ↓
34//! Hardware Abstraction (Register access, DMA/PIO control)
35//! ↓
36//! Hardware Support (IoPad pin configuration, OSA memory/timing)
37//! ```
38//!
39//! ## Modules
40//!
41//! - [`iopad`] - I/O pad configuration for pin multiplexing
42//! - [`mci`] - Hardware controller driver (register access, DMA/PIO, interrupts)
43//! - [`mci_host`] - Host controller protocol layer (SD/MMC protocol)
44//! - [`osa`] - OS abstraction layer (memory management, event flags)
45//!
46//! ## Platform Integration
47//!
48//! To use this driver, you must implement the [`Kernel`] trait to provide
49//! platform-specific functionality:
50//!
51//! ```rust
52//! use phytium_mci::{Kernel, set_impl};
53//! use core::{ptr::NonNull, time::Duration};
54//!
55//! struct MyPlatform;
56//!
57//! impl Kernel for MyPlatform {
58//! fn sleep(duration: Duration) {
59//! // Platform-specific delay implementation
60//! }
61//!
62//! #[cfg(feature = "dma")]
63//! fn mmap(virt_addr: NonNull<u8>) -> u64 {
64//! // Virtual to physical address translation
65//! }
66//!
67//! fn flush(addr: NonNull<u8>, size: usize) {
68//! // Cache clean for DMA
69//! }
70//!
71//! fn invalidate(addr: NonNull<u8>, size: usize) {
72//! // Cache invalidate for DMA
73//! }
74//! }
75//!
76//! // Register your implementation
77//! set_impl!(MyPlatform);
78//! ```
79//!
80//! ## Hardware Configuration
81//!
82//! Target Hardware:
83//! - **SoC**: Phytium E2000 series (ARMv8-A)
84//! - **Board**: Phytium Pi development board
85//! - **Controller**: Phytium SDIF (Synopsys DesignWare-based)
86//! - **MCI0 Base**: 0x2800_1000
87//! - **MCI1 Base**: 0x2800_2000
88//! - **IOPAD Base**: 0x2800_0000
89//!
90//! ## Example
91//!
92//! ```rust,ignore
93//! use phytium_mci::{sd::SdCard, IoPad};
94//! use core::ptr::NonNull;
95//!
96//! // Initialize IOPAD
97//! let iopad = unsafe { IoPad::new(NonNull::new_unchecked(0x2800_0000 as *mut u8)) };
98//!
99//! // Create SD card instance
100//! let mut sdcard = unsafe {
101//! SdCard::new(
102//! NonNull::new_unchecked(0x2800_1000 as *mut u8),
103//! iopad
104//! )
105//! };
106//!
107//! // Initialize the card
108//! sdcard.init(NonNull::new_unchecked(0x2800_1000 as *mut u8))?;
109//!
110//! // Read blocks
111//! let mut buffer = Vec::new();
112//! sdcard.read_blocks(&mut buffer, 0, 1)?;
113//! ```
114
115extern crate alloc;
116
117use core::{ptr::NonNull, time::Duration};
118
119#[macro_use]
120mod regs;
121mod aarch;
122pub mod iopad;
123pub mod mci;
124pub mod mci_host;
125pub mod osa;
126mod tools;
127
128pub use iopad::*;
129pub use mci_host::*;
130
131/// Platform abstraction trait for phytium-mci driver.
132///
133/// This trait must be implemented by the platform to provide platform-specific
134/// functionality required by the driver, including delay operations, memory
135/// management, and cache operations.
136///
137/// # Example
138///
139/// ```rust
140/// use phytium_mci::Kernel;
141/// use core::{ptr::NonNull, time::Duration};
142///
143/// struct MyPlatform;
144///
145/// impl Kernel for MyPlatform {
146/// fn sleep(duration: Duration) {
147/// // Implement platform-specific delay
148/// // e.g., using a timer or busy-waiting
149/// }
150///
151/// #[cfg(feature = "dma")]
152/// fn mmap(virt_addr: NonNull<u8>) -> u64 {
153/// // Convert virtual address to physical address
154/// // Required for DMA operations
155/// }
156///
157/// fn flush(addr: NonNull<u8>, size: usize) {
158/// // Clean data cache to ensure data is written to memory
159/// // Required before DMA write operations
160/// }
161///
162/// fn invalidate(addr: NonNull<u8>, size: usize) {
163/// // Invalidate data cache to ensure fresh data is read
164/// // Required after DMA read operations
165/// }
166/// }
167/// ```
168pub trait Kernel {
169 /// Delay execution for the specified duration.
170 ///
171 /// This is used for timing delays during card initialization and
172 /// command processing.
173 ///
174 /// # Arguments
175 ///
176 /// * `duration` - The duration to sleep
177 fn sleep(duration: Duration);
178
179 /// Convert virtual address to physical address.
180 ///
181 /// This is required for DMA operations to provide the physical
182 /// address of DMA buffers to the hardware.
183 ///
184 /// # Arguments
185 ///
186 /// * `virt_addr` - Virtual address to translate
187 ///
188 /// # Returns
189 ///
190 /// Physical address corresponding to the virtual address
191 #[cfg(feature = "dma")]
192 fn mmap(virt_addr: NonNull<u8>) -> u64;
193
194 /// Clean data cache for the specified memory range.
195 ///
196 /// Ensures that data in the cache is written back to memory.
197 /// This must be called before DMA write operations to ensure
198 /// the hardware sees the correct data.
199 ///
200 /// # Arguments
201 ///
202 /// * `addr` - Start address of the memory range
203 /// * `size` - Size of the memory range in bytes
204 fn flush(addr: NonNull<u8>, size: usize);
205
206 /// Invalidate data cache for the specified memory range.
207 ///
208 /// Discards cached data so that subsequent reads fetch fresh
209 /// data from memory. This must be called after DMA read
210 /// operations to ensure the CPU sees the data written by the hardware.
211 ///
212 /// # Arguments
213 ///
214 /// * `addr` - Start address of the memory range
215 /// * `size` - Size of the memory range in bytes
216 fn invalidate(addr: core::ptr::NonNull<u8>, size: usize);
217}
218
219pub(crate) fn sleep(duration: Duration) {
220 unsafe extern "Rust" {
221 fn _phytium_mci_sleep(duration: Duration);
222 }
223
224 unsafe {
225 _phytium_mci_sleep(duration);
226 }
227}
228
229#[cfg(feature = "dma")]
230pub(crate) fn mmap(virt_addr: NonNull<u8>) -> u64 {
231 unsafe extern "Rust" {
232 fn _phytium_mci_map(virt_addr: NonNull<u8>) -> u64;
233 }
234
235 unsafe { _phytium_mci_map(virt_addr) }
236}
237
238pub(crate) fn flush(addr: NonNull<u8>, size: usize) {
239 unsafe extern "Rust" {
240 fn _phytium_mci_flush(addr: NonNull<u8>, size: usize);
241 }
242
243 unsafe {
244 _phytium_mci_flush(addr, size);
245 }
246}
247
248pub(crate) fn invalidate(addr: core::ptr::NonNull<u8>, size: usize) {
249 unsafe extern "Rust" {
250 fn _phytium_mci_invalidate(addr: core::ptr::NonNull<u8>, size: usize);
251 }
252
253 unsafe {
254 _phytium_mci_invalidate(addr, size);
255 }
256}
257
258/// Register a platform-specific implementation of the [`Kernel`] trait.
259///
260/// This macro generates the external interface functions that the phytium-mci
261/// driver uses to call platform-specific operations. It should be called once
262/// with your platform type that implements the [`Kernel`] trait.
263///
264/// # Example
265///
266/// ```rust
267/// use phytium_mci::{Kernel, set_impl};
268/// use core::{ptr::NonNull, time::Duration};
269///
270/// struct MyPlatform;
271///
272/// impl Kernel for MyPlatform {
273/// fn sleep(duration: Duration) {
274/// // Your implementation
275/// }
276///
277/// #[cfg(feature = "dma")]
278/// fn mmap(virt_addr: NonNull<u8>) -> u64 {
279/// // Your implementation
280/// }
281///
282/// fn flush(addr: NonNull<u8>, size: usize) {
283/// // Your implementation
284/// }
285///
286/// fn invalidate(addr: NonNull<u8>, size: usize) {
287/// // Your implementation
288/// }
289/// }
290///
291/// // Register the implementation
292/// set_impl!(MyPlatform);
293/// ```
294///
295/// # Generated Functions
296///
297/// This macro generates the following `no_mangle` functions:
298/// - `_phytium_mci_sleep` - Sleep/delay functionality
299/// - `_phytium_mci_map` - Virtual to physical address translation (DMA only)
300/// - `_phytium_mci_flush` - Cache clean operation
301/// - `_phytium_mci_invalidate` - Cache invalidate operation
302#[macro_export]
303macro_rules! set_impl {
304 ($t: ty) => {
305 #[unsafe(no_mangle)]
306 unsafe fn _phytium_mci_sleep(duration: core::time::Duration) {
307 <$t as $crate::Kernel>::sleep(duration)
308 }
309 #[cfg(feature = "dma")]
310 #[unsafe(no_mangle)]
311 fn _phytium_mci_map(addr: core::ptr::NonNull<u8>) -> u64 {
312 <$t as $crate::Kernel>::mmap(addr)
313 }
314 #[unsafe(no_mangle)]
315 fn _phytium_mci_flush(addr: core::ptr::NonNull<u8>, size: usize) {
316 <$t as $crate::Kernel>::flush(addr, size)
317 }
318 #[unsafe(no_mangle)]
319 fn _phytium_mci_invalidate(addr: core::ptr::NonNull<u8>, size: usize) {
320 <$t as $crate::Kernel>::invalidate(addr, size)
321 }
322 };
323}