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]

Reply via email to