sdio_host/
emmc.rs

1//! eMMC-specific extensions to the core SDMMC protocol.
2
3pub use crate::common::*;
4
5use core::{fmt, str};
6
7/// Type marker for eMMC-specific extensions.
8#[derive(Clone, Copy, Default, Debug)]
9pub struct EMMC;
10
11impl OCR<EMMC> {
12    /// OCR \[7\]. False for High Voltage, true for Dual voltage
13    pub fn is_dual_voltage_card(&self) -> bool {
14        self.0 & 0x0000_0080 != 0
15    }
16    /// OCR \[30:29\]. Access mode. Defines the addressing mode used between host and card
17    ///
18    /// 0b00: byte mode
19    /// 0b10: sector mode
20    pub fn access_mode(&self) -> u8 {
21        (self.0 & 0x6000_0000 >> 29) as u8
22    }
23}
24impl fmt::Debug for OCR<EMMC> {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        f.debug_struct("OCR: Operation Conditions Register")
27            .field(
28                "Dual Voltage",
29                &if self.is_dual_voltage_card() {
30                    "yes"
31                } else {
32                    "no"
33                },
34            )
35            .field(
36                "Access mode",
37                &match self.access_mode() {
38                    0b00 => "byte",
39                    0b10 => "sector",
40                    _ => "unknown",
41                },
42            )
43            .field("Busy", &self.is_busy())
44            .finish()
45    }
46}
47
48/// All possible values of the CBX field of the CID register on eMMC devices.
49#[derive(Debug, Copy, Clone, Eq, PartialEq)]
50pub enum DeviceType {
51    RemovableDevice = 0b00,
52    BGA = 0b01,
53    POP = 0b10,
54    Unknown = 0b11,
55}
56
57impl CID<EMMC> {
58    /// CBX field, indicating device type.
59    pub fn device_type(&self) -> DeviceType {
60        match self.bytes[1] & 0x3 {
61            0b00 => DeviceType::RemovableDevice,
62            0b01 => DeviceType::BGA,
63            0b10 => DeviceType::POP,
64            _ => DeviceType::POP,
65        }
66    }
67
68    /// OID field, indicating OEM/Application ID.
69    ///
70    /// The OID number is controlled, defined and allocated to an eMMC manufacturer by JEDEC.
71    pub fn oem_application_id(&self) -> u8 {
72        self.bytes[2]
73    }
74
75    /// PNM field, indicating product name.
76    pub fn product_name(&self) -> &str {
77        str::from_utf8(&self.bytes[3..9]).unwrap_or(&"<ERR>")
78    }
79
80    /// PRV field, indicating product revision.
81    ///
82    /// The return value is a (major, minor) version tuple.
83    pub fn product_revision(&self) -> (u8, u8) {
84        let major = (self.bytes[9] & 0xF0) >> 4;
85        let minor = self.bytes[9] & 0x0F;
86        (major, minor)
87    }
88
89    /// PSN field, indicating product serial number.
90    pub fn serial(&self) -> u32 {
91        (self.inner >> 16) as u32
92    }
93
94    /// MDT field, indicating manufacturing date.
95    ///
96    /// The return value is a (month, year) tuple where the month code has 1 = January and the year
97    /// is an offset from either 1997 or 2013 depending on the value of `EXT_CSD_REV`.
98    pub fn manufacturing_date(&self) -> (u8, u8) {
99        let month = (self.inner >> 12) as u8 & 0xF;
100        let year = (self.inner >> 8) as u8 & 0xF;
101        (month, year)
102    }
103}
104impl fmt::Debug for CID<EMMC> {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        f.debug_struct("CID: Card Identification")
107            .field("Manufacturer ID", &self.manufacturer_id())
108            .field("Device Type", &self.device_type())
109            .field("OEM ID", &self.oem_application_id())
110            .field("Product Name", &self.product_name())
111            .field("Product Revision", &self.product_revision())
112            .field("Product Serial Number", &self.serial())
113            .field("Manufacturing Date", &self.manufacturing_date())
114            .finish()
115    }
116}
117
118impl CSD<EMMC> {
119    /// Erase size (in blocks)
120    ///
121    /// Minimum number of write blocks that must be erased in a single erase
122    /// command
123    pub fn erase_size_blocks(&self) -> u32 {
124        let erase_grp_size = (self.0 >> 42) & 0x1F;
125        let erase_grp_mult = (self.0 >> 37) & 0x1F;
126
127        (erase_grp_size as u32 + 1) + (erase_grp_mult as u32 + 1)
128    }
129}
130impl fmt::Debug for CSD<EMMC> {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        f.debug_struct("CSD: Card Specific Data")
133            .field("Transfer Rate", &self.transfer_rate())
134            .field("Read I (@min VDD)", &self.read_current_minimum_vdd())
135            .field("Write I (@min VDD)", &self.write_current_minimum_vdd())
136            .field("Read I (@max VDD)", &self.read_current_maximum_vdd())
137            .field("Write I (@max VDD)", &self.write_current_maximum_vdd())
138            .field("Erase Size (Blocks)", &self.erase_size_blocks())
139            .finish()
140    }
141}
142
143impl CardStatus<EMMC> {
144    /// If set, the Device did not switch to the expected mode as requested by the SWITCH command
145    pub fn switch_error(&self) -> bool {
146        self.0 & 0x80 != 0
147    }
148    /// If set, one of the exception bits in field EXCEPTION_EVENTS_STATUS was set to indicate some
149    /// exception has occurred. Host should check that field to discover the exception that has
150    /// occurred to understand what further actions are needed in order to clear this bit.
151    pub fn exception_event(&self) -> bool {
152        self.0 & 0x40 != 0
153    }
154}
155impl fmt::Debug for CardStatus<EMMC> {
156    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157        f.debug_struct("Card Status")
158            .field("Out of range error", &self.out_of_range())
159            .field("Address error", &self.address_error())
160            .field("Block len error", &self.block_len_error())
161            .field("Erase seq error", &self.erase_seq_error())
162            .field("Erase param error", &self.erase_param())
163            .field("Write protect error", &self.wp_violation())
164            .field("Card locked", &self.card_is_locked())
165            .field("Password lock unlock error", &self.lock_unlock_failed())
166            .field(
167                "Crc check for the previous command failed",
168                &self.com_crc_error(),
169            )
170            .field("Illegal command", &self.illegal_command())
171            .field("Card internal ecc failed", &self.card_ecc_failed())
172            .field("Internal card controller error", &self.cc_error())
173            .field("General Error", &self.error())
174            .field("Csd error", &self.csd_overwrite())
175            .field("Write protect error", &self.wp_erase_skip())
176            .field("Erase sequence cleared", &self.erase_reset())
177            .field("Card state", &self.state())
178            .field("Buffer empty", &self.ready_for_data())
179            .field("Switch error", &self.switch_error())
180            .field("Exception event", &self.exception_event())
181            .field("Card expects app cmd", &self.app_cmd())
182            .finish()
183    }
184}
185
186/// Extended Card Specific Data
187///
188/// Ref JEDEC 84-A43 Section 8.4
189#[derive(Clone, Copy)]
190pub struct ExtCSD {
191    pub inner: [u32; 128],
192}
193impl Default for ExtCSD {
194    fn default() -> ExtCSD {
195        ExtCSD { inner: [0; 128] }
196    }
197}
198/// From little endian words
199impl From<[u32; 128]> for ExtCSD {
200    fn from(inner: [u32; 128]) -> Self {
201        Self { inner }
202    }
203}
204impl ExtCSD {
205    pub fn boot_info(&self) -> u8 {
206        // byte 228
207        (self.inner[57] >> 24) as u8
208    }
209    pub fn sleep_awake_timeout(&self) -> u8 {
210        // byte 217
211        (self.inner[54] >> 16) as u8
212    }
213    pub fn sleep_notification_time(&self) -> u8 {
214        // byte 216
215        (self.inner[54] >> 24) as u8
216    }
217    pub fn sector_count(&self) -> u32 {
218        // bytes [215:212]
219        self.inner[53]
220    }
221    pub fn driver_strength(&self) -> u8 {
222        // byte 197
223        (self.inner[49] >> 16) as u8
224    }
225    pub fn card_type(&self) -> u8 {
226        // byte 196
227        (self.inner[49] >> 24) as u8
228    }
229    pub fn csd_structure_version(&self) -> u8 {
230        // byte 194
231        (self.inner[48] >> 8) as u8
232    }
233    pub fn extended_csd_revision(&self) -> u8 {
234        // byte 192
235        (self.inner[48] >> 24) as u8
236    }
237    pub fn data_sector_size(&self) -> u8 {
238        // byte 61
239        (self.inner[15] >> 16) as u8
240    }
241    pub fn secure_removal_type(&self) -> u8 {
242        // byte 16
243        (self.inner[4] >> 24) as u8
244    }
245}
246impl fmt::Debug for ExtCSD {
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        f.debug_struct("Extended CSD")
249            .field("Boot Info", &self.boot_info())
250            .field("Sleep/Awake Timeout", &self.sleep_awake_timeout())
251            .field("Sleep Notification Time", &self.sleep_notification_time())
252            .field("Sector Count", &self.sector_count())
253            .field("Driver Strength", &self.driver_strength())
254            .field("Card Type", &self.card_type())
255            .field("CSD Structure Version", &self.csd_structure_version())
256            .field("Extended CSD Revision", &self.extended_csd_revision())
257            .field("Sector Size", &self.data_sector_size())
258            .field("Secure removal type", &self.secure_removal_type())
259            .finish()
260    }
261}
262
263/// eMMC hosts need to be able to create relative card addresses so that they can be assigned to
264/// devices. SD hosts only ever retrieve RCAs from 32-bit card responses.
265impl From<u16> for RCA<EMMC> {
266    fn from(address: u16) -> Self {
267        Self::from((address as u32) << 16)
268    }
269}