RT-Thread RTOS
An open source embedded real-time operating system
SDHCI host controller

SDHCI (SD Host Controller Interface)

Requires device model. In **components/drivers/sdio/SConscript**, **dev_sdhci.c**, **dev_sdhci_dm.c**, and **dev_sdhci_host.c** are built only when **RT_USING_DM**, **RT_USING_SDIO**, and **RT_USING_SDHCI** are all enabled. Kconfig may list **RT_USING_SDHCI** under SDIO alone, but the SDHCI sources in this tree do not compile without DM.

**dev_sdhci.c** implements SDHCI 2.x/3.x/4.x on the shared MMC/SD stack. Types and register offsets: **drivers/dev_sdhci.h**; **struct rt_mmc_host** bridge: **drivers/dev_sdhci_host.h**.

Path DM needed? Notes
Platform **rt_sdhci_pltfm_*** Yes **dev_sdhci_dm.c**: **rt_dm_dev_iomap**, **rt_dm_dev_get_irq**, DT quirks
PCI **sdhci-pci.c** Yes **host/Kconfig** is under **RT_USING_DM && RT_USING_SDIO**
Custom host without SDHCI No (core only) **rt_mmcsd_host_ops** per SDIO / MMC core

**vmmc / vqmmc**: power/UHS paths call **sdio_regulator_*** when **RT_USING_REGULATOR** is on—see SDIO supplies (regulator).

Driver / BSP quick notes

Topic Guidance
**quirks / quirks2** Prefer DT-driven bits from **rt_sdhci_get_property** / **rt_sdhci_get_of_property**, then add SoC-only flags—wrong ADMA or DMA width quirks often show up only under load as CMD / data errors.
Order of init With DM, **rt_dm_dev_iomap / rt_dm_dev_get_irq** (or PCI BAR/IRQ) must be valid before **rt_sdhci_setup_host** reads capabilities and selects SDMA/ADMA/PIO.
Probe failure / remove Mirror **rt_sdhci_init_host** with **rt_sdhci_uninit_host** and **rt_sdhci_free_host** on error and on **remove**—leaving a registered IRQ or workqueue causes use-after-free on unplug.
UHS / 1.8 V **set_uhs_signaling**, **voltage_switch**, and tuning paths are board-sensitive; with regulator support, **sdio_regulator_set_vqmmc** must succeed.
Card detect DT **broken-cd**, **non-removable**, and **cap-*** must match the socket—wrong CD polarity or missing **non-removable** generates spurious detect storms or no card at all.
OFW Property names and capability flags: SDIO device model.

Layering

Piece Role
**struct rt_sdhci_host** Hardware state: **ioaddr**, **irq**, **quirks/quirks2**, **ops**, DMA flags, linked **struct rt_mmc_host *mmc**.
**struct rt_mmc_host** Core MMC/SD/SDIO view; embedded **rthost** (**struct rt_mmcsd_host**) is what **mmcsd_core** uses.
**struct rt_sdhci_ops** Optional MMIO overrides and SoC hooks (clock, bus width, reset, UHS, tuning, …).

Default MMIO access uses **rt_sdhci_readl / writel** (and 8/16-bit variants) when **ops->read_*/write_*** are not set.

Bring-up sequence (driver writer)

Typical order matches **rt_sdhci_set_and_add_host** in **dev_sdhci.c**:

  1. **rt_sdhci_alloc_host(dev, priv_size)** — allocates **rt_sdhci_host** plus tail **private** bytes; wires **mmc** and default **mmc_host_ops**.
  2. Fill **host->ioaddr**, **host->irq**, **host->hw_name**, optional **host->ops**, **quirks**, **dma_mask**, etc. (platform: via **rt_sdhci_pltfm_init**).
  3. **rt_sdhci_setup_host** — read HCI capabilities, OCR masks, choose SDMA/ADMA/PIO, host limits.
  4. **rt_sdhci_init_host** — timers, workqueues, IRQ **rt_hw_interrupt_install**, **rt_mmc_add_host**, card-detect enable. **rt_sdhci_set_and_add_host** wraps **setup_host + init_host**.

Teardown: **rt_sdhci_uninit_host**, **rt_sdhci_free_host**.

<tt>struct rt_sdhci_ops</tt> (selected callbacks)

Callback Typical use
**set_clock / set_bus_width / reset / set_uhs_signaling** Platform defaults in **dev_sdhci_dm.c** delegate to **rt_sdhci_set_clock**, **rt_sdhci_set_bus_width**, **rt_sdhci_reset**, **rt_sdhci_set_uhs**.
**read_* / write_*** Non-memory-mapped HCI (sparse IO) or endian fixups.
**irq** Vendor-specific interrupt demux before generic SDHCI handling.
**set_power**, **voltage_switch**, **hw_reset**, **card_event** Power / card-detect / eMMC HW reset integration.
**platform_execute_tuning** SoC-specific tuning when the generic CMD19 path is not enough.

Full list: **drivers/dev_sdhci.h**.

Quirks

**RT_SDHCI_QUIRK_*** and **RT_SDHCI_QUIRK2_*** in **dev_sdhci.h** document controller-specific workarounds (DMA width, ADMA, card-detect, HS200/DDR50, CMD23, preset values, …). Set them from **struct rt_sdhci_pltfm_data** or after **rt_sdhci_get_property** merges DT-driven bits.

Platform DM (<tt>dev_sdhci_dm.c</tt> / <tt>dev_sdhci_dm.h</tt>)

Only with **RT_USING_DM**. **rt_platform_device** probe should use these helpers instead of duplicating MMIO/IRQ mapping.

API Role
**rt_sdhci_pltfm_init(pdev, pdata, priv_size)** **rt_dm_dev_iomap(dev, 0)**, **rt_dm_dev_get_irq(dev, 0)**, **rt_sdhci_alloc_host**, assign **sdhci_pltfm_ops** or **pdata->ops**, copy **pdata->quirks**.
**rt_sdhci_get_property / rt_sdhci_get_of_property** Reads **sdhci,auto-cmd12**, **sdhci,1-bit-only**, **bus-width**, **broken-cd**, **no-1-8-v**, **clock-frequency**, **keep-power-in-suspend**, **wakeup-source** / **enable-sdio-wakeup**, and sets **quirks**, **quirks2**, **pm_caps**.
**rt_sdhci_pltfm_init_and_add_host** **pltfm_init** → **get_property** → **rt_sdhci_init_host**.
**rt_sdhci_pltfm_remove / rt_sdhci_pltfm_free** **rt_sdhci_uninit_host** and **rt_sdhci_free_host**.
**rt_sdhci_pltfm_clk_get_max_clock** **rt_clk_get_rate** on the platform **clk**.

**struct rt_sdhci_pltfm_data** carries **ops**, **quirks**, **quirks2**. **struct rt_sdhci_pltfm_host** holds **clk**, **clock**, **xfer_mode_shadow**, and trailing private data (**rt_sdhci_pltfm_priv**).

PCI glue

**components/drivers/sdio/host/sdhci-pci.c** (Kconfig: **RT_SDIO_SDHCI_PCI**, requires **RT_USING_DM** and **RT_USING_SDIO**) allocates the host with **rt_sdhci_alloc_host**, maps BAR0 via **rt_pci_iomap**, uses **pdev->irq**, **rt_pci_irq_unmask**, **rt_pci_set_master**, then **rt_sdhci_set_and_add_host**.

Registers and spec

**drivers/dev_sdhci.h** defines **RT_SDHCI_*** MMIO offsets and capability bits aligned with the SDHCI and SD Physical Layer documents. For behaviour beyond this tree, refer to the SD Host Controller Simplified Specification (SD Association).

See also