dwmmc-host 0.1.3

Synopsys DesignWare Mobile Storage Host Controller backend for sdmmc-protocol (no_std, FIFO/IDMAC)
Documentation
# dwmmc-host

`no_std` Synopsys DesignWare Mobile Storage Host Controller (DW_mshc)
backend for [`sdmmc-protocol`](../sdmmc-protocol).

This crate plugs the IP block known as `DWC_mobile_storage` / `dw_mshc` /
`dw_mmc` (Linux) into the `SdioHost` trait so
`sdmmc_protocol::sdio::SdioSdmmc` can drive real hardware. The same core
appears in Rockchip RK33xx/RK35xx, Allwinner A-series, StarFive JH7110,
and a long tail of mid-range SoCs.

This crate implements `sdmmc_protocol::sdio::SdioHost` for the controller while
leaving MMIO mapping, SoC clocks, resets, pinmux, power rails, IRQ routing, and
DMA cache policy to platform glue.

## Status

- Compiles as a `no_std` controller backend.
- Intended for use through `sdmmc_protocol::sdio::SdioSdmmc`.
- Board-specific clock, power, pinmux, and tuning policy must be supplied by
  the caller.
- Real hardware bring-up still depends on the surrounding SoC integration.

## Scope

| Area                | Implemented |
|---------------------|-------------|
| PIO read / write (FIFO) ||
| 1-bit / 4-bit / 8-bit bus ||
| Default speed       ||
| High Speed (50 MHz) ||
| UHS-I / HS200 clock targets ||
| 32-bit / 136-bit responses ||
| R3 / R4 (no CRC) responses ||
| Software reset / clock setup ||
| Configurable FIFO offset ||
| 1.8 V signaling register path | ✅ (board validation required) |
| DDR50 register bit path | ✅ (board validation required) |
| IDMAC descriptor read / write ||
| SdioHost IDMAC data path | ✅ (FIFO fallback) |
| External-DMA data path ||
| Controller-specific DLL/strobe/tuning windows ||

The `SdioHost` implementation tries IDMAC for 512-byte CMD17/CMD18/CMD24/CMD25
block I/O when a `dma_api::DeviceDma` capability is installed with
`DwMmc::set_dma`; otherwise it uses the FIFO path. `DwMmc::block_buffer_config`
exposes the selected queue constraints for block-device adapters.

## Usage

```rust,no_run
use core::ptr::NonNull;
use sdmmc_protocol::{OperationPoll, sdio::{SdioInitScratch, SdioSdmmc}};
use dwmmc_host::DwMmc;

// SAFETY: 0xFE2B_0000 must point at a valid DW_mshc register file the
// caller has exclusive access to.
let mmio = NonNull::new(0xFE2B_0000 as *mut u8).unwrap();
let mut host = unsafe { DwMmc::new(mmio) };
host.set_reference_clock(50_000_000);
host.reset_and_init().expect("controller reset");

let mut card = SdioSdmmc::new(host);
let mut scratch = SdioInitScratch::new();
let mut request = card.submit_init(&mut scratch)?;
while let OperationPoll::Pending = card.poll_init_request(&mut request)? {
    // Runtime policy belongs here: spin, yield, wait for IRQ, or sleep/timer
    // when request.take_needs_pace() is set.
}
# Ok::<(), sdmmc_protocol::Error>(())
```

Construction is `unsafe` because the caller must guarantee that the supplied
address is a valid, exclusively-owned DW_mshc register file for the lifetime of
the driver.

### Bring-up checklist (for real-hardware validation)

1. Map the DW_mshc register file (e.g. RK3568 SDMMC0 at `0xFE2B_0000`).
2. Configure the platform clock so the controller has a viable
   reference clock before calling `DwMmc::new`. Most SoCs route a
   selectable mux through the CRU; pick a rate that divides cleanly
   to 400 kHz for ID mode.
3. Pass that rate to `DwMmc::set_reference_clock` so the divider
   programmed by `set_clock` lands on the right frequency.
4. `host.reset_and_init()?` — clears the controller / FIFO / DMA
   state and arms a 400 kHz ID-mode clock.
5. Build `SdioSdmmc::new(host)`, submit initialization with
   `submit_init`, and drive it with `poll_init_request`. The
   protocol layer will ramp the clock up via `set_clock`; platform/runtime
   code chooses whether pending work spins, yields, or waits for an IRQ.
6. Add board-specific tuning before relying on SDR50, SDR104, DDR50, or HS200
   modes.

### FIFO offset

The data FIFO sits at a fixed offset that varies by IP revision /
integration:

- `0x100`: very old DWC_mobile_storage builds.
- `0x200` (default): Rockchip RK33xx/RK35xx, StarFive JH7110.
- `0x400`: some Allwinner integrations.

Use `DwMmc::new_with_fifo_offset` if your SoC differs from the default.

## Testing

From this crate directory:

```bash
cargo fmt --check
cargo test
cargo clippy --all-features -- -D warnings
```

In this workspace, prefer the project `xtask` flow for final validation:

```bash
cargo fmt
cargo xtask clippy --package dwmmc-host
```

## License

Licensed under the Apache License, Version 2.0.