diff options
| -rw-r--r-- | embassy-stm32/src/sdmmc/mod.rs | 185 |
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; | |||
| 13 | use sdio_host::common_cmd::{self, Resp, ResponseLen}; | 13 | use sdio_host::common_cmd::{self, Resp, ResponseLen}; |
| 14 | use sdio_host::emmc::{ExtCSD, EMMC}; | 14 | use sdio_host::emmc::{ExtCSD, EMMC}; |
| 15 | use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; | 15 | use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; |
| 16 | use sdio_host::{sd_cmd, Cmd}; | 16 | use sdio_host::{emmc_cmd, sd_cmd, Cmd}; |
| 17 | 17 | ||
| 18 | #[cfg(sdmmc_v1)] | 18 | #[cfg(sdmmc_v1)] |
| 19 | use crate::dma::ChannelAndRequest; | 19 | use crate::dma::ChannelAndRequest; |
| @@ -1412,6 +1412,189 @@ impl<'d, T: Instance> Sdmmc<'d, T> { | |||
| 1412 | } | 1412 | } |
| 1413 | } | 1413 | } |
| 1414 | 1414 | ||
| 1415 | /// eMMC only. | ||
| 1416 | impl<'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 | |||
| 1415 | impl<'d, T: Instance> Drop for Sdmmc<'d, T> { | 1598 | impl<'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(); |
