Fishwaldo opened a new pull request, #19883:
URL: https://github.com/apache/nuttx/pull/19883
## Summary
An SD card is never switched out of default speed, so it runs at 25MHz when
almost every card made since 2006 will run at 50MHz. This adds the CMD6
switch
that the eMMC path beside it has performed for years, and measures 1.85x more
throughput on the same card as a result.
A `TODO` in `mmcsd_sdio.c` has asked for this since 2010:
```c
/* TODO: If wide-bus selected, then send CMD6 to see if the card supports
* high speed mode. A new SDIO method will be needed to set high speed
* mode.
*/
```
This implements it and removes the comment.
### Why the card has to be asked
Default speed and high speed are not simply clock rates the host may choose.
In the SD Physical Layer Specification they are bus speed modes, and a card
starts in default speed after identification. `SWITCH_FUNC` (CMD6) is the way
to change function group 1, *Access Mode*, from `0h` (default speed, 25MHz)
to
`1h` (high speed, 50MHz).
Until the card has accepted that switch it is specified only to 25MHz, so the
host cannot simply raise its clock and hope: a card that is not in high speed
timing may return corrupt data or fail transfers, and that is
indistinguishable
from a bad card.
### Why the card's answer is believed, not the command's
CMD6 returns R1 and then a 512-bit status block. Bits `379:376` report the
function *actually selected* for group 1. A card that cannot honour the
request
does not fail the command — it returns `Fh` in that field and stays where it
was. So the R1 response alone does not tell you whether the switch happened.
This code reads the status block and requires `1h` before reporting success.
The argument is:
```c
#define MMCSD_SWITCH_HIGHSPEED (0x80fffff1)
```
Bit 31 set makes it a switch rather than a query; `f` in a group's nibble
means
leave that group alone; group 1 gets function `1`. So: change access mode to
high speed, touch nothing else.
Bits `379:376` are the low nibble of byte 16 of the block, which is where the
code reads it.
### Why cards below version 1.10 are not asked
CMD6 was introduced in version 1.10 of the specification, and earlier cards
treat it as an illegal command. The version is already available in the SCR
register as `SD_SPEC`, so this decodes it alongside the bus width and CMD23
support already decoded there, and does not ask a card that predates the
command.
### Why a new clock rate rather than a flag
The host is clocked twice during initialization: once at the default transfer
rate before any switch can have happened, and again afterwards. A host that
could not tell those two apart would clock a card still in default speed at
50MHz, which is the out-of-specification case above. So a confirmed switch is
reported as a distinct rate, `CLOCK_SD_TRANSFER_4BIT_HS`, sent only to a host
that asked for high speed by reporting `SDIO_CAPS_SD_HS_MODE` — mirroring
`SDIO_CAPS_MMC_HS_MODE`, which the eMMC path already uses this way.
The enumerator is added last in `enum sdio_clock_e`, so no existing driver's
switch statement changes meaning, and no in-tree driver can receive the new
rate because none reports the new capability.
Every failure path stays where it is today, at the default rate: a card that
declines, a card too old to ask, a host that never asks, or a failed
transfer.
## Impact
`enum sdio_clock_e` gains a final enumerator and `sdio.h` gains one
capability
bit and the `SD_CMD6` encoding. `struct mmcsd_state_s` gains the SD
specification version decoded from the SCR.
**No existing driver changes behaviour.** The switch is attempted only for a
host reporting `SDIO_CAPS_SD_HS_MODE`, and no in-tree driver does.
Twenty-four
drivers switch on `enum sdio_clock_e` and twelve of those have no `default:`
case; the new enumerator is added last, and I compiled one of the twelve
(`mpfs_emmcsd.c`, via `icicle:opensbi`) to confirm no switch warning appears.
eMMC is untouched.
`Documentation/.../sdio.rst` now documents both high speed capabilities and
the
three transfer clock rates, including the requirement that a lower half
reporting the SD capability must handle the new rate distinctly.
## Testing
Host: macOS 26.5.1 (arm64), `riscv-none-elf-gcc` 15.2.0, Sphinx 6.2.1.
Documentation builds with no new warnings.
**Hardware**: ESWIN EIC7700 EVB (EIC7700X, 4 x RV64GC), whose Synopsys MSHC
driver adopts the capability in a following change. 8GB SDHC card.
The same card and the same board, with the host capability removed and
restored, is the whole argument.
**Without `SDIO_CAPS_SD_HS_MODE`** — the behaviour before this patch:
```
[CPU0] SD: 7.4 GiB at /dev/mmcsd1, 4 bits at 25 MHz default speed, 1 by DMA
and 0 by the buffer port
nsh> dd if=/dev/mmcsd1 of=/dev/null bs=65536 count=256
16777216 bytes (256 blocks) copied, 1468000 usec, 11160 KB/s
```
**With it**:
```
[CPU0] SD: 7.4 GiB at /dev/mmcsd1, 4 bits at 50 MHz high speed, 1 by DMA and
0 by the buffer port
nsh> dd if=/dev/mmcsd1 of=/dev/null bs=65536 count=256
16777216 bytes (256 blocks) copied, 792000 usec, 20686 KB/s
```
**1.85x**, from 11.2MB/s to 20.7MB/s, on an unchanged card. The card
switched on
the first ask, and the filesystem on it is intact afterwards:
```
nsh> mount -t vfat /dev/mmcsd1 /mnt
nsh> ls /mnt
/mnt:
big
u1.bin
c1
c2
c3
a
b
c
nsh> df -h
Filesystem Size Used Available Mounted on
vfat 7576M 34M 7541M /mnt
```
eMMC on the same board is unaffected and still reaches its own high speed
mode
through the pre-existing eMMC path:
```
[CPU0] eMMC: 29.1 GiB at /dev/mmcsd0, 8 bits at 52 MHz high speed, 1 by DMA
and 0 by the buffer port, boot partitions 2 x 4096 KiB
```
Not covered by test, and reasoned only: a card that declines the switch, and
a
card older than version 1.10. I have neither to hand.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]