1use core::{
32 cell::UnsafeCell,
33 future::poll_fn,
34 marker::PhantomData,
35 pin::Pin,
36 sync::atomic::Ordering,
37 task::{Context, Poll},
38};
39
40use embassy_futures::yield_now;
41use embassy_sync::{mutex::MutexGuard, waitqueue::WakerRegistration};
42use esp_sync::{NonReentrantMutex, RawMutex};
43use portable_atomic::AtomicBool;
44use procmacros::{BuilderLite, handler};
45use sdio::{self as _, MmcError};
46
47#[cfg(sdmmc_has_gpio_matrix)]
48use crate::gpio::{OutputSignal, PinGuard, Pull};
49use crate::{
50 Async,
51 Blocking,
52 DriverMode,
53 asynch::AtomicWaker,
54 dma::{
55 DmaBufError,
56 aligned::{DmaAlignedMut, DmaAlignedRef, InternalMemory},
57 },
58 gpio::{
59 InputSignal,
60 OutputConfig,
61 interconnect::{self, PeripheralInput, PeripheralOutput},
62 },
63 peripherals::{Interrupt, SDHOST},
64 private::DropGuard,
65 system::{Peripheral, PeripheralGuard},
66 time::{Duration, Instant},
67};
68
69#[cfg_attr(esp32, path = "esp32.rs")]
70#[cfg_attr(esp32s3, path = "esp32s3.rs")]
71#[cfg_attr(esp32p4, path = "esp32p4.rs")]
72#[cfg_attr(esp32s31, path = "esp32s31.rs")]
73mod chip_specific;
74
75#[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
76mod bounce;
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
80#[cfg_attr(feature = "defmt", derive(defmt::Format))]
81pub enum ClockSource {
82 #[cfg(not(esp32s31))]
84 Pll160m,
85 #[cfg(esp32s31)]
87 Mpll,
88 #[cfg(not(esp32p4))]
90 Xtal,
91}
92
93#[cfg(sdmmc_delay_phase_num_is_set)]
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
96#[cfg_attr(feature = "defmt", derive(defmt::Format))]
97pub enum DelayPhase {
98 #[default]
100 _0,
101 _1,
103 _2,
105 _3,
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub enum BusWidth {
113 #[default]
115 Bit1,
116 Bit4,
118 Bit8,
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, BuilderLite)]
127#[cfg_attr(feature = "defmt", derive(defmt::Format))]
128#[non_exhaustive]
129pub struct Config {
130 clock_source: ClockSource,
132
133 module_div: u8,
135}
136
137impl Default for Config {
138 fn default() -> Self {
139 Self::const_default()
140 }
141}
142
143impl Config {
144 pub(crate) const fn const_default() -> Self {
145 cfg_select! {
146 esp32s31 => Self {
147 clock_source: ClockSource::Mpll,
148 module_div: 8,
149 },
150 _ => Self {
151 clock_source: ClockSource::Pll160m,
152 module_div: 2,
153 },
154 }
155 }
156
157 fn validate(&self) -> Result<(), ConfigError> {
159 if !(2..=16).contains(&self.module_div) {
160 return Err(ConfigError::InvalidModuleDivider);
161 }
162 Ok(())
163 }
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, BuilderLite)]
168#[cfg_attr(feature = "defmt", derive(defmt::Format))]
169#[non_exhaustive]
170pub struct SlotConfig {
171 #[cfg(sdmmc_delay_phase_num_is_set)]
173 input_delay_phase: DelayPhase,
174
175 wp_active_high: bool,
177}
178
179#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
181#[cfg_attr(feature = "defmt", derive(defmt::Format))]
182pub enum ResponseLen {
183 None,
185 Short,
187 Long,
189}
190
191#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
193#[cfg_attr(feature = "defmt", derive(defmt::Format))]
194pub struct CommandFlags {
195 pub wait_complete: bool,
197 pub stop_abort: bool,
199 pub busy: bool,
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
205#[cfg_attr(feature = "defmt", derive(defmt::Format))]
206#[non_exhaustive]
207#[expect(clippy::enum_variant_names)]
208pub enum Error {
209 Timeout,
211 ResponseCrc,
213 DataCrc,
215 ResponseTimeout,
217 DataTimeout,
219 FifoOverrun,
221 StartBitError,
223 HardwareLocked,
225 ResponseError,
227 DmaError,
229 NoCard,
231 BufferNotDmaCapable,
233 Unsupported,
235}
236
237impl core::error::Error for Error {}
238
239impl core::fmt::Display for Error {
240 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
241 match self {
242 Error::Timeout => write!(f, "A hardware operation did not complete in time"),
243 Error::ResponseCrc => write!(f, "Response CRC check failed"),
244 Error::DataCrc => write!(f, "Data CRC or end-bit error"),
245 Error::ResponseTimeout => write!(f, "Card did not respond to the command"),
246 Error::DataTimeout => write!(f, "Data transfer timed out"),
247 Error::FifoOverrun => write!(f, "FIFO under- or overrun during a transfer"),
248 Error::StartBitError => write!(f, "Data start-bit error"),
249 Error::HardwareLocked => write!(f, "Command could not be loaded (hardware locked)"),
250 Error::ResponseError => write!(f, "Controller flagged a response error"),
251 Error::DmaError => write!(f, "IDMAC transfer error"),
252 Error::NoCard => write!(f, "No card present in the slot"),
253 Error::BufferNotDmaCapable => {
254 write!(f, "Buffer lies in a region the IDMAC cannot reach")
255 }
256 Error::Unsupported => write!(f, "Operation not supported"),
257 }
258 }
259}
260
261#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
263#[cfg_attr(feature = "defmt", derive(defmt::Format))]
264#[non_exhaustive]
265pub enum ConfigError {
266 InvalidModuleDivider,
268 SlotInUse,
270 MissingClkOrCmd,
272 NoData0,
274}
275
276impl core::error::Error for ConfigError {}
277
278impl core::fmt::Display for ConfigError {
279 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
280 match self {
281 ConfigError::InvalidModuleDivider => {
282 write!(f, "Module-clock divider is outside 2..=16")
283 }
284 ConfigError::SlotInUse => write!(f, "The slot is already in use"),
285 ConfigError::MissingClkOrCmd => write!(f, "The clock or command pin was not connected"),
286 ConfigError::NoData0 => write!(f, "Data line 0 was not connected"),
287 }
288 }
289}
290
291#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
294#[cfg_attr(feature = "defmt", derive(defmt::Format))]
295#[non_exhaustive]
296pub enum BlockingError {
297 Busy,
299 Op(Error),
301}
302
303impl core::error::Error for BlockingError {}
304
305impl core::fmt::Display for BlockingError {
306 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
307 match self {
308 BlockingError::Busy => write!(f, "The shared SDMMC engine is busy"),
309 BlockingError::Op(e) => write!(f, "{e}"),
310 }
311 }
312}
313
314impl From<Error> for BlockingError {
315 fn from(error: Error) -> Self {
316 BlockingError::Op(error)
317 }
318}
319
320impl From<BlockingError> for MmcError {
321 fn from(error: BlockingError) -> Self {
322 match error {
323 BlockingError::Busy => MmcError::Other,
324 BlockingError::Op(e) => e.into(),
325 }
326 }
327}
328
329impl From<Error> for MmcError {
330 fn from(error: Error) -> Self {
331 warn!("{:?}", error);
332 match error {
333 Error::ResponseTimeout | Error::DataTimeout | Error::Timeout | Error::NoCard => {
334 MmcError::Timeout
335 }
336 Error::ResponseCrc | Error::DataCrc | Error::StartBitError => MmcError::Crc,
337 Error::FifoOverrun
338 | Error::DmaError
339 | Error::ResponseError
340 | Error::BufferNotDmaCapable => MmcError::Io,
341 Error::HardwareLocked => MmcError::Other,
342 Error::Unsupported => MmcError::Unsupported,
343 }
344 }
345}
346
347impl From<DmaBufError> for MmcError {
348 fn from(error: DmaBufError) -> Self {
349 warn!("{:?}", error);
350 match error {
351 DmaBufError::InvalidAlignment(_) => MmcError::Other,
352 _ => MmcError::Io,
353 }
354 }
355}
356
357const POLL_LIMIT: u32 = 1_000_000;
359
360const EVT_RESP_ERR: u32 = 1 << 1;
362const EVT_CMD_DONE: u32 = 1 << 2;
363const EVT_DATA_OVER: u32 = 1 << 3;
364const EVT_RCRC: u32 = 1 << 6;
365const EVT_DCRC: u32 = 1 << 7;
366const EVT_RTO: u32 = 1 << 8;
367const EVT_DTO: u32 = 1 << 9;
368const EVT_HTO: u32 = 1 << 10;
369const EVT_FRUN: u32 = 1 << 11;
370const EVT_HLE: u32 = 1 << 12;
371const EVT_SBE: u32 = 1 << 13;
372const EVT_ACD: u32 = 1 << 14;
373const EVT_EBE: u32 = 1 << 15;
374
375const CTRL_DMA_ENABLE: u32 = 1 << 5;
377const CTRL_USE_INTERNAL_DMA: u32 = 1 << 25;
378
379const RING_LEN: usize = 4;
381const DMA_MAX_BUF_LEN: usize = 4096;
383
384const DESC_LAST: u32 = 1 << 2;
386const DESC_FIRST: u32 = 1 << 3;
387const DESC_CHAINED: u32 = 1 << 4;
388const DESC_OWN: u32 = 1 << 31;
389
390#[repr(C, align(4))]
392#[derive(Clone, Copy)]
393struct Desc {
394 flags: u32,
395 sizes: u32,
396 buf1: u32,
397 next: u32,
398}
399
400impl Desc {
401 const ZERO: Self = Desc {
402 flags: 0,
403 sizes: 0,
404 buf1: 0,
405 next: 0,
406 };
407}
408
409type Seg = (u32, usize);
411
412#[derive(Clone, Copy)]
420struct Transfer {
421 segs: [Seg; 3],
422 seg: usize,
424 next_desc: usize,
425}
426
427impl Transfer {
428 fn single(ptr: u32, len: usize) -> Self {
430 Transfer {
431 segs: [(ptr, len), (0, 0), (0, 0)],
432 seg: 0,
433 next_desc: 0,
434 }
435 }
436
437 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
440 fn split(head: Seg, middle: Seg, tail: Seg) -> Self {
441 Transfer {
442 segs: [head, middle, tail],
443 seg: 0,
444 next_desc: 0,
445 }
446 }
447
448 fn remaining(&self) -> usize {
451 self.segs.iter().map(|(_, len)| *len).sum()
452 }
453}
454
455struct DescRing(UnsafeCell<InternalMemory<[Desc; RING_LEN]>>);
457unsafe impl Sync for DescRing {}
459
460static DESC_RING: DescRing = DescRing(UnsafeCell::new(InternalMemory::new([Desc::ZERO; RING_LEN])));
461
462fn ring() -> DmaAlignedMut<'static, [Desc; RING_LEN]> {
463 unsafe { &mut *DESC_RING.0.get() }.get_mut()
464}
465
466struct EngineSession {
468 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
469 bounce: bounce::Bounce,
470 active_slot: Option<SlotId>,
471}
472
473impl EngineSession {
474 const INIT: Self = EngineSession {
475 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
476 bounce: bounce::Bounce::INIT,
477 active_slot: None,
478 };
479
480 fn select_and_apply(&mut self, slot: SlotId) -> Result<(), Error> {
481 let wait = SETTINGS.with(|s| {
482 let idx = slot.index() as usize;
483 let cached = &mut s.slots[idx];
484 if self.active_slot == Some(slot) && !cached.dirty {
485 return Ok(false);
486 }
487 self.program_slot_hw(slot, cached, s.module)?;
488 cached.dirty = false;
489 self.active_slot = Some(slot);
490 Ok(true)
491 })?;
492
493 if wait {
494 crate::rom::ets_delay_us(10);
495 }
496 Ok(())
497 }
498
499 fn program_slot_hw(
500 &mut self,
501 slot: SlotId,
502 cached: &SlotSettings,
503 module: Config,
504 ) -> Result<(), Error> {
505 self.set_card_width(slot, cached.width);
506 let card_div =
507 freq_to_card_div(module_hz(module.clock_source, module.module_div), cached.hz);
508 self.set_card_clock(slot, card_div)?;
509 #[cfg(sdmmc_delay_phase_num_is_set)]
510 if cached.hz > 25_000_000 {
511 chip_specific::set_input_delay_phase(cached.input_delay_phase, cached.hz);
512 }
513 Ok(())
514 }
515
516 fn set_card_width(&mut self, id: SlotId, width: BusWidth) {
517 let slot = id.index();
518 SDHOST::regs().ctype().modify(|rd, w| unsafe {
519 let mut w4 = rd.card_width4().bits() & !(1 << slot);
520 let mut w8 = rd.card_width8().bits() & !(1 << slot);
521 match width {
522 BusWidth::Bit8 => w8 |= 1 << slot,
523 BusWidth::Bit4 => w4 |= 1 << slot,
524 BusWidth::Bit1 => {}
525 }
526 w.card_width4().bits(w4);
527 w.card_width8().bits(w8)
528 });
529 }
530
531 fn set_card_clock(&mut self, id: SlotId, card_div: u8) -> Result<(), Error> {
532 let slot = id.index();
533 let r = SDHOST::regs();
534
535 r.clkena().modify(|rd, w| unsafe {
536 w.cclk_enable().bits(rd.cclk_enable().bits() & !(1 << slot))
537 });
538 self.apply_clock_update(id)?;
539
540 r.clksrc().modify(|rd, w| unsafe {
541 let mut v = rd.clksrc().bits();
542 match id {
543 SlotId::_0 => v &= !0b11,
544 SlotId::_1 => {
545 v &= !0b1100;
546 v |= 1 << 2;
547 }
548 }
549 w.clksrc().bits(v)
550 });
551 r.clkdiv().modify(|_, w| unsafe {
552 match id {
553 SlotId::_0 => w.clk_divider0().bits(card_div),
554 SlotId::_1 => w.clk_divider1().bits(card_div),
555 }
556 });
557
558 r.clkena().modify(|rd, w| unsafe {
559 w.cclk_enable().bits(rd.cclk_enable().bits() | (1 << slot));
560 w.lp_enable().bits(rd.lp_enable().bits() | (1 << slot))
561 });
562 self.apply_clock_update(id)
563 }
564
565 fn apply_clock_update(&mut self, id: SlotId) -> Result<(), Error> {
566 let r = SDHOST::regs();
567 r.cmdarg().write(|w| unsafe { w.bits(0) });
568 r.cmd().write(|w| unsafe {
569 w.update_clock_registers_only().set_bit();
570 w.wait_prvdata_complete().set_bit();
571 w.card_number().bits(id.index());
572 w.start_cmd().set_bit()
573 });
574 wait_command_accepted()
575 }
576
577 fn send_init_sequence(&mut self, slot: SlotId) -> Result<(), Error> {
578 let r = SDHOST::regs();
579 r.rintsts().write(|w| unsafe { w.bits(EVT_CMD_DONE) });
580 r.cmdarg().write(|w| unsafe { w.bits(0) });
581 r.cmd().write(|w| unsafe {
582 w.send_initialization().set_bit();
583 w.wait_prvdata_complete().set_bit();
584 w.card_number().bits(slot.index());
585 w.start_cmd().set_bit()
586 });
587 wait_command_accepted()?;
588
589 let result = poll_until(|| r.rintsts().read().bits() & EVT_CMD_DONE != 0);
590 if result.is_ok() {
591 r.rintsts().write(|w| unsafe { w.bits(EVT_CMD_DONE) });
592 }
593 result
594 }
595
596 fn send_command_blocking(
597 &mut self,
598 slot: SlotId,
599 index: u8,
600 arg: u32,
601 resp_len: ResponseLen,
602 check_crc: bool,
603 flags: CommandFlags,
604 ) -> Result<[u32; 4], Error> {
605 let r = SDHOST::regs();
606 let consume = EVT_CMD_DONE | EVT_RTO | EVT_RCRC | EVT_RESP_ERR | EVT_HLE;
607
608 r.rintsts().write(|w| unsafe { w.bits(consume) });
609
610 self.issue_command(slot, index, arg, resp_len, check_crc, flags)?;
611
612 let done = EVT_CMD_DONE | EVT_RTO | EVT_RCRC | EVT_RESP_ERR;
613 let mut sts = 0;
614 poll_until(|| {
615 sts = r.rintsts().read().bits();
616 sts & done != 0
617 })?;
618 map_rintsts(sts)?;
619
620 let resp = read_response(resp_len);
621 r.rintsts().write(|w| unsafe { w.bits(consume) });
622
623 if flags.busy {
624 wait_busy_cleared()?;
625 }
626 Ok(resp)
627 }
628
629 #[allow(clippy::too_many_arguments)]
630 fn transfer_blocking(
631 &mut self,
632 slot: SlotId,
633 index: u8,
634 arg: u32,
635 write: bool,
636 mut t: Transfer,
637 block_size: u16,
638 block_count: u32,
639 ) -> Result<[u32; 4], Error> {
640 let r = SDHOST::regs();
641
642 reset_transfer()?;
643 let total_len = t.remaining();
644 r.blksiz().write(|w| unsafe { w.bits(block_size as u32) });
645 r.bytcnt().write(|w| unsafe { w.bits(total_len as u32) });
646
647 let mut ring = ring();
648 *ring.reborrow().into_inner() = [Desc::ZERO; RING_LEN];
649 ring[0].flags |= DESC_FIRST;
650 fill_descriptors(ring.reborrow(), &mut t, RING_LEN);
651 enable_idmac(ring.as_ptr() as u32);
652 r.pldmnd().write(|w| unsafe { w.bits(1) });
653
654 let auto_stop = needs_auto_stop(index, block_count);
655 self.issue_data_command(slot, index, arg, write, auto_stop)?;
656
657 let result = run_data_phase(&mut t, ring, write, auto_stop);
658
659 disable_idmac();
660 r.rintsts().write(|w| unsafe { w.bits(0xFFFF_FFFF) });
661 r.idsts().write(|w| unsafe { w.bits(0xFFFF_FFFF) });
662
663 result?;
664 Ok(read_response(ResponseLen::Short))
665 }
666
667 fn issue_command(
668 &mut self,
669 slot: SlotId,
670 index: u8,
671 arg: u32,
672 resp_len: ResponseLen,
673 check_crc: bool,
674 flags: CommandFlags,
675 ) -> Result<(), Error> {
676 let r = SDHOST::regs();
677 r.cmdarg().write(|w| unsafe { w.bits(arg) });
678 r.cmd().write(|w| unsafe {
679 w.index().bits(index);
680 w.response_expect()
681 .bit(!matches!(resp_len, ResponseLen::None));
682 w.response_length()
683 .bit(matches!(resp_len, ResponseLen::Long));
684 w.check_response_crc().bit(check_crc);
685 w.wait_prvdata_complete().bit(flags.wait_complete);
686 w.stop_abort_cmd().bit(flags.stop_abort);
687 w.use_hole().set_bit();
688 w.card_number().bits(slot.index());
689 w.start_cmd().set_bit()
690 });
691 wait_command_accepted()
692 }
693
694 fn issue_data_command(
695 &mut self,
696 slot: SlotId,
697 index: u8,
698 arg: u32,
699 write: bool,
700 auto_stop: bool,
701 ) -> Result<(), Error> {
702 let r = SDHOST::regs();
703 r.cmdarg().write(|w| unsafe { w.bits(arg) });
704 r.cmd().write(|w| unsafe {
705 w.index().bits(index);
706 w.response_expect().set_bit();
707 w.check_response_crc().set_bit();
708 w.data_expected().set_bit();
709 w.read_write().bit(write);
710 w.send_auto_stop().bit(auto_stop);
711 w.wait_prvdata_complete().set_bit();
712 w.use_hole().set_bit();
713 w.card_number().bits(slot.index());
714 w.start_cmd().set_bit()
715 });
716 wait_command_accepted()
717 }
718
719 async fn send_command_async(
720 &mut self,
721 slot: SlotId,
722 index: u8,
723 arg: u32,
724 resp_len: ResponseLen,
725 check_crc: bool,
726 flags: CommandFlags,
727 ) -> Result<[u32; 4], Error> {
728 let r = SDHOST::regs();
729 let guard = DropGuard::new((), |()| abort_transfer());
730
731 r.rintsts().write(|w| unsafe { w.bits(INTMASK_CMD) });
732 arm_transfer(false, false, None);
733 r.intmask()
734 .write(|w| unsafe { w.bits(idle_intmask() | INTMASK_CMD) });
735
736 self.issue_command(slot, index, arg, resp_len, check_crc, flags)?;
737 wait_result().await?;
738 let resp = read_response(resp_len);
739 if flags.busy {
740 wait_busy_poll().await?;
741 }
742 guard.defuse();
743 Ok(resp)
744 }
745
746 #[allow(clippy::too_many_arguments)]
747 async fn transfer_async(
748 &mut self,
749 slot: SlotId,
750 index: u8,
751 arg: u32,
752 write: bool,
753 mut t: Transfer,
754 block_size: u16,
755 auto_stop: bool,
756 ) -> Result<[u32; 4], Error> {
757 let guard = DropGuard::new((), |()| abort_transfer());
758 let r = SDHOST::regs();
759
760 reset_transfer()?;
761 let total_len = t.remaining();
762 r.blksiz().write(|w| unsafe { w.bits(block_size as u32) });
763 r.bytcnt().write(|w| unsafe { w.bits(total_len as u32) });
764
765 let mut ring = ring();
766 *ring.reborrow().into_inner() = [Desc::ZERO; RING_LEN];
767 ring[0].flags |= DESC_FIRST;
768 fill_descriptors(ring.reborrow(), &mut t, RING_LEN);
769 enable_idmac(ring.as_ptr() as u32);
770 r.pldmnd().write(|w| unsafe { w.bits(1) });
771
772 arm_transfer(true, auto_stop, Some(t));
773 r.idinten().write(|w| unsafe { w.bits(IDINTEN_ALL) });
774 r.intmask()
775 .write(|w| unsafe { w.bits(idle_intmask() | INTMASK_DATA) });
776
777 self.issue_data_command(slot, index, arg, write, auto_stop)?;
778 wait_result().await?;
779 if write {
780 wait_busy_async().await?;
781 }
782 disable_idmac();
783 let resp = read_response(ResponseLen::Short);
784 guard.defuse();
785 Ok(resp)
786 }
787
788 async fn read_async(
789 &mut self,
790 slot: SlotId,
791 index: u8,
792 arg: u32,
793 buf: &mut [u8],
794 block_size: u16,
795 auto_stop: bool,
796 ) -> Result<[u32; 4], MmcError> {
797 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
798 if let Some(split) = bounce::Bounce::split(buf) {
799 let transfer = self
800 .bounce
801 .read_dma_setup(buf, split)
802 .map_err(MmcError::from)?;
803
804 let resp = self
805 .transfer_async(slot, index, arg, false, transfer, block_size, auto_stop)
806 .await?;
807
808 self.bounce.read_finish(buf, split);
809 return Ok(resp);
810 }
811
812 let mut dma = DmaAlignedMut::new(buf)?;
813 let ptr = dma_ptr(dma.reborrow())?;
814 let total = dma.len();
815 let resp = self
816 .transfer_async(
817 slot,
818 index,
819 arg,
820 false,
821 Transfer::single(ptr, total),
822 block_size,
823 auto_stop,
824 )
825 .await?;
826 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
827 dma.invalidate();
828 Ok(resp)
829 }
830
831 async fn write_async(
832 &mut self,
833 slot: SlotId,
834 index: u8,
835 arg: u32,
836 buf: &[u8],
837 block_size: u16,
838 auto_stop: bool,
839 ) -> Result<[u32; 4], MmcError> {
840 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
841 if let Some(split) = bounce::Bounce::split(buf) {
842 let transfer = self
843 .bounce
844 .write_dma_setup(buf, split)
845 .map_err(MmcError::from)?;
846
847 return Ok(self
848 .transfer_async(slot, index, arg, true, transfer, block_size, auto_stop)
849 .await?);
850 }
851
852 let dma = DmaAlignedRef::new(buf)?;
853
854 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
858 dma.writeback();
859
860 let total = dma.len();
861 let ptr = dma_ptr_ref(dma)?;
862 Ok(self
863 .transfer_async(
864 slot,
865 index,
866 arg,
867 true,
868 Transfer::single(ptr, total),
869 block_size,
870 auto_stop,
871 )
872 .await?)
873 }
874}
875
876const EVT_CD: u32 = 1 << 0;
878const EVT_IO_SLOT0: u32 = 1 << 16;
880const EVT_IO_SLOT1: u32 = 1 << 17;
881
882const IDSTS_FBE: u32 = 1 << 2;
884const IDSTS_DU: u32 = 1 << 4;
885
886const INTMASK_IDLE: u32 = EVT_CD;
888const INTMASK_CMD: u32 = EVT_CMD_DONE | EVT_RTO | EVT_RCRC | EVT_RESP_ERR | EVT_HLE;
890const INTMASK_DATA: u32 = INTMASK_CMD
892 | EVT_DATA_OVER
893 | EVT_DCRC
894 | EVT_DTO
895 | EVT_HTO
896 | EVT_SBE
897 | EVT_EBE
898 | EVT_FRUN
899 | EVT_ACD;
900
901const IDINTEN_ALL: u32 = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 8) | (1 << 9);
903
904struct TransferState {
906 transfer: Option<Transfer>,
907 result: Option<Result<(), Error>>,
908 expect_data: bool,
909 multiblock: bool,
910 over_seen: bool,
911 acd_seen: bool,
912 wait_busy: bool,
913 waker: WakerRegistration,
914}
915
916impl TransferState {
917 const IDLE: Self = TransferState {
918 transfer: None,
919 result: None,
920 expect_data: false,
921 multiblock: false,
922 over_seen: false,
923 acd_seen: false,
924 wait_busy: false,
925 waker: WakerRegistration::new(),
926 };
927}
928
929struct Settings {
931 module: Config,
932 slots: [SlotSettings; SLOT_COUNT],
933}
934
935impl Settings {
936 const INIT: Self = Settings {
937 module: Config::const_default(),
938 slots: [SlotSettings::INIT; SLOT_COUNT],
939 };
940
941 fn set_slot_bus(&mut self, slot: SlotId, width: BusWidth, hz: u32) -> Result<(), Error> {
942 if hz == 0 || hz > 40_000_000 {
943 return Err(Error::Unsupported);
944 }
945 let idx = slot.index() as usize;
946 self.slots[idx].hz = hz;
947 self.slots[idx].width = width;
948 self.slots[idx].dirty = true;
949 Ok(())
950 }
951}
952
953#[derive(Clone, Copy)]
954struct SlotSettings {
955 hz: u32,
956 width: BusWidth,
957 dirty: bool,
958 #[cfg(sdmmc_delay_phase_num_is_set)]
959 input_delay_phase: DelayPhase,
960}
961
962impl SlotSettings {
963 const INIT: Self = SlotSettings {
964 hz: 25_000_000,
965 width: BusWidth::Bit1,
966 dirty: true,
967 #[cfg(sdmmc_delay_phase_num_is_set)]
968 input_delay_phase: DelayPhase::_0,
969 };
970}
971
972static ENGINE: embassy_sync::mutex::Mutex<RawMutex, EngineSession> =
973 embassy_sync::mutex::Mutex::new(EngineSession::INIT);
974static SETTINGS: NonReentrantMutex<Settings> = NonReentrantMutex::new(Settings::INIT);
975static TRANSFER: NonReentrantMutex<TransferState> = NonReentrantMutex::new(TransferState::IDLE);
976
977fn with_engine_try<R>(
978 slot: SlotId,
979 f: impl FnOnce(&mut EngineSession) -> Result<R, Error>,
980) -> Result<R, BlockingError> {
981 let mut session = ENGINE.try_lock().map_err(|_| BlockingError::Busy)?;
982 session.select_and_apply(slot).map_err(BlockingError::Op)?;
983 f(&mut session).map_err(BlockingError::Op)
984}
985
986async fn lock_engine(slot: SlotId) -> Result<MutexGuard<'static, RawMutex, EngineSession>, Error> {
987 let mut guard = ENGINE.lock().await;
988 guard.select_and_apply(slot)?;
989 Ok(guard)
990}
991
992#[cfg(sdmmc_has_gpio_matrix)]
997struct SlotPins {
998 clk: PinGuard,
999 cmd: PinGuard,
1000 data: [PinGuard; 4],
1001}
1002
1003#[cfg(sdmmc_has_gpio_matrix)]
1004impl SlotPins {
1005 const fn new() -> Self {
1006 Self {
1007 clk: PinGuard::new_unconnected(),
1008 cmd: PinGuard::new_unconnected(),
1009 data: [const { PinGuard::new_unconnected() }; 4],
1010 }
1011 }
1012}
1013
1014struct SlotState {
1016 io_waker: AtomicWaker,
1017 cd_waker: AtomicWaker,
1018 io_pending: AtomicBool,
1021 #[cfg(sdmmc_has_gpio_matrix)]
1022 pins: UnsafeCell<SlotPins>,
1023}
1024
1025#[cfg(sdmmc_has_gpio_matrix)]
1028unsafe impl Sync for SlotState {}
1029
1030impl SlotState {
1031 const fn new() -> Self {
1032 Self {
1033 io_waker: AtomicWaker::new(),
1034 cd_waker: AtomicWaker::new(),
1035 io_pending: AtomicBool::new(false),
1036 #[cfg(sdmmc_has_gpio_matrix)]
1037 pins: UnsafeCell::new(SlotPins::new()),
1038 }
1039 }
1040}
1041
1042static SLOT_STATE: [SlotState; SLOT_COUNT] = [const { SlotState::new() }; SLOT_COUNT];
1043
1044#[cfg(sdmmc_has_gpio_matrix)]
1046fn slot_state(id: SlotId) -> &'static SlotState {
1047 &SLOT_STATE[id.index() as usize]
1048}
1049
1050#[cfg(sdmmc_has_gpio_matrix)]
1052fn slot_pins(id: SlotId) -> &'static mut SlotPins {
1053 unsafe { &mut *slot_state(id).pins.get() }
1054}
1055
1056struct SlotInfo {
1066 io_event: u32,
1067 #[cfg(sdmmc_has_gpio_matrix)]
1068 clk_out: Option<OutputSignal>,
1069 #[cfg(sdmmc_has_gpio_matrix)]
1070 cmd_in: Option<InputSignal>,
1071 #[cfg(sdmmc_has_gpio_matrix)]
1072 cmd_out: Option<OutputSignal>,
1073 #[cfg(sdmmc_has_gpio_matrix)]
1074 data_in: &'static [InputSignal],
1075 #[cfg(sdmmc_has_gpio_matrix)]
1076 data_out: &'static [OutputSignal],
1077 cd_in: Option<InputSignal>,
1078 wp_in: Option<InputSignal>,
1079}
1080
1081macro_rules! opt_in {
1084 () => {
1085 None
1086 };
1087 ($signal:ident) => {
1088 Some(InputSignal::$signal)
1089 };
1090}
1091
1092#[cfg(sdmmc_has_gpio_matrix)]
1093macro_rules! opt_out {
1094 () => {
1095 None
1096 };
1097 ($signal:ident) => {
1098 Some(OutputSignal::$signal)
1099 };
1100}
1101
1102for_each_sdmmc! {
1105 (all $( (
1106 $slot:ident, $idx:literal, $iomux:literal,
1107 [$($clk:ident)?], [$($cmd_in:ident)?], [$($cmd_out:ident)?],
1108 [$($data_in:ident),*], [$($data_out:ident),*],
1109 [$($cd:ident)?], [$($wp:ident)?], [$($card_int:ident)?],
1110 [$($data_strobe:ident)?], [$($rst:ident)?]
1111 ) ),*) => {
1112 const SLOT_COUNT: usize = 0 $(+ { crate::ignore!($slot); 1 })*;
1113 static SLOT_INFO: [SlotInfo; SLOT_COUNT] = [ $(
1114 SlotInfo {
1115 io_event: 1u32 << (16 + $idx),
1116
1117 #[cfg(sdmmc_has_gpio_matrix)]
1118 clk_out: opt_out!($($clk)?),
1119 #[cfg(sdmmc_has_gpio_matrix)]
1120 cmd_in: opt_in!($($cmd_in)?),
1121 #[cfg(sdmmc_has_gpio_matrix)]
1122 cmd_out: opt_out!($($cmd_out)?),
1123 #[cfg(sdmmc_has_gpio_matrix)]
1124 data_in: &[ $(InputSignal::$data_in),* ],
1125 #[cfg(sdmmc_has_gpio_matrix)]
1126 data_out: &[ $(OutputSignal::$data_out),* ],
1127
1128 cd_in: opt_in!($($cd)?),
1129 wp_in: opt_in!($($wp)?),
1130 }
1131 ),* ];
1132
1133 paste::paste! {
1134 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1136 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
1137 pub enum SlotId {
1138 $(
1139 #[doc = concat!("Slot ", stringify!($idx), ".")]
1140 [<_ $idx>],
1141 )*
1142 }
1143
1144 impl SlotId {
1145 fn index(self) -> u8 {
1147 match self {
1148 $(
1149 SlotId::[<_ $idx >] => $idx,
1150 )*
1151 }
1152 }
1153 }
1154
1155 const fn slot_id(s: u8) -> SlotId {
1157 match s {
1158 $($idx => SlotId::[<_ $idx>],)*
1159 _ => ::core::unreachable!(),
1160 }
1161 }
1162 }
1163 };
1164}
1165
1166fn slot_info(id: SlotId) -> &'static SlotInfo {
1168 &SLOT_INFO[id.index() as usize]
1169}
1170
1171fn idle_intmask() -> u32 {
1175 SDHOST::regs().intmask().read().bits() & (EVT_IO_SLOT0 | EVT_IO_SLOT1) | INTMASK_IDLE
1176}
1177
1178fn arm_transfer(expect_data: bool, multiblock: bool, transfer: Option<Transfer>) {
1180 TRANSFER.with(|ts| {
1181 *ts = TransferState {
1182 transfer,
1183 result: None,
1184 expect_data,
1185 multiblock,
1186 over_seen: false,
1187 acd_seen: false,
1188 wait_busy: false,
1189 waker: WakerRegistration::new(),
1190 };
1191 });
1192}
1193
1194#[handler]
1196fn on_interrupt() {
1197 let r = SDHOST::regs();
1198 let pending = r.mintsts().read().bits();
1199 let idsts = r.idsts().read().bits();
1200
1201 TRANSFER.with(|ts| {
1202 if ts.wait_busy {
1203 if pending & EVT_SBE != 0 {
1206 ts.result = Some(Ok(()));
1207 }
1208 } else {
1209 if let Some(t) = ts.transfer.as_mut()
1211 && t.remaining() > 0
1212 {
1213 let mut ring = ring();
1214 let free = free_descriptors(ring.reborrow(), t.next_desc);
1215 if free > 0 {
1216 fill_descriptors(ring.reborrow(), t, free);
1217 r.pldmnd().write(|w| unsafe { w.bits(1) });
1218 }
1219 }
1220
1221 if ts.result.is_none() {
1222 let err = map_rintsts(pending)
1223 .err()
1224 .or(if idsts & (IDSTS_FBE | IDSTS_DU) != 0 {
1225 Some(Error::DmaError)
1226 } else {
1227 None
1228 });
1229 if let Some(e) = err {
1230 ts.result = Some(Err(e));
1231 } else if ts.expect_data {
1232 if pending & EVT_DATA_OVER != 0 {
1233 ts.over_seen = true;
1234 }
1235 if pending & EVT_ACD != 0 {
1236 ts.acd_seen = true;
1237 }
1238 if ts.over_seen && (!ts.multiblock || ts.acd_seen) {
1239 ts.result = Some(Ok(()));
1240 }
1241 } else if pending & EVT_CMD_DONE != 0 {
1242 ts.result = Some(Ok(()));
1243 }
1244 }
1245 }
1246
1247 if ts.result.is_some() {
1248 ts.wait_busy = false;
1249 ts.transfer = None;
1250 r.intmask().write(|w| unsafe { w.bits(idle_intmask()) });
1251 r.idinten().write(|w| unsafe { w.bits(0) });
1252 ts.waker.wake();
1253 }
1254 });
1255
1256 if pending & EVT_IO_SLOT0 != 0 {
1260 SLOT_STATE[0].io_pending.store(true, Ordering::Release);
1261 SLOT_STATE[0].io_waker.wake();
1262 }
1263 if pending & EVT_IO_SLOT1 != 0 {
1264 SLOT_STATE[1].io_pending.store(true, Ordering::Release);
1265 SLOT_STATE[1].io_waker.wake();
1266 }
1267
1268 if pending & EVT_CD != 0 {
1270 SLOT_STATE[0].cd_waker.wake();
1271 SLOT_STATE[1].cd_waker.wake();
1272 }
1273
1274 r.rintsts().write(|w| unsafe { w.bits(pending) });
1276 r.idsts().write(|w| unsafe { w.bits(idsts) });
1277}
1278
1279pub struct SdHostController<'d> {
1283 _peri: SDHOST<'d>,
1284 _guard: PeripheralGuard,
1285 taken: [AtomicBool; SLOT_COUNT],
1286}
1287
1288impl<'d> SdHostController<'d> {
1289 pub fn new(peri: SDHOST<'d>, config: Config) -> Result<Self, ConfigError> {
1292 config.validate()?;
1293 let guard = PeripheralGuard::new(Peripheral::SdioHost);
1294 chip_specific::chip_setup();
1295 let this = Self {
1296 _peri: peri,
1297 _guard: guard,
1298 taken: [const { AtomicBool::new(false) }; SLOT_COUNT],
1299 };
1300
1301 chip_specific::set_module_clock(config.clock_source, config.module_div);
1307 this.reset_engine();
1308
1309 SETTINGS.with(|s| s.module = config);
1310 let r = SDHOST::regs();
1311 r.tmout().write(|w| unsafe {
1312 w.response_timeout().bits(0xFF);
1313 w.data_timeout().bits(0xFF_FFFF)
1314 });
1315 r.rintsts().write(|w| unsafe { w.bits(0xFFFF_FFFF) });
1316 r.ctrl().modify(|_, w| w.int_enable().clear_bit());
1317
1318 Ok(this)
1319 }
1320
1321 fn reset_engine(&self) {
1323 let r = SDHOST::regs();
1324 r.ctrl().modify(|_, w| {
1325 w.controller_reset().set_bit();
1326 w.fifo_reset().set_bit();
1327 w.dma_reset().set_bit()
1328 });
1329
1330 let _ = poll_until_timeout(Duration::from_millis(100), || {
1334 let c = r.ctrl().read();
1335 !c.controller_reset().bit_is_set()
1336 && !c.fifo_reset().bit_is_set()
1337 && !c.dma_reset().bit_is_set()
1338 });
1339 }
1340
1341 pub fn slot<const S: u8>(
1351 &self,
1352 config: SlotConfig,
1353 ) -> Result<Slot<'_, S, Blocking>, ConfigError> {
1354 const { ::core::assert!(S < 2, "SDMMC has only slots 0 and 1") };
1355 let idx = S as usize;
1356 if self.taken[idx].swap(true, Ordering::Relaxed) {
1357 return Err(ConfigError::SlotInUse);
1358 }
1359 #[cfg(sdmmc_delay_phase_num_is_set)]
1360 SETTINGS.with(|s| {
1361 s.slots[idx].input_delay_phase = config.input_delay_phase;
1362 s.slots[idx].dirty = true;
1363 });
1364 Ok(Slot {
1365 config,
1366 data_pins: 0,
1367 clk_connected: false,
1368 cmd_connected: false,
1369 cd_connected: false,
1370 wp_connected: false,
1371 _guard: PeripheralGuard::new(Peripheral::SdioHost),
1372 power: None,
1373 _pd: PhantomData,
1374 })
1375 }
1376}
1377
1378pub trait SlotClk<'d, const S: u8> {
1380 #[doc(hidden)]
1381 fn configure(self);
1382}
1383
1384pub trait SlotCmd<'d, const S: u8> {
1386 #[doc(hidden)]
1387 fn configure(self);
1388}
1389
1390pub trait SlotData<'d, const S: u8, const L: u8> {
1392 #[doc(hidden)]
1393 fn configure(self);
1394}
1395
1396#[cfg(sdmmc_has_gpio_matrix)]
1404for_each_sdmmc! {
1405 (
1406 $slot:ident, $idx:literal, false,
1407 [$($clk:ident)?], [$($cmd_in:ident)?], [$($cmd_out:ident)?],
1408 [$($data_in:ident),*], [$($data_out:ident),*],
1409 [$($cd:ident)?], [$($wp:ident)?], [$($card_int:ident)?],
1410 [$($data_strobe:ident)?], [$($rst:ident)?]
1411 ) => {
1412 impl<'d, P: PeripheralOutput<'d>> SlotClk<'d, $idx> for P {
1413 fn configure(self) {
1414 let pin = self.into();
1415 pin.apply_output_config(&OutputConfig::default());
1416 pin.set_output_enable(true);
1417 slot_pins(slot_id($idx)).clk = interconnect::OutputSignal::connect_with_guard(
1418 pin,
1419 slot_info(slot_id($idx)).clk_out.unwrap(),
1420 );
1421 }
1422 }
1423
1424 impl<'d, P: PeripheralInput<'d> + PeripheralOutput<'d>> SlotCmd<'d, $idx> for P {
1425 fn configure(self) {
1426 slot_pins(slot_id($idx)).cmd = connect_bidir(
1427 self.into(),
1428 slot_info(slot_id($idx)).cmd_in.unwrap(),
1429 slot_info(slot_id($idx)).cmd_out.unwrap(),
1430 );
1431 }
1432 }
1433
1434 impl<'d, const L: u8, P: PeripheralInput<'d> + PeripheralOutput<'d>>
1435 SlotData<'d, $idx, L> for P
1436 {
1437 fn configure(self) {
1438 slot_pins(slot_id($idx)).data[L as usize] = connect_bidir(
1439 self.into(),
1440 slot_info(slot_id($idx)).data_in[L as usize],
1441 slot_info(slot_id($idx)).data_out[L as usize],
1442 );
1443 }
1444 }
1445 };
1446
1447 (
1450 $slot:ident, $idx:literal, true,
1451 [$($clk:ident)?], [$($cmd_in:ident)?], [$($cmd_out:ident)?],
1452 [$($data_in:ident),*], [$($data_out:ident),*],
1453 [$($cd:ident)?], [$($wp:ident)?], [$($card_int:ident)?],
1454 [$($data_strobe:ident)?], [$($rst:ident)?]
1455 ) => {};
1456}
1457
1458#[cfg(sdmmc_has_iomux)]
1464fn configure_iomux_pad(pin: u8, af: crate::gpio::AlternateFunction) {
1465 crate::gpio::io_mux_reg(pin).modify(|_, w| {
1466 unsafe { w.mcu_sel().bits(af as u8) };
1467 w.fun_ie().set_bit();
1468 w.fun_wpu().set_bit();
1469 #[cfg(not(esp32))]
1473 unsafe {
1474 w.fun_drv().bits(3)
1475 };
1476 w
1477 });
1478}
1479
1480#[cfg(sdmmc_has_iomux)]
1481macro_rules! impl_signal_trait {
1482 ($gpio:ident, $trait:ident, $af:ident, $s:literal) => {
1483 impl<'d> $trait<'d, $s> for crate::peripherals::$gpio<'d> {
1484 fn configure(self) {
1485 configure_iomux_pad(
1486 crate::gpio::Pin::number(&self),
1487 crate::gpio::AlternateFunction::$af,
1488 );
1489 }
1490 }
1491 };
1492
1493 ($gpio:ident, $trait:ident, $af:ident, $s:literal, $l:literal) => {
1494 impl<'d> $trait<'d, $s, $l> for crate::peripherals::$gpio<'d> {
1495 fn configure(self) {
1496 configure_iomux_pad(
1497 crate::gpio::Pin::number(&self),
1498 crate::gpio::AlternateFunction::$af,
1499 );
1500 }
1501 }
1502 };
1503}
1504
1505#[cfg(sdmmc_has_iomux)]
1508for_each_iomux_function! {
1509 (SD1_CLK, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotClk, $af, 0); };
1510 (SD1_CMD, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotCmd, $af, 0); };
1511 (SD1_DATA0, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 0, 0); };
1512 (SD1_DATA1, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 0, 1); };
1513 (SD1_DATA2, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 0, 2); };
1514 (SD1_DATA3, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 0, 3); };
1515 (SD1_DATA4, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 0, 4); };
1516 (SD1_DATA5, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 0, 5); };
1517 (SD1_DATA6, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 0, 6); };
1518 (SD1_DATA7, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 0, 7); };
1519
1520 (SD2_CLK, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotClk, $af, 1); };
1521 (SD2_CMD, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotCmd, $af, 1); };
1522 (SD2_DATA0, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 1, 0); };
1523 (SD2_DATA1, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 1, 1); };
1524 (SD2_DATA2, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 1, 2); };
1525 (SD2_DATA3, $gpio:ident, $af:ident) => { impl_signal_trait!($gpio, SlotData, $af, 1, 3); };
1526}
1527
1528pub struct Slot<'d, const S: u8, Dm: DriverMode> {
1530 config: SlotConfig,
1531 data_pins: u8,
1532 clk_connected: bool,
1533 cmd_connected: bool,
1534 cd_connected: bool,
1535 wp_connected: bool,
1536 _guard: PeripheralGuard,
1537 power: Option<interconnect::OutputSignal<'d>>,
1538 _pd: PhantomData<(&'d mut (), Dm)>,
1539}
1540
1541impl<'d, const S: u8, Dm: DriverMode> Slot<'d, S, Dm> {
1542 pub fn with_clk(mut self, clk: impl SlotClk<'d, S>) -> Self {
1544 clk.configure();
1545 self.clk_connected = true;
1546 self
1547 }
1548
1549 pub fn with_cmd(mut self, cmd: impl SlotCmd<'d, S>) -> Self {
1551 cmd.configure();
1552 self.cmd_connected = true;
1553 self
1554 }
1555
1556 pub fn with_data0(mut self, d0: impl SlotData<'d, S, 0>) -> Self {
1558 d0.configure();
1559 self.note_data_pin(1);
1560 self
1561 }
1562
1563 pub fn with_data1(mut self, d1: impl SlotData<'d, S, 1>) -> Self {
1565 d1.configure();
1566 self.note_data_pin(2);
1567 self
1568 }
1569
1570 pub fn with_data2(mut self, d2: impl SlotData<'d, S, 2>) -> Self {
1572 d2.configure();
1573 self.note_data_pin(3);
1574 self
1575 }
1576
1577 pub fn with_data3(mut self, d3: impl SlotData<'d, S, 3>) -> Self {
1579 d3.configure();
1580 self.note_data_pin(4);
1581 self
1582 }
1583
1584 pub fn with_data4(mut self, d4: impl SlotData<'d, S, 4>) -> Self {
1586 d4.configure();
1587 self.note_data_pin(5);
1588 self
1589 }
1590
1591 pub fn with_data5(mut self, d5: impl SlotData<'d, S, 5>) -> Self {
1593 d5.configure();
1594 self.note_data_pin(6);
1595 self
1596 }
1597
1598 pub fn with_data6(mut self, d6: impl SlotData<'d, S, 6>) -> Self {
1600 d6.configure();
1601 self.note_data_pin(7);
1602 self
1603 }
1604
1605 pub fn with_data7(mut self, d7: impl SlotData<'d, S, 7>) -> Self {
1607 d7.configure();
1608 self.note_data_pin(8);
1609 self
1610 }
1611
1612 pub fn with_card_detect(mut self, cd: impl PeripheralInput<'d>) -> Self {
1614 let pin = cd.into();
1615 pin.set_input_enable(true);
1616 slot_info(slot_id(S)).cd_in.unwrap().connect_to(&pin);
1617 self.cd_connected = true;
1618 self
1619 }
1620
1621 pub fn with_write_protect(mut self, wp: impl PeripheralInput<'d>) -> Self {
1623 let pin = wp.into();
1624 pin.set_input_enable(true);
1625 slot_info(slot_id(S)).wp_in.unwrap().connect_to(&pin);
1626 self.wp_connected = true;
1627 self
1628 }
1629
1630 pub fn with_power_enable(mut self, power: impl PeripheralOutput<'d>) -> Self {
1632 let pin = power.into();
1633 pin.set_output_high(true);
1634 pin.apply_output_config(&OutputConfig::default());
1635 pin.set_output_enable(true);
1636 self.power = Some(pin);
1637 self
1638 }
1639
1640 pub fn is_card_present(&self) -> bool {
1643 if !self.cd_connected {
1644 return true;
1645 }
1646 (SDHOST::regs().cdetect().read().card_detect_n().bits() & (1 << S)) == 0
1647 }
1648
1649 pub fn is_write_protected(&self) -> bool {
1653 if !self.wp_connected {
1654 return false;
1655 }
1656 let level = (SDHOST::regs().wrtprt().read().write_protect().bits() & (1 << S)) != 0;
1657 level == self.config.wp_active_high
1658 }
1659
1660 pub fn set_bus_low_level(&mut self, width: BusWidth, hz: u32) -> Result<(), Error> {
1662 SETTINGS.with(|s| s.set_slot_bus(slot_id(S), width, hz))
1663 }
1664
1665 fn validate_pins(&self) -> Result<(), ConfigError> {
1667 if !self.clk_connected || !self.cmd_connected {
1668 return Err(ConfigError::MissingClkOrCmd);
1669 }
1670 if self.data_pins < 1 {
1671 return Err(ConfigError::NoData0);
1672 }
1673 Ok(())
1674 }
1675
1676 pub fn send_init_sequence(&mut self) -> Result<(), BlockingError> {
1678 with_engine_try(slot_id(S), |session| session.send_init_sequence(slot_id(S)))
1679 }
1680
1681 pub fn command_blocking(
1683 &mut self,
1684 index: u8,
1685 arg: u32,
1686 resp_len: ResponseLen,
1687 check_crc: bool,
1688 flags: CommandFlags,
1689 ) -> Result<[u32; 4], BlockingError> {
1690 if !self.is_card_present() {
1691 return Err(BlockingError::Op(Error::NoCard));
1692 }
1693 let slot = slot_id(S);
1694 with_engine_try(slot, |session| {
1695 session.send_command_blocking(slot, index, arg, resp_len, check_crc, flags)
1696 })
1697 }
1698
1699 pub fn read_blocks_blocking(
1701 &mut self,
1702 cmd_index: u8,
1703 arg: u32,
1704 mut buf: DmaAlignedMut<'_, [u8]>,
1705 block_size: u16,
1706 block_count: u32,
1707 ) -> Result<[u32; 4], BlockingError> {
1708 let slot = slot_id(S);
1709 with_engine_try(slot, |session| {
1710 let total = buf.len();
1711 let ptr = dma_ptr(buf.reborrow())?;
1712 let resp = session.transfer_blocking(
1713 slot,
1714 cmd_index,
1715 arg,
1716 false,
1717 Transfer::single(ptr, total),
1718 block_size,
1719 block_count,
1720 )?;
1721 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1722 buf.invalidate();
1723 Ok(resp)
1724 })
1725 }
1726
1727 pub fn write_blocks_blocking(
1729 &mut self,
1730 cmd_index: u8,
1731 arg: u32,
1732 mut buf: DmaAlignedMut<'_, [u8]>,
1733 block_size: u16,
1734 block_count: u32,
1735 ) -> Result<[u32; 4], BlockingError> {
1736 let slot = slot_id(S);
1737 with_engine_try(slot, |session| {
1738 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1739 buf.writeback();
1740 let total = buf.len();
1741 let ptr = dma_ptr(buf.reborrow())?;
1742 session.transfer_blocking(
1743 slot,
1744 cmd_index,
1745 arg,
1746 true,
1747 Transfer::single(ptr, total),
1748 block_size,
1749 block_count,
1750 )
1751 })
1752 }
1753
1754 fn note_data_pin(&mut self, count: u8) {
1755 self.data_pins = self.data_pins.max(count);
1756 }
1757}
1758
1759impl<'d, const S: u8> Slot<'d, S, Blocking> {
1760 pub fn into_async(self) -> Slot<'d, S, Async> {
1764 let r = SDHOST::regs();
1765 r.rintsts().write(|w| unsafe { w.bits(0xFFFF_FFFF) });
1766 r.idsts().write(|w| unsafe { w.bits(0xFFFF_FFFF) });
1767 r.intmask().write(|w| unsafe { w.bits(idle_intmask()) });
1768 r.idinten().write(|w| unsafe { w.bits(0) });
1769 r.ctrl().modify(|_, w| w.int_enable().set_bit());
1770 crate::interrupt::bind_handler(Interrupt::SDIO_HOST, on_interrupt);
1771
1772 Slot {
1773 config: self.config,
1774 data_pins: self.data_pins,
1775 clk_connected: self.clk_connected,
1776 cmd_connected: self.cmd_connected,
1777 _guard: self._guard,
1778 power: self.power,
1779 cd_connected: self.cd_connected,
1780 wp_connected: self.wp_connected,
1781 _pd: PhantomData,
1782 }
1783 }
1784}
1785
1786impl<'d, const S: u8> Slot<'d, S, Async> {
1787 pub fn into_blocking(self) -> Slot<'d, S, Blocking> {
1789 let r = SDHOST::regs();
1790 r.ctrl().modify(|_, w| w.int_enable().clear_bit());
1791 r.intmask().write(|w| unsafe { w.bits(0) });
1792 r.idinten().write(|w| unsafe { w.bits(0) });
1793 crate::interrupt::disable(crate::system::Cpu::current(), Interrupt::SDIO_HOST);
1794
1795 Slot {
1796 config: self.config,
1797 data_pins: self.data_pins,
1798 clk_connected: self.clk_connected,
1799 cmd_connected: self.cmd_connected,
1800 _guard: self._guard,
1801 power: self.power,
1802 cd_connected: self.cd_connected,
1803 wp_connected: self.wp_connected,
1804 _pd: PhantomData,
1805 }
1806 }
1807
1808 #[must_use = "futures do nothing unless you `.await` or poll them"]
1810 pub fn wait_for_sdio_interrupt(&mut self) -> impl Future<Output = ()> {
1811 let slot_id = slot_id(S);
1812 let slot = slot_id.index() as usize;
1813 let bit = slot_info(slot_id).io_event;
1814
1815 WaitForInterruptFuture { slot, bit }
1816 }
1817
1818 async fn cmd_async<'a, C: sdio::ControlCommand + 'a>(
1820 &mut self,
1821 session: &mut EngineSession,
1822 cmd: C,
1823 ) -> Result<C::Resp<'a>, MmcError> {
1824 let slot = slot_id(S);
1825 let resp_len = match <C::Resp<'a> as sdio::Response>::LEN {
1826 sdio::ResponseLen::Zero => ResponseLen::None,
1827 sdio::ResponseLen::R48 => ResponseLen::Short,
1828 sdio::ResponseLen::R136 => ResponseLen::Long,
1829 };
1830 let flags = CommandFlags {
1831 wait_complete: !is_stop_or_abort(C::INDEX),
1832 stop_abort: is_stop_or_abort(C::INDEX),
1833 busy: <C::Resp<'a> as sdio::Response>::BUSY,
1834 };
1835 let crc = <C::Resp<'a> as sdio::Response>::CRC;
1836 let words = session
1837 .send_command_async(slot, C::INDEX, cmd.arg(), resp_len, crc, flags)
1838 .await?;
1839 Ok(<C::Resp<'a> as sdio::Response>::from_words(&words))
1840 }
1841}
1842
1843impl<'d, const S: u8> sdio::MmcBus for Slot<'d, S, Async> {
1844 async fn wait_for_event(&mut self) -> Result<(), MmcError> {
1845 self.wait_for_sdio_interrupt().await;
1846 Ok(())
1847 }
1848
1849 async fn send_command<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
1850 where
1851 C: sdio::ControlCommand + 'a,
1852 {
1853 let mut session = lock_engine(slot_id(S)).await?;
1854 self.cmd_async(&mut session, cmd).await
1855 }
1856
1857 async fn read_blocks<'a, C>(
1858 &mut self,
1859 mut cmd: C,
1860 auto_stop: bool,
1861 ) -> Result<C::Resp<'a>, MmcError>
1862 where
1863 C: sdio::BlockReadCommand + 'a,
1864 {
1865 let mut session = lock_engine(slot_id(S)).await?;
1866 let slot = slot_id(S);
1867 let (bs, arg) = (cmd.block_size().len() as u16, cmd.arg());
1868 let words = session
1869 .read_async(slot, C::INDEX, arg, cmd.buf(), bs, auto_stop)
1870 .await?;
1871 Ok(<C::Resp<'a> as sdio::Response>::from_words(&words))
1872 }
1873
1874 async fn write_blocks<'a, C>(
1875 &mut self,
1876 cmd: C,
1877 auto_stop: bool,
1878 ) -> Result<C::Resp<'a>, MmcError>
1879 where
1880 C: sdio::BlockWriteCommand + 'a,
1881 {
1882 let mut session = lock_engine(slot_id(S)).await?;
1883 let slot = slot_id(S);
1884 let (bs, arg) = (cmd.block_size().len() as u16, cmd.arg());
1885 let words = session
1886 .write_async(slot, C::INDEX, arg, cmd.buf(), bs, auto_stop)
1887 .await?;
1888 Ok(<C::Resp<'a> as sdio::Response>::from_words(&words))
1889 }
1890
1891 async fn read_bytes<'a, C>(&mut self, mut cmd: C) -> Result<C::Resp<'a>, MmcError>
1892 where
1893 C: sdio::ByteReadCommand + 'a,
1894 {
1895 let mut session = lock_engine(slot_id(S)).await?;
1896 let slot = slot_id(S);
1897 let (n, arg) = (cmd.byte_count(), cmd.arg());
1898 let words = session
1899 .read_async(slot, C::INDEX, arg, cmd.buf(), n as u16, false)
1900 .await?;
1901 Ok(<C::Resp<'a> as sdio::Response>::from_words(&words))
1902 }
1903
1904 async fn write_bytes<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
1905 where
1906 C: sdio::ByteWriteCommand + 'a,
1907 {
1908 let mut session = lock_engine(slot_id(S)).await?;
1909 let slot = slot_id(S);
1910 let (n, arg) = (cmd.byte_count(), cmd.arg());
1911 let words = session
1912 .write_async(slot, C::INDEX, arg, cmd.buf(), n as u16, false)
1913 .await?;
1914 Ok(<C::Resp<'a> as sdio::Response>::from_words(&words))
1915 }
1916
1917 async fn init_idle(&mut self, hz: u32) -> Result<(), MmcError> {
1918 let mut session = lock_engine(slot_id(S)).await?;
1919 self.validate_pins().map_err(|_| MmcError::Other)?;
1920 self.set_bus_low_level(BusWidth::Bit1, hz)?;
1921 session.send_init_sequence(slot_id(S))?;
1922 Ok(())
1923 }
1924
1925 fn set_bus(&mut self, width: sdio::BusWidth, hz: u32) -> Result<(), MmcError> {
1926 let w = match width {
1927 sdio::BusWidth::W1 => BusWidth::Bit1,
1928 sdio::BusWidth::W4 => BusWidth::Bit4,
1929 sdio::BusWidth::W8 => BusWidth::Bit8,
1930 };
1931 if matches!(w, BusWidth::Bit4) && self.data_pins < 4 {
1932 return Err(MmcError::Unsupported);
1933 }
1934 if matches!(w, BusWidth::Bit8) && self.data_pins < 8 {
1935 return Err(MmcError::Unsupported);
1936 }
1937 if hz > 40_000_000 {
1938 return Err(MmcError::Unsupported);
1939 }
1940 self.set_bus_low_level(w, hz)?;
1941 Ok(())
1942 }
1943
1944 fn supports_mmc(&self) -> bool {
1945 true
1947 }
1948
1949 fn supports_auto_stop(&self) -> bool {
1950 true
1951 }
1952
1953 fn supports_bus_width(&self) -> sdio::BusWidth {
1954 if self.data_pins >= 8 {
1955 sdio::BusWidth::W8
1956 } else if self.data_pins >= 4 {
1957 sdio::BusWidth::W4
1958 } else {
1959 sdio::BusWidth::W1
1960 }
1961 }
1962
1963 fn supports_frequency(&self) -> u32 {
1964 40_000_000
1965 }
1966}
1967
1968fn is_stop_or_abort(index: u8) -> bool {
1971 index == 12
1972}
1973
1974fn needs_auto_stop(index: u8, block_count: u32) -> bool {
1983 block_count > 1 && matches!(index, 18 | 25)
1984}
1985
1986#[cfg(sdmmc_has_gpio_matrix)]
1987fn connect_bidir(
1988 pin: interconnect::OutputSignal<'_>,
1989 input: InputSignal,
1990 output: OutputSignal,
1991) -> PinGuard {
1992 pin.set_output_high(true);
1993 pin.apply_output_config(&OutputConfig::default().with_pull(Pull::Up));
1994 pin.set_output_enable(true);
1995 pin.set_input_enable(true);
1996 input.connect_to(&pin);
1997 interconnect::OutputSignal::connect_with_guard(pin, output)
1998}
1999
2000fn poll_until(mut ready: impl FnMut() -> bool) -> Result<(), Error> {
2002 for _ in 0..POLL_LIMIT {
2003 if ready() {
2004 return Ok(());
2005 }
2006 }
2007 Err(Error::Timeout)
2008}
2009
2010fn poll_until_timeout(timeout: Duration, mut ready: impl FnMut() -> bool) -> Result<(), Error> {
2011 let start = Instant::now();
2012 while !ready() {
2013 if start.elapsed() > timeout {
2014 return Err(Error::Timeout);
2015 }
2016 }
2017 Ok(())
2018}
2019
2020fn wait_command_accepted() -> Result<(), Error> {
2022 let r = SDHOST::regs();
2023 for _ in 0..POLL_LIMIT {
2024 if !r.cmd().read().start_cmd().bit_is_set() {
2025 return Ok(());
2026 }
2027 const HW_LOCKED: u32 = 1 << 12;
2029 if (r.rintsts().read().bits() & HW_LOCKED) != 0 {
2030 r.rintsts().write(|w| unsafe { w.bits(HW_LOCKED) });
2031 return Err(Error::Timeout);
2032 }
2033 }
2034 Err(Error::Timeout)
2035}
2036
2037fn abort_transfer() {
2039 let r = SDHOST::regs();
2040 r.intmask().write(|w| unsafe { w.bits(idle_intmask()) });
2041 r.idinten().write(|w| unsafe { w.bits(0) });
2042 disable_idmac();
2043 let _ = reset_transfer();
2044 TRANSFER.with(|ts| *ts = TransferState::IDLE);
2045}
2046
2047#[must_use = "futures do nothing unless you `.await` or poll them"]
2049fn wait_result() -> impl Future<Output = Result<(), Error>> {
2050 poll_fn(|cx| {
2051 TRANSFER.with(|ts| match ts.result.take() {
2052 Some(res) => Poll::Ready(res),
2053 None => {
2054 ts.waker.register(cx.waker());
2055 Poll::Pending
2056 }
2057 })
2058 })
2059}
2060
2061async fn wait_busy_async() -> Result<(), Error> {
2069 let r = SDHOST::regs();
2070
2071 if !r.status().read().data_busy().bit_is_set() {
2073 return Ok(());
2074 }
2075
2076 r.cardthrctl().modify(|_, w| w.cardclrinten().set_bit());
2078 TRANSFER.with(|ts| {
2079 *ts = TransferState {
2080 wait_busy: true,
2081 ..TransferState::IDLE
2082 };
2083 });
2084 r.rintsts().write(|w| unsafe { w.bits(EVT_SBE) });
2085 r.intmask()
2086 .write(|w| unsafe { w.bits(idle_intmask() | EVT_SBE) });
2087
2088 let res = if !r.status().read().data_busy().bit_is_set() {
2092 TRANSFER.with(|ts| *ts = TransferState::IDLE);
2093 Ok(())
2094 } else {
2095 wait_result().await
2096 };
2097
2098 r.cardthrctl().modify(|_, w| w.cardclrinten().clear_bit());
2100 r.intmask().write(|w| unsafe { w.bits(idle_intmask()) });
2101 res
2102}
2103
2104async fn wait_busy_poll() -> Result<(), Error> {
2110 for _ in 0..POLL_LIMIT {
2111 if !SDHOST::regs().status().read().data_busy().bit_is_set() {
2112 return Ok(());
2113 }
2114 yield_now().await;
2115 }
2116 Err(Error::Timeout)
2117}
2118
2119fn read_response(resp_len: ResponseLen) -> [u32; 4] {
2121 let r = SDHOST::regs();
2122 match resp_len {
2123 ResponseLen::None => [0; 4],
2124 ResponseLen::Short => [r.resp0().read().bits(), 0, 0, 0],
2125 ResponseLen::Long => [
2126 r.resp0().read().bits(),
2127 r.resp1().read().bits(),
2128 r.resp2().read().bits(),
2129 r.resp3().read().bits(),
2130 ],
2131 }
2132}
2133
2134fn map_rintsts(sts: u32) -> Result<(), Error> {
2136 if sts & EVT_HLE != 0 {
2137 return Err(Error::HardwareLocked);
2138 }
2139 if sts & EVT_RTO != 0 {
2140 return Err(Error::ResponseTimeout);
2141 }
2142 if sts & EVT_RCRC != 0 {
2143 return Err(Error::ResponseCrc);
2144 }
2145 if sts & EVT_RESP_ERR != 0 {
2146 return Err(Error::ResponseError);
2147 }
2148 if sts & (EVT_DTO | EVT_HTO) != 0 {
2149 return Err(Error::DataTimeout);
2150 }
2151 if sts & (EVT_DCRC | EVT_EBE) != 0 {
2152 return Err(Error::DataCrc);
2153 }
2154 if sts & EVT_SBE != 0 {
2155 return Err(Error::StartBitError);
2156 }
2157 if sts & EVT_FRUN != 0 {
2158 return Err(Error::FifoOverrun);
2159 }
2160 Ok(())
2161}
2162
2163fn wait_busy_cleared() -> Result<(), Error> {
2165 poll_until(|| !SDHOST::regs().status().read().data_busy().bit_is_set())
2166}
2167
2168fn dma_ptr(buf: DmaAlignedMut<'_, [u8]>) -> Result<u32, Error> {
2172 dma_ptr_from_raw(buf.as_ptr())
2173}
2174
2175fn dma_ptr_ref(buf: DmaAlignedRef<'_, [u8]>) -> Result<u32, Error> {
2179 dma_ptr_from_raw(buf.as_ptr())
2180}
2181
2182fn dma_ptr_from_raw(addr: *const u8) -> Result<u32, Error> {
2183 if crate::soc::is_valid_ram_address(addr as usize) {
2185 return Ok(addr as u32);
2186 }
2187 #[cfg(all(soc_has_psram, sdmmc_psram_dma))]
2188 if crate::soc::is_valid_psram_address(addr as usize) {
2189 return Ok(addr as u32);
2190 }
2191
2192 Err(Error::BufferNotDmaCapable)
2193}
2194
2195fn run_data_phase(
2197 t: &mut Transfer,
2198 mut ring: DmaAlignedMut<'_, [Desc; RING_LEN]>,
2199 write: bool,
2200 auto_stop: bool,
2201) -> Result<(), Error> {
2202 let r = SDHOST::regs();
2203 let consume = EVT_CMD_DONE | EVT_RTO | EVT_RCRC | EVT_RESP_ERR | EVT_HLE;
2204
2205 let done = EVT_CMD_DONE | EVT_RTO | EVT_RCRC | EVT_RESP_ERR;
2207 let mut sts = 0;
2208 poll_until(|| {
2209 sts = r.rintsts().read().bits();
2210 sts & done != 0
2211 })?;
2212 map_rintsts(sts)?;
2213 r.rintsts().write(|w| unsafe { w.bits(consume) });
2214
2215 let data_err = EVT_DCRC | EVT_DTO | EVT_HTO | EVT_SBE | EVT_EBE | EVT_FRUN;
2221 loop {
2222 let sts = r.rintsts().read().bits();
2223 if sts & data_err != 0 {
2224 map_rintsts(sts)?;
2225 }
2226 let id_sts = r.idsts().read();
2227 if id_sts.fbe().bit_is_set() || id_sts.du().bit_is_set() {
2228 return Err(Error::DmaError);
2229 }
2230 if t.remaining() > 0 {
2231 let free = free_descriptors(ring.reborrow(), t.next_desc);
2232 if free > 0 {
2233 fill_descriptors(ring.reborrow(), t, free);
2234 r.pldmnd().write(|w| unsafe { w.bits(1) });
2235 }
2236 }
2237 if sts & EVT_DATA_OVER != 0 {
2238 break;
2239 }
2240 }
2241
2242 if auto_stop {
2248 poll_until(|| r.rintsts().read().bits() & EVT_ACD != 0)?;
2249 }
2250 if write {
2251 wait_busy_cleared()?;
2252 }
2253 Ok(())
2254}
2255
2256fn free_descriptors(ring: DmaAlignedMut<'_, [Desc; RING_LEN]>, next: usize) -> usize {
2258 let mut count = 0;
2259 for i in 0..RING_LEN {
2260 let d = &ring[(next + i) % RING_LEN];
2261 if d.flags & DESC_OWN != 0 {
2262 break;
2263 }
2264 count += 1;
2265 if d.next == 0 {
2266 break;
2267 }
2268 }
2269 count
2270}
2271
2272fn fill_descriptors(mut ring: DmaAlignedMut<'_, [Desc; RING_LEN]>, t: &mut Transfer, count: usize) {
2275 for _ in 0..count {
2276 while t.seg < t.segs.len() && t.segs[t.seg].1 == 0 {
2278 t.seg += 1;
2279 }
2280 if t.seg >= t.segs.len() {
2281 break;
2282 }
2283
2284 let (ptr, rem) = t.segs[t.seg];
2285 let i = t.next_desc;
2286 let size = rem.min(DMA_MAX_BUF_LEN);
2287 let exhausts_seg = size == rem;
2290 let later_data = t.segs[t.seg + 1..].iter().any(|(_, len)| *len > 0);
2291 let last = exhausts_seg && !later_data;
2292 let next_ptr = if last {
2293 0
2294 } else {
2295 &ring[(i + 1) % RING_LEN] as *const Desc as u32
2296 };
2297 let first = ring[i].flags & DESC_FIRST;
2298 let d = &mut ring[i];
2299 d.flags = DESC_OWN | DESC_CHAINED | first | if last { DESC_LAST } else { 0 };
2300 d.sizes = ((size + 3) & !3) as u32;
2301 d.buf1 = ptr;
2302 d.next = next_ptr;
2303 t.segs[t.seg].0 = ptr + size as u32;
2304 t.segs[t.seg].1 = rem - size;
2305 t.next_desc = (i + 1) % RING_LEN;
2306 }
2307
2308 #[cfg(soc_internal_memory_cached)]
2309 ring.writeback();
2310}
2311
2312fn reset_transfer() -> Result<(), Error> {
2313 let r = SDHOST::regs();
2314 r.ctrl().modify(|_, w| w.fifo_reset().set_bit());
2315 let res = poll_until(|| !r.ctrl().read().fifo_reset().bit_is_set());
2316
2317 r.rintsts()
2318 .write(|w| unsafe { w.bits(!(EVT_IO_SLOT0 | EVT_IO_SLOT1)) });
2319 r.idsts().write(|w| unsafe { w.bits(0xFFFF_FFFF) });
2320
2321 res
2322}
2323
2324fn enable_idmac(dbaddr: u32) {
2330 let r = SDHOST::regs();
2331 r.ctrl()
2332 .modify(|rd, w| unsafe { w.bits(rd.bits() | CTRL_DMA_ENABLE | CTRL_USE_INTERNAL_DMA) });
2333 r.bmod().modify(|_, w| w.swr().set_bit());
2334 r.idinten().write(|w| unsafe { w.bits(0) });
2335 r.dbaddr().write(|w| unsafe { w.bits(dbaddr) });
2336 r.bmod().modify(|_, w| {
2337 w.de().set_bit();
2338 w.fb().set_bit()
2339 });
2340}
2341
2342fn disable_idmac() {
2344 let r = SDHOST::regs();
2345 r.ctrl()
2346 .modify(|rd, w| unsafe { w.bits(rd.bits() & !CTRL_USE_INTERNAL_DMA) });
2347 r.bmod().modify(|_, w| {
2348 w.de().clear_bit();
2349 w.fb().clear_bit()
2350 });
2351 r.ctrl().modify(|_, w| w.dma_reset().set_bit());
2352}
2353
2354fn module_hz(source: ClockSource, div: u8) -> u32 {
2356 let base = match source {
2357 #[cfg(esp32s31)]
2358 ClockSource::Mpll => 500_000_000,
2359 #[cfg(not(esp32s31))]
2360 ClockSource::Pll160m => 160_000_000,
2361 #[cfg(not(esp32p4))]
2364 ClockSource::Xtal => 40_000_000,
2365 };
2366 base / (div as u32)
2367}
2368
2369fn freq_to_card_div(module_hz: u32, target_hz: u32) -> u8 {
2373 if target_hz == 0 || module_hz <= target_hz {
2374 return 0;
2375 }
2376 let div = module_hz.div_ceil(2 * target_hz);
2377 div.clamp(1, 255) as u8
2378}
2379
2380#[must_use = "futures do nothing unless you `.await` or poll them"]
2381struct WaitForInterruptFuture {
2382 slot: usize,
2383 bit: u32,
2384}
2385
2386impl Future for WaitForInterruptFuture {
2387 type Output = ();
2388 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
2389 SLOT_STATE[self.slot].io_waker.register(cx.waker());
2391
2392 SDHOST::regs()
2393 .intmask()
2394 .modify(|rd, w| unsafe { w.bits(rd.bits() | self.bit) });
2395
2396 if SLOT_STATE[self.slot]
2397 .io_pending
2398 .swap(false, Ordering::AcqRel)
2399 {
2400 Poll::Ready(())
2401 } else {
2402 Poll::Pending
2403 }
2404 }
2405}
2406
2407impl Drop for WaitForInterruptFuture {
2408 fn drop(&mut self) {
2409 SDHOST::regs()
2410 .intmask()
2411 .modify(|rd, w| unsafe { w.bits(rd.bits() & !self.bit) });
2412 }
2413}