diff options
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 1260 |
1 files changed, 578 insertions, 682 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index ad00b4398..0d5260016 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -5,14 +5,16 @@ use core::default::Default; | |||
| 5 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | 6 | use core::marker::PhantomData; |
| 7 | use core::ops::{Deref, DerefMut}; | 7 | use core::ops::{Deref, DerefMut}; |
| 8 | use core::slice; | ||
| 8 | use core::task::Poll; | 9 | use core::task::Poll; |
| 9 | 10 | ||
| 10 | use embassy_hal_internal::drop::OnDrop; | 11 | use embassy_hal_internal::drop::OnDrop; |
| 11 | use embassy_hal_internal::{Peri, PeripheralType}; | 12 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 12 | use embassy_sync::waitqueue::AtomicWaker; | 13 | use embassy_sync::waitqueue::AtomicWaker; |
| 13 | use sdio_host::common_cmd::{self, Resp, ResponseLen}; | 14 | use sdio_host::common_cmd::{self, R1, R2, R3, Resp, ResponseLen, Rz}; |
| 14 | use sdio_host::emmc::{EMMC, ExtCSD}; | 15 | use sdio_host::emmc::{EMMC, ExtCSD}; |
| 15 | use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; | 16 | use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; |
| 17 | use sdio_host::sd_cmd::{R6, R7}; | ||
| 16 | use sdio_host::{Cmd, emmc_cmd, sd_cmd}; | 18 | use sdio_host::{Cmd, emmc_cmd, sd_cmd}; |
| 17 | 19 | ||
| 18 | #[cfg(sdmmc_v1)] | 20 | #[cfg(sdmmc_v1)] |
| @@ -23,7 +25,7 @@ use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; | |||
| 23 | use crate::interrupt::typelevel::Interrupt; | 25 | use crate::interrupt::typelevel::Interrupt; |
| 24 | use crate::pac::sdmmc::Sdmmc as RegBlock; | 26 | use crate::pac::sdmmc::Sdmmc as RegBlock; |
| 25 | use crate::rcc::{self, RccInfo, RccPeripheral, SealedRccPeripheral}; | 27 | use crate::rcc::{self, RccInfo, RccPeripheral, SealedRccPeripheral}; |
| 26 | use crate::time::Hertz; | 28 | use crate::time::{Hertz, mhz}; |
| 27 | use crate::{interrupt, peripherals}; | 29 | use crate::{interrupt, peripherals}; |
| 28 | 30 | ||
| 29 | /// Interrupt handler. | 31 | /// Interrupt handler. |
| @@ -60,6 +62,57 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 60 | } | 62 | } |
| 61 | } | 63 | } |
| 62 | 64 | ||
| 65 | struct U128(pub u128); | ||
| 66 | |||
| 67 | trait TypedResp: Resp { | ||
| 68 | type Word: From<U128>; | ||
| 69 | } | ||
| 70 | |||
| 71 | impl From<U128> for () { | ||
| 72 | fn from(value: U128) -> Self { | ||
| 73 | match value.0 { | ||
| 74 | 0 => (), | ||
| 75 | _ => unreachable!(), | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | impl From<U128> for u32 { | ||
| 81 | fn from(value: U128) -> Self { | ||
| 82 | unwrap!(value.0.try_into()) | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | impl From<U128> for u128 { | ||
| 87 | fn from(value: U128) -> Self { | ||
| 88 | value.0 | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | impl TypedResp for Rz { | ||
| 93 | type Word = (); | ||
| 94 | } | ||
| 95 | |||
| 96 | impl TypedResp for R1 { | ||
| 97 | type Word = u32; | ||
| 98 | } | ||
| 99 | |||
| 100 | impl TypedResp for R2 { | ||
| 101 | type Word = u128; | ||
| 102 | } | ||
| 103 | |||
| 104 | impl TypedResp for R3 { | ||
| 105 | type Word = u32; | ||
| 106 | } | ||
| 107 | |||
| 108 | impl TypedResp for R6 { | ||
| 109 | type Word = u32; | ||
| 110 | } | ||
| 111 | |||
| 112 | impl TypedResp for R7 { | ||
| 113 | type Word = u32; | ||
| 114 | } | ||
| 115 | |||
| 63 | /// Frequency used for SD Card initialization. Must be no higher than 400 kHz. | 116 | /// Frequency used for SD Card initialization. Must be no higher than 400 kHz. |
| 64 | const SD_INIT_FREQ: Hertz = Hertz(400_000); | 117 | const SD_INIT_FREQ: Hertz = Hertz(400_000); |
| 65 | 118 | ||
| @@ -104,6 +157,11 @@ impl DerefMut for DataBlock { | |||
| 104 | } | 157 | } |
| 105 | } | 158 | } |
| 106 | 159 | ||
| 160 | fn slice8_mut(x: &mut [u32]) -> &mut [u8] { | ||
| 161 | let len = x.len() * 4; | ||
| 162 | unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } | ||
| 163 | } | ||
| 164 | |||
| 107 | /// Command Block buffer for SDMMC command transfers. | 165 | /// Command Block buffer for SDMMC command transfers. |
| 108 | /// | 166 | /// |
| 109 | /// This is a 16-word array, exposed so that DMA commpatible memory can be used if required. | 167 | /// This is a 16-word array, exposed so that DMA commpatible memory can be used if required. |
| @@ -190,70 +248,119 @@ pub struct StorageDevice<'a, 'b, T: Addressable> { | |||
| 190 | impl<'a, 'b> StorageDevice<'a, 'b, Card> { | 248 | impl<'a, 'b> StorageDevice<'a, 'b, Card> { |
| 191 | /// Create a new SD card | 249 | /// Create a new SD card |
| 192 | pub async fn new_sd_card(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> { | 250 | pub async fn new_sd_card(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> { |
| 193 | let info = sdmmc.init_sd_card(cmd_block, freq).await?; | 251 | let mut s = Self { |
| 252 | info: Card::default(), | ||
| 253 | sdmmc, | ||
| 254 | }; | ||
| 255 | |||
| 256 | s.acquire(cmd_block, freq).await?; | ||
| 194 | 257 | ||
| 195 | Ok(Self { info, sdmmc }) | 258 | Ok(s) |
| 196 | } | 259 | } |
| 197 | } | ||
| 198 | 260 | ||
| 199 | /// Emmc storage device | 261 | /// Initializes the card into a known state (or at least tries to). |
| 200 | impl<'a, 'b> StorageDevice<'a, 'b, Emmc> { | 262 | pub async fn acquire(&mut self, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<(), Error> { |
| 201 | /// Create a new EMMC card | 263 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); |
| 202 | pub async fn new_emmc(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> { | 264 | let regs = self.sdmmc.info.regs; |
| 203 | let info = sdmmc.init_emmc(cmd_block, freq).await?; | ||
| 204 | 265 | ||
| 205 | Ok(Self { info, sdmmc }) | 266 | let _bus_width = match self.sdmmc.bus_width() { |
| 206 | } | 267 | BusWidth::Eight => return Err(Error::BusWidth), |
| 207 | } | 268 | bus_width => bus_width, |
| 269 | }; | ||
| 208 | 270 | ||
| 209 | /// Card or Emmc storage device | 271 | // While the SD/SDIO card or eMMC is in identification mode, |
| 210 | impl<'a, 'b, T: Addressable> StorageDevice<'a, 'b, T> { | 272 | // the SDMMC_CK frequency must be no more than 400 kHz. |
| 211 | /// Write a block | 273 | self.sdmmc.init_idle()?; |
| 212 | pub fn card(&self) -> T { | ||
| 213 | self.info.clone() | ||
| 214 | } | ||
| 215 | 274 | ||
| 216 | /// Write a block | 275 | // Check if cards supports CMD8 (with pattern) |
| 217 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | 276 | self.sdmmc.cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; |
| 218 | self.sdmmc.write_block(&mut self.info, block_idx, buffer).await | 277 | let cic = CIC::from(regs.respr(0).read().cardstatus()); |
| 219 | } | ||
| 220 | 278 | ||
| 221 | /// Write a block | 279 | if cic.pattern() != 0xAA { |
| 222 | pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> { | 280 | return Err(Error::UnsupportedCardVersion); |
| 223 | self.sdmmc.write_blocks(&mut self.info, block_idx, blocks).await | 281 | } |
| 224 | } | ||
| 225 | 282 | ||
| 226 | /// Read a block | 283 | if cic.voltage_accepted() & 1 == 0 { |
| 227 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | 284 | return Err(Error::UnsupportedVoltage); |
| 228 | self.sdmmc.read_block(&mut self.info, block_idx, buffer).await | 285 | } |
| 229 | } | ||
| 230 | 286 | ||
| 231 | /// Read a block | 287 | let ocr = loop { |
| 232 | pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { | 288 | // Signal that next command is a app command |
| 233 | self.sdmmc.read_blocks(&mut self.info, block_idx, blocks).await | 289 | self.sdmmc.cmd(common_cmd::app_cmd(0), false)?; // CMD55 |
| 234 | } | ||
| 235 | } | ||
| 236 | 290 | ||
| 237 | #[derive(Clone, Copy, Debug, Default)] | 291 | // 3.2-3.3V |
| 238 | /// SD Card | 292 | let voltage_window = 1 << 5; |
| 239 | pub struct Card { | 293 | // Initialize card |
| 240 | /// The type of this card | 294 | match self |
| 241 | pub card_type: CardCapacity, | 295 | .sdmmc |
| 242 | /// Operation Conditions Register | 296 | .cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) |
| 243 | pub ocr: OCR<SD>, | 297 | { |
| 244 | /// Relative Card Address | 298 | // ACMD41 |
| 245 | pub rca: u16, | 299 | Ok(_) => (), |
| 246 | /// Card ID | 300 | Err(Error::Crc) => (), |
| 247 | pub cid: CID<SD>, | 301 | Err(err) => return Err(err), |
| 248 | /// Card Specific Data | 302 | } |
| 249 | pub csd: CSD<SD>, | 303 | |
| 250 | /// SD CARD Configuration Register | 304 | let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into(); |
| 251 | pub scr: SCR, | 305 | if !ocr.is_busy() { |
| 252 | /// SD Status | 306 | // Power up done |
| 253 | pub status: SDStatus, | 307 | break ocr; |
| 254 | } | 308 | } |
| 309 | }; | ||
| 310 | |||
| 311 | if ocr.high_capacity() { | ||
| 312 | // Card is SDHC or SDXC or SDUC | ||
| 313 | self.info.card_type = CardCapacity::HighCapacity; | ||
| 314 | } else { | ||
| 315 | self.info.card_type = CardCapacity::StandardCapacity; | ||
| 316 | } | ||
| 317 | self.info.ocr = ocr; | ||
| 318 | |||
| 319 | self.info.cid = self.sdmmc.get_cid()?.into(); | ||
| 320 | |||
| 321 | self.sdmmc.cmd(sd_cmd::send_relative_address(), false)?; | ||
| 322 | let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus()); | ||
| 323 | self.info.rca = rca.address(); | ||
| 324 | |||
| 325 | self.info.csd = self.sdmmc.get_csd(self.info.get_address())?.into(); | ||
| 326 | self.sdmmc.select_card(Some(self.info.get_address()))?; | ||
| 327 | |||
| 328 | self.info.scr = self.get_scr(cmd_block).await?; | ||
| 329 | |||
| 330 | let (bus_width, acmd_arg) = if !self.info.scr.bus_width_four() { | ||
| 331 | (BusWidth::One, 0) | ||
| 332 | } else { | ||
| 333 | (BusWidth::Four, 2) | ||
| 334 | }; | ||
| 335 | |||
| 336 | self.sdmmc.cmd(common_cmd::app_cmd(self.info.rca), false)?; | ||
| 337 | self.sdmmc.cmd(sd_cmd::cmd6(acmd_arg), false)?; | ||
| 338 | |||
| 339 | self.sdmmc.clkcr_set_clkdiv(freq.clamp(mhz(0), mhz(25)), bus_width)?; | ||
| 340 | |||
| 341 | // Read status | ||
| 342 | self.info.status = self.read_sd_status(cmd_block).await?; | ||
| 343 | |||
| 344 | if freq > mhz(25) { | ||
| 345 | // Switch to SDR25 | ||
| 346 | self.sdmmc.signalling = self.switch_signalling_mode(cmd_block, Signalling::SDR25).await?; | ||
| 347 | |||
| 348 | if self.sdmmc.signalling == Signalling::SDR25 { | ||
| 349 | // Set final clock frequency | ||
| 350 | self.sdmmc.clkcr_set_clkdiv(freq, bus_width)?; | ||
| 351 | |||
| 352 | if self.sdmmc.read_status(&self.info)?.state() != CurrentState::Transfer { | ||
| 353 | return Err(Error::SignalingSwitchFailed); | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | // Read status after signalling change | ||
| 358 | self.read_sd_status(cmd_block).await?; | ||
| 359 | } | ||
| 360 | |||
| 361 | Ok(()) | ||
| 362 | } | ||
| 255 | 363 | ||
| 256 | impl Card { | ||
| 257 | /// Switch mode using CMD6. | 364 | /// Switch mode using CMD6. |
| 258 | /// | 365 | /// |
| 259 | /// Attempt to set a new signalling mode. The selected | 366 | /// Attempt to set a new signalling mode. The selected |
| @@ -261,9 +368,8 @@ impl Card { | |||
| 261 | /// frequency to be > 12.5MHz. | 368 | /// frequency to be > 12.5MHz. |
| 262 | /// | 369 | /// |
| 263 | /// SD only. | 370 | /// SD only. |
| 264 | async fn switch_signalling_mode<'a>( | 371 | async fn switch_signalling_mode( |
| 265 | &mut self, | 372 | &self, |
| 266 | sdmmc: &mut Sdmmc<'a>, | ||
| 267 | cmd_block: &mut CmdBlock, | 373 | cmd_block: &mut CmdBlock, |
| 268 | signalling: Signalling, | 374 | signalling: Signalling, |
| 269 | ) -> Result<Signalling, Error> { | 375 | ) -> Result<Signalling, Error> { |
| @@ -281,13 +387,12 @@ impl Card { | |||
| 281 | }; | 387 | }; |
| 282 | 388 | ||
| 283 | // Arm `OnDrop` after the buffer, so it will be dropped first | 389 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 284 | let on_drop = OnDrop::new(|| sdmmc.on_drop()); | 390 | let on_drop = OnDrop::new(|| self.sdmmc.on_drop()); |
| 285 | 391 | ||
| 286 | let transfer = sdmmc.prepare_datapath_read(&sdmmc.config, cmd_block.as_mut(), 64, 6); | 392 | let transfer = self.sdmmc.prepare_datapath_read(cmd_block.as_mut(), 64, 6); |
| 287 | sdmmc.enable_interrupts(); | 393 | self.sdmmc.cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 |
| 288 | sdmmc.cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 | ||
| 289 | 394 | ||
| 290 | let res = sdmmc.complete_datapath_transfer(true).await; | 395 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; |
| 291 | 396 | ||
| 292 | // Host is allowed to use the new functions at least 8 | 397 | // Host is allowed to use the new functions at least 8 |
| 293 | // clocks after the end of the switch command | 398 | // clocks after the end of the switch command |
| @@ -297,92 +402,373 @@ impl Card { | |||
| 297 | cortex_m::asm::nop(); | 402 | cortex_m::asm::nop(); |
| 298 | } | 403 | } |
| 299 | 404 | ||
| 300 | match res { | 405 | on_drop.defuse(); |
| 301 | Ok(_) => { | 406 | |
| 302 | on_drop.defuse(); | 407 | // Function Selection of Function Group 1 |
| 303 | sdmmc.stop_datapath(); | 408 | let selection = (u32::from_be(cmd_block[4]) >> 24) & 0xF; |
| 304 | drop(transfer); | 409 | |
| 305 | 410 | match selection { | |
| 306 | // Function Selection of Function Group 1 | 411 | 0 => Ok(Signalling::SDR12), |
| 307 | let selection = (u32::from_be(cmd_block[4]) >> 24) & 0xF; | 412 | 1 => Ok(Signalling::SDR25), |
| 308 | 413 | 2 => Ok(Signalling::SDR50), | |
| 309 | match selection { | 414 | 3 => Ok(Signalling::SDR104), |
| 310 | 0 => Ok(Signalling::SDR12), | 415 | 4 => Ok(Signalling::DDR50), |
| 311 | 1 => Ok(Signalling::SDR25), | 416 | _ => Err(Error::UnsupportedCardType), |
| 312 | 2 => Ok(Signalling::SDR50), | ||
| 313 | 3 => Ok(Signalling::SDR104), | ||
| 314 | 4 => Ok(Signalling::DDR50), | ||
| 315 | _ => Err(Error::UnsupportedCardType), | ||
| 316 | } | ||
| 317 | } | ||
| 318 | Err(e) => Err(e), | ||
| 319 | } | 417 | } |
| 320 | } | 418 | } |
| 321 | 419 | ||
| 322 | /// Reads the SCR register. | 420 | /// Reads the SCR register. |
| 323 | /// | 421 | /// |
| 324 | /// SD only. | 422 | /// SD only. |
| 325 | async fn get_scr<'a>(&mut self, sdmmc: &mut Sdmmc<'a>, cmd_block: &mut CmdBlock) -> Result<(), Error> { | 423 | async fn get_scr(&self, cmd_block: &mut CmdBlock) -> Result<SCR, Error> { |
| 326 | // Read the 64-bit SCR register | 424 | // Read the 64-bit SCR register |
| 327 | sdmmc.cmd(common_cmd::set_block_length(8), false)?; // CMD16 | 425 | self.sdmmc.cmd(common_cmd::set_block_length(8), false)?; // CMD16 |
| 328 | sdmmc.cmd(common_cmd::app_cmd(self.rca), false)?; | 426 | self.sdmmc.cmd(common_cmd::app_cmd(self.info.rca), false)?; |
| 329 | 427 | ||
| 330 | let scr = &mut cmd_block.0[..2]; | 428 | let scr = &mut cmd_block.0[..2]; |
| 331 | 429 | ||
| 332 | // Arm `OnDrop` after the buffer, so it will be dropped first | 430 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 333 | let on_drop = OnDrop::new(|| sdmmc.on_drop()); | 431 | let on_drop = OnDrop::new(|| self.sdmmc.on_drop()); |
| 334 | 432 | ||
| 335 | let transfer = sdmmc.prepare_datapath_read(&sdmmc.config, scr, 8, 3); | 433 | let transfer = self.sdmmc.prepare_datapath_read(scr, 8, 3); |
| 336 | sdmmc.enable_interrupts(); | 434 | self.sdmmc.cmd(sd_cmd::send_scr(), true)?; |
| 337 | sdmmc.cmd(sd_cmd::send_scr(), true)?; | ||
| 338 | 435 | ||
| 339 | let res = sdmmc.complete_datapath_transfer(true).await; | 436 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; |
| 340 | 437 | ||
| 341 | if res.is_ok() { | 438 | on_drop.defuse(); |
| 342 | on_drop.defuse(); | ||
| 343 | sdmmc.stop_datapath(); | ||
| 344 | drop(transfer); | ||
| 345 | 439 | ||
| 346 | unsafe { | 440 | Ok(SCR(u64::from_be_bytes(unwrap!(slice8_mut(scr).try_into())))) |
| 347 | let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); | ||
| 348 | self.scr = SCR(u64::from_be_bytes(*scr_bytes)); | ||
| 349 | } | ||
| 350 | } | ||
| 351 | res | ||
| 352 | } | 441 | } |
| 353 | 442 | ||
| 354 | /// Reads the SD Status (ACMD13) | 443 | /// Reads the SD Status (ACMD13) |
| 355 | /// | 444 | /// |
| 356 | /// SD only. | 445 | /// SD only. |
| 357 | async fn read_sd_status<'a>(&mut self, sdmmc: &mut Sdmmc<'a>, cmd_block: &mut CmdBlock) -> Result<(), Error> { | 446 | async fn read_sd_status(&self, cmd_block: &mut CmdBlock) -> Result<SDStatus, Error> { |
| 358 | let rca = self.rca; | 447 | let rca = self.info.rca; |
| 359 | 448 | ||
| 360 | sdmmc.cmd(common_cmd::set_block_length(64), false)?; // CMD16 | 449 | self.sdmmc.cmd(common_cmd::set_block_length(64), false)?; // CMD16 |
| 361 | sdmmc.cmd(common_cmd::app_cmd(rca), false)?; // APP | 450 | self.sdmmc.cmd(common_cmd::app_cmd(rca), false)?; // APP |
| 362 | 451 | ||
| 363 | let status = cmd_block; | 452 | let status = cmd_block; |
| 364 | 453 | ||
| 365 | // Arm `OnDrop` after the buffer, so it will be dropped first | 454 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 366 | let on_drop = OnDrop::new(|| sdmmc.on_drop()); | 455 | let on_drop = OnDrop::new(|| self.sdmmc.on_drop()); |
| 456 | |||
| 457 | let transfer = self.sdmmc.prepare_datapath_read(status.as_mut(), 64, 6); | ||
| 458 | self.sdmmc.cmd(sd_cmd::sd_status(), true)?; | ||
| 367 | 459 | ||
| 368 | let transfer = sdmmc.prepare_datapath_read(&sdmmc.config, status.as_mut(), 64, 6); | 460 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; |
| 369 | sdmmc.enable_interrupts(); | ||
| 370 | sdmmc.cmd(sd_cmd::sd_status(), true)?; | ||
| 371 | 461 | ||
| 372 | let res = sdmmc.complete_datapath_transfer(true).await; | 462 | on_drop.defuse(); |
| 373 | 463 | ||
| 374 | if res.is_ok() { | 464 | for byte in status.iter_mut() { |
| 375 | on_drop.defuse(); | 465 | *byte = u32::from_be(*byte); |
| 376 | sdmmc.stop_datapath(); | 466 | } |
| 377 | drop(transfer); | ||
| 378 | 467 | ||
| 379 | for byte in status.iter_mut() { | 468 | Ok(status.0.into()) |
| 380 | *byte = u32::from_be(*byte); | 469 | } |
| 470 | } | ||
| 471 | |||
| 472 | /// Emmc storage device | ||
| 473 | impl<'a, 'b> StorageDevice<'a, 'b, Emmc> { | ||
| 474 | /// Create a new EMMC card | ||
| 475 | pub async fn new_emmc(sdmmc: &'a mut Sdmmc<'b>, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Self, Error> { | ||
| 476 | let mut s = Self { | ||
| 477 | info: Emmc::default(), | ||
| 478 | sdmmc, | ||
| 479 | }; | ||
| 480 | |||
| 481 | s.acquire(cmd_block, freq).await?; | ||
| 482 | |||
| 483 | Ok(s) | ||
| 484 | } | ||
| 485 | |||
| 486 | async fn acquire(&mut self, _cmd_block: &mut CmdBlock, freq: Hertz) -> Result<(), Error> { | ||
| 487 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 488 | let regs = self.sdmmc.info.regs; | ||
| 489 | |||
| 490 | let bus_width = self.sdmmc.bus_width(); | ||
| 491 | |||
| 492 | // While the SD/SDIO card or eMMC is in identification mode, | ||
| 493 | // the SDMMC_CK frequency must be no more than 400 kHz. | ||
| 494 | self.sdmmc.init_idle()?; | ||
| 495 | |||
| 496 | let ocr = loop { | ||
| 497 | let high_voltage = 0b0 << 7; | ||
| 498 | let access_mode = 0b10 << 29; | ||
| 499 | let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; | ||
| 500 | // Initialize card | ||
| 501 | match self.sdmmc.cmd(emmc_cmd::send_op_cond(op_cond), false) { | ||
| 502 | Ok(_) => (), | ||
| 503 | Err(Error::Crc) => (), | ||
| 504 | Err(err) => return Err(err), | ||
| 505 | } | ||
| 506 | let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into(); | ||
| 507 | if !ocr.is_busy() { | ||
| 508 | // Power up done | ||
| 509 | break ocr; | ||
| 510 | } | ||
| 511 | }; | ||
| 512 | |||
| 513 | self.info.capacity = if ocr.access_mode() == 0b10 { | ||
| 514 | // Card is SDHC or SDXC or SDUC | ||
| 515 | CardCapacity::HighCapacity | ||
| 516 | } else { | ||
| 517 | CardCapacity::StandardCapacity | ||
| 518 | }; | ||
| 519 | self.info.ocr = ocr; | ||
| 520 | |||
| 521 | self.info.cid = self.sdmmc.get_cid()?.into(); | ||
| 522 | |||
| 523 | self.info.rca = 1u16.into(); | ||
| 524 | self.sdmmc | ||
| 525 | .cmd(emmc_cmd::assign_relative_address(self.info.rca), false)?; | ||
| 526 | |||
| 527 | self.info.csd = self.sdmmc.get_csd(self.info.get_address())?.into(); | ||
| 528 | self.sdmmc.select_card(Some(self.info.get_address()))?; | ||
| 529 | |||
| 530 | let (widbus, _) = bus_width_vals(bus_width); | ||
| 531 | |||
| 532 | // Write bus width to ExtCSD byte 183 | ||
| 533 | self.sdmmc.cmd( | ||
| 534 | emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), | ||
| 535 | false, | ||
| 536 | )?; | ||
| 537 | |||
| 538 | // Wait for ready after R1b response | ||
| 539 | loop { | ||
| 540 | let status = self.sdmmc.read_status(&self.info)?; | ||
| 541 | |||
| 542 | if status.ready_for_data() { | ||
| 543 | break; | ||
| 381 | } | 544 | } |
| 382 | self.status = status.0.into(); | ||
| 383 | } | 545 | } |
| 384 | res | 546 | |
| 547 | self.sdmmc.clkcr_set_clkdiv(freq.clamp(mhz(0), mhz(25)), bus_width)?; | ||
| 548 | self.info.ext_csd = self.read_ext_csd().await?; | ||
| 549 | |||
| 550 | Ok(()) | ||
| 385 | } | 551 | } |
| 552 | |||
| 553 | /// Gets the EXT_CSD register. | ||
| 554 | /// | ||
| 555 | /// eMMC only. | ||
| 556 | async fn read_ext_csd(&self) -> Result<ExtCSD, Error> { | ||
| 557 | // Note: cmd_block can't be used because ExtCSD is too long to fit. | ||
| 558 | let mut data_block = DataBlock([0u8; 512]); | ||
| 559 | |||
| 560 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 561 | let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 562 | |||
| 563 | self.sdmmc.cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16 | ||
| 564 | |||
| 565 | let transfer = self.sdmmc.prepare_datapath_read(buffer, 512, 9); | ||
| 566 | self.sdmmc.cmd(emmc_cmd::send_ext_csd(), true)?; | ||
| 567 | |||
| 568 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 569 | let on_drop = OnDrop::new(|| self.sdmmc.on_drop()); | ||
| 570 | |||
| 571 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 572 | |||
| 573 | on_drop.defuse(); | ||
| 574 | |||
| 575 | Ok(unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into()) | ||
| 576 | } | ||
| 577 | } | ||
| 578 | |||
| 579 | /// Card or Emmc storage device | ||
| 580 | impl<'a, 'b, A: Addressable> StorageDevice<'a, 'b, A> { | ||
| 581 | /// Write a block | ||
| 582 | pub fn card(&self) -> A { | ||
| 583 | self.info.clone() | ||
| 584 | } | ||
| 585 | |||
| 586 | /// Read a data block. | ||
| 587 | #[inline] | ||
| 588 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | ||
| 589 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 590 | let card_capacity = self.info.get_capacity(); | ||
| 591 | |||
| 592 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 593 | let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 594 | |||
| 595 | // Always read 1 block of 512 bytes | ||
| 596 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 597 | let address = match card_capacity { | ||
| 598 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 599 | _ => block_idx, | ||
| 600 | }; | ||
| 601 | self.sdmmc.cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 602 | |||
| 603 | let on_drop = OnDrop::new(|| self.sdmmc.on_drop()); | ||
| 604 | |||
| 605 | let transfer = self.sdmmc.prepare_datapath_read(buffer, 512, 9); | ||
| 606 | self.sdmmc.cmd(common_cmd::read_single_block(address), true)?; | ||
| 607 | |||
| 608 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 609 | |||
| 610 | on_drop.defuse(); | ||
| 611 | |||
| 612 | Ok(()) | ||
| 613 | } | ||
| 614 | |||
| 615 | /// Read multiple data blocks. | ||
| 616 | #[inline] | ||
| 617 | pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { | ||
| 618 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 619 | let card_capacity = self.info.get_capacity(); | ||
| 620 | |||
| 621 | // NOTE(unsafe) reinterpret buffer as &mut [u32] | ||
| 622 | let buffer = unsafe { | ||
| 623 | let ptr = blocks.as_mut_ptr() as *mut u32; | ||
| 624 | let len = blocks.len() * 128; | ||
| 625 | core::slice::from_raw_parts_mut(ptr, len) | ||
| 626 | }; | ||
| 627 | |||
| 628 | // Always read 1 block of 512 bytes | ||
| 629 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 630 | let address = match card_capacity { | ||
| 631 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 632 | _ => block_idx, | ||
| 633 | }; | ||
| 634 | self.sdmmc.cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 635 | |||
| 636 | let on_drop = OnDrop::new(|| self.sdmmc.on_drop()); | ||
| 637 | let transfer = self.sdmmc.prepare_datapath_read(buffer, 512 * blocks.len() as u32, 9); | ||
| 638 | self.sdmmc.cmd(common_cmd::read_multiple_blocks(address), true)?; | ||
| 639 | |||
| 640 | self.sdmmc.complete_datapath_transfer(transfer, false).await?; | ||
| 641 | |||
| 642 | self.sdmmc.cmd(common_cmd::stop_transmission(), false)?; // CMD12 | ||
| 643 | self.sdmmc.clear_interrupt_flags(); | ||
| 644 | |||
| 645 | on_drop.defuse(); | ||
| 646 | |||
| 647 | Ok(()) | ||
| 648 | } | ||
| 649 | |||
| 650 | /// Write a data block. | ||
| 651 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> | ||
| 652 | where | ||
| 653 | CardStatus<A::Ext>: From<u32>, | ||
| 654 | { | ||
| 655 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 656 | |||
| 657 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 658 | let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; | ||
| 659 | |||
| 660 | // Always read 1 block of 512 bytes | ||
| 661 | // cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 662 | let address = match self.info.get_capacity() { | ||
| 663 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 664 | _ => block_idx, | ||
| 665 | }; | ||
| 666 | self.sdmmc.cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 667 | |||
| 668 | let on_drop = OnDrop::new(|| self.sdmmc.on_drop()); | ||
| 669 | |||
| 670 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||
| 671 | #[cfg(sdmmc_v1)] | ||
| 672 | self.sdmmc.cmd(common_cmd::write_single_block(address), true)?; | ||
| 673 | |||
| 674 | let transfer = self.sdmmc.prepare_datapath_write(buffer, 512, 9); | ||
| 675 | |||
| 676 | #[cfg(sdmmc_v2)] | ||
| 677 | self.sdmmc.cmd(common_cmd::write_single_block(address), true)?; | ||
| 678 | |||
| 679 | self.sdmmc.complete_datapath_transfer(transfer, true).await?; | ||
| 680 | |||
| 681 | on_drop.defuse(); | ||
| 682 | |||
| 683 | // TODO: Make this configurable | ||
| 684 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 685 | |||
| 686 | while timeout > 0 { | ||
| 687 | let ready_for_data = self.sdmmc.read_status(&self.info)?.ready_for_data(); | ||
| 688 | if ready_for_data { | ||
| 689 | return Ok(()); | ||
| 690 | } | ||
| 691 | timeout -= 1; | ||
| 692 | } | ||
| 693 | |||
| 694 | Err(Error::SoftwareTimeout) | ||
| 695 | } | ||
| 696 | |||
| 697 | /// Write multiple data blocks. | ||
| 698 | pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> | ||
| 699 | where | ||
| 700 | CardStatus<A::Ext>: From<u32>, | ||
| 701 | { | ||
| 702 | let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); | ||
| 703 | |||
| 704 | // NOTE(unsafe) reinterpret buffer as &[u32] | ||
| 705 | let buffer = unsafe { | ||
| 706 | let ptr = blocks.as_ptr() as *const u32; | ||
| 707 | let len = blocks.len() * 128; | ||
| 708 | core::slice::from_raw_parts(ptr, len) | ||
| 709 | }; | ||
| 710 | |||
| 711 | // Always read 1 block of 512 bytes | ||
| 712 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 713 | let address = match self.info.get_capacity() { | ||
| 714 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 715 | _ => block_idx, | ||
| 716 | }; | ||
| 717 | |||
| 718 | self.sdmmc.cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 719 | |||
| 720 | let block_count = blocks.len(); | ||
| 721 | |||
| 722 | let on_drop = OnDrop::new(|| self.sdmmc.on_drop()); | ||
| 723 | |||
| 724 | #[cfg(sdmmc_v1)] | ||
| 725 | self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | ||
| 726 | |||
| 727 | // Setup write command | ||
| 728 | let transfer = self.sdmmc.prepare_datapath_write(buffer, 512 * block_count as u32, 9); | ||
| 729 | |||
| 730 | #[cfg(sdmmc_v2)] | ||
| 731 | self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | ||
| 732 | |||
| 733 | self.sdmmc.complete_datapath_transfer(transfer, false).await?; | ||
| 734 | |||
| 735 | self.sdmmc.cmd(common_cmd::stop_transmission(), false)?; // CMD12 | ||
| 736 | self.sdmmc.clear_interrupt_flags(); | ||
| 737 | |||
| 738 | on_drop.defuse(); | ||
| 739 | |||
| 740 | // TODO: Make this configurable | ||
| 741 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 742 | |||
| 743 | while timeout > 0 { | ||
| 744 | let ready_for_data = self.sdmmc.read_status(&self.info)?.ready_for_data(); | ||
| 745 | |||
| 746 | if ready_for_data { | ||
| 747 | return Ok(()); | ||
| 748 | } | ||
| 749 | timeout -= 1; | ||
| 750 | } | ||
| 751 | Err(Error::SoftwareTimeout) | ||
| 752 | } | ||
| 753 | } | ||
| 754 | |||
| 755 | #[derive(Clone, Copy, Debug, Default)] | ||
| 756 | /// SD Card | ||
| 757 | pub struct Card { | ||
| 758 | /// The type of this card | ||
| 759 | pub card_type: CardCapacity, | ||
| 760 | /// Operation Conditions Register | ||
| 761 | pub ocr: OCR<SD>, | ||
| 762 | /// Relative Card Address | ||
| 763 | pub rca: u16, | ||
| 764 | /// Card ID | ||
| 765 | pub cid: CID<SD>, | ||
| 766 | /// Card Specific Data | ||
| 767 | pub csd: CSD<SD>, | ||
| 768 | /// SD CARD Configuration Register | ||
| 769 | pub scr: SCR, | ||
| 770 | /// SD Status | ||
| 771 | pub status: SDStatus, | ||
| 386 | } | 772 | } |
| 387 | 773 | ||
| 388 | impl Addressable for Card { | 774 | impl Addressable for Card { |
| @@ -421,40 +807,6 @@ pub struct Emmc { | |||
| 421 | pub ext_csd: ExtCSD, | 807 | pub ext_csd: ExtCSD, |
| 422 | } | 808 | } |
| 423 | 809 | ||
| 424 | impl Emmc { | ||
| 425 | /// Gets the EXT_CSD register. | ||
| 426 | /// | ||
| 427 | /// eMMC only. | ||
| 428 | async fn read_ext_csd<'a>(&mut self, sdmmc: &mut Sdmmc<'a>) -> Result<(), Error> { | ||
| 429 | // Note: cmd_block can't be used because ExtCSD is too long to fit. | ||
| 430 | let mut data_block = DataBlock([0u8; 512]); | ||
| 431 | |||
| 432 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 433 | let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 434 | |||
| 435 | sdmmc.cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16 | ||
| 436 | |||
| 437 | let transfer = sdmmc.prepare_datapath_read(&sdmmc.config, buffer, 512, 9); | ||
| 438 | sdmmc.enable_interrupts(); | ||
| 439 | sdmmc.cmd(emmc_cmd::send_ext_csd(), true)?; | ||
| 440 | |||
| 441 | // Arm `OnDrop` after the buffer, so it will be dropped first | ||
| 442 | let on_drop = OnDrop::new(|| sdmmc.on_drop()); | ||
| 443 | |||
| 444 | let res = sdmmc.complete_datapath_transfer(true).await; | ||
| 445 | |||
| 446 | if res.is_ok() { | ||
| 447 | on_drop.defuse(); | ||
| 448 | sdmmc.stop_datapath(); | ||
| 449 | drop(transfer); | ||
| 450 | |||
| 451 | self.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into(); | ||
| 452 | } | ||
| 453 | |||
| 454 | res | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | impl Addressable for Emmc { | 810 | impl Addressable for Emmc { |
| 459 | type Ext = EMMC; | 811 | type Ext = EMMC; |
| 460 | 812 | ||
| @@ -516,6 +868,15 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u8, Hertz), Error> { | |||
| 516 | Ok((false, clk_div, clk_f)) | 868 | Ok((false, clk_div, clk_f)) |
| 517 | } | 869 | } |
| 518 | 870 | ||
| 871 | fn bus_width_vals(bus_width: BusWidth) -> (u8, u32) { | ||
| 872 | match bus_width { | ||
| 873 | BusWidth::One => (0, 1u32), | ||
| 874 | BusWidth::Four => (1, 4u32), | ||
| 875 | BusWidth::Eight => (2, 8u32), | ||
| 876 | _ => panic!("Invalid Bus Width"), | ||
| 877 | } | ||
| 878 | } | ||
| 879 | |||
| 519 | /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to | 880 | /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to |
| 520 | /// `sdmmc_ck` in Hertz. | 881 | /// `sdmmc_ck` in Hertz. |
| 521 | /// | 882 | /// |
| @@ -580,25 +941,6 @@ impl Default for Config { | |||
| 580 | } | 941 | } |
| 581 | } | 942 | } |
| 582 | 943 | ||
| 583 | /// Peripheral that can be operated over SDMMC | ||
| 584 | #[derive(Clone, Copy, Debug)] | ||
| 585 | pub enum SdmmcPeripheral { | ||
| 586 | /// SD Card | ||
| 587 | SdCard(Card), | ||
| 588 | /// eMMC memory | ||
| 589 | Emmc(Emmc), | ||
| 590 | } | ||
| 591 | |||
| 592 | impl SdmmcPeripheral { | ||
| 593 | /// Get this peripheral's address on the SDMMC bus | ||
| 594 | fn get_address(&self) -> u16 { | ||
| 595 | match self { | ||
| 596 | Self::SdCard(c) => c.rca, | ||
| 597 | Self::Emmc(e) => e.rca, | ||
| 598 | } | ||
| 599 | } | ||
| 600 | } | ||
| 601 | |||
| 602 | /// Sdmmc device | 944 | /// Sdmmc device |
| 603 | pub struct Sdmmc<'d> { | 945 | pub struct Sdmmc<'d> { |
| 604 | info: &'static Info, | 946 | info: &'static Info, |
| @@ -989,17 +1331,19 @@ impl<'d> Sdmmc<'d> { | |||
| 989 | while self.data_active() || self.cmd_active() {} | 1331 | while self.data_active() || self.cmd_active() {} |
| 990 | } | 1332 | } |
| 991 | 1333 | ||
| 1334 | fn bus_width(&self) -> BusWidth { | ||
| 1335 | match (self.d3.is_some(), self.d7.is_some()) { | ||
| 1336 | (true, true) => BusWidth::Eight, | ||
| 1337 | (true, false) => BusWidth::Four, | ||
| 1338 | _ => BusWidth::One, | ||
| 1339 | } | ||
| 1340 | } | ||
| 1341 | |||
| 992 | /// # Safety | 1342 | /// # Safety |
| 993 | /// | 1343 | /// |
| 994 | /// `buffer` must be valid for the whole transfer and word aligned | 1344 | /// `buffer` must be valid for the whole transfer and word aligned |
| 995 | #[allow(unused_variables)] | 1345 | #[allow(unused_variables)] |
| 996 | fn prepare_datapath_read<'a>( | 1346 | fn prepare_datapath_read<'a>(&'a self, buffer: &'a mut [u32], length_bytes: u32, block_size: u8) -> Transfer<'a> { |
| 997 | &'a self, | ||
| 998 | config: &Config, | ||
| 999 | buffer: &'a mut [u32], | ||
| 1000 | length_bytes: u32, | ||
| 1001 | block_size: u8, | ||
| 1002 | ) -> Transfer<'a> { | ||
| 1003 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 1347 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); |
| 1004 | let regs = self.info.regs; | 1348 | let regs = self.info.regs; |
| 1005 | 1349 | ||
| @@ -1034,6 +1378,8 @@ impl<'d> Sdmmc<'d> { | |||
| 1034 | } | 1378 | } |
| 1035 | }); | 1379 | }); |
| 1036 | 1380 | ||
| 1381 | self.enable_interrupts(); | ||
| 1382 | |||
| 1037 | transfer | 1383 | transfer |
| 1038 | } | 1384 | } |
| 1039 | 1385 | ||
| @@ -1075,6 +1421,8 @@ impl<'d> Sdmmc<'d> { | |||
| 1075 | } | 1421 | } |
| 1076 | }); | 1422 | }); |
| 1077 | 1423 | ||
| 1424 | self.enable_interrupts(); | ||
| 1425 | |||
| 1078 | transfer | 1426 | transfer |
| 1079 | } | 1427 | } |
| 1080 | 1428 | ||
| @@ -1091,18 +1439,23 @@ impl<'d> Sdmmc<'d> { | |||
| 1091 | regs.idmactrlr().modify(|w| w.set_idmaen(false)); | 1439 | regs.idmactrlr().modify(|w| w.set_idmaen(false)); |
| 1092 | } | 1440 | } |
| 1093 | 1441 | ||
| 1094 | /// Sets the CLKDIV field in CLKCR. Updates clock field in self | 1442 | fn init_idle(&mut self) -> Result<(), Error> { |
| 1095 | fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> { | ||
| 1096 | let regs = self.info.regs; | 1443 | let regs = self.info.regs; |
| 1097 | 1444 | ||
| 1098 | let width_u32 = match width { | 1445 | self.clkcr_set_clkdiv(SD_INIT_FREQ, BusWidth::One)?; |
| 1099 | BusWidth::One => 1u32, | 1446 | regs.dtimer() |
| 1100 | BusWidth::Four => 4u32, | 1447 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); |
| 1101 | BusWidth::Eight => 8u32, | 1448 | |
| 1102 | _ => panic!("Invalid Bus Width"), | 1449 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); |
| 1103 | }; | 1450 | self.cmd(common_cmd::idle(), false) |
| 1451 | } | ||
| 1452 | |||
| 1453 | /// Sets the CLKDIV field in CLKCR. Updates clock field in self | ||
| 1454 | fn clkcr_set_clkdiv(&mut self, freq: Hertz, width: BusWidth) -> Result<(), Error> { | ||
| 1455 | let regs = self.info.regs; | ||
| 1104 | 1456 | ||
| 1105 | let (_bypass, clkdiv, new_clock) = clk_div(self.ker_clk, freq)?; | 1457 | let (widbus, width_u32) = bus_width_vals(width); |
| 1458 | let (_bypass, clkdiv, new_clock) = clk_div(self.ker_clk, freq.0)?; | ||
| 1106 | 1459 | ||
| 1107 | // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 | 1460 | // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 |
| 1108 | // Section 55.5.8 | 1461 | // Section 55.5.8 |
| @@ -1110,29 +1463,34 @@ impl<'d> Sdmmc<'d> { | |||
| 1110 | assert!(self.ker_clk.0 > 3 * sdmmc_bus_bandwidth / 32); | 1463 | assert!(self.ker_clk.0 > 3 * sdmmc_bus_bandwidth / 32); |
| 1111 | self.clock = new_clock; | 1464 | self.clock = new_clock; |
| 1112 | 1465 | ||
| 1113 | // CPSMACT and DPSMACT must be 0 to set CLKDIV | 1466 | // CPSMACT and DPSMACT must be 0 to set CLKDIV or WIDBUS |
| 1114 | self.wait_idle(); | 1467 | self.wait_idle(); |
| 1115 | regs.clkcr().modify(|w| { | 1468 | regs.clkcr().modify(|w| { |
| 1116 | w.set_clkdiv(clkdiv); | 1469 | w.set_clkdiv(clkdiv); |
| 1117 | #[cfg(sdmmc_v1)] | 1470 | #[cfg(sdmmc_v1)] |
| 1118 | w.set_bypass(_bypass); | 1471 | w.set_bypass(_bypass); |
| 1472 | w.set_widbus(widbus); | ||
| 1119 | }); | 1473 | }); |
| 1120 | 1474 | ||
| 1121 | Ok(()) | 1475 | Ok(()) |
| 1122 | } | 1476 | } |
| 1123 | 1477 | ||
| 1478 | fn get_cid(&self) -> Result<u128, Error> { | ||
| 1479 | self.cmd(common_cmd::all_send_cid(), false) // CMD2 | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | fn get_csd(&self, address: u16) -> Result<u128, Error> { | ||
| 1483 | self.cmd(common_cmd::send_csd(address), false) | ||
| 1484 | } | ||
| 1485 | |||
| 1124 | /// Query the card status (CMD13, returns R1) | 1486 | /// Query the card status (CMD13, returns R1) |
| 1125 | fn read_status<A: Addressable>(&self, card: &A) -> Result<CardStatus<A::Ext>, Error> | 1487 | fn read_status<A: Addressable>(&self, card: &A) -> Result<CardStatus<A::Ext>, Error> |
| 1126 | where | 1488 | where |
| 1127 | CardStatus<A::Ext>: From<u32>, | 1489 | CardStatus<A::Ext>: From<u32>, |
| 1128 | { | 1490 | { |
| 1129 | let regs = self.info.regs; | ||
| 1130 | let rca = card.get_address(); | 1491 | let rca = card.get_address(); |
| 1131 | 1492 | ||
| 1132 | self.cmd(common_cmd::card_status(rca, false), false)?; // CMD13 | 1493 | Ok(self.cmd(common_cmd::card_status(rca, false), false)?.into()) // CMD13 |
| 1133 | |||
| 1134 | let r1 = regs.respr(0).read().cardstatus(); | ||
| 1135 | Ok(r1.into()) | ||
| 1136 | } | 1494 | } |
| 1137 | 1495 | ||
| 1138 | /// Select one card and place it into the _Tranfer State_ | 1496 | /// Select one card and place it into the _Tranfer State_ |
| @@ -1143,11 +1501,17 @@ impl<'d> Sdmmc<'d> { | |||
| 1143 | // Determine Relative Card Address (RCA) of given card | 1501 | // Determine Relative Card Address (RCA) of given card |
| 1144 | let rca = rca.unwrap_or(0); | 1502 | let rca = rca.unwrap_or(0); |
| 1145 | 1503 | ||
| 1146 | let r = self.cmd(common_cmd::select_card(rca), false); | 1504 | let resp = self.cmd(common_cmd::select_card(rca), false); |
| 1147 | match (r, rca) { | 1505 | |
| 1148 | (Err(Error::Timeout), 0) => Ok(()), | 1506 | if let Err(Error::Timeout) = resp |
| 1149 | _ => r, | 1507 | && rca == 0 |
| 1508 | { | ||
| 1509 | return Ok(()); | ||
| 1150 | } | 1510 | } |
| 1511 | |||
| 1512 | resp?; | ||
| 1513 | |||
| 1514 | Ok(()) | ||
| 1151 | } | 1515 | } |
| 1152 | 1516 | ||
| 1153 | /// Clear flags in interrupt clear register | 1517 | /// Clear flags in interrupt clear register |
| @@ -1186,7 +1550,7 @@ impl<'d> Sdmmc<'d> { | |||
| 1186 | 1550 | ||
| 1187 | /// Send command to card | 1551 | /// Send command to card |
| 1188 | #[allow(unused_variables)] | 1552 | #[allow(unused_variables)] |
| 1189 | fn cmd<R: Resp>(&self, cmd: Cmd<R>, data: bool) -> Result<(), Error> { | 1553 | fn cmd<R: TypedResp>(&self, cmd: Cmd<R>, data: bool) -> Result<R::Word, Error> { |
| 1190 | let regs = self.info.regs; | 1554 | let regs = self.info.regs; |
| 1191 | 1555 | ||
| 1192 | self.clear_interrupt_flags(); | 1556 | self.clear_interrupt_flags(); |
| @@ -1233,7 +1597,20 @@ impl<'d> Sdmmc<'d> { | |||
| 1233 | } else if status.ccrcfail() { | 1597 | } else if status.ccrcfail() { |
| 1234 | return Err(Error::Crc); | 1598 | return Err(Error::Crc); |
| 1235 | } | 1599 | } |
| 1236 | Ok(()) | 1600 | |
| 1601 | Ok(match R::LENGTH { | ||
| 1602 | ResponseLen::Zero => U128(0u128), | ||
| 1603 | ResponseLen::R48 => U128(self.info.regs.respr(0).read().cardstatus() as u128), | ||
| 1604 | ResponseLen::R136 => { | ||
| 1605 | let cid0 = self.info.regs.respr(0).read().cardstatus() as u128; | ||
| 1606 | let cid1 = self.info.regs.respr(1).read().cardstatus() as u128; | ||
| 1607 | let cid2 = self.info.regs.respr(2).read().cardstatus() as u128; | ||
| 1608 | let cid3 = self.info.regs.respr(3).read().cardstatus() as u128; | ||
| 1609 | |||
| 1610 | U128((cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3)) | ||
| 1611 | } | ||
| 1612 | } | ||
| 1613 | .into()) | ||
| 1237 | } | 1614 | } |
| 1238 | 1615 | ||
| 1239 | fn on_drop(&self) { | 1616 | fn on_drop(&self) { |
| @@ -1272,7 +1649,7 @@ impl<'d> Sdmmc<'d> { | |||
| 1272 | /// Wait for a previously started datapath transfer to complete from an interrupt. | 1649 | /// Wait for a previously started datapath transfer to complete from an interrupt. |
| 1273 | #[inline] | 1650 | #[inline] |
| 1274 | #[allow(unused)] | 1651 | #[allow(unused)] |
| 1275 | async fn complete_datapath_transfer(&self, block: bool) -> Result<(), Error> { | 1652 | async fn complete_datapath_transfer(&self, transfer: Transfer<'_>, block: bool) -> Result<(), Error> { |
| 1276 | let res = poll_fn(|cx| { | 1653 | let res = poll_fn(|cx| { |
| 1277 | // Compiler might not be sufficiently constrained here | 1654 | // Compiler might not be sufficiently constrained here |
| 1278 | // https://github.com/embassy-rs/embassy/issues/4723 | 1655 | // https://github.com/embassy-rs/embassy/issues/4723 |
| @@ -1307,498 +1684,17 @@ impl<'d> Sdmmc<'d> { | |||
| 1307 | .await; | 1684 | .await; |
| 1308 | 1685 | ||
| 1309 | self.clear_interrupt_flags(); | 1686 | self.clear_interrupt_flags(); |
| 1687 | self.stop_datapath(); | ||
| 1310 | 1688 | ||
| 1311 | res | 1689 | drop(transfer); |
| 1312 | } | ||
| 1313 | |||
| 1314 | /// Read a data block. | ||
| 1315 | #[inline] | ||
| 1316 | pub async fn read_block( | ||
| 1317 | &mut self, | ||
| 1318 | card: &mut impl Addressable, | ||
| 1319 | block_idx: u32, | ||
| 1320 | buffer: &mut DataBlock, | ||
| 1321 | ) -> Result<(), Error> { | ||
| 1322 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1323 | let card_capacity = card.get_capacity(); | ||
| 1324 | |||
| 1325 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 1326 | let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 1327 | |||
| 1328 | // Always read 1 block of 512 bytes | ||
| 1329 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1330 | let address = match card_capacity { | ||
| 1331 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1332 | _ => block_idx, | ||
| 1333 | }; | ||
| 1334 | self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1335 | |||
| 1336 | let on_drop = OnDrop::new(|| self.on_drop()); | ||
| 1337 | |||
| 1338 | let transfer = self.prepare_datapath_read(&self.config, buffer, 512, 9); | ||
| 1339 | self.enable_interrupts(); | ||
| 1340 | self.cmd(common_cmd::read_single_block(address), true)?; | ||
| 1341 | |||
| 1342 | let res = self.complete_datapath_transfer(true).await; | ||
| 1343 | |||
| 1344 | if res.is_ok() { | ||
| 1345 | on_drop.defuse(); | ||
| 1346 | self.stop_datapath(); | ||
| 1347 | drop(transfer); | ||
| 1348 | } | ||
| 1349 | res | ||
| 1350 | } | ||
| 1351 | |||
| 1352 | /// Read multiple data blocks. | ||
| 1353 | #[inline] | ||
| 1354 | pub async fn read_blocks( | ||
| 1355 | &mut self, | ||
| 1356 | card: &mut impl Addressable, | ||
| 1357 | block_idx: u32, | ||
| 1358 | blocks: &mut [DataBlock], | ||
| 1359 | ) -> Result<(), Error> { | ||
| 1360 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1361 | let card_capacity = card.get_capacity(); | ||
| 1362 | |||
| 1363 | // NOTE(unsafe) reinterpret buffer as &mut [u32] | ||
| 1364 | let buffer = unsafe { | ||
| 1365 | let ptr = blocks.as_mut_ptr() as *mut u32; | ||
| 1366 | let len = blocks.len() * 128; | ||
| 1367 | core::slice::from_raw_parts_mut(ptr, len) | ||
| 1368 | }; | ||
| 1369 | |||
| 1370 | // Always read 1 block of 512 bytes | ||
| 1371 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1372 | let address = match card_capacity { | ||
| 1373 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1374 | _ => block_idx, | ||
| 1375 | }; | ||
| 1376 | self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1377 | |||
| 1378 | let on_drop = OnDrop::new(|| self.on_drop()); | ||
| 1379 | |||
| 1380 | let transfer = self.prepare_datapath_read(&self.config, buffer, 512 * blocks.len() as u32, 9); | ||
| 1381 | self.enable_interrupts(); | ||
| 1382 | |||
| 1383 | self.cmd(common_cmd::read_multiple_blocks(address), true)?; | ||
| 1384 | |||
| 1385 | let res = self.complete_datapath_transfer(false).await; | ||
| 1386 | |||
| 1387 | self.cmd(common_cmd::stop_transmission(), false)?; // CMD12 | ||
| 1388 | self.clear_interrupt_flags(); | ||
| 1389 | 1690 | ||
| 1390 | if res.is_ok() { | ||
| 1391 | on_drop.defuse(); | ||
| 1392 | self.stop_datapath(); | ||
| 1393 | drop(transfer); | ||
| 1394 | } | ||
| 1395 | res | 1691 | res |
| 1396 | } | 1692 | } |
| 1397 | 1693 | ||
| 1398 | /// Write a data block. | ||
| 1399 | pub async fn write_block<A: Addressable>( | ||
| 1400 | &mut self, | ||
| 1401 | card: &mut A, | ||
| 1402 | block_idx: u32, | ||
| 1403 | buffer: &DataBlock, | ||
| 1404 | ) -> Result<(), Error> | ||
| 1405 | where | ||
| 1406 | CardStatus<A::Ext>: From<u32>, | ||
| 1407 | { | ||
| 1408 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1409 | |||
| 1410 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 1411 | let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; | ||
| 1412 | |||
| 1413 | // Always read 1 block of 512 bytes | ||
| 1414 | // cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1415 | let address = match card.get_capacity() { | ||
| 1416 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1417 | _ => block_idx, | ||
| 1418 | }; | ||
| 1419 | self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1420 | |||
| 1421 | let on_drop = OnDrop::new(|| self.on_drop()); | ||
| 1422 | |||
| 1423 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||
| 1424 | #[cfg(sdmmc_v1)] | ||
| 1425 | self.cmd(common_cmd::write_single_block(address), true)?; | ||
| 1426 | |||
| 1427 | let transfer = self.prepare_datapath_write(buffer, 512, 9); | ||
| 1428 | self.enable_interrupts(); | ||
| 1429 | |||
| 1430 | #[cfg(sdmmc_v2)] | ||
| 1431 | self.cmd(common_cmd::write_single_block(address), true)?; | ||
| 1432 | |||
| 1433 | let res = self.complete_datapath_transfer(true).await; | ||
| 1434 | |||
| 1435 | match res { | ||
| 1436 | Ok(_) => { | ||
| 1437 | on_drop.defuse(); | ||
| 1438 | self.stop_datapath(); | ||
| 1439 | drop(transfer); | ||
| 1440 | |||
| 1441 | // TODO: Make this configurable | ||
| 1442 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 1443 | |||
| 1444 | while timeout > 0 { | ||
| 1445 | let ready_for_data = self.read_status(card)?.ready_for_data(); | ||
| 1446 | if ready_for_data { | ||
| 1447 | return Ok(()); | ||
| 1448 | } | ||
| 1449 | timeout -= 1; | ||
| 1450 | } | ||
| 1451 | Err(Error::SoftwareTimeout) | ||
| 1452 | } | ||
| 1453 | Err(e) => Err(e), | ||
| 1454 | } | ||
| 1455 | } | ||
| 1456 | |||
| 1457 | /// Write multiple data blocks. | ||
| 1458 | pub async fn write_blocks<A: Addressable>( | ||
| 1459 | &mut self, | ||
| 1460 | card: &mut A, | ||
| 1461 | block_idx: u32, | ||
| 1462 | blocks: &[DataBlock], | ||
| 1463 | ) -> Result<(), Error> | ||
| 1464 | where | ||
| 1465 | CardStatus<A::Ext>: From<u32>, | ||
| 1466 | { | ||
| 1467 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1468 | |||
| 1469 | // NOTE(unsafe) reinterpret buffer as &[u32] | ||
| 1470 | let buffer = unsafe { | ||
| 1471 | let ptr = blocks.as_ptr() as *const u32; | ||
| 1472 | let len = blocks.len() * 128; | ||
| 1473 | core::slice::from_raw_parts(ptr, len) | ||
| 1474 | }; | ||
| 1475 | |||
| 1476 | // Always read 1 block of 512 bytes | ||
| 1477 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1478 | let address = match card.get_capacity() { | ||
| 1479 | CardCapacity::StandardCapacity => block_idx * 512, | ||
| 1480 | _ => block_idx, | ||
| 1481 | }; | ||
| 1482 | |||
| 1483 | self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 | ||
| 1484 | |||
| 1485 | let block_count = blocks.len(); | ||
| 1486 | |||
| 1487 | let on_drop = OnDrop::new(|| self.on_drop()); | ||
| 1488 | |||
| 1489 | #[cfg(sdmmc_v1)] | ||
| 1490 | self.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | ||
| 1491 | |||
| 1492 | // Setup write command | ||
| 1493 | let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); | ||
| 1494 | self.enable_interrupts(); | ||
| 1495 | |||
| 1496 | #[cfg(sdmmc_v2)] | ||
| 1497 | self.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 | ||
| 1498 | |||
| 1499 | let res = self.complete_datapath_transfer(false).await; | ||
| 1500 | |||
| 1501 | self.cmd(common_cmd::stop_transmission(), false)?; // CMD12 | ||
| 1502 | self.clear_interrupt_flags(); | ||
| 1503 | |||
| 1504 | match res { | ||
| 1505 | Ok(_) => { | ||
| 1506 | on_drop.defuse(); | ||
| 1507 | self.stop_datapath(); | ||
| 1508 | drop(transfer); | ||
| 1509 | |||
| 1510 | // TODO: Make this configurable | ||
| 1511 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 1512 | |||
| 1513 | while timeout > 0 { | ||
| 1514 | let ready_for_data = self.read_status(card)?.ready_for_data(); | ||
| 1515 | |||
| 1516 | if ready_for_data { | ||
| 1517 | return Ok(()); | ||
| 1518 | } | ||
| 1519 | timeout -= 1; | ||
| 1520 | } | ||
| 1521 | Err(Error::SoftwareTimeout) | ||
| 1522 | } | ||
| 1523 | Err(e) => Err(e), | ||
| 1524 | } | ||
| 1525 | } | ||
| 1526 | |||
| 1527 | /// Get the current SDMMC bus clock | 1694 | /// Get the current SDMMC bus clock |
| 1528 | pub fn clock(&self) -> Hertz { | 1695 | pub fn clock(&self) -> Hertz { |
| 1529 | self.clock | 1696 | self.clock |
| 1530 | } | 1697 | } |
| 1531 | |||
| 1532 | async fn init_internal( | ||
| 1533 | &mut self, | ||
| 1534 | cmd_block: &mut CmdBlock, | ||
| 1535 | freq: Hertz, | ||
| 1536 | card: &mut SdmmcPeripheral, | ||
| 1537 | ) -> Result<(), Error> { | ||
| 1538 | let _scoped_block_stop = self.info.rcc.block_stop(); | ||
| 1539 | |||
| 1540 | let regs = self.info.regs; | ||
| 1541 | |||
| 1542 | let bus_width = match (self.d3.is_some(), self.d7.is_some()) { | ||
| 1543 | (true, true) => { | ||
| 1544 | if matches!(card, SdmmcPeripheral::SdCard(_)) { | ||
| 1545 | return Err(Error::BusWidth); | ||
| 1546 | } | ||
| 1547 | BusWidth::Eight | ||
| 1548 | } | ||
| 1549 | (true, false) => BusWidth::Four, | ||
| 1550 | _ => BusWidth::One, | ||
| 1551 | }; | ||
| 1552 | |||
| 1553 | // While the SD/SDIO card or eMMC is in identification mode, | ||
| 1554 | // the SDMMC_CK frequency must be no more than 400 kHz. | ||
| 1555 | let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(self.ker_clk, SD_INIT_FREQ.0)); | ||
| 1556 | self.clock = init_clock; | ||
| 1557 | |||
| 1558 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 1559 | self.wait_idle(); | ||
| 1560 | |||
| 1561 | regs.clkcr().modify(|w| { | ||
| 1562 | w.set_widbus(0); | ||
| 1563 | w.set_clkdiv(clkdiv); | ||
| 1564 | #[cfg(sdmmc_v1)] | ||
| 1565 | w.set_bypass(_bypass); | ||
| 1566 | }); | ||
| 1567 | regs.dtimer() | ||
| 1568 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 1569 | |||
| 1570 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | ||
| 1571 | self.cmd(common_cmd::idle(), false)?; | ||
| 1572 | |||
| 1573 | match card { | ||
| 1574 | SdmmcPeripheral::SdCard(card) => { | ||
| 1575 | // Check if cards supports CMD8 (with pattern) | ||
| 1576 | self.cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; | ||
| 1577 | let cic = CIC::from(regs.respr(0).read().cardstatus()); | ||
| 1578 | |||
| 1579 | if cic.pattern() != 0xAA { | ||
| 1580 | return Err(Error::UnsupportedCardVersion); | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | if cic.voltage_accepted() & 1 == 0 { | ||
| 1584 | return Err(Error::UnsupportedVoltage); | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | let ocr = loop { | ||
| 1588 | // Signal that next command is a app command | ||
| 1589 | self.cmd(common_cmd::app_cmd(0), false)?; // CMD55 | ||
| 1590 | |||
| 1591 | // 3.2-3.3V | ||
| 1592 | let voltage_window = 1 << 5; | ||
| 1593 | // Initialize card | ||
| 1594 | match self.cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) { | ||
| 1595 | // ACMD41 | ||
| 1596 | Ok(_) => (), | ||
| 1597 | Err(Error::Crc) => (), | ||
| 1598 | Err(err) => return Err(err), | ||
| 1599 | } | ||
| 1600 | let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into(); | ||
| 1601 | if !ocr.is_busy() { | ||
| 1602 | // Power up done | ||
| 1603 | break ocr; | ||
| 1604 | } | ||
| 1605 | }; | ||
| 1606 | |||
| 1607 | if ocr.high_capacity() { | ||
| 1608 | // Card is SDHC or SDXC or SDUC | ||
| 1609 | card.card_type = CardCapacity::HighCapacity; | ||
| 1610 | } else { | ||
| 1611 | card.card_type = CardCapacity::StandardCapacity; | ||
| 1612 | } | ||
| 1613 | card.ocr = ocr; | ||
| 1614 | } | ||
| 1615 | SdmmcPeripheral::Emmc(emmc) => { | ||
| 1616 | let ocr = loop { | ||
| 1617 | let high_voltage = 0b0 << 7; | ||
| 1618 | let access_mode = 0b10 << 29; | ||
| 1619 | let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; | ||
| 1620 | // Initialize card | ||
| 1621 | match self.cmd(emmc_cmd::send_op_cond(op_cond), false) { | ||
| 1622 | Ok(_) => (), | ||
| 1623 | Err(Error::Crc) => (), | ||
| 1624 | Err(err) => return Err(err), | ||
| 1625 | } | ||
| 1626 | let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into(); | ||
| 1627 | if !ocr.is_busy() { | ||
| 1628 | // Power up done | ||
| 1629 | break ocr; | ||
| 1630 | } | ||
| 1631 | }; | ||
| 1632 | |||
| 1633 | emmc.capacity = if ocr.access_mode() == 0b10 { | ||
| 1634 | // Card is SDHC or SDXC or SDUC | ||
| 1635 | CardCapacity::HighCapacity | ||
| 1636 | } else { | ||
| 1637 | CardCapacity::StandardCapacity | ||
| 1638 | }; | ||
| 1639 | emmc.ocr = ocr; | ||
| 1640 | } | ||
| 1641 | } | ||
| 1642 | |||
| 1643 | self.cmd(common_cmd::all_send_cid(), false)?; // CMD2 | ||
| 1644 | let cid0 = regs.respr(0).read().cardstatus() as u128; | ||
| 1645 | let cid1 = regs.respr(1).read().cardstatus() as u128; | ||
| 1646 | let cid2 = regs.respr(2).read().cardstatus() as u128; | ||
| 1647 | let cid3 = regs.respr(3).read().cardstatus() as u128; | ||
| 1648 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | ||
| 1649 | |||
| 1650 | match card { | ||
| 1651 | SdmmcPeripheral::SdCard(card) => { | ||
| 1652 | card.cid = cid.into(); | ||
| 1653 | |||
| 1654 | self.cmd(sd_cmd::send_relative_address(), false)?; | ||
| 1655 | let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus()); | ||
| 1656 | card.rca = rca.address(); | ||
| 1657 | } | ||
| 1658 | SdmmcPeripheral::Emmc(emmc) => { | ||
| 1659 | emmc.cid = cid.into(); | ||
| 1660 | |||
| 1661 | emmc.rca = 1u16.into(); | ||
| 1662 | self.cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?; | ||
| 1663 | } | ||
| 1664 | } | ||
| 1665 | |||
| 1666 | self.cmd(common_cmd::send_csd(card.get_address()), false)?; | ||
| 1667 | let csd0 = regs.respr(0).read().cardstatus() as u128; | ||
| 1668 | let csd1 = regs.respr(1).read().cardstatus() as u128; | ||
| 1669 | let csd2 = regs.respr(2).read().cardstatus() as u128; | ||
| 1670 | let csd3 = regs.respr(3).read().cardstatus() as u128; | ||
| 1671 | let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); | ||
| 1672 | |||
| 1673 | self.select_card(Some(card.get_address()))?; | ||
| 1674 | |||
| 1675 | let bus_width = match card { | ||
| 1676 | SdmmcPeripheral::SdCard(card) => { | ||
| 1677 | card.csd = csd.into(); | ||
| 1678 | |||
| 1679 | card.get_scr(self, cmd_block).await?; | ||
| 1680 | |||
| 1681 | if !card.scr.bus_width_four() { | ||
| 1682 | BusWidth::One | ||
| 1683 | } else { | ||
| 1684 | BusWidth::Four | ||
| 1685 | } | ||
| 1686 | } | ||
| 1687 | SdmmcPeripheral::Emmc(emmc) => { | ||
| 1688 | emmc.csd = csd.into(); | ||
| 1689 | |||
| 1690 | bus_width | ||
| 1691 | } | ||
| 1692 | }; | ||
| 1693 | |||
| 1694 | // Set bus width | ||
| 1695 | let widbus = match bus_width { | ||
| 1696 | BusWidth::Eight => 2, | ||
| 1697 | BusWidth::Four => 1, | ||
| 1698 | BusWidth::One => 0, | ||
| 1699 | _ => unreachable!(), | ||
| 1700 | }; | ||
| 1701 | |||
| 1702 | match card { | ||
| 1703 | SdmmcPeripheral::SdCard(card) => { | ||
| 1704 | let acmd_arg = match bus_width { | ||
| 1705 | BusWidth::Four if card.scr.bus_width_four() => 2, | ||
| 1706 | _ => 0, | ||
| 1707 | }; | ||
| 1708 | self.cmd(common_cmd::app_cmd(card.rca), false)?; | ||
| 1709 | self.cmd(sd_cmd::cmd6(acmd_arg), false)?; | ||
| 1710 | } | ||
| 1711 | SdmmcPeripheral::Emmc(emmc) => { | ||
| 1712 | // Write bus width to ExtCSD byte 183 | ||
| 1713 | self.cmd( | ||
| 1714 | emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), | ||
| 1715 | false, | ||
| 1716 | )?; | ||
| 1717 | |||
| 1718 | // Wait for ready after R1b response | ||
| 1719 | loop { | ||
| 1720 | let status = self.read_status(emmc)?; | ||
| 1721 | |||
| 1722 | if status.ready_for_data() { | ||
| 1723 | break; | ||
| 1724 | } | ||
| 1725 | } | ||
| 1726 | } | ||
| 1727 | } | ||
| 1728 | |||
| 1729 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 1730 | self.wait_idle(); | ||
| 1731 | |||
| 1732 | regs.clkcr().modify(|w| w.set_widbus(widbus)); | ||
| 1733 | |||
| 1734 | // Set Clock | ||
| 1735 | if freq.0 <= 25_000_000 { | ||
| 1736 | // Final clock frequency | ||
| 1737 | self.clkcr_set_clkdiv(freq.0, bus_width)?; | ||
| 1738 | } else { | ||
| 1739 | // Switch to max clock for SDR12 | ||
| 1740 | self.clkcr_set_clkdiv(25_000_000, bus_width)?; | ||
| 1741 | } | ||
| 1742 | |||
| 1743 | match card { | ||
| 1744 | SdmmcPeripheral::SdCard(card) => { | ||
| 1745 | // Read status | ||
| 1746 | card.read_sd_status(self, cmd_block).await?; | ||
| 1747 | |||
| 1748 | if freq.0 > 25_000_000 { | ||
| 1749 | // Switch to SDR25 | ||
| 1750 | self.signalling = card.switch_signalling_mode(self, cmd_block, Signalling::SDR25).await?; | ||
| 1751 | |||
| 1752 | if self.signalling == Signalling::SDR25 { | ||
| 1753 | // Set final clock frequency | ||
| 1754 | self.clkcr_set_clkdiv(freq.0, bus_width)?; | ||
| 1755 | |||
| 1756 | if self.read_status(card)?.state() != CurrentState::Transfer { | ||
| 1757 | return Err(Error::SignalingSwitchFailed); | ||
| 1758 | } | ||
| 1759 | } | ||
| 1760 | } | ||
| 1761 | |||
| 1762 | // Read status after signalling change | ||
| 1763 | card.read_sd_status(self, cmd_block).await?; | ||
| 1764 | } | ||
| 1765 | SdmmcPeripheral::Emmc(emmc) => { | ||
| 1766 | emmc.read_ext_csd(self).await?; | ||
| 1767 | } | ||
| 1768 | } | ||
| 1769 | |||
| 1770 | Ok(()) | ||
| 1771 | } | ||
| 1772 | |||
| 1773 | /// Initializes card (if present) and sets the bus at the specified frequency. | ||
| 1774 | /// | ||
| 1775 | /// SD only. | ||
| 1776 | async fn init_sd_card(&mut self, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Card, Error> { | ||
| 1777 | let mut card = SdmmcPeripheral::SdCard(Card::default()); | ||
| 1778 | self.init_internal(cmd_block, freq, &mut card).await?; | ||
| 1779 | |||
| 1780 | let card = match card { | ||
| 1781 | SdmmcPeripheral::SdCard(card) => card, | ||
| 1782 | _ => unreachable!(), | ||
| 1783 | }; | ||
| 1784 | |||
| 1785 | Ok(card) | ||
| 1786 | } | ||
| 1787 | |||
| 1788 | /// Initializes eMMC and sets the bus at the specified frequency. | ||
| 1789 | /// | ||
| 1790 | /// eMMC only. | ||
| 1791 | async fn init_emmc(&mut self, cmd_block: &mut CmdBlock, freq: Hertz) -> Result<Emmc, Error> { | ||
| 1792 | let mut card = SdmmcPeripheral::Emmc(Emmc::default()); | ||
| 1793 | self.init_internal(cmd_block, freq, &mut card).await?; | ||
| 1794 | |||
| 1795 | let card = match card { | ||
| 1796 | SdmmcPeripheral::Emmc(card) => card, | ||
| 1797 | _ => unreachable!(), | ||
| 1798 | }; | ||
| 1799 | |||
| 1800 | Ok(card) | ||
| 1801 | } | ||
| 1802 | } | 1698 | } |
| 1803 | 1699 | ||
| 1804 | impl<'d> Drop for Sdmmc<'d> { | 1700 | impl<'d> Drop for Sdmmc<'d> { |
