aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs185
1 files changed, 184 insertions, 1 deletions
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 6dbb524b7..f92c0260b 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -13,7 +13,7 @@ use embassy_sync::waitqueue::AtomicWaker;
13use sdio_host::common_cmd::{self, Resp, ResponseLen}; 13use sdio_host::common_cmd::{self, Resp, ResponseLen};
14use sdio_host::emmc::{ExtCSD, EMMC}; 14use sdio_host::emmc::{ExtCSD, EMMC};
15use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; 15use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD};
16use sdio_host::{sd_cmd, Cmd}; 16use sdio_host::{emmc_cmd, sd_cmd, Cmd};
17 17
18#[cfg(sdmmc_v1)] 18#[cfg(sdmmc_v1)]
19use crate::dma::ChannelAndRequest; 19use crate::dma::ChannelAndRequest;
@@ -1412,6 +1412,189 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1412 } 1412 }
1413} 1413}
1414 1414
1415/// eMMC only.
1416impl<'d, T: Instance> Sdmmc<'d, T> {
1417 /// Initializes eMMC and sets the bus at the specified frequency.
1418 pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> {
1419 let regs = T::regs();
1420 let ker_ck = T::frequency();
1421
1422 let bus_width = match self.d3.is_some() {
1423 true => BusWidth::Four,
1424 false => BusWidth::One,
1425 };
1426
1427 // While the SD/SDIO card or eMMC is in identification mode,
1428 // the SDMMC_CK frequency must be no more than 400 kHz.
1429 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
1430 self.clock = init_clock;
1431
1432 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1433 Self::wait_idle();
1434
1435 regs.clkcr().modify(|w| {
1436 w.set_widbus(0);
1437 w.set_clkdiv(clkdiv);
1438 #[cfg(sdmmc_v1)]
1439 w.set_bypass(_bypass);
1440 });
1441
1442 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
1443 Self::cmd(common_cmd::idle(), false)?;
1444
1445 let mut card = Emmc::default();
1446
1447 let ocr = loop {
1448 let high_voltage = 0b0 << 7;
1449 let access_mode = 0b10 << 29;
1450 let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15;
1451 // Initialize card
1452 match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) {
1453 Ok(_) => (),
1454 Err(Error::Crc) => (),
1455 Err(err) => return Err(err),
1456 }
1457 let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into();
1458 if !ocr.is_busy() {
1459 // Power up done
1460 break ocr;
1461 }
1462 };
1463
1464 card.capacity = if ocr.access_mode() == 0b10 {
1465 // Card is SDHC or SDXC or SDUC
1466 CardCapacity::HighCapacity
1467 } else {
1468 CardCapacity::StandardCapacity
1469 };
1470 card.ocr = ocr;
1471
1472 Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2
1473 let cid0 = regs.respr(0).read().cardstatus() as u128;
1474 let cid1 = regs.respr(1).read().cardstatus() as u128;
1475 let cid2 = regs.respr(2).read().cardstatus() as u128;
1476 let cid3 = regs.respr(3).read().cardstatus() as u128;
1477 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
1478 card.cid = cid.into();
1479
1480 card.rca = 1u16.into();
1481 Self::cmd(emmc_cmd::assign_relative_address(card.rca), false)?;
1482
1483 Self::cmd(common_cmd::send_csd(card.rca), false)?;
1484 let csd0 = regs.respr(0).read().cardstatus() as u128;
1485 let csd1 = regs.respr(1).read().cardstatus() as u128;
1486 let csd2 = regs.respr(2).read().cardstatus() as u128;
1487 let csd3 = regs.respr(3).read().cardstatus() as u128;
1488 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
1489 card.csd = csd.into();
1490
1491 self.select_card(Some(card.rca))?;
1492
1493 // Set bus width
1494 let (width, widbus) = match bus_width {
1495 BusWidth::Eight => (BusWidth::Eight, 2),
1496 BusWidth::Four => (BusWidth::Four, 1),
1497 _ => (BusWidth::One, 0),
1498 };
1499 // Write bus width to ExtCSD byte 183
1500 Self::cmd(
1501 emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus),
1502 false,
1503 )?;
1504
1505 self.card = Some(SdmmcPeripheral::Emmc(card));
1506
1507 // Wait for ready after R1b response
1508 loop {
1509 let status = self.read_status::<EMMC>(self.card.as_ref().unwrap())?;
1510
1511 if status.ready_for_data() {
1512 break;
1513 }
1514 }
1515
1516 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1517 Self::wait_idle();
1518
1519 regs.clkcr().modify(|w| w.set_widbus(widbus));
1520
1521 // Set Clock
1522 if freq.0 <= 25_000_000 {
1523 // Final clock frequency
1524 self.clkcr_set_clkdiv(freq.0, width)?;
1525 } else {
1526 // Switch to max clock for SDR12
1527 self.clkcr_set_clkdiv(25_000_000, width)?;
1528 }
1529
1530 // Read status
1531 self.read_ext_csd().await?;
1532
1533 Ok(())
1534 }
1535
1536 /// Gets the EXT_CSD register.
1537 ///
1538 /// eMMC only.
1539 async fn read_ext_csd(&mut self) -> Result<(), Error> {
1540 let card = self.card.as_mut().ok_or(Error::NoCard)?.get_emmc();
1541
1542 // Note: cmd_block can't be used because ExtCSD is too long to fit.
1543 let mut data_block = DataBlock([0u8; 512]);
1544
1545 // NOTE(unsafe) DataBlock uses align 4
1546 let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) };
1547
1548 Self::cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16
1549
1550 // Arm `OnDrop` after the buffer, so it will be dropped first
1551 let regs = T::regs();
1552 let on_drop = OnDrop::new(|| Self::on_drop());
1553
1554 let transfer = Self::prepare_datapath_read(
1555 &self.config,
1556 #[cfg(sdmmc_v1)]
1557 &mut self.dma,
1558 buffer,
1559 512,
1560 9,
1561 );
1562 InterruptHandler::<T>::data_interrupts(true);
1563 Self::cmd(emmc_cmd::send_ext_csd(), true)?;
1564
1565 let res = poll_fn(|cx| {
1566 T::state().register(cx.waker());
1567 let status = regs.star().read();
1568
1569 if status.dcrcfail() {
1570 return Poll::Ready(Err(Error::Crc));
1571 }
1572 if status.dtimeout() {
1573 return Poll::Ready(Err(Error::Timeout));
1574 }
1575 #[cfg(sdmmc_v1)]
1576 if status.stbiterr() {
1577 return Poll::Ready(Err(Error::StBitErr));
1578 }
1579 if status.dataend() {
1580 return Poll::Ready(Ok(()));
1581 }
1582 Poll::Pending
1583 })
1584 .await;
1585 Self::clear_interrupt_flags();
1586
1587 if res.is_ok() {
1588 on_drop.defuse();
1589 Self::stop_datapath();
1590 drop(transfer);
1591
1592 card.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into();
1593 }
1594 res
1595 }
1596}
1597
1415impl<'d, T: Instance> Drop for Sdmmc<'d, T> { 1598impl<'d, T: Instance> Drop for Sdmmc<'d, T> {
1416 fn drop(&mut self) { 1599 fn drop(&mut self) {
1417 T::Interrupt::disable(); 1600 T::Interrupt::disable();