sdio_host/
sd.rs

1//! SD-specific extensions to the core SDMMC protocol.
2
3pub use crate::common::*;
4
5/// Type marker for SD-specific extensions.
6#[derive(Clone, Copy, Default)]
7pub struct SD;
8
9use core::{fmt, str};
10
11#[non_exhaustive]
12#[derive(Debug, Copy, Clone, Eq, PartialEq)]
13pub enum SDSpecVersion {
14    /// Version 1.0 and and 1.0.1
15    V1_0,
16    /// Version 1.10
17    V1_10,
18    /// Version 2.0
19    V2,
20    /// Version 3.0
21    V3,
22    /// Version 4.0
23    V4,
24    /// Version 5.0
25    V5,
26    /// Version 6.0
27    V6,
28    /// Version 7.0
29    V7,
30    /// Version not known by this crate
31    Unknown,
32}
33
34/// SD CARD Configuration Register (SCR)
35#[derive(Clone, Copy, Default)]
36pub struct SCR(pub u64);
37/// From little endian words
38impl From<[u32; 2]> for SCR {
39    fn from(words: [u32; 2]) -> Self {
40        Self(((words[1] as u64) << 32) | words[0] as u64)
41    }
42}
43impl SCR {
44    /// Physical Layer Specification Version Number
45    pub fn version(&self) -> SDSpecVersion {
46        let spec = (self.0 >> 56) & 0xF;
47        let spec3 = (self.0 >> 47) & 1;
48        let spec4 = (self.0 >> 42) & 1;
49        let specx = (self.0 >> 38) & 0xF;
50
51        // Ref PLSS_v7_10 Table 5-17
52        match (spec, spec3, spec4, specx) {
53            (0, 0, 0, 0) => SDSpecVersion::V1_0,
54            (1, 0, 0, 0) => SDSpecVersion::V1_10,
55            (2, 0, 0, 0) => SDSpecVersion::V2,
56            (2, 1, 0, 0) => SDSpecVersion::V3,
57            (2, 1, 1, 0) => SDSpecVersion::V4,
58            (2, 1, _, 1) => SDSpecVersion::V5,
59            (2, 1, _, 2) => SDSpecVersion::V6,
60            (2, 1, _, 3) => SDSpecVersion::V7,
61            _ => SDSpecVersion::Unknown,
62        }
63    }
64    /// Bus widths supported
65    pub fn bus_widths(&self) -> u8 {
66        // Ref PLSS_v7_10 Table 5-21
67        ((self.0 >> 48) as u8) & 0xF
68    }
69    /// Supports 1-bit bus width
70    pub fn bus_width_one(&self) -> bool {
71        (self.0 >> 48) & 1 != 0
72    }
73    /// Supports 4-bit bus width
74    pub fn bus_width_four(&self) -> bool {
75        (self.0 >> 50) & 1 != 0
76    }
77}
78impl core::fmt::Debug for SCR {
79    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80        f.debug_struct("SCR: SD CARD Configuration Register")
81            .field("Version", &self.version())
82            .field("1-bit width", &self.bus_width_one())
83            .field("4-bit width", &self.bus_width_four())
84            .finish()
85    }
86}
87
88impl OCR<SD> {
89    /// VDD voltage window.
90    // 00000000 00000000 00000000 00000000
91    // 00000000 00000000 0
92    //          11111111 1
93    // OCR [23:15].
94    pub fn voltage_window_mv(&self) -> Option<(u16, u16)> {
95        let mut window = (self.0 >> 15) & 0x1FF;
96        let mut min = 2_700;
97
98        while window & 1 == 0 && window != 0 {
99            min += 100;
100            window >>= 1;
101        }
102        let mut max = min;
103        while window != 0 {
104            max += 100;
105            window >>= 1;
106        }
107
108        if max == min {
109            None
110        } else {
111            Some((min, max))
112        }
113    }
114    /// Switching to 1.8V Accepted (S18A). Only UHS-I cards support this bit
115    // 00000000 00000000 00000000 00000000
116    //        1
117    // OCR [24].
118    pub fn v18_allowed(&self) -> bool {
119        self.0 & 0x0100_0000 != 0
120    }
121    /// Over 2TB support Status. Only SDUC card support this bit
122    // 00000000 00000000 00000000 00000000
123    //     1
124    // OCR [27].
125    pub fn over_2tb(&self) -> bool {
126        self.0 & 0x0800_0000 != 0
127    }
128    /// Indicates whether the card supports UHS-II Interface
129    // 00000000 00000000 00000000 00000000
130    //   1
131    // OCR [29].
132    pub fn uhs2_card_status(&self) -> bool {
133        self.0 & 0x2000_0000 != 0
134    }
135    /// Card Capacity Status (CCS)
136    ///
137    /// For SD cards, this is true for SDHC/SDXC/SDUC, false for SDSC
138    pub fn high_capacity(&self) -> bool {
139        self.0 & 0x4000_0000 != 0
140    }
141}
142impl fmt::Debug for OCR<SD> {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        f.debug_struct("OCR: Operation Conditions Register")
145            .field(
146                "Voltage Window (mV)",
147                &self.voltage_window_mv().unwrap_or((0, 0)),
148            )
149            .field("S18A (UHS-I only)", &self.v18_allowed())
150            .field("Over 2TB flag (SDUC only)", &self.over_2tb())
151            .field("UHS-II Card", &self.uhs2_card_status())
152            .field(
153                "Card Capacity Status (CSS)",
154                &if self.high_capacity() {
155                    "SDHC/SDXC/SDUC"
156                } else {
157                    "SDSC"
158                },
159            )
160            .field("Busy", &self.is_busy())
161            .finish()
162    }
163}
164
165impl CID<SD> {
166    /// OEM/Application ID
167    pub fn oem_id(&self) -> &str {
168        str::from_utf8(&self.bytes[1..3]).unwrap_or(&"<ERR>")
169    }
170    /// Product name
171    pub fn product_name(&self) -> &str {
172        str::from_utf8(&self.bytes[3..8]).unwrap_or(&"<ERR>")
173    }
174    /// Product revision
175    pub fn product_revision(&self) -> u8 {
176        self.bytes[8]
177    }
178    /// Product serial number
179    pub fn serial(&self) -> u32 {
180        (self.inner >> 24) as u32
181    }
182    /// Manufacturing date
183    pub fn manufacturing_date(&self) -> (u8, u16) {
184        (
185            (self.inner >> 8) as u8 & 0xF,             // Month
186            ((self.inner >> 12) as u16 & 0xFF) + 2000, // Year
187        )
188    }
189}
190
191impl fmt::Debug for CID<SD> {
192    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193        f.debug_struct("CID: Card Identification")
194            .field("Manufacturer ID", &self.manufacturer_id())
195            .field("OEM ID", &self.oem_id())
196            .field("Product Name", &self.product_name())
197            .field("Product Revision", &self.product_revision())
198            .field("Product Serial Number", &self.serial())
199            .field("Manufacturing Date", &self.manufacturing_date())
200            .finish()
201    }
202}
203
204impl CSD<SD> {
205    /// Number of blocks in the card
206    pub fn block_count(&self) -> u64 {
207        match self.version() {
208            0 => {
209                // SDSC
210                let c_size: u16 = ((self.0 >> 62) as u16) & 0xFFF;
211                let c_size_mult: u8 = ((self.0 >> 47) as u8) & 7;
212
213                ((c_size + 1) as u64) * ((1 << (c_size_mult + 2)) as u64)
214            }
215            1 => {
216                // SDHC/SDXC
217                (((self.0 >> 48) as u64 & 0x3F_FFFF) + 1) * 1024
218            }
219            2 => {
220                // SDUC
221                (((self.0 >> 48) as u64 & 0xFFF_FFFF) + 1) * 1024
222            }
223            _ => 0,
224        }
225    }
226    /// Card size in bytes
227    pub fn card_size(&self) -> u64 {
228        let block_size_bytes = 1 << self.block_length() as u64;
229
230        self.block_count() * block_size_bytes
231    }
232    /// Erase size (in blocks)
233    pub fn erase_size_blocks(&self) -> u32 {
234        if (self.0 >> 46) & 1 == 1 {
235            // ERASE_BLK_EN
236            1
237        } else {
238            let sector_size_tens = (self.0 >> 43) & 0x7;
239            let sector_size_units = (self.0 >> 39) & 0xF;
240
241            (sector_size_tens as u32 * 10) + (sector_size_units as u32)
242        }
243    }
244}
245
246impl fmt::Debug for CSD<SD> {
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        f.debug_struct("CSD: Card Specific Data")
249            .field("Transfer Rate", &self.transfer_rate())
250            .field("Block Count", &self.block_count())
251            .field("Card Size (bytes)", &self.card_size())
252            .field("Read I (@min VDD)", &self.read_current_minimum_vdd())
253            .field("Write I (@min VDD)", &self.write_current_minimum_vdd())
254            .field("Read I (@max VDD)", &self.read_current_maximum_vdd())
255            .field("Write I (@max VDD)", &self.write_current_maximum_vdd())
256            .field("Erase Size (Blocks)", &self.erase_size_blocks())
257            .finish()
258    }
259}
260
261impl CardStatus<SD> {
262    /// Command was executed without internal ECC
263    pub fn ecc_disabled(&self) -> bool {
264        self.0 & 0x4000 != 0
265    }
266    /// Extension function specific status
267    pub fn fx_event(&self) -> bool {
268        self.0 & 0x40 != 0
269    }
270    /// Authentication sequence error
271    pub fn ake_seq_error(&self) -> bool {
272        self.0 & 0x8 != 0
273    }
274}
275
276impl fmt::Debug for CardStatus<SD> {
277    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278        f.debug_struct("Card Status")
279            .field("Out of range error", &self.out_of_range())
280            .field("Address error", &self.address_error())
281            .field("Block len error", &self.block_len_error())
282            .field("Erase seq error", &self.erase_seq_error())
283            .field("Erase param error", &self.erase_param())
284            .field("Write protect error", &self.wp_violation())
285            .field("Card locked", &self.card_is_locked())
286            .field("Password lock unlock error", &self.lock_unlock_failed())
287            .field(
288                "Crc check for the previous command failed",
289                &self.com_crc_error(),
290            )
291            .field("Illegal command", &self.illegal_command())
292            .field("Card internal ecc failed", &self.card_ecc_failed())
293            .field("Internal card controller error", &self.cc_error())
294            .field("General Error", &self.error())
295            .field("Csd error", &self.csd_overwrite())
296            .field("Write protect error", &self.wp_erase_skip())
297            .field("Command ecc disabled", &self.ecc_disabled())
298            .field("Erase sequence cleared", &self.erase_reset())
299            .field("Card state", &self.state())
300            .field("Buffer empty", &self.ready_for_data())
301            .field("Extension event", &self.fx_event())
302            .field("Card expects app cmd", &self.app_cmd())
303            .field("Auth process error", &self.ake_seq_error())
304            .finish()
305    }
306}
307
308/// SD Status
309///
310/// Status bits related to SD Memory Card proprietary features
311///
312/// Ref PLSS_v7_10 Section 4.10.2 SD Status
313#[derive(Clone, Copy, Default)]
314pub struct SDStatus {
315    inner: [u32; 16],
316}
317/// From little endian words
318impl From<[u32; 16]> for SDStatus {
319    fn from(inner: [u32; 16]) -> Self {
320        Self { inner }
321    }
322}
323impl SDStatus {
324    /// Current data bus width
325    pub fn bus_width(&self) -> BusWidth {
326        match (self.inner[15] >> 30) & 3 {
327            0 => BusWidth::One,
328            2 => BusWidth::Four,
329            _ => BusWidth::Unknown,
330        }
331    }
332    /// Is the card currently in the secured mode
333    pub fn secure_mode(&self) -> bool {
334        self.inner[15] & 0x2000_0000 != 0
335    }
336    /// SD Memory Card type (ROM, OTP, etc)
337    pub fn sd_memory_card_type(&self) -> u16 {
338        self.inner[15] as u16
339    }
340    /// SDHC / SDXC: Capacity of Protected Area in bytes
341    pub fn protected_area_size(&self) -> u32 {
342        self.inner[14]
343    }
344    /// Speed Class
345    pub fn speed_class(&self) -> u8 {
346        (self.inner[13] >> 24) as u8
347    }
348    /// "Performance Move" indicator in 1 MB/s units
349    pub fn move_performance(&self) -> u8 {
350        (self.inner[13] >> 16) as u8
351    }
352    /// Allocation Unit (AU) size. Lookup in PLSS v7_10 Table 4-47
353    pub fn allocation_unit_size(&self) -> u8 {
354        (self.inner[13] >> 12) as u8 & 0xF
355    }
356    /// Indicates N_Erase, in units of AU
357    pub fn erase_size(&self) -> u16 {
358        (self.inner[13] & 0xFF) as u16 | ((self.inner[12] >> 24) & 0xFF) as u16
359    }
360    /// Indicates T_Erase / Erase Timeout (s)
361    pub fn erase_timeout(&self) -> u8 {
362        (self.inner[12] >> 18) as u8 & 0x3F
363    }
364    /// Video speed class
365    pub fn video_speed_class(&self) -> u8 {
366        (self.inner[11] & 0xFF) as u8
367    }
368    /// Application Performance Class
369    pub fn app_perf_class(&self) -> u8 {
370        (self.inner[9] >> 16) as u8 & 0xF
371    }
372    /// Discard Support
373    pub fn discard_support(&self) -> bool {
374        self.inner[8] & 0x0200_0000 != 0
375    }
376}
377impl fmt::Debug for SDStatus {
378    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
379        f.debug_struct("SD Status")
380            .field("Bus Width", &self.bus_width())
381            .field("Secured Mode", &self.secure_mode())
382            .field("SD Memory Card Type", &self.sd_memory_card_type())
383            .field("Protected Area Size (B)", &self.protected_area_size())
384            .field("Speed Class", &self.speed_class())
385            .field("Video Speed Class", &self.video_speed_class())
386            .field("Application Performance Class", &self.app_perf_class())
387            .field("Move Performance (MB/s)", &self.move_performance())
388            .field("AU Size", &self.allocation_unit_size())
389            .field("Erase Size (units of AU)", &self.erase_size())
390            .field("Erase Timeout (s)", &self.erase_timeout())
391            .field("Discard Support", &self.discard_support())
392            .finish()
393    }
394}
395
396/// Card interface condition (R7)
397#[derive(Copy, Clone, Default)]
398pub struct CIC(u32);
399impl From<u32> for CIC {
400    fn from(word: u32) -> Self {
401        Self(word)
402    }
403}
404impl CIC {
405    /// The voltage range the card accepts
406    pub fn voltage_accepted(&self) -> u8 {
407        (self.0 >> 8) as u8
408    }
409    /// Echo-back check pattern
410    pub fn pattern(&self) -> u8 {
411        self.0 as u8
412    }
413}
414
415impl RCA<SD> {
416    /// Status
417    pub fn status(&self) -> u16 {
418        self.0 as u16
419    }
420}