diff options
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 998 |
1 files changed, 419 insertions, 579 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 22b578dcf..23ece3a2a 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -41,7 +41,7 @@ impl Default for Signalling { | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | #[repr(align(4))] | 43 | #[repr(align(4))] |
| 44 | #[derive(Debug, Clone)] | 44 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 45 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 45 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 46 | pub struct DataBlock(pub [u8; 512]); | 46 | pub struct DataBlock(pub [u8; 512]); |
| 47 | 47 | ||
| @@ -61,7 +61,7 @@ impl DerefMut for DataBlock { | |||
| 61 | 61 | ||
| 62 | /// Errors | 62 | /// Errors |
| 63 | #[non_exhaustive] | 63 | #[non_exhaustive] |
| 64 | #[derive(Debug, Copy, Clone)] | 64 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 65 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 65 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 66 | pub enum Error { | 66 | pub enum Error { |
| 67 | Timeout, | 67 | Timeout, |
| @@ -175,7 +175,7 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u16, Hertz), Error> { | |||
| 175 | match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck { | 175 | match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck { |
| 176 | 0 | 1 => Ok((false, 0, ker_ck)), | 176 | 0 | 1 => Ok((false, 0, ker_ck)), |
| 177 | x @ 2..=2046 => { | 177 | x @ 2..=2046 => { |
| 178 | // SDMMC_CK frequency = SDMMCCLK / [CLKDIV + 2] | 178 | // SDMMC_CK frequency = SDMMCCLK / [CLKDIV * 2] |
| 179 | let clk_div = ((x + 1) / 2) as u16; | 179 | let clk_div = ((x + 1) / 2) as u16; |
| 180 | let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2)); | 180 | let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2)); |
| 181 | 181 | ||
| @@ -204,9 +204,10 @@ impl Default for Config { | |||
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | /// Sdmmc device | 206 | /// Sdmmc device |
| 207 | pub struct Sdmmc<'d, T: Instance, Dma = NoDma> { | 207 | pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> { |
| 208 | _peri: PeripheralRef<'d, T>, | 208 | _peri: PeripheralRef<'d, T>, |
| 209 | irq: PeripheralRef<'d, T::Interrupt>, | 209 | irq: PeripheralRef<'d, T::Interrupt>, |
| 210 | #[allow(unused)] | ||
| 210 | dma: PeripheralRef<'d, Dma>, | 211 | dma: PeripheralRef<'d, Dma>, |
| 211 | 212 | ||
| 212 | clk: PeripheralRef<'d, AnyPin>, | 213 | clk: PeripheralRef<'d, AnyPin>, |
| @@ -305,49 +306,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | |||
| 305 | config, | 306 | config, |
| 306 | ) | 307 | ) |
| 307 | } | 308 | } |
| 308 | |||
| 309 | fn new_inner( | ||
| 310 | sdmmc: impl Peripheral<P = T> + 'd, | ||
| 311 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 312 | dma: impl Peripheral<P = Dma> + 'd, | ||
| 313 | clk: PeripheralRef<'d, AnyPin>, | ||
| 314 | cmd: PeripheralRef<'d, AnyPin>, | ||
| 315 | d0: PeripheralRef<'d, AnyPin>, | ||
| 316 | d1: Option<PeripheralRef<'d, AnyPin>>, | ||
| 317 | d2: Option<PeripheralRef<'d, AnyPin>>, | ||
| 318 | d3: Option<PeripheralRef<'d, AnyPin>>, | ||
| 319 | config: Config, | ||
| 320 | ) -> Self { | ||
| 321 | into_ref!(sdmmc, irq, dma); | ||
| 322 | |||
| 323 | T::enable(); | ||
| 324 | T::reset(); | ||
| 325 | |||
| 326 | let inner = T::inner(); | ||
| 327 | unsafe { inner.new_inner() }; | ||
| 328 | |||
| 329 | irq.set_handler(Self::on_interrupt); | ||
| 330 | irq.unpend(); | ||
| 331 | irq.enable(); | ||
| 332 | |||
| 333 | Self { | ||
| 334 | _peri: sdmmc, | ||
| 335 | irq, | ||
| 336 | dma, | ||
| 337 | |||
| 338 | clk, | ||
| 339 | cmd, | ||
| 340 | d0, | ||
| 341 | d1, | ||
| 342 | d2, | ||
| 343 | d3, | ||
| 344 | |||
| 345 | config, | ||
| 346 | clock: SD_INIT_FREQ, | ||
| 347 | signalling: Default::default(), | ||
| 348 | card: None, | ||
| 349 | } | ||
| 350 | } | ||
| 351 | } | 309 | } |
| 352 | 310 | ||
| 353 | #[cfg(sdmmc_v2)] | 311 | #[cfg(sdmmc_v2)] |
| @@ -375,6 +333,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | |||
| 375 | Self::new_inner( | 333 | Self::new_inner( |
| 376 | sdmmc, | 334 | sdmmc, |
| 377 | irq, | 335 | irq, |
| 336 | NoDma.into_ref(), | ||
| 378 | clk.map_into(), | 337 | clk.map_into(), |
| 379 | cmd.map_into(), | 338 | cmd.map_into(), |
| 380 | d0.map_into(), | 339 | d0.map_into(), |
| @@ -417,6 +376,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | |||
| 417 | Self::new_inner( | 376 | Self::new_inner( |
| 418 | sdmmc, | 377 | sdmmc, |
| 419 | irq, | 378 | irq, |
| 379 | NoDma.into_ref(), | ||
| 420 | clk.map_into(), | 380 | clk.map_into(), |
| 421 | cmd.map_into(), | 381 | cmd.map_into(), |
| 422 | d0.map_into(), | 382 | d0.map_into(), |
| @@ -426,10 +386,13 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | |||
| 426 | config, | 386 | config, |
| 427 | ) | 387 | ) |
| 428 | } | 388 | } |
| 389 | } | ||
| 429 | 390 | ||
| 391 | impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | ||
| 430 | fn new_inner( | 392 | fn new_inner( |
| 431 | sdmmc: impl Peripheral<P = T> + 'd, | 393 | sdmmc: impl Peripheral<P = T> + 'd, |
| 432 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 394 | irq: impl Peripheral<P = T::Interrupt> + 'd, |
| 395 | dma: impl Peripheral<P = Dma> + 'd, | ||
| 433 | clk: PeripheralRef<'d, AnyPin>, | 396 | clk: PeripheralRef<'d, AnyPin>, |
| 434 | cmd: PeripheralRef<'d, AnyPin>, | 397 | cmd: PeripheralRef<'d, AnyPin>, |
| 435 | d0: PeripheralRef<'d, AnyPin>, | 398 | d0: PeripheralRef<'d, AnyPin>, |
| @@ -438,22 +401,41 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | |||
| 438 | d3: Option<PeripheralRef<'d, AnyPin>>, | 401 | d3: Option<PeripheralRef<'d, AnyPin>>, |
| 439 | config: Config, | 402 | config: Config, |
| 440 | ) -> Self { | 403 | ) -> Self { |
| 441 | into_ref!(sdmmc, irq); | 404 | into_ref!(sdmmc, irq, dma); |
| 442 | 405 | ||
| 443 | T::enable(); | 406 | T::enable(); |
| 444 | T::reset(); | 407 | T::reset(); |
| 445 | 408 | ||
| 446 | let inner = T::inner(); | ||
| 447 | unsafe { inner.new_inner() }; | ||
| 448 | |||
| 449 | irq.set_handler(Self::on_interrupt); | 409 | irq.set_handler(Self::on_interrupt); |
| 450 | irq.unpend(); | 410 | irq.unpend(); |
| 451 | irq.enable(); | 411 | irq.enable(); |
| 452 | 412 | ||
| 413 | let regs = T::regs(); | ||
| 414 | unsafe { | ||
| 415 | regs.clkcr().write(|w| { | ||
| 416 | w.set_pwrsav(false); | ||
| 417 | w.set_negedge(false); | ||
| 418 | |||
| 419 | // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors. | ||
| 420 | // See chip erratas for more details. | ||
| 421 | #[cfg(sdmmc_v1)] | ||
| 422 | w.set_hwfc_en(false); | ||
| 423 | #[cfg(sdmmc_v2)] | ||
| 424 | w.set_hwfc_en(true); | ||
| 425 | |||
| 426 | #[cfg(sdmmc_v1)] | ||
| 427 | w.set_clken(true); | ||
| 428 | }); | ||
| 429 | |||
| 430 | // Power off, writen 00: Clock to the card is stopped; | ||
| 431 | // D[7:0], CMD, and CK are driven high. | ||
| 432 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); | ||
| 433 | } | ||
| 434 | |||
| 453 | Self { | 435 | Self { |
| 454 | _peri: sdmmc, | 436 | _peri: sdmmc, |
| 455 | irq, | 437 | irq, |
| 456 | dma: NoDma.into_ref(), | 438 | dma, |
| 457 | 439 | ||
| 458 | clk, | 440 | clk, |
| 459 | cmd, | 441 | cmd, |
| @@ -468,434 +450,11 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | |||
| 468 | card: None, | 450 | card: None, |
| 469 | } | 451 | } |
| 470 | } | 452 | } |
| 471 | } | ||
| 472 | |||
| 473 | impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | ||
| 474 | #[inline(always)] | ||
| 475 | pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { | ||
| 476 | let inner = T::inner(); | ||
| 477 | let freq = freq.into(); | ||
| 478 | |||
| 479 | let bus_width = match self.d3.is_some() { | ||
| 480 | true => BusWidth::Four, | ||
| 481 | false => BusWidth::One, | ||
| 482 | }; | ||
| 483 | |||
| 484 | inner | ||
| 485 | .init_card( | ||
| 486 | freq, | ||
| 487 | bus_width, | ||
| 488 | &mut self.card, | ||
| 489 | &mut self.signalling, | ||
| 490 | T::kernel_clk(), | ||
| 491 | &mut self.clock, | ||
| 492 | T::state(), | ||
| 493 | self.config.data_transfer_timeout, | ||
| 494 | &mut *self.dma, | ||
| 495 | ) | ||
| 496 | .await | ||
| 497 | } | ||
| 498 | |||
| 499 | #[inline(always)] | ||
| 500 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | ||
| 501 | let card_capacity = self.card()?.card_type; | ||
| 502 | let inner = T::inner(); | ||
| 503 | let state = T::state(); | ||
| 504 | |||
| 505 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 506 | let buf = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 507 | inner | ||
| 508 | .read_block( | ||
| 509 | block_idx, | ||
| 510 | buf, | ||
| 511 | card_capacity, | ||
| 512 | state, | ||
| 513 | self.config.data_transfer_timeout, | ||
| 514 | &mut *self.dma, | ||
| 515 | ) | ||
| 516 | .await | ||
| 517 | } | ||
| 518 | |||
| 519 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | ||
| 520 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | ||
| 521 | let inner = T::inner(); | ||
| 522 | let state = T::state(); | ||
| 523 | |||
| 524 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 525 | let buf = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; | ||
| 526 | inner | ||
| 527 | .write_block( | ||
| 528 | block_idx, | ||
| 529 | buf, | ||
| 530 | card, | ||
| 531 | state, | ||
| 532 | self.config.data_transfer_timeout, | ||
| 533 | &mut *self.dma, | ||
| 534 | ) | ||
| 535 | .await | ||
| 536 | } | ||
| 537 | |||
| 538 | /// Get a reference to the initialized card | ||
| 539 | /// | ||
| 540 | /// # Errors | ||
| 541 | /// | ||
| 542 | /// Returns Error::NoCard if [`init_card`](#method.init_card) | ||
| 543 | /// has not previously succeeded | ||
| 544 | #[inline(always)] | ||
| 545 | pub fn card(&self) -> Result<&Card, Error> { | ||
| 546 | self.card.as_ref().ok_or(Error::NoCard) | ||
| 547 | } | ||
| 548 | |||
| 549 | /// Get the current SDMMC bus clock | ||
| 550 | pub fn clock(&self) -> Hertz { | ||
| 551 | self.clock | ||
| 552 | } | ||
| 553 | |||
| 554 | #[inline(always)] | ||
| 555 | fn on_interrupt(_: *mut ()) { | ||
| 556 | let regs = T::inner(); | ||
| 557 | let state = T::state(); | ||
| 558 | |||
| 559 | regs.data_interrupts(false); | ||
| 560 | state.wake(); | ||
| 561 | } | ||
| 562 | } | ||
| 563 | |||
| 564 | impl<'d, T: Instance, Dma> Drop for Sdmmc<'d, T, Dma> { | ||
| 565 | fn drop(&mut self) { | ||
| 566 | self.irq.disable(); | ||
| 567 | let inner = T::inner(); | ||
| 568 | unsafe { inner.on_drop() }; | ||
| 569 | |||
| 570 | critical_section::with(|_| unsafe { | ||
| 571 | self.clk.set_as_disconnected(); | ||
| 572 | self.cmd.set_as_disconnected(); | ||
| 573 | self.d0.set_as_disconnected(); | ||
| 574 | if let Some(x) = &mut self.d1 { | ||
| 575 | x.set_as_disconnected(); | ||
| 576 | } | ||
| 577 | if let Some(x) = &mut self.d2 { | ||
| 578 | x.set_as_disconnected(); | ||
| 579 | } | ||
| 580 | if let Some(x) = &mut self.d3 { | ||
| 581 | x.set_as_disconnected(); | ||
| 582 | } | ||
| 583 | }); | ||
| 584 | } | ||
| 585 | } | ||
| 586 | |||
| 587 | pub struct SdmmcInner(pub(crate) RegBlock); | ||
| 588 | |||
| 589 | impl SdmmcInner { | ||
| 590 | /// # Safety | ||
| 591 | /// | ||
| 592 | /// Access to `regs` registers should be exclusive | ||
| 593 | unsafe fn new_inner(&self) { | ||
| 594 | let regs = self.0; | ||
| 595 | |||
| 596 | regs.clkcr().write(|w| { | ||
| 597 | w.set_pwrsav(false); | ||
| 598 | w.set_negedge(false); | ||
| 599 | |||
| 600 | // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors. | ||
| 601 | // See chip erratas for more details. | ||
| 602 | #[cfg(sdmmc_v1)] | ||
| 603 | w.set_hwfc_en(false); | ||
| 604 | #[cfg(sdmmc_v2)] | ||
| 605 | w.set_hwfc_en(true); | ||
| 606 | |||
| 607 | #[cfg(sdmmc_v1)] | ||
| 608 | w.set_clken(true); | ||
| 609 | }); | ||
| 610 | |||
| 611 | // Power off, writen 00: Clock to the card is stopped; | ||
| 612 | // D[7:0], CMD, and CK are driven high. | ||
| 613 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); | ||
| 614 | } | ||
| 615 | |||
| 616 | /// Initializes card (if present) and sets the bus at the | ||
| 617 | /// specified frequency. | ||
| 618 | #[allow(clippy::too_many_arguments)] | ||
| 619 | async fn init_card<T: Instance, Dma: SdmmcDma<T>>( | ||
| 620 | &self, | ||
| 621 | freq: Hertz, | ||
| 622 | bus_width: BusWidth, | ||
| 623 | old_card: &mut Option<Card>, | ||
| 624 | signalling: &mut Signalling, | ||
| 625 | ker_ck: Hertz, | ||
| 626 | clock: &mut Hertz, | ||
| 627 | waker_reg: &AtomicWaker, | ||
| 628 | data_transfer_timeout: u32, | ||
| 629 | dma: &mut Dma, | ||
| 630 | ) -> Result<(), Error> { | ||
| 631 | let regs = self.0; | ||
| 632 | |||
| 633 | // NOTE(unsafe) We have exclusive access to the peripheral | ||
| 634 | unsafe { | ||
| 635 | // While the SD/SDIO card or eMMC is in identification mode, | ||
| 636 | // the SDMMC_CK frequency must be no more than 400 kHz. | ||
| 637 | let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); | ||
| 638 | *clock = init_clock; | ||
| 639 | |||
| 640 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 641 | self.wait_idle(); | ||
| 642 | |||
| 643 | regs.clkcr().modify(|w| { | ||
| 644 | w.set_widbus(0); | ||
| 645 | w.set_clkdiv(clkdiv); | ||
| 646 | #[cfg(sdmmc_v1)] | ||
| 647 | w.set_bypass(_bypass); | ||
| 648 | }); | ||
| 649 | |||
| 650 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | ||
| 651 | self.cmd(Cmd::idle(), false)?; | ||
| 652 | |||
| 653 | // Check if cards supports CMD8 (with pattern) | ||
| 654 | self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; | ||
| 655 | let r1 = regs.respr(0).read().cardstatus(); | ||
| 656 | |||
| 657 | let mut card = if r1 == 0x1AA { | ||
| 658 | // Card echoed back the pattern. Must be at least v2 | ||
| 659 | Card::default() | ||
| 660 | } else { | ||
| 661 | return Err(Error::UnsupportedCardVersion); | ||
| 662 | }; | ||
| 663 | |||
| 664 | let ocr = loop { | ||
| 665 | // Signal that next command is a app command | ||
| 666 | self.cmd(Cmd::app_cmd(0), false)?; // CMD55 | ||
| 667 | |||
| 668 | let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 | ||
| 669 | | CmdAppOper::HIGH_CAPACITY as u32 | ||
| 670 | | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; | ||
| 671 | |||
| 672 | // Initialize card | ||
| 673 | match self.cmd(Cmd::app_op_cmd(arg), false) { | ||
| 674 | // ACMD41 | ||
| 675 | Ok(_) => (), | ||
| 676 | Err(Error::Crc) => (), | ||
| 677 | Err(err) => return Err(err), | ||
| 678 | } | ||
| 679 | let ocr: OCR = regs.respr(0).read().cardstatus().into(); | ||
| 680 | if !ocr.is_busy() { | ||
| 681 | // Power up done | ||
| 682 | break ocr; | ||
| 683 | } | ||
| 684 | }; | ||
| 685 | |||
| 686 | if ocr.high_capacity() { | ||
| 687 | // Card is SDHC or SDXC or SDUC | ||
| 688 | card.card_type = CardCapacity::SDHC; | ||
| 689 | } else { | ||
| 690 | card.card_type = CardCapacity::SDSC; | ||
| 691 | } | ||
| 692 | card.ocr = ocr; | ||
| 693 | |||
| 694 | self.cmd(Cmd::all_send_cid(), false)?; // CMD2 | ||
| 695 | let cid0 = regs.respr(0).read().cardstatus() as u128; | ||
| 696 | let cid1 = regs.respr(1).read().cardstatus() as u128; | ||
| 697 | let cid2 = regs.respr(2).read().cardstatus() as u128; | ||
| 698 | let cid3 = regs.respr(3).read().cardstatus() as u128; | ||
| 699 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | ||
| 700 | card.cid = cid.into(); | ||
| 701 | |||
| 702 | self.cmd(Cmd::send_rel_addr(), false)?; | ||
| 703 | card.rca = regs.respr(0).read().cardstatus() >> 16; | ||
| 704 | |||
| 705 | self.cmd(Cmd::send_csd(card.rca << 16), false)?; | ||
| 706 | let csd0 = regs.respr(0).read().cardstatus() as u128; | ||
| 707 | let csd1 = regs.respr(1).read().cardstatus() as u128; | ||
| 708 | let csd2 = regs.respr(2).read().cardstatus() as u128; | ||
| 709 | let csd3 = regs.respr(3).read().cardstatus() as u128; | ||
| 710 | let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); | ||
| 711 | card.csd = csd.into(); | ||
| 712 | |||
| 713 | self.select_card(Some(&card))?; | ||
| 714 | |||
| 715 | self.get_scr(&mut card, waker_reg, data_transfer_timeout, dma).await?; | ||
| 716 | |||
| 717 | // Set bus width | ||
| 718 | let (width, acmd_arg) = match bus_width { | ||
| 719 | BusWidth::Eight => unimplemented!(), | ||
| 720 | BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), | ||
| 721 | _ => (BusWidth::One, 0), | ||
| 722 | }; | ||
| 723 | self.cmd(Cmd::app_cmd(card.rca << 16), false)?; | ||
| 724 | self.cmd(Cmd::cmd6(acmd_arg), false)?; | ||
| 725 | |||
| 726 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 727 | self.wait_idle(); | ||
| 728 | |||
| 729 | regs.clkcr().modify(|w| { | ||
| 730 | w.set_widbus(match width { | ||
| 731 | BusWidth::One => 0, | ||
| 732 | BusWidth::Four => 1, | ||
| 733 | BusWidth::Eight => 2, | ||
| 734 | _ => panic!("Invalid Bus Width"), | ||
| 735 | }) | ||
| 736 | }); | ||
| 737 | |||
| 738 | // Set Clock | ||
| 739 | if freq.0 <= 25_000_000 { | ||
| 740 | // Final clock frequency | ||
| 741 | self.clkcr_set_clkdiv(freq.0, width, ker_ck, clock)?; | ||
| 742 | } else { | ||
| 743 | // Switch to max clock for SDR12 | ||
| 744 | self.clkcr_set_clkdiv(25_000_000, width, ker_ck, clock)?; | ||
| 745 | } | ||
| 746 | |||
| 747 | // Read status | ||
| 748 | self.read_sd_status(&mut card, waker_reg, data_transfer_timeout, dma) | ||
| 749 | .await?; | ||
| 750 | |||
| 751 | if freq.0 > 25_000_000 { | ||
| 752 | // Switch to SDR25 | ||
| 753 | *signalling = self | ||
| 754 | .switch_signalling_mode(Signalling::SDR25, waker_reg, data_transfer_timeout, dma) | ||
| 755 | .await?; | ||
| 756 | |||
| 757 | if *signalling == Signalling::SDR25 { | ||
| 758 | // Set final clock frequency | ||
| 759 | self.clkcr_set_clkdiv(freq.0, width, ker_ck, clock)?; | ||
| 760 | |||
| 761 | if self.read_status(&card)?.state() != CurrentState::Transfer { | ||
| 762 | return Err(Error::SignalingSwitchFailed); | ||
| 763 | } | ||
| 764 | } | ||
| 765 | } | ||
| 766 | // Read status after signalling change | ||
| 767 | self.read_sd_status(&mut card, waker_reg, data_transfer_timeout, dma) | ||
| 768 | .await?; | ||
| 769 | old_card.replace(card); | ||
| 770 | } | ||
| 771 | |||
| 772 | Ok(()) | ||
| 773 | } | ||
| 774 | |||
| 775 | async fn read_block<T: Instance, Dma: SdmmcDma<T>>( | ||
| 776 | &self, | ||
| 777 | block_idx: u32, | ||
| 778 | buffer: &mut [u32; 128], | ||
| 779 | capacity: CardCapacity, | ||
| 780 | waker_reg: &AtomicWaker, | ||
| 781 | data_transfer_timeout: u32, | ||
| 782 | dma: &mut Dma, | ||
| 783 | ) -> Result<(), Error> { | ||
| 784 | // Always read 1 block of 512 bytes | ||
| 785 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 786 | let address = match capacity { | ||
| 787 | CardCapacity::SDSC => block_idx * 512, | ||
| 788 | _ => block_idx, | ||
| 789 | }; | ||
| 790 | self.cmd(Cmd::set_block_length(512), false)?; // CMD16 | ||
| 791 | |||
| 792 | let regs = self.0; | ||
| 793 | let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); | ||
| 794 | |||
| 795 | unsafe { | ||
| 796 | self.prepare_datapath_read(buffer, 512, 9, data_transfer_timeout, dma); | ||
| 797 | self.data_interrupts(true); | ||
| 798 | } | ||
| 799 | self.cmd(Cmd::read_single_block(address), true)?; | ||
| 800 | |||
| 801 | let res = poll_fn(|cx| { | ||
| 802 | waker_reg.register(cx.waker()); | ||
| 803 | let status = unsafe { regs.star().read() }; | ||
| 804 | |||
| 805 | if status.dcrcfail() { | ||
| 806 | return Poll::Ready(Err(Error::Crc)); | ||
| 807 | } else if status.dtimeout() { | ||
| 808 | return Poll::Ready(Err(Error::Timeout)); | ||
| 809 | } else if status.dataend() { | ||
| 810 | return Poll::Ready(Ok(())); | ||
| 811 | } | ||
| 812 | Poll::Pending | ||
| 813 | }) | ||
| 814 | .await; | ||
| 815 | self.clear_interrupt_flags(); | ||
| 816 | |||
| 817 | if res.is_ok() { | ||
| 818 | on_drop.defuse(); | ||
| 819 | self.stop_datapath(); | ||
| 820 | } | ||
| 821 | res | ||
| 822 | } | ||
| 823 | |||
| 824 | async fn write_block<T: Instance, Dma: SdmmcDma<T>>( | ||
| 825 | &self, | ||
| 826 | block_idx: u32, | ||
| 827 | buffer: &[u32; 128], | ||
| 828 | card: &mut Card, | ||
| 829 | waker_reg: &AtomicWaker, | ||
| 830 | data_transfer_timeout: u32, | ||
| 831 | dma: &mut Dma, | ||
| 832 | ) -> Result<(), Error> { | ||
| 833 | // Always read 1 block of 512 bytes | ||
| 834 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 835 | let address = match card.card_type { | ||
| 836 | CardCapacity::SDSC => block_idx * 512, | ||
| 837 | _ => block_idx, | ||
| 838 | }; | ||
| 839 | self.cmd(Cmd::set_block_length(512), false)?; // CMD16 | ||
| 840 | |||
| 841 | let regs = self.0; | ||
| 842 | let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); | ||
| 843 | |||
| 844 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||
| 845 | #[cfg(sdmmc_v1)] | ||
| 846 | self.cmd(Cmd::write_single_block(address), true)?; | ||
| 847 | |||
| 848 | unsafe { | ||
| 849 | self.prepare_datapath_write(buffer as *const [u32; 128], 512, 9, data_transfer_timeout, dma); | ||
| 850 | self.data_interrupts(true); | ||
| 851 | } | ||
| 852 | |||
| 853 | #[cfg(sdmmc_v2)] | ||
| 854 | self.cmd(Cmd::write_single_block(address), true)?; | ||
| 855 | |||
| 856 | let res = poll_fn(|cx| { | ||
| 857 | waker_reg.register(cx.waker()); | ||
| 858 | let status = unsafe { regs.star().read() }; | ||
| 859 | |||
| 860 | if status.dcrcfail() { | ||
| 861 | return Poll::Ready(Err(Error::Crc)); | ||
| 862 | } else if status.dtimeout() { | ||
| 863 | return Poll::Ready(Err(Error::Timeout)); | ||
| 864 | } else if status.dataend() { | ||
| 865 | return Poll::Ready(Ok(())); | ||
| 866 | } | ||
| 867 | Poll::Pending | ||
| 868 | }) | ||
| 869 | .await; | ||
| 870 | self.clear_interrupt_flags(); | ||
| 871 | |||
| 872 | match res { | ||
| 873 | Ok(_) => { | ||
| 874 | on_drop.defuse(); | ||
| 875 | self.stop_datapath(); | ||
| 876 | |||
| 877 | // TODO: Make this configurable | ||
| 878 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 879 | |||
| 880 | // Try to read card status (ACMD13) | ||
| 881 | while timeout > 0 { | ||
| 882 | match self.read_sd_status(card, waker_reg, data_transfer_timeout, dma).await { | ||
| 883 | Ok(_) => return Ok(()), | ||
| 884 | Err(Error::Timeout) => (), // Try again | ||
| 885 | Err(e) => return Err(e), | ||
| 886 | } | ||
| 887 | timeout -= 1; | ||
| 888 | } | ||
| 889 | Err(Error::SoftwareTimeout) | ||
| 890 | } | ||
| 891 | Err(e) => Err(e), | ||
| 892 | } | ||
| 893 | } | ||
| 894 | 453 | ||
| 895 | /// Data transfer is in progress | 454 | /// Data transfer is in progress |
| 896 | #[inline(always)] | 455 | #[inline(always)] |
| 897 | fn data_active(&self) -> bool { | 456 | fn data_active() -> bool { |
| 898 | let regs = self.0; | 457 | let regs = T::regs(); |
| 899 | 458 | ||
| 900 | // NOTE(unsafe) Atomic read with no side-effects | 459 | // NOTE(unsafe) Atomic read with no side-effects |
| 901 | unsafe { | 460 | unsafe { |
| @@ -909,8 +468,8 @@ impl SdmmcInner { | |||
| 909 | 468 | ||
| 910 | /// Coammand transfer is in progress | 469 | /// Coammand transfer is in progress |
| 911 | #[inline(always)] | 470 | #[inline(always)] |
| 912 | fn cmd_active(&self) -> bool { | 471 | fn cmd_active() -> bool { |
| 913 | let regs = self.0; | 472 | let regs = T::regs(); |
| 914 | 473 | ||
| 915 | // NOTE(unsafe) Atomic read with no side-effects | 474 | // NOTE(unsafe) Atomic read with no side-effects |
| 916 | unsafe { | 475 | unsafe { |
| @@ -924,37 +483,31 @@ impl SdmmcInner { | |||
| 924 | 483 | ||
| 925 | /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) | 484 | /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) |
| 926 | #[inline(always)] | 485 | #[inline(always)] |
| 927 | fn wait_idle(&self) { | 486 | fn wait_idle() { |
| 928 | while self.data_active() || self.cmd_active() {} | 487 | while Self::data_active() || Self::cmd_active() {} |
| 929 | } | 488 | } |
| 930 | 489 | ||
| 931 | /// # Safety | 490 | /// # Safety |
| 932 | /// | 491 | /// |
| 933 | /// `buffer` must be valid for the whole transfer and word aligned | 492 | /// `buffer` must be valid for the whole transfer and word aligned |
| 934 | unsafe fn prepare_datapath_read<T: Instance, Dma: SdmmcDma<T>>( | 493 | unsafe fn prepare_datapath_read(&mut self, buffer: *mut [u32], length_bytes: u32, block_size: u8) { |
| 935 | &self, | ||
| 936 | buffer: *mut [u32], | ||
| 937 | length_bytes: u32, | ||
| 938 | block_size: u8, | ||
| 939 | data_transfer_timeout: u32, | ||
| 940 | #[allow(unused_variables)] dma: &mut Dma, | ||
| 941 | ) { | ||
| 942 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 494 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); |
| 943 | let regs = self.0; | 495 | let regs = T::regs(); |
| 944 | 496 | ||
| 945 | // Command AND Data state machines must be idle | 497 | // Command AND Data state machines must be idle |
| 946 | self.wait_idle(); | 498 | Self::wait_idle(); |
| 947 | self.clear_interrupt_flags(); | 499 | Self::clear_interrupt_flags(); |
| 948 | 500 | ||
| 949 | // NOTE(unsafe) We have exclusive access to the regisers | 501 | // NOTE(unsafe) We have exclusive access to the regisers |
| 950 | 502 | ||
| 951 | regs.dtimer().write(|w| w.set_datatime(data_transfer_timeout)); | 503 | regs.dtimer() |
| 504 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 952 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | 505 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); |
| 953 | 506 | ||
| 954 | #[cfg(sdmmc_v1)] | 507 | #[cfg(sdmmc_v1)] |
| 955 | { | 508 | { |
| 956 | let request = dma.request(); | 509 | let request = self.dma.request(); |
| 957 | dma.start_read( | 510 | self.dma.start_read( |
| 958 | request, | 511 | request, |
| 959 | regs.fifor().ptr() as *const u32, | 512 | regs.fifor().ptr() as *const u32, |
| 960 | buffer, | 513 | buffer, |
| @@ -987,30 +540,24 @@ impl SdmmcInner { | |||
| 987 | /// # Safety | 540 | /// # Safety |
| 988 | /// | 541 | /// |
| 989 | /// `buffer` must be valid for the whole transfer and word aligned | 542 | /// `buffer` must be valid for the whole transfer and word aligned |
| 990 | unsafe fn prepare_datapath_write<T: Instance, Dma: SdmmcDma<T>>( | 543 | unsafe fn prepare_datapath_write(&mut self, buffer: *const [u32], length_bytes: u32, block_size: u8) { |
| 991 | &self, | ||
| 992 | buffer: *const [u32], | ||
| 993 | length_bytes: u32, | ||
| 994 | block_size: u8, | ||
| 995 | data_transfer_timeout: u32, | ||
| 996 | #[allow(unused_variables)] dma: &mut Dma, | ||
| 997 | ) { | ||
| 998 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); | 544 | assert!(block_size <= 14, "Block size up to 2^14 bytes"); |
| 999 | let regs = self.0; | 545 | let regs = T::regs(); |
| 1000 | 546 | ||
| 1001 | // Command AND Data state machines must be idle | 547 | // Command AND Data state machines must be idle |
| 1002 | self.wait_idle(); | 548 | Self::wait_idle(); |
| 1003 | self.clear_interrupt_flags(); | 549 | Self::clear_interrupt_flags(); |
| 1004 | 550 | ||
| 1005 | // NOTE(unsafe) We have exclusive access to the regisers | 551 | // NOTE(unsafe) We have exclusive access to the regisers |
| 1006 | 552 | ||
| 1007 | regs.dtimer().write(|w| w.set_datatime(data_transfer_timeout)); | 553 | regs.dtimer() |
| 554 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 1008 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | 555 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); |
| 1009 | 556 | ||
| 1010 | #[cfg(sdmmc_v1)] | 557 | #[cfg(sdmmc_v1)] |
| 1011 | { | 558 | { |
| 1012 | let request = dma.request(); | 559 | let request = self.dma.request(); |
| 1013 | dma.start_write( | 560 | self.dma.start_write( |
| 1014 | request, | 561 | request, |
| 1015 | buffer, | 562 | buffer, |
| 1016 | regs.fifor().ptr() as *mut u32, | 563 | regs.fifor().ptr() as *mut u32, |
| @@ -1042,8 +589,8 @@ impl SdmmcInner { | |||
| 1042 | } | 589 | } |
| 1043 | 590 | ||
| 1044 | /// Stops the DMA datapath | 591 | /// Stops the DMA datapath |
| 1045 | fn stop_datapath(&self) { | 592 | fn stop_datapath() { |
| 1046 | let regs = self.0; | 593 | let regs = T::regs(); |
| 1047 | 594 | ||
| 1048 | unsafe { | 595 | unsafe { |
| 1049 | #[cfg(sdmmc_v1)] | 596 | #[cfg(sdmmc_v1)] |
| @@ -1057,8 +604,8 @@ impl SdmmcInner { | |||
| 1057 | } | 604 | } |
| 1058 | 605 | ||
| 1059 | /// Sets the CLKDIV field in CLKCR. Updates clock field in self | 606 | /// Sets the CLKDIV field in CLKCR. Updates clock field in self |
| 1060 | fn clkcr_set_clkdiv(&self, freq: u32, width: BusWidth, ker_ck: Hertz, clock: &mut Hertz) -> Result<(), Error> { | 607 | fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> { |
| 1061 | let regs = self.0; | 608 | let regs = T::regs(); |
| 1062 | 609 | ||
| 1063 | let width_u32 = match width { | 610 | let width_u32 = match width { |
| 1064 | BusWidth::One => 1u32, | 611 | BusWidth::One => 1u32, |
| @@ -1067,18 +614,19 @@ impl SdmmcInner { | |||
| 1067 | _ => panic!("Invalid Bus Width"), | 614 | _ => panic!("Invalid Bus Width"), |
| 1068 | }; | 615 | }; |
| 1069 | 616 | ||
| 617 | let ker_ck = T::kernel_clk(); | ||
| 1070 | let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; | 618 | let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; |
| 1071 | 619 | ||
| 1072 | // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 | 620 | // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 |
| 1073 | // Section 55.5.8 | 621 | // Section 55.5.8 |
| 1074 | let sdmmc_bus_bandwidth = new_clock.0 * width_u32; | 622 | let sdmmc_bus_bandwidth = new_clock.0 * width_u32; |
| 1075 | assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); | 623 | assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); |
| 1076 | *clock = new_clock; | 624 | self.clock = new_clock; |
| 1077 | 625 | ||
| 1078 | // NOTE(unsafe) We have exclusive access to the regblock | 626 | // NOTE(unsafe) We have exclusive access to the regblock |
| 1079 | unsafe { | 627 | unsafe { |
| 1080 | // CPSMACT and DPSMACT must be 0 to set CLKDIV | 628 | // CPSMACT and DPSMACT must be 0 to set CLKDIV |
| 1081 | self.wait_idle(); | 629 | Self::wait_idle(); |
| 1082 | regs.clkcr().modify(|w| { | 630 | regs.clkcr().modify(|w| { |
| 1083 | w.set_clkdiv(clkdiv); | 631 | w.set_clkdiv(clkdiv); |
| 1084 | #[cfg(sdmmc_v1)] | 632 | #[cfg(sdmmc_v1)] |
| @@ -1094,13 +642,7 @@ impl SdmmcInner { | |||
| 1094 | /// Attempt to set a new signalling mode. The selected | 642 | /// Attempt to set a new signalling mode. The selected |
| 1095 | /// signalling mode is returned. Expects the current clock | 643 | /// signalling mode is returned. Expects the current clock |
| 1096 | /// frequency to be > 12.5MHz. | 644 | /// frequency to be > 12.5MHz. |
| 1097 | async fn switch_signalling_mode<T: Instance, Dma: SdmmcDma<T>>( | 645 | async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> { |
| 1098 | &self, | ||
| 1099 | signalling: Signalling, | ||
| 1100 | waker_reg: &AtomicWaker, | ||
| 1101 | data_transfer_timeout: u32, | ||
| 1102 | dma: &mut Dma, | ||
| 1103 | ) -> Result<Signalling, Error> { | ||
| 1104 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not | 646 | // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not |
| 1105 | // necessary" | 647 | // necessary" |
| 1106 | 648 | ||
| @@ -1117,17 +659,17 @@ impl SdmmcInner { | |||
| 1117 | let mut status = [0u32; 16]; | 659 | let mut status = [0u32; 16]; |
| 1118 | 660 | ||
| 1119 | // Arm `OnDrop` after the buffer, so it will be dropped first | 661 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 1120 | let regs = self.0; | 662 | let regs = T::regs(); |
| 1121 | let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); | 663 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); |
| 1122 | 664 | ||
| 1123 | unsafe { | 665 | unsafe { |
| 1124 | self.prepare_datapath_read(&mut status, 64, 6, data_transfer_timeout, dma); | 666 | self.prepare_datapath_read(&mut status, 64, 6); |
| 1125 | self.data_interrupts(true); | 667 | Self::data_interrupts(true); |
| 1126 | } | 668 | } |
| 1127 | self.cmd(Cmd::cmd6(set_function), true)?; // CMD6 | 669 | self.cmd(Cmd::cmd6(set_function), true)?; // CMD6 |
| 1128 | 670 | ||
| 1129 | let res = poll_fn(|cx| { | 671 | let res = poll_fn(|cx| { |
| 1130 | waker_reg.register(cx.waker()); | 672 | T::state().register(cx.waker()); |
| 1131 | let status = unsafe { regs.star().read() }; | 673 | let status = unsafe { regs.star().read() }; |
| 1132 | 674 | ||
| 1133 | if status.dcrcfail() { | 675 | if status.dcrcfail() { |
| @@ -1140,7 +682,7 @@ impl SdmmcInner { | |||
| 1140 | Poll::Pending | 682 | Poll::Pending |
| 1141 | }) | 683 | }) |
| 1142 | .await; | 684 | .await; |
| 1143 | self.clear_interrupt_flags(); | 685 | Self::clear_interrupt_flags(); |
| 1144 | 686 | ||
| 1145 | // Host is allowed to use the new functions at least 8 | 687 | // Host is allowed to use the new functions at least 8 |
| 1146 | // clocks after the end of the switch command | 688 | // clocks after the end of the switch command |
| @@ -1153,7 +695,7 @@ impl SdmmcInner { | |||
| 1153 | match res { | 695 | match res { |
| 1154 | Ok(_) => { | 696 | Ok(_) => { |
| 1155 | on_drop.defuse(); | 697 | on_drop.defuse(); |
| 1156 | self.stop_datapath(); | 698 | Self::stop_datapath(); |
| 1157 | 699 | ||
| 1158 | // Function Selection of Function Group 1 | 700 | // Function Selection of Function Group 1 |
| 1159 | let selection = (u32::from_be(status[4]) >> 24) & 0xF; | 701 | let selection = (u32::from_be(status[4]) >> 24) & 0xF; |
| @@ -1173,7 +715,7 @@ impl SdmmcInner { | |||
| 1173 | 715 | ||
| 1174 | /// Query the card status (CMD13, returns R1) | 716 | /// Query the card status (CMD13, returns R1) |
| 1175 | fn read_status(&self, card: &Card) -> Result<CardStatus, Error> { | 717 | fn read_status(&self, card: &Card) -> Result<CardStatus, Error> { |
| 1176 | let regs = self.0; | 718 | let regs = T::regs(); |
| 1177 | let rca = card.rca; | 719 | let rca = card.rca; |
| 1178 | 720 | ||
| 1179 | self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13 | 721 | self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13 |
| @@ -1184,31 +726,27 @@ impl SdmmcInner { | |||
| 1184 | } | 726 | } |
| 1185 | 727 | ||
| 1186 | /// Reads the SD Status (ACMD13) | 728 | /// Reads the SD Status (ACMD13) |
| 1187 | async fn read_sd_status<T: Instance, Dma: SdmmcDma<T>>( | 729 | async fn read_sd_status(&mut self) -> Result<(), Error> { |
| 1188 | &self, | 730 | let card = self.card.as_mut().ok_or(Error::NoCard)?; |
| 1189 | card: &mut Card, | ||
| 1190 | waker_reg: &AtomicWaker, | ||
| 1191 | data_transfer_timeout: u32, | ||
| 1192 | dma: &mut Dma, | ||
| 1193 | ) -> Result<(), Error> { | ||
| 1194 | let rca = card.rca; | 731 | let rca = card.rca; |
| 732 | |||
| 1195 | self.cmd(Cmd::set_block_length(64), false)?; // CMD16 | 733 | self.cmd(Cmd::set_block_length(64), false)?; // CMD16 |
| 1196 | self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP | 734 | self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP |
| 1197 | 735 | ||
| 1198 | let mut status = [0u32; 16]; | 736 | let mut status = [0u32; 16]; |
| 1199 | 737 | ||
| 1200 | // Arm `OnDrop` after the buffer, so it will be dropped first | 738 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 1201 | let regs = self.0; | 739 | let regs = T::regs(); |
| 1202 | let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); | 740 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); |
| 1203 | 741 | ||
| 1204 | unsafe { | 742 | unsafe { |
| 1205 | self.prepare_datapath_read(&mut status, 64, 6, data_transfer_timeout, dma); | 743 | self.prepare_datapath_read(&mut status, 64, 6); |
| 1206 | self.data_interrupts(true); | 744 | Self::data_interrupts(true); |
| 1207 | } | 745 | } |
| 1208 | self.cmd(Cmd::card_status(0), true)?; | 746 | self.cmd(Cmd::card_status(0), true)?; |
| 1209 | 747 | ||
| 1210 | let res = poll_fn(|cx| { | 748 | let res = poll_fn(|cx| { |
| 1211 | waker_reg.register(cx.waker()); | 749 | T::state().register(cx.waker()); |
| 1212 | let status = unsafe { regs.star().read() }; | 750 | let status = unsafe { regs.star().read() }; |
| 1213 | 751 | ||
| 1214 | if status.dcrcfail() { | 752 | if status.dcrcfail() { |
| @@ -1221,16 +759,16 @@ impl SdmmcInner { | |||
| 1221 | Poll::Pending | 759 | Poll::Pending |
| 1222 | }) | 760 | }) |
| 1223 | .await; | 761 | .await; |
| 1224 | self.clear_interrupt_flags(); | 762 | Self::clear_interrupt_flags(); |
| 1225 | 763 | ||
| 1226 | if res.is_ok() { | 764 | if res.is_ok() { |
| 1227 | on_drop.defuse(); | 765 | on_drop.defuse(); |
| 1228 | self.stop_datapath(); | 766 | Self::stop_datapath(); |
| 1229 | 767 | ||
| 1230 | for byte in status.iter_mut() { | 768 | for byte in status.iter_mut() { |
| 1231 | *byte = u32::from_be(*byte); | 769 | *byte = u32::from_be(*byte); |
| 1232 | } | 770 | } |
| 1233 | card.status = status.into(); | 771 | self.card.as_mut().unwrap().status = status.into(); |
| 1234 | } | 772 | } |
| 1235 | res | 773 | res |
| 1236 | } | 774 | } |
| @@ -1252,8 +790,8 @@ impl SdmmcInner { | |||
| 1252 | 790 | ||
| 1253 | /// Clear flags in interrupt clear register | 791 | /// Clear flags in interrupt clear register |
| 1254 | #[inline(always)] | 792 | #[inline(always)] |
| 1255 | fn clear_interrupt_flags(&self) { | 793 | fn clear_interrupt_flags() { |
| 1256 | let regs = self.0; | 794 | let regs = T::regs(); |
| 1257 | // NOTE(unsafe) Atomic write | 795 | // NOTE(unsafe) Atomic write |
| 1258 | unsafe { | 796 | unsafe { |
| 1259 | regs.icr().write(|w| { | 797 | regs.icr().write(|w| { |
| @@ -1287,8 +825,8 @@ impl SdmmcInner { | |||
| 1287 | 825 | ||
| 1288 | /// Enables the interrupts for data transfer | 826 | /// Enables the interrupts for data transfer |
| 1289 | #[inline(always)] | 827 | #[inline(always)] |
| 1290 | fn data_interrupts(&self, enable: bool) { | 828 | fn data_interrupts(enable: bool) { |
| 1291 | let regs = self.0; | 829 | let regs = T::regs(); |
| 1292 | // NOTE(unsafe) Atomic write | 830 | // NOTE(unsafe) Atomic write |
| 1293 | unsafe { | 831 | unsafe { |
| 1294 | regs.maskr().write(|w| { | 832 | regs.maskr().write(|w| { |
| @@ -1302,13 +840,7 @@ impl SdmmcInner { | |||
| 1302 | } | 840 | } |
| 1303 | } | 841 | } |
| 1304 | 842 | ||
| 1305 | async fn get_scr<T: Instance, Dma: SdmmcDma<T>>( | 843 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { |
| 1306 | &self, | ||
| 1307 | card: &mut Card, | ||
| 1308 | waker_reg: &AtomicWaker, | ||
| 1309 | data_transfer_timeout: u32, | ||
| 1310 | dma: &mut Dma, | ||
| 1311 | ) -> Result<(), Error> { | ||
| 1312 | // Read the the 64-bit SCR register | 844 | // Read the the 64-bit SCR register |
| 1313 | self.cmd(Cmd::set_block_length(8), false)?; // CMD16 | 845 | self.cmd(Cmd::set_block_length(8), false)?; // CMD16 |
| 1314 | self.cmd(Cmd::app_cmd(card.rca << 16), false)?; | 846 | self.cmd(Cmd::app_cmd(card.rca << 16), false)?; |
| @@ -1316,17 +848,17 @@ impl SdmmcInner { | |||
| 1316 | let mut scr = [0u32; 2]; | 848 | let mut scr = [0u32; 2]; |
| 1317 | 849 | ||
| 1318 | // Arm `OnDrop` after the buffer, so it will be dropped first | 850 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 1319 | let regs = self.0; | 851 | let regs = T::regs(); |
| 1320 | let on_drop = OnDrop::new(move || unsafe { self.on_drop() }); | 852 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); |
| 1321 | 853 | ||
| 1322 | unsafe { | 854 | unsafe { |
| 1323 | self.prepare_datapath_read(&mut scr[..], 8, 3, data_transfer_timeout, dma); | 855 | self.prepare_datapath_read(&mut scr[..], 8, 3); |
| 1324 | self.data_interrupts(true); | 856 | Self::data_interrupts(true); |
| 1325 | } | 857 | } |
| 1326 | self.cmd(Cmd::cmd51(), true)?; | 858 | self.cmd(Cmd::cmd51(), true)?; |
| 1327 | 859 | ||
| 1328 | let res = poll_fn(|cx| { | 860 | let res = poll_fn(|cx| { |
| 1329 | waker_reg.register(cx.waker()); | 861 | T::state().register(cx.waker()); |
| 1330 | let status = unsafe { regs.star().read() }; | 862 | let status = unsafe { regs.star().read() }; |
| 1331 | 863 | ||
| 1332 | if status.dcrcfail() { | 864 | if status.dcrcfail() { |
| @@ -1339,11 +871,11 @@ impl SdmmcInner { | |||
| 1339 | Poll::Pending | 871 | Poll::Pending |
| 1340 | }) | 872 | }) |
| 1341 | .await; | 873 | .await; |
| 1342 | self.clear_interrupt_flags(); | 874 | Self::clear_interrupt_flags(); |
| 1343 | 875 | ||
| 1344 | if res.is_ok() { | 876 | if res.is_ok() { |
| 1345 | on_drop.defuse(); | 877 | on_drop.defuse(); |
| 1346 | self.stop_datapath(); | 878 | Self::stop_datapath(); |
| 1347 | 879 | ||
| 1348 | unsafe { | 880 | unsafe { |
| 1349 | let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]); | 881 | let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]); |
| @@ -1356,13 +888,13 @@ impl SdmmcInner { | |||
| 1356 | /// Send command to card | 888 | /// Send command to card |
| 1357 | #[allow(unused_variables)] | 889 | #[allow(unused_variables)] |
| 1358 | fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> { | 890 | fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> { |
| 1359 | let regs = self.0; | 891 | let regs = T::regs(); |
| 1360 | 892 | ||
| 1361 | self.clear_interrupt_flags(); | 893 | Self::clear_interrupt_flags(); |
| 1362 | // NOTE(safety) Atomic operations | 894 | // NOTE(safety) Atomic operations |
| 1363 | unsafe { | 895 | unsafe { |
| 1364 | // CP state machine must be idle | 896 | // CP state machine must be idle |
| 1365 | while self.cmd_active() {} | 897 | while Self::cmd_active() {} |
| 1366 | 898 | ||
| 1367 | // Command arg | 899 | // Command arg |
| 1368 | regs.argr().write(|w| w.set_cmdarg(cmd.arg)); | 900 | regs.argr().write(|w| w.set_cmdarg(cmd.arg)); |
| @@ -1411,13 +943,13 @@ impl SdmmcInner { | |||
| 1411 | /// # Safety | 943 | /// # Safety |
| 1412 | /// | 944 | /// |
| 1413 | /// Ensure that `regs` has exclusive access to the regblocks | 945 | /// Ensure that `regs` has exclusive access to the regblocks |
| 1414 | unsafe fn on_drop(&self) { | 946 | unsafe fn on_drop() { |
| 1415 | let regs = self.0; | 947 | let regs = T::regs(); |
| 1416 | if self.data_active() { | 948 | if Self::data_active() { |
| 1417 | self.clear_interrupt_flags(); | 949 | Self::clear_interrupt_flags(); |
| 1418 | // Send abort | 950 | // Send abort |
| 1419 | // CP state machine must be idle | 951 | // CP state machine must be idle |
| 1420 | while self.cmd_active() {} | 952 | while Self::cmd_active() {} |
| 1421 | 953 | ||
| 1422 | // Command arg | 954 | // Command arg |
| 1423 | regs.argr().write(|w| w.set_cmdarg(0)); | 955 | regs.argr().write(|w| w.set_cmdarg(0)); |
| @@ -1437,11 +969,320 @@ impl SdmmcInner { | |||
| 1437 | }); | 969 | }); |
| 1438 | 970 | ||
| 1439 | // Wait for the abort | 971 | // Wait for the abort |
| 1440 | while self.data_active() {} | 972 | while Self::data_active() {} |
| 1441 | } | 973 | } |
| 1442 | self.data_interrupts(false); | 974 | Self::data_interrupts(false); |
| 1443 | self.clear_interrupt_flags(); | 975 | Self::clear_interrupt_flags(); |
| 1444 | self.stop_datapath(); | 976 | Self::stop_datapath(); |
| 977 | } | ||
| 978 | |||
| 979 | /// Initializes card (if present) and sets the bus at the | ||
| 980 | /// specified frequency. | ||
| 981 | pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { | ||
| 982 | let regs = T::regs(); | ||
| 983 | let ker_ck = T::kernel_clk(); | ||
| 984 | |||
| 985 | let bus_width = match self.d3.is_some() { | ||
| 986 | true => BusWidth::Four, | ||
| 987 | false => BusWidth::One, | ||
| 988 | }; | ||
| 989 | |||
| 990 | // NOTE(unsafe) We have exclusive access to the peripheral | ||
| 991 | unsafe { | ||
| 992 | // While the SD/SDIO card or eMMC is in identification mode, | ||
| 993 | // the SDMMC_CK frequency must be no more than 400 kHz. | ||
| 994 | let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); | ||
| 995 | self.clock = init_clock; | ||
| 996 | |||
| 997 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 998 | Self::wait_idle(); | ||
| 999 | |||
| 1000 | regs.clkcr().modify(|w| { | ||
| 1001 | w.set_widbus(0); | ||
| 1002 | w.set_clkdiv(clkdiv); | ||
| 1003 | #[cfg(sdmmc_v1)] | ||
| 1004 | w.set_bypass(_bypass); | ||
| 1005 | }); | ||
| 1006 | |||
| 1007 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | ||
| 1008 | self.cmd(Cmd::idle(), false)?; | ||
| 1009 | |||
| 1010 | // Check if cards supports CMD8 (with pattern) | ||
| 1011 | self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; | ||
| 1012 | let r1 = regs.respr(0).read().cardstatus(); | ||
| 1013 | |||
| 1014 | let mut card = if r1 == 0x1AA { | ||
| 1015 | // Card echoed back the pattern. Must be at least v2 | ||
| 1016 | Card::default() | ||
| 1017 | } else { | ||
| 1018 | return Err(Error::UnsupportedCardVersion); | ||
| 1019 | }; | ||
| 1020 | |||
| 1021 | let ocr = loop { | ||
| 1022 | // Signal that next command is a app command | ||
| 1023 | self.cmd(Cmd::app_cmd(0), false)?; // CMD55 | ||
| 1024 | |||
| 1025 | let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 | ||
| 1026 | | CmdAppOper::HIGH_CAPACITY as u32 | ||
| 1027 | | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; | ||
| 1028 | |||
| 1029 | // Initialize card | ||
| 1030 | match self.cmd(Cmd::app_op_cmd(arg), false) { | ||
| 1031 | // ACMD41 | ||
| 1032 | Ok(_) => (), | ||
| 1033 | Err(Error::Crc) => (), | ||
| 1034 | Err(err) => return Err(err), | ||
| 1035 | } | ||
| 1036 | let ocr: OCR = regs.respr(0).read().cardstatus().into(); | ||
| 1037 | if !ocr.is_busy() { | ||
| 1038 | // Power up done | ||
| 1039 | break ocr; | ||
| 1040 | } | ||
| 1041 | }; | ||
| 1042 | |||
| 1043 | if ocr.high_capacity() { | ||
| 1044 | // Card is SDHC or SDXC or SDUC | ||
| 1045 | card.card_type = CardCapacity::SDHC; | ||
| 1046 | } else { | ||
| 1047 | card.card_type = CardCapacity::SDSC; | ||
| 1048 | } | ||
| 1049 | card.ocr = ocr; | ||
| 1050 | |||
| 1051 | self.cmd(Cmd::all_send_cid(), false)?; // CMD2 | ||
| 1052 | let cid0 = regs.respr(0).read().cardstatus() as u128; | ||
| 1053 | let cid1 = regs.respr(1).read().cardstatus() as u128; | ||
| 1054 | let cid2 = regs.respr(2).read().cardstatus() as u128; | ||
| 1055 | let cid3 = regs.respr(3).read().cardstatus() as u128; | ||
| 1056 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | ||
| 1057 | card.cid = cid.into(); | ||
| 1058 | |||
| 1059 | self.cmd(Cmd::send_rel_addr(), false)?; | ||
| 1060 | card.rca = regs.respr(0).read().cardstatus() >> 16; | ||
| 1061 | |||
| 1062 | self.cmd(Cmd::send_csd(card.rca << 16), false)?; | ||
| 1063 | let csd0 = regs.respr(0).read().cardstatus() as u128; | ||
| 1064 | let csd1 = regs.respr(1).read().cardstatus() as u128; | ||
| 1065 | let csd2 = regs.respr(2).read().cardstatus() as u128; | ||
| 1066 | let csd3 = regs.respr(3).read().cardstatus() as u128; | ||
| 1067 | let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); | ||
| 1068 | card.csd = csd.into(); | ||
| 1069 | |||
| 1070 | self.select_card(Some(&card))?; | ||
| 1071 | |||
| 1072 | self.get_scr(&mut card).await?; | ||
| 1073 | |||
| 1074 | // Set bus width | ||
| 1075 | let (width, acmd_arg) = match bus_width { | ||
| 1076 | BusWidth::Eight => unimplemented!(), | ||
| 1077 | BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), | ||
| 1078 | _ => (BusWidth::One, 0), | ||
| 1079 | }; | ||
| 1080 | self.cmd(Cmd::app_cmd(card.rca << 16), false)?; | ||
| 1081 | self.cmd(Cmd::cmd6(acmd_arg), false)?; | ||
| 1082 | |||
| 1083 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 1084 | Self::wait_idle(); | ||
| 1085 | |||
| 1086 | regs.clkcr().modify(|w| { | ||
| 1087 | w.set_widbus(match width { | ||
| 1088 | BusWidth::One => 0, | ||
| 1089 | BusWidth::Four => 1, | ||
| 1090 | BusWidth::Eight => 2, | ||
| 1091 | _ => panic!("Invalid Bus Width"), | ||
| 1092 | }) | ||
| 1093 | }); | ||
| 1094 | |||
| 1095 | // Set Clock | ||
| 1096 | if freq.0 <= 25_000_000 { | ||
| 1097 | // Final clock frequency | ||
| 1098 | self.clkcr_set_clkdiv(freq.0, width)?; | ||
| 1099 | } else { | ||
| 1100 | // Switch to max clock for SDR12 | ||
| 1101 | self.clkcr_set_clkdiv(25_000_000, width)?; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | self.card = Some(card); | ||
| 1105 | |||
| 1106 | // Read status | ||
| 1107 | self.read_sd_status().await?; | ||
| 1108 | |||
| 1109 | if freq.0 > 25_000_000 { | ||
| 1110 | // Switch to SDR25 | ||
| 1111 | self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; | ||
| 1112 | |||
| 1113 | if self.signalling == Signalling::SDR25 { | ||
| 1114 | // Set final clock frequency | ||
| 1115 | self.clkcr_set_clkdiv(freq.0, width)?; | ||
| 1116 | |||
| 1117 | if self.read_status(&card)?.state() != CurrentState::Transfer { | ||
| 1118 | return Err(Error::SignalingSwitchFailed); | ||
| 1119 | } | ||
| 1120 | } | ||
| 1121 | } | ||
| 1122 | // Read status after signalling change | ||
| 1123 | self.read_sd_status().await?; | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | Ok(()) | ||
| 1127 | } | ||
| 1128 | |||
| 1129 | #[inline(always)] | ||
| 1130 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | ||
| 1131 | let card_capacity = self.card()?.card_type; | ||
| 1132 | |||
| 1133 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 1134 | let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; | ||
| 1135 | |||
| 1136 | // Always read 1 block of 512 bytes | ||
| 1137 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1138 | let address = match card_capacity { | ||
| 1139 | CardCapacity::SDSC => block_idx * 512, | ||
| 1140 | _ => block_idx, | ||
| 1141 | }; | ||
| 1142 | self.cmd(Cmd::set_block_length(512), false)?; // CMD16 | ||
| 1143 | |||
| 1144 | let regs = T::regs(); | ||
| 1145 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | ||
| 1146 | |||
| 1147 | unsafe { | ||
| 1148 | self.prepare_datapath_read(buffer, 512, 9); | ||
| 1149 | Self::data_interrupts(true); | ||
| 1150 | } | ||
| 1151 | self.cmd(Cmd::read_single_block(address), true)?; | ||
| 1152 | |||
| 1153 | let res = poll_fn(|cx| { | ||
| 1154 | T::state().register(cx.waker()); | ||
| 1155 | let status = unsafe { regs.star().read() }; | ||
| 1156 | |||
| 1157 | if status.dcrcfail() { | ||
| 1158 | return Poll::Ready(Err(Error::Crc)); | ||
| 1159 | } else if status.dtimeout() { | ||
| 1160 | return Poll::Ready(Err(Error::Timeout)); | ||
| 1161 | } else if status.dataend() { | ||
| 1162 | return Poll::Ready(Ok(())); | ||
| 1163 | } | ||
| 1164 | Poll::Pending | ||
| 1165 | }) | ||
| 1166 | .await; | ||
| 1167 | Self::clear_interrupt_flags(); | ||
| 1168 | |||
| 1169 | if res.is_ok() { | ||
| 1170 | on_drop.defuse(); | ||
| 1171 | Self::stop_datapath(); | ||
| 1172 | } | ||
| 1173 | res | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | ||
| 1177 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | ||
| 1178 | |||
| 1179 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 1180 | let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; | ||
| 1181 | |||
| 1182 | // Always read 1 block of 512 bytes | ||
| 1183 | // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes | ||
| 1184 | let address = match card.card_type { | ||
| 1185 | CardCapacity::SDSC => block_idx * 512, | ||
| 1186 | _ => block_idx, | ||
| 1187 | }; | ||
| 1188 | self.cmd(Cmd::set_block_length(512), false)?; // CMD16 | ||
| 1189 | |||
| 1190 | let regs = T::regs(); | ||
| 1191 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | ||
| 1192 | |||
| 1193 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | ||
| 1194 | #[cfg(sdmmc_v1)] | ||
| 1195 | self.cmd(Cmd::write_single_block(address), true)?; | ||
| 1196 | |||
| 1197 | unsafe { | ||
| 1198 | self.prepare_datapath_write(buffer as *const [u32; 128], 512, 9); | ||
| 1199 | Self::data_interrupts(true); | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | #[cfg(sdmmc_v2)] | ||
| 1203 | self.cmd(Cmd::write_single_block(address), true)?; | ||
| 1204 | |||
| 1205 | let res = poll_fn(|cx| { | ||
| 1206 | T::state().register(cx.waker()); | ||
| 1207 | let status = unsafe { regs.star().read() }; | ||
| 1208 | |||
| 1209 | if status.dcrcfail() { | ||
| 1210 | return Poll::Ready(Err(Error::Crc)); | ||
| 1211 | } else if status.dtimeout() { | ||
| 1212 | return Poll::Ready(Err(Error::Timeout)); | ||
| 1213 | } else if status.dataend() { | ||
| 1214 | return Poll::Ready(Ok(())); | ||
| 1215 | } | ||
| 1216 | Poll::Pending | ||
| 1217 | }) | ||
| 1218 | .await; | ||
| 1219 | Self::clear_interrupt_flags(); | ||
| 1220 | |||
| 1221 | match res { | ||
| 1222 | Ok(_) => { | ||
| 1223 | on_drop.defuse(); | ||
| 1224 | Self::stop_datapath(); | ||
| 1225 | |||
| 1226 | // TODO: Make this configurable | ||
| 1227 | let mut timeout: u32 = 0x00FF_FFFF; | ||
| 1228 | |||
| 1229 | // Try to read card status (ACMD13) | ||
| 1230 | while timeout > 0 { | ||
| 1231 | match self.read_sd_status().await { | ||
| 1232 | Ok(_) => return Ok(()), | ||
| 1233 | Err(Error::Timeout) => (), // Try again | ||
| 1234 | Err(e) => return Err(e), | ||
| 1235 | } | ||
| 1236 | timeout -= 1; | ||
| 1237 | } | ||
| 1238 | Err(Error::SoftwareTimeout) | ||
| 1239 | } | ||
| 1240 | Err(e) => Err(e), | ||
| 1241 | } | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | /// Get a reference to the initialized card | ||
| 1245 | /// | ||
| 1246 | /// # Errors | ||
| 1247 | /// | ||
| 1248 | /// Returns Error::NoCard if [`init_card`](#method.init_card) | ||
| 1249 | /// has not previously succeeded | ||
| 1250 | #[inline(always)] | ||
| 1251 | pub fn card(&self) -> Result<&Card, Error> { | ||
| 1252 | self.card.as_ref().ok_or(Error::NoCard) | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | /// Get the current SDMMC bus clock | ||
| 1256 | pub fn clock(&self) -> Hertz { | ||
| 1257 | self.clock | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | #[inline(always)] | ||
| 1261 | fn on_interrupt(_: *mut ()) { | ||
| 1262 | Self::data_interrupts(false); | ||
| 1263 | T::state().wake(); | ||
| 1264 | } | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { | ||
| 1268 | fn drop(&mut self) { | ||
| 1269 | self.irq.disable(); | ||
| 1270 | unsafe { Self::on_drop() }; | ||
| 1271 | |||
| 1272 | critical_section::with(|_| unsafe { | ||
| 1273 | self.clk.set_as_disconnected(); | ||
| 1274 | self.cmd.set_as_disconnected(); | ||
| 1275 | self.d0.set_as_disconnected(); | ||
| 1276 | if let Some(x) = &mut self.d1 { | ||
| 1277 | x.set_as_disconnected(); | ||
| 1278 | } | ||
| 1279 | if let Some(x) = &mut self.d2 { | ||
| 1280 | x.set_as_disconnected(); | ||
| 1281 | } | ||
| 1282 | if let Some(x) = &mut self.d3 { | ||
| 1283 | x.set_as_disconnected(); | ||
| 1284 | } | ||
| 1285 | }); | ||
| 1445 | } | 1286 | } |
| 1446 | } | 1287 | } |
| 1447 | 1288 | ||
| @@ -1540,7 +1381,7 @@ pub(crate) mod sealed { | |||
| 1540 | pub trait Instance { | 1381 | pub trait Instance { |
| 1541 | type Interrupt: Interrupt; | 1382 | type Interrupt: Interrupt; |
| 1542 | 1383 | ||
| 1543 | fn inner() -> SdmmcInner; | 1384 | fn regs() -> RegBlock; |
| 1544 | fn state() -> &'static AtomicWaker; | 1385 | fn state() -> &'static AtomicWaker; |
| 1545 | fn kernel_clk() -> Hertz; | 1386 | fn kernel_clk() -> Hertz; |
| 1546 | } | 1387 | } |
| @@ -1629,9 +1470,8 @@ foreach_peripheral!( | |||
| 1629 | impl sealed::Instance for peripherals::$inst { | 1470 | impl sealed::Instance for peripherals::$inst { |
| 1630 | type Interrupt = crate::interrupt::$inst; | 1471 | type Interrupt = crate::interrupt::$inst; |
| 1631 | 1472 | ||
| 1632 | fn inner() -> SdmmcInner { | 1473 | fn regs() -> RegBlock { |
| 1633 | const INNER: SdmmcInner = SdmmcInner(crate::pac::$inst); | 1474 | crate::pac::$inst |
| 1634 | INNER | ||
| 1635 | } | 1475 | } |
| 1636 | 1476 | ||
| 1637 | fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker { | 1477 | fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker { |
