summaryrefslogtreecommitdiff
path: root/documentation/6.components/device-driver/sdio/sdhci.md
blob: ddd7526c28f7c0a35f278ff22b62e21f4a773f3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
@page page_device_sdhci 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 @ref page_device_sdio |

**`vmmc` / `vqmmc`**: power/UHS paths call **`sdio_regulator_*`** when **`RT_USING_REGULATOR`** is on—see @ref page_device_sdio_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: @ref page_device_sdio_dm. |

## 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`**.

## `struct rt_sdhci_ops` (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 (`dev_sdhci_dm.c` / `dev_sdhci_dm.h`)

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

- `components/drivers/sdio/dev_sdhci.c`, `dev_sdhci_host.c`, `dev_sdhci_dm.c`, `host/sdhci-pci.c`
- `components/drivers/sdio/SConscript`
- `components/drivers/include/drivers/dev_sdhci.h`, `dev_sdhci_host.h`, `sdio/dev_sdhci_dm.h`
- @ref page_device_sdio
- @ref page_device_sdio_dm
- @ref page_device_sdio_regulator
- @ref page_device_pci