diff options
Diffstat (limited to 'embassy-stm32/src/sdmmc/sd.rs')
| -rw-r--r-- | embassy-stm32/src/sdmmc/sd.rs | 693 |
1 files changed, 693 insertions, 0 deletions
diff --git a/embassy-stm32/src/sdmmc/sd.rs b/embassy-stm32/src/sdmmc/sd.rs new file mode 100644 index 000000000..6190226b8 --- /dev/null +++ b/embassy-stm32/src/sdmmc/sd.rs | |||
| @@ -0,0 +1,693 @@ | |||
| 1 | use core::default::Default; | ||
| 2 | use core::ops::{Deref, DerefMut}; | ||
| 3 | |||
| 4 | use sdio_host::emmc::{EMMC, ExtCSD}; | ||
| 5 | use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; | ||
| 6 | use sdio_host::{common_cmd, emmc_cmd, sd_cmd}; | ||
| 7 | |||
| 8 | use crate::sdmmc::{BlockSize, Error, Sdmmc, Signalling, block_size, bus_width_vals, slice8_mut, slice8_ref}; | ||
| 9 | use crate::time::{Hertz, mhz}; | ||
| 10 | |||
| 11 | /// Aligned data block for SDMMC transfers. | ||
| 12 | /// | ||
| 13 | /// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements. | ||
| 14 | #[repr(align(4))] | ||
| 15 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 16 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 17 | pub struct DataBlock(pub [u32; 128]); | ||
| 18 | |||
| 19 | impl DataBlock { | ||
| 20 | /// Create a new DataBlock | ||
| 21 | pub const fn new() -> Self { | ||
| 22 | DataBlock([0u32; 128]) | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | impl Deref for DataBlock { | ||
| 27 | type Target = [u8; 512]; | ||
| 28 | |||
| 29 | fn deref(&self) -> &Self::Target { | ||
| 30 | unwrap!(slice8_ref(&self.0[..]).try_into()) | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | impl DerefMut for DataBlock { | ||
| 35 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 36 | unwrap!(slice8_mut(&mut self.0[..]).try_into()) | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | /// Command Block buffer for SDMMC command transfers. | ||
| 41 | /// | ||
| 42 | /// This is a 16-word array, exposed so that DMA commpatible memory can be used if required. | ||
| 43 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 44 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 45 | pub struct CmdBlock(pub [u32; 16]); | ||
| 46 | |||
| 47 | impl CmdBlock { | ||
| 48 | /// Creates a new instance of CmdBlock | ||
| 49 | pub const fn new() -> Self { | ||
| 50 | Self([0u32; 16]) | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | impl Deref for CmdBlock { | ||
| 55 | type Target = [u32; 16]; | ||
| 56 | |||
| 57 | fn deref(&self) -> &Self::Target { | ||
| 58 | &self.0 | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | impl DerefMut for CmdBlock { | ||
| 63 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 64 | &mut self.0 | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Represents either an SD or EMMC card | ||
| 69 | pub trait Addressable: Sized + Clone { | ||
| 70 | /// Associated type | ||
| 71 | type Ext; | ||
| 72 | |||
| 73 | /// Get this peripheral's address on the SDMMC bus | ||
| 74 | fn get_address(&self) -> u16; | ||
| 75 | |||
| 76 | /// Is this a standard or high capacity peripheral? | ||
| 77 | fn get_capacity(&self) -> CardCapacity; | ||
| 78 | |||
| 79 | /// Size in bytes | ||
| 80 | fn size(&self) -> u64; | ||
| 81 | } | ||
| 82 | |||
| 83 | /// Storage Device | ||
| 84 | pub struct StorageDevice<'a, 'b, T: Addressable> { | ||
| 85 | info: T, | ||
| 86 | /// Inner member | ||
| 87 | pub sdmmc: &'a mut Sdmmc<'b>, | ||
| 88 | } | ||
| 89 | |||
| 90 | /// Card Storage Device | ||
| 91 | impl<'a, 'b> StorageDevice<'a, 'b, Card> { | ||
| 92 | /// Create a new SD card | ||
| 93 | pub async fn new_sd_card(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> { | ||
| 94 | let mut s = Self { | ||
| 95 | info: Card::default(), | ||
| 96 | sdmmc, | ||
| 97 | }; | ||
| 98 | |||
| 99 | s.acquire(cmd_block, freq).await?; | ||
| 100 | |||
| 101 | Ok(s) | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Initializes the card into a known state (or at least tries to). | ||
| 105 | async fn acquire(&mut self, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<(), Error> { | ||
| 106 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 107 | let regs = self.sdmmc.info.regs; | ||
| 108 | |||
| 109 | let _bus_width = match self.sdmmc.bus_width() { | ||
| 110 | BusWidth::Eight => return Err(Error::BusWidth), | ||
| 111 | bus_width => bus_width, | ||
| 112 | }; | ||
| 113 | |||
| 114 | // While the SD/SDIO card or eMMC is in identification mode, | ||
| 115 | // the SDMMC_CK frequency must be no more than 400 kHz. | ||
| 116 | self.sdmmc.init_idle()?; | ||
| 117 | |||
| 118 | // Check if cards supports CMD8 (with pattern) | ||
| 119 | self.sdmmc.cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; | ||
| 120 | let cic = CIC::from(regs.respr(0).read().cardstatus()); | ||
| 121 | |||
| 122 | if cic.pattern() != 0xAA { | ||
| 123 | return Err(Error::UnsupportedCardVersion); | ||
| 124 | } | ||
| 125 | |||
| 126 | if cic.voltage_accepted() & 1 == 0 { | ||
| 127 | return Err(Error::UnsupportedVoltage); | ||
| 128 | } | ||
| 129 | |||
| 130 | let ocr = loop { | ||
| 131 | // Signal that next command is a app command | ||
| 132 | self.sdmmc.cmd(common_cmd::app_cmd(0), false)?; // CMD55 | ||
| 133 | |||
| 134 | // 3.2-3.3V | ||
| 135 | let voltage_window = 1 << 5; | ||
| 136 | // Initialize card | ||
| 137 | match self | ||
| 138 | .sdmmc | ||
| 139 | .cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) | ||
| 140 | { | ||
| 141 | // ACMD41 | ||
| 142 | Ok(_) => (), | ||
| 143 | Err(Error::Crc) => (), | ||
| 144 | Err(err) => return Err(err), | ||
| 145 | } | ||
| 146 | |||
| 147 | let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into(); | ||
| 148 | if !ocr.is_busy() { | ||
| 149 | // Power up done | ||
| 150 | break ocr; | ||
| 151 | } | ||
| 152 | }; | ||
| 153 | |||
| 154 | if ocr.high_capacity() { | ||
| 155 | // Card is SDHC or SDXC or SDUC | ||
| 156 | self.info.card_type = CardCapacity::HighCapacity; | ||
| 157 | } else { | ||
| 158 | self.info.card_type = CardCapacity::StandardCapacity; | ||
| 159 | } | ||
| 160 | self.info.ocr = ocr; | ||
| 161 | |||
| 162 | self.info.cid = self.sdmmc.get_cid()?.into(); | ||
| 163 | |||
| 164 | self.sdmmc.cmd(sd_cmd::send_relative_address(), false)?; | ||
| 165 | let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus()); | ||
| 166 | self.info.rca = rca.address(); | ||
| 167 | |||
| 168 | self.info.csd = self.sdmmc.get_csd(self.info.get_address())?.into(); | ||
| 169 | self.sdmmc.select_card(Some(self.info.get_address()))?; | ||
| 170 | |||
| 171 | self.info.scr = self.get_scr(cmd_block).await?; | ||
| 172 | |||
| 173 | let (bus_width, acmd_arg) = if !self.info.scr.bus_width_four() { | ||
| 174 | (BusWidth::One, 0) | ||
| 175 | } else { | ||
| 176 | (BusWidth::Four, 2) | ||
| 177 | }; | ||
| 178 | |||
| 179 | self.sdmmc.cmd(common_cmd::app_cmd(self.info.rca), false)?; | ||
| 180 | self.sdmmc.cmd(sd_cmd::cmd6(acmd_arg), false)?; | ||
| 181 | |||
| 182 | self.sdmmc.clkcr_set_clkdiv(freq.clamp(mhz(0), mhz(25)), bus_width)?; | ||
| 183 | |||
| 184 | // Read status | ||
| 185 | self.info.status = self.read_sd_status(cmd_block).await?; | ||
| 186 | |||
| 187 | if freq > mhz(25) { | ||
| 188 | // Switch to SDR25 | ||
| 189 | self.sdmmc.signalling = self.switch_signalling_mode(cmd_block, Signalling::SDR25).await?; | ||
| 190 | |||
| 191 | if self.sdmmc.signalling == Signalling::SDR25 { | ||
| 192 | // Set final clock frequency | ||
| 193 | self.sdmmc.clkcr_set_clkdiv(freq, bus_width)?; | ||
| 194 | |||
| 195 | if self.sdmmc.read_status(&self.info)?.state() != CurrentState::Transfer { | ||
| 196 | return Err(Error::SignalingSwitchFailed); | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | // Read status after signalling change | ||
| 201 | self.read_sd_status(cmd_block).await?; | ||
| 202 | } | ||
| 203 | |||
| 204 | Ok(()) | ||
| 205 | } | ||
| 206 | |||
| 207 | /// Switch mode using CMD6. | ||
| 208 | /// | ||
| 209 | /// Attempt to set a new signalling mode. The selected | ||
| 210 | /// signalling mode is returned. Expects the current clock | ||
| 211 | /// frequency to be > 12.5MHz. | ||
| 212 | /// | ||
| 213 | /// SD only. | ||
| 214 | async fn switch_signalling_mode( | ||
| 215 | &self, | ||
| 216 | cmd_block: &mut CmdBlock, | ||
| 217 | signalling: Signalling, | ||
| 218 | ) -> Result<Signalling, Error> { | ||
| 219 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not | ||
| 220 | // necessary" | ||
| 221 | |||
| 222 | let set_function = 0x8000_0000 | ||
| 223 | | match signalling { | ||
| 224 | // See PLSS v7_10 Table 4-11 | ||
| 225 | Signalling::DDR50 => 0xFF_FF04, | ||
| 226 | Signalling::SDR104 => 0xFF_1F03, | ||
| 227 | Signalling::SDR50 => 0xFF_1F02, | ||
| 228 | Signalling::SDR25 => 0xFF_FF01, | ||
| 229 | Signalling::SDR12 => 0xFF_FF00, | ||
| 230 | }; | ||
| 231 | |||
| 232 | let buffer = &mut cmd_block.0[..64 / 4]; | ||
| 233 | |||
| 234 | let transfer = self | ||
| 235 | .sdmmc | ||
| 236 | .prepare_datapath_read(buffer, block_size(size_of_val(buffer)), false); | ||
| 237 | |||
| 238 | self.sdmmc.cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 | ||
| 239 | |||
| 240 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 241 | |||
| 242 | // Host is allowed to use the new functions at least 8 | ||
| 243 | // clocks after the end of the switch command | ||
| 244 | // transaction. We know the current clock period is < 80ns, | ||
| 245 | // so a total delay of 640ns is required here | ||
| 246 | for _ in 0..300 { | ||
| 247 | cortex_m::asm::nop(); | ||
| 248 | } | ||
| 249 | |||
| 250 | // Function Selection of Function Group 1 | ||
| 251 | let selection = (u32::from_be(cmd_block[4]) >> 24) & 0xF; | ||
| 252 | |||
| 253 | match selection { | ||
| 254 | 0 => Ok(Signalling::SDR12), | ||
| 255 | 1 => Ok(Signalling::SDR25), | ||
| 256 | 2 => Ok(Signalling::SDR50), | ||
| 257 | 3 => Ok(Signalling::SDR104), | ||
| 258 | 4 => Ok(Signalling::DDR50), | ||
| 259 | _ => Err(Error::UnsupportedCardType), | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | /// Reads the SCR register. | ||
| 264 | /// | ||
| 265 | /// SD only. | ||
| 266 | async fn get_scr(&self, cmd_block: &mut CmdBlock) -> Result<SCR, Error> { | ||
| 267 | // Read the 64-bit SCR register | ||
| 268 | self.sdmmc.cmd(common_cmd::set_block_length(8), false)?; // CMD16 | ||
| 269 | self.sdmmc.cmd(common_cmd::app_cmd(self.info.rca), false)?; | ||
| 270 | |||
| 271 | let scr = &mut cmd_block.0[..2]; | ||
| 272 | |||
| 273 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 274 | |||
| 275 | let transfer = self.sdmmc.prepare_datapath_read(scr, BlockSize::Size8, false); | ||
| 276 | self.sdmmc.cmd(sd_cmd::send_scr(), true)?; | ||
| 277 | |||
| 278 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 279 | |||
| 280 | Ok(SCR(u64::from_be_bytes(unwrap!(slice8_mut(scr).try_into())))) | ||
| 281 | } | ||
| 282 | |||
| 283 | /// Reads the SD Status (ACMD13) | ||
| 284 | /// | ||
| 285 | /// SD only. | ||
| 286 | async fn read_sd_status(&self, cmd_block: &mut CmdBlock) -> Result<SDStatus, Error> { | ||
| 287 | let rca = self.info.rca; | ||
| 288 | |||
| 289 | self.sdmmc.cmd(common_cmd::set_block_length(64), false)?; // CMD16 | ||
| 290 | self.sdmmc.cmd(common_cmd::app_cmd(rca), false)?; // APP | ||
| 291 | |||
| 292 | let buffer = &mut cmd_block.as_mut()[..64 / 4]; | ||
| 293 | |||
| 294 | let transfer = self | ||
| 295 | .sdmmc | ||
| 296 | .prepare_datapath_read(buffer, block_size(size_of_val(buffer)), false); | ||
| 297 | self.sdmmc.cmd(sd_cmd::sd_status(), true)?; | ||
| 298 | |||
| 299 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 300 | |||
| 301 | for byte in cmd_block.iter_mut() { | ||
| 302 | *byte = u32::from_be(*byte); | ||
| 303 | } | ||
| 304 | |||
| 305 | Ok(cmd_block.0.into()) | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | /// Emmc storage device | ||
| 310 | impl<'a, 'b> StorageDevice<'a, 'b, Emmc> { | ||
| 311 | /// Create a new EMMC card | ||
| 312 | pub async fn new_emmc(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> { | ||
| 313 | let mut s = Self { | ||
| 314 | info: Emmc::default(), | ||
| 315 | sdmmc, | ||
| 316 | }; | ||
| 317 | |||
| 318 | s.acquire(cmd_block, freq).await?; | ||
| 319 | |||
| 320 | Ok(s) | ||
| 321 | } | ||
| 322 | |||
| 323 | async fn acquire(&mut self, _cmd_block: &mut CmdBlock, freq: Hertz) -> Result<(), Error> { | ||
| 324 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 325 | let regs = self.sdmmc.info.regs; | ||
| 326 | |||
| 327 | let bus_width = self.sdmmc.bus_width(); | ||
| 328 | |||
| 329 | // While the SD/SDIO card or eMMC is in identification mode, | ||
| 330 | // the SDMMC_CK frequency must be no more than 400 kHz. | ||
| 331 | self.sdmmc.init_idle()?; | ||
| 332 | |||
| 333 | let ocr = loop { | ||
| 334 | let high_voltage = 0b0 << 7; | ||
| 335 | let access_mode = 0b10 << 29; | ||
| 336 | let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; | ||
| 337 | // Initialize card | ||
| 338 | match self.sdmmc.cmd(emmc_cmd::send_op_cond(op_cond), false) { | ||
| 339 | Ok(_) => (), | ||
| 340 | Err(Error::Crc) => (), | ||
| 341 | Err(err) => return Err(err), | ||
| 342 | } | ||
| 343 | let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into(); | ||
| 344 | if !ocr.is_busy() { | ||
| 345 | // Power up done | ||
| 346 | break ocr; | ||
| 347 | } | ||
| 348 | }; | ||
| 349 | |||
| 350 | self.info.capacity = if ocr.access_mode() == 0b10 { | ||
| 351 | // Card is SDHC or SDXC or SDUC | ||
| 352 | CardCapacity::HighCapacity | ||
| 353 | } else { | ||
| 354 | CardCapacity::StandardCapacity | ||
| 355 | }; | ||
| 356 | self.info.ocr = ocr; | ||
| 357 | |||
| 358 | self.info.cid = self.sdmmc.get_cid()?.into(); | ||
| 359 | |||
| 360 | self.info.rca = 1u16.into(); | ||
| 361 | self.sdmmc | ||
| 362 | .cmd(emmc_cmd::assign_relative_address(self.info.rca), false)?; | ||
| 363 | |||
| 364 | self.info.csd = self.sdmmc.get_csd(self.info.get_address())?.into(); | ||
| 365 | self.sdmmc.select_card(Some(self.info.get_address()))?; | ||
| 366 | |||
| 367 | let (widbus, _) = bus_width_vals(bus_width); | ||
| 368 | |||
| 369 | // Write bus width to ExtCSD byte 183 | ||
| 370 | self.sdmmc.cmd( | ||
| 371 | emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), | ||
| 372 | false, | ||
| 373 | )?; | ||
| 374 | |||
| 375 | // Wait for ready after R1b response | ||
| 376 | loop { | ||
| 377 | let status = self.sdmmc.read_status(&self.info)?; | ||
| 378 | |||
| 379 | if status.ready_for_data() { | ||
| 380 | break; | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | self.sdmmc.clkcr_set_clkdiv(freq.clamp(mhz(0), mhz(25)), bus_width)?; | ||
| 385 | self.info.ext_csd = self.read_ext_csd().await?; | ||
| 386 | |||
| 387 | Ok(()) | ||
| 388 | } | ||
| 389 | |||
| 390 | /// Gets the EXT_CSD register. | ||
| 391 | /// | ||
| 392 | /// eMMC only. | ||
| 393 | async fn read_ext_csd(&self) -> Result<ExtCSD, Error> { | ||
| 394 | // Note: cmd_block can't be used because ExtCSD is too long to fit. | ||
| 395 | let mut data_block = DataBlock::new(); | ||
| 396 | |||
| 397 | self.sdmmc | ||
| 398 | .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false) | ||
| 399 | .unwrap(); // CMD16 | ||
| 400 | |||
| 401 | let transfer = self | ||
| 402 | .sdmmc | ||
| 403 | .prepare_datapath_read(&mut data_block.0, block_size(size_of::<DataBlock>()), false); | ||
| 404 | self.sdmmc.cmd(emmc_cmd::send_ext_csd(), true)?; | ||
| 405 | |||
| 406 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 407 | |||
| 408 | Ok(data_block.0.into()) | ||
| 409 | } | ||
| 410 | } | ||
| 411 | |||
| 412 | /// Card or Emmc storage device | ||
| 413 | impl<'a, 'b, A: Addressable> StorageDevice<'a, 'b, A> { | ||
| 414 | /// Write a block | ||
| 415 | pub fn card(&self) -> A { | ||
| 416 | self.info.clone() | ||
| 417 | } | ||
| 418 | |||
| 419 | /// Read a data block. | ||
| 420 | #[inline] | ||
| 421 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | ||
| 422 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 423 | let card_capacity = self.info.get_capacity(); | ||
| 424 | |||
| 425 | // Always read 1 block of 512 bytes | ||
| 426 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 427 | let address = match card_capacity { | ||
| 428 | CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32, | ||
| 429 | _ => block_idx, | ||
| 430 | }; | ||
| 431 | self.sdmmc | ||
| 432 | .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16 | ||
| 433 | |||
| 434 | let transfer = self | ||
| 435 | .sdmmc | ||
| 436 | .prepare_datapath_read(&mut buffer.0, block_size(size_of::<DataBlock>()), false); | ||
| 437 | self.sdmmc.cmd(common_cmd::read_single_block(address), true)?; | ||
| 438 | |||
| 439 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 440 | |||
| 441 | Ok(()) | ||
| 442 | } | ||
| 443 | |||
| 444 | /// Read multiple data blocks. | ||
| 445 | #[inline] | ||
| 446 | pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { | ||
| 447 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 448 | let card_capacity = self.info.get_capacity(); | ||
| 449 | |||
| 450 | // NOTE(unsafe) reinterpret buffer as &mut [u32] | ||
| 451 | let buffer = unsafe { | ||
| 452 | core::slice::from_raw_parts_mut( | ||
| 453 | blocks.as_mut_ptr() as *mut u32, | ||
| 454 | blocks.len() * size_of::<DataBlock>() / size_of::<u32>(), | ||
| 455 | ) | ||
| 456 | }; | ||
| 457 | |||
| 458 | // Always read 1 block of 512 bytes | ||
| 459 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 460 | let address = match card_capacity { | ||
| 461 | CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32, | ||
| 462 | _ => block_idx, | ||
| 463 | }; | ||
| 464 | self.sdmmc | ||
| 465 | .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16 | ||
| 466 | |||
| 467 | let transfer = self | ||
| 468 | .sdmmc | ||
| 469 | .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), false); | ||
| 470 | self.sdmmc.cmd(common_cmd::read_multiple_blocks(address), true)?; | ||
| 471 | |||
| 472 | self.sdmmc.complete_datapath_transfer(transfer, false).await?; | ||
| 473 | |||
| 474 | self.sdmmc.cmd(common_cmd::stop_transmission(), false)?; // CMD12 | ||
| 475 | self.sdmmc.clear_interrupt_flags(); | ||
| 476 | |||
| 477 | Ok(()) | ||
| 478 | } | ||
| 479 | |||
| 480 | /// Write a data block. | ||
| 481 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> | ||
| 482 | where | ||
| 483 | CardStatus<A::Ext>: From<u32>, | ||
| 484 | { | ||
| 485 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 486 | |||
| 487 | // Always read 1 block of 512 bytes | ||
| 488 | // cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 489 | let address = match self.info.get_capacity() { | ||
| 490 | CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32, | ||
| 491 | _ => block_idx, | ||
| 492 | }; | ||
| 493 | self.sdmmc | ||
| 494 | .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16 | ||
| 495 | |||
| 496 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||
| 497 | #[cfg(sdmmc_v1)] | ||
| 498 | self.sdmmc.cmd(common_cmd::write_single_block(address), true)?; | ||
| 499 | |||
| 500 | let transfer = self | ||
| 501 | .sdmmc | ||
| 502 | .prepare_datapath_write(&buffer.0, block_size(size_of::<DataBlock>()), false); | ||
| 503 | |||
| 504 | #[cfg(sdmmc_v2)] | ||
| 505 | self.sdmmc.cmd(common_cmd::write_single_block(address), true)?; | ||
| 506 | |||
| 507 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 508 | |||
| 509 | // TODO: Make this configurable | ||
| 510 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 511 | |||
| 512 | while timeout > 0 { | ||
| 513 | let ready_for_data = self.sdmmc.read_status(&self.info)?.ready_for_data(); | ||
| 514 | if ready_for_data { | ||
| 515 | return Ok(()); | ||
| 516 | } | ||
| 517 | timeout -= 1; | ||
| 518 | } | ||
| 519 | |||
| 520 | Err(Error::SoftwareTimeout) | ||
| 521 | } | ||
| 522 | |||
| 523 | /// Write multiple data blocks. | ||
| 524 | pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> | ||
| 525 | where | ||
| 526 | CardStatus<A::Ext>: From<u32>, | ||
| 527 | { | ||
| 528 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 529 | |||
| 530 | // NOTE(unsafe) reinterpret buffer as &[u32] | ||
| 531 | let buffer = unsafe { | ||
| 532 | core::slice::from_raw_parts( | ||
| 533 | blocks.as_ptr() as *const u32, | ||
| 534 | blocks.len() * size_of::<DataBlock>() / size_of::<u32>(), | ||
| 535 | ) | ||
| 536 | }; | ||
| 537 | // Always read 1 block of 512 bytes | ||
| 538 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 539 | let address = match self.info.get_capacity() { | ||
| 540 | CardCapacity::StandardCapacity => block_idx * size_of::<DataBlock>() as u32, | ||
| 541 | _ => block_idx, | ||
| 542 | }; | ||
| 543 | |||
| 544 | self.sdmmc | ||
| 545 | .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16 | ||
| 546 | |||
| 547 | #[cfg(sdmmc_v1)] | ||
| 548 | self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | ||
| 549 | |||
| 550 | // Setup write command | ||
| 551 | let transfer = self | ||
| 552 | .sdmmc | ||
| 553 | .prepare_datapath_write(buffer, block_size(size_of::<DataBlock>()), false); | ||
| 554 | |||
| 555 | #[cfg(sdmmc_v2)] | ||
| 556 | self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | ||
| 557 | |||
| 558 | self.sdmmc.complete_datapath_transfer(transfer, false).await?; | ||
| 559 | |||
| 560 | self.sdmmc.cmd(common_cmd::stop_transmission(), false)?; // CMD12 | ||
| 561 | self.sdmmc.clear_interrupt_flags(); | ||
| 562 | |||
| 563 | // TODO: Make this configurable | ||
| 564 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 565 | |||
| 566 | while timeout > 0 { | ||
| 567 | let ready_for_data = self.sdmmc.read_status(&self.info)?.ready_for_data(); | ||
| 568 | |||
| 569 | if ready_for_data { | ||
| 570 | return Ok(()); | ||
| 571 | } | ||
| 572 | timeout -= 1; | ||
| 573 | } | ||
| 574 | Err(Error::SoftwareTimeout) | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | #[derive(Clone, Copy, Debug, Default)] | ||
| 579 | /// SD Card | ||
| 580 | pub struct Card { | ||
| 581 | /// The type of this card | ||
| 582 | pub card_type: CardCapacity, | ||
| 583 | /// Operation Conditions Register | ||
| 584 | pub ocr: OCR<SD>, | ||
| 585 | /// Relative Card Address | ||
| 586 | pub rca: u16, | ||
| 587 | /// Card ID | ||
| 588 | pub cid: CID<SD>, | ||
| 589 | /// Card Specific Data | ||
| 590 | pub csd: CSD<SD>, | ||
| 591 | /// SD CARD Configuration Register | ||
| 592 | pub scr: SCR, | ||
| 593 | /// SD Status | ||
| 594 | pub status: SDStatus, | ||
| 595 | } | ||
| 596 | |||
| 597 | impl Addressable for Card { | ||
| 598 | type Ext = SD; | ||
| 599 | |||
| 600 | /// Get this peripheral's address on the SDMMC bus | ||
| 601 | fn get_address(&self) -> u16 { | ||
| 602 | self.rca | ||
| 603 | } | ||
| 604 | |||
| 605 | /// Is this a standard or high capacity peripheral? | ||
| 606 | fn get_capacity(&self) -> CardCapacity { | ||
| 607 | self.card_type | ||
| 608 | } | ||
| 609 | |||
| 610 | /// Size in bytes | ||
| 611 | fn size(&self) -> u64 { | ||
| 612 | u64::from(self.csd.block_count()) * 512 | ||
| 613 | } | ||
| 614 | } | ||
| 615 | |||
| 616 | #[derive(Clone, Copy, Debug, Default)] | ||
| 617 | /// eMMC storage | ||
| 618 | pub struct Emmc { | ||
| 619 | /// The capacity of this card | ||
| 620 | pub capacity: CardCapacity, | ||
| 621 | /// Operation Conditions Register | ||
| 622 | pub ocr: OCR<EMMC>, | ||
| 623 | /// Relative Card Address | ||
| 624 | pub rca: u16, | ||
| 625 | /// Card ID | ||
| 626 | pub cid: CID<EMMC>, | ||
| 627 | /// Card Specific Data | ||
| 628 | pub csd: CSD<EMMC>, | ||
| 629 | /// Extended Card Specific Data | ||
| 630 | pub ext_csd: ExtCSD, | ||
| 631 | } | ||
| 632 | |||
| 633 | impl Addressable for Emmc { | ||
| 634 | type Ext = EMMC; | ||
| 635 | |||
| 636 | /// Get this peripheral's address on the SDMMC bus | ||
| 637 | fn get_address(&self) -> u16 { | ||
| 638 | self.rca | ||
| 639 | } | ||
| 640 | |||
| 641 | /// Is this a standard or high capacity peripheral? | ||
| 642 | fn get_capacity(&self) -> CardCapacity { | ||
| 643 | self.capacity | ||
| 644 | } | ||
| 645 | |||
| 646 | /// Size in bytes | ||
| 647 | fn size(&self) -> u64 { | ||
| 648 | u64::from(self.ext_csd.sector_count()) * 512 | ||
| 649 | } | ||
| 650 | } | ||
| 651 | |||
| 652 | impl<'d, 'e, A: Addressable> block_device_driver::BlockDevice<512> for StorageDevice<'d, 'e, A> { | ||
| 653 | type Error = Error; | ||
| 654 | type Align = aligned::A4; | ||
| 655 | |||
| 656 | async fn read( | ||
| 657 | &mut self, | ||
| 658 | block_address: u32, | ||
| 659 | buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>], | ||
| 660 | ) -> Result<(), Self::Error> { | ||
| 661 | // TODO: I think block_address needs to be adjusted by the partition start offset | ||
| 662 | if buf.len() == 1 { | ||
| 663 | let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut DataBlock) }; | ||
| 664 | self.read_block(block_address, block).await?; | ||
| 665 | } else { | ||
| 666 | let blocks: &mut [DataBlock] = | ||
| 667 | unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) }; | ||
| 668 | self.read_blocks(block_address, blocks).await?; | ||
| 669 | } | ||
| 670 | Ok(()) | ||
| 671 | } | ||
| 672 | |||
| 673 | async fn write( | ||
| 674 | &mut self, | ||
| 675 | block_address: u32, | ||
| 676 | buf: &[aligned::Aligned<Self::Align, [u8; 512]>], | ||
| 677 | ) -> Result<(), Self::Error> { | ||
| 678 | // TODO: I think block_address needs to be adjusted by the partition start offset | ||
| 679 | if buf.len() == 1 { | ||
| 680 | let block = unsafe { &*(&buf[0] as *const _ as *const DataBlock) }; | ||
| 681 | self.write_block(block_address, block).await?; | ||
| 682 | } else { | ||
| 683 | let blocks: &[DataBlock] = | ||
| 684 | unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) }; | ||
| 685 | self.write_blocks(block_address, blocks).await?; | ||
| 686 | } | ||
| 687 | Ok(()) | ||
| 688 | } | ||
| 689 | |||
| 690 | async fn size(&mut self) -> Result<u64, Self::Error> { | ||
| 691 | Ok(self.info.size()) | ||
| 692 | } | ||
| 693 | } | ||
