The purpose of this page (and related pages) is to capture useful information and observations about various SD drivers that exist in the Open Source community, notably Linux, but without documenting any specifics (e.g. source code examples). This will hopefully aid in a clean-room implementation of an SD driver for RISC OS.
Notes based on reading linux/drivers/mmc/host/sdhci.c and associated files. sdhci.c 20% complete.
HC = Host Controller
0 Resets not honoured until we provide a clock SDHCI_QUIRK_CLOCK_BEFORE_RESET
1 Really supports DMA but caps bits lie SDHCI_QUIRK_FORCE_DMA
2 Doesn't like being reset when there's no card SDHCI_QUIRK_NO_CARD_NO_RESET
3 Doesn't like clearing the power register before being changed SDHCI_QUIRK_SINGLE_POWER_WRITE
4 Needs command data reset on each ios change due to flaky internal state SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS
5 Broken DMA engine SDHCI_QUIRK_BROKEN_DMA
6 Broken ADMA engine SDHCI_QUIRK_BROKEN_ADMA
7 Needs DMA addresses to be 32 bit aligned SDHCI_QUIRK_32BIT_DMA_ADDR
8 Needs DMA chunks to be a multiple of 32 bits SDHCI_QUIRK_32BIT_DMA_SIZE
9 Needs ADMA chunks to be a multiple of 32 bits SDHCI_QUIRK_32BIT_ADMA_SIZE
10 Have to reset after every request to stay stable SDHCI_QUIRK_RESET_AFTER_REQUEST
11 Can't cope with simulataneous voltage and power writes SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER
12 Provides broken timeout value for transfers SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
13 Has problem with buffer bits in PIO transfers < 4 bytes (eg JMicron JMB38x) SDHCI_QUIRK_BROKEN_SMALL_PIO
14 Doesn't provide a transfer-complete IRQ if not busy SDHCI_QUIRK_NO_BUSY_IRQ
15 Can't reliably detect cards SDHCI_QUIRK_BROKEN_CARD_DETECTION
16 Write protect state inverted SDHCI_QUIRK_INVERTED_WRITE_PROTECT
17 Clock management non-standard SDHCI_QUIRK_NONSTANDARD_CLOCK
18 Needs delay for PIO transfers (doesn't like them fast) SDHCI_QUIRK_PIO_NEEDS_DELAY
19 Loses signal/IRQ enable states over reset - have to restore afterwards SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET
20 Needs forcing of block size to be 2048 bytes SDHCI_QUIRK_FORCE_BLK_SZ_2048
21 Can't do multi-block transfers SDHCI_QUIRK_NO_MULTIBLOCK
22 Can only do 1 bit data transfers SDHCI_QUIRK_FORCE_1_BIT_DATA
23 Needs 10ms delay between power and clock SDHCI_QUIRK_DELAY_AFTER_POWER
24 SDCLK used instead of TMCLK for data timeouts SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
25 Capability reports wrong base clock SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN
26 Can't support End Attribute in NOP ADMA descriptor SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
27 No device capabilities register. Need to be faked up by host SDHCI_QUIRK_MISSING_CAPS
28 Multiblock transfers stopped with ACMD12 SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12
29 No HISPD bit field for HI-SPEED SD cards SDHCI_QUIRK_NO_HISPD_BIT
30 ADMA descriptors with length 0 are treated incorrectly SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
31 Read-only detection using the SDHCI_PRESENT_STATE register is not reliable SDHCI_QUIRK_UNSTABLE_RO_DETECT
Platform drivers (ie specific ARM boards with SDHCI ports) only set SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, SDHCI_QUIRK_FORCE_1_BIT_DATA, SDHCI_QUIRK_INVERTED_WRITE_PROTECT. Some SoCs have extra drivers for their own weirdnesses (Tegra does, OMAP doesn’t AFAICS) which may set more quirk bits.
0 Driver does its own card detection SDHCI_QUIRK2_OWN_CARD_DETECTION
0 SDIO FN0 outside the VS CCCR range are permitted MMC_QUIRK_LENIENT_FN0
1 Use current block size for byte mode MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
2 SDIO attached is missing CIA registers MMC_QUIRK_NONSTD_SDIO
3 Card will fail if SDIO bus clock gated MMC_QUIRK_BROKEN_CLK_GATING
4 Non-standard function interfaces on SDIO card MMC_QUIRK_NONSTD_FUNC_IF
5 Resistor for CD/DAT[3] should be disconnected MMC_QUIRK_DISABLE_CD
6 CMD38 broken for iNAND devices MMC_QUIRK_INAND_CMD38
7 Don't use CMD23 for regular multiblock MMC_QUIRK_BLK_NO_CMD23
8 Don't send 512 bytes in byte mode MMC_QUIRK_BROKEN_BYTE_MODE_512
0x0,SDHCI_DMA_ADDRESS/SDHCI_ARGUMENT2
0x4,SDHCI_BLOCK_SIZE
0x06,SDHCI_BLOCK_COUNT
0x08,SDHCI_ARGUMENT
0x0C,SDHCI_TRANSFER_MODE
0x0E,SDHCI_COMMAND
0x10,SDHCI_RESPONSE
0x20,SDHCI_BUFFER
0x24,SDHCI_PRESENT_STATE
0x28,SDHCI_HOST_CONTROL
0x29,SDHCI_POWER_CONTROL
0x2A,SDHCI_BLOCK_GAP_CONTROL
0x2B,SDHCI_WAKE_UP_CONTROL
0x2C,SDHCI_CLOCK_CONTROL
0x2E,SDHCI_TIMEOUT_CONTROL
0x2F,SDHCI_SOFTWARE_RESET
0x30,SDHCI_INT_STATUS
0x34,SDHCI_INT_ENABLE
0x38,SDHCI_SIGNAL_ENABLE
0x3C,SDHCI_ACMD12_ERR
0x3E,SDHCI_HOST_CONTROL2
0x40,SDHCI_CAPABILITIES
0x44,SDHCI_CAPABILITIES_1
0x48,SDHCI_MAX_CURRENT (4C-4F reserved for further max current)
0x50,SDHCI_SET_ACMD12_ERROR
0x52,SDHCI_SET_INT_ERROR
0x54,SDHCI_ADMA_ERROR
0x55-0x57,reserved
0x58,SDHCI_ADMA_ADDRESS
0x60-0xFB,reserved
0xFC,SDHCI_SLOT_INT_STATUS
0xFE,SDHCI_HOST_VERSION
To reset the controller:
To clear and set IRQs:
Read a block into a scatter/gather list. Perform read32s of SDHCI_BUFFER, but watch that the scatter/gather blocks may not be multiples of 4 bytes.
Save the local Linux interrupt state before and restore after the PIO loop
The same as above, but for writes. Uses write32 to SDHCI_BUFFER
(complete)