Mobile Storage Host Controller. Power on/off state is ignored when reading from SD card

0

I'm afraid my question could be board- or SoC-specific. Anyway, I hope someone has experience in it.

SoC: RK3308 (board: ROCK Pi S). I read from SD card in bare-metal environment: AArch64 EL3, DDR initialized, MMU/GIC disabled.

Reading a block from SD card. I assumed, that BootROM will do all initialization for me and SD card will be ready for use when my code gains control. It is. I can successfully read from the card - FIFO gets filled. My question is the following:

RK3308 Technical Reference Manual Part 2, Chapter 3 describes the Mobile Storage Host Controller.

SDMMC_PWREN Power-enable register

Bit [0]: power_enable. Power on/off switch for the card. Once power is turned on, firmware should wait for regulator/switch ramp-up time before trying to initialize card.

1'b0: power off 1'b1: power on

Bit values output to card_power_en port

Also,

SDMMC_CMD Command register

Bit [15] send_initialization

1'b0: do not send initialization sequence (80 clocks of 1) before sending this command

1'b1: send initialization sequence before sending this command After power on, 80 clocks must be sent to card for initialization before sending any commands to card. Bit should be set while sending first command to card so that controller will initialize clocks before sending command to card. This bit should not be set for either of the boot modes (alternate or mandatory)

The problem is when my code gains control from the BootROM code, SDMMC_PWREN[0] = 0 (power off). But reads from the card are successful. I tried setting SDMMC_PWREN[0] = 1, I also tried setting SDMMC_CMD[15] = 1 for the 80-clocks initialization sequence before the first command after power up. This all doesn't seem to have any effect. In all cases read from the card (CMD17) is successful. However, CMD0/CMD8 sequence fails with response timed out error if I try to issue these commands after setting power_enable=1.

Register values when my code gains control:

SDMMC_CTRL    0x00000000
SDMMC_PWREN   0x00000000
SDMMC_CLKDIV  0x00000000
SDMMC_CLKSRC  0x00000000
SDMMC_CLKENA  0x00000001
SDMMC_TMOUT   0xFFFFFF40
SDMMC_CTYPE   0x00000001
SDMMC_BLKSIZ  0x00000200
SDMMC_BYTCNT  0x00000200
SDMMC_INTMASK 0x00000000
SDMMC_CMDARG  0x00001040
SDMMC_CMD     0x20002351
SDMMC_RESP0   0x00000000
SDMMC_RESP1   0x2023BC16
SDMMC_RESP2   0x53443030
SDMMC_RESP3   0x9C534F55
SDMMC_MINTSTS 0x00000000
SDMMC_RINTSTS 0x0000000C
SDMMC_STATUS  0x03000101
SDMMC_FIFOTH  0x307F0080
SDMMC_CDETECT 0x00000000
SDMMC_WRTPRT  0x00000000
SDMMC_TCBCNT  0x00000000
SDMMC_TBBCNT  0x00000000
SDMMC_DEBNCE  0x00FFFFFF
SDMMC_HCON    0x04C434C1
SDMMC_UHS_REG 0x00000000
SDMMC_RSTN    0x00000001

I do not understand the actual purpose of SDMMC_PWREN register and how/when to use it. Any details will be highly appreciated.

My test code is very simple:

        . . .
.probe_device:

        str x30, [sp, -16]!
        bl .serial__send_string
        ldr w11, [x2, SDMMC_CDETECT]
        tbnz w11, 0, .device_absent
        adr x0, .msg__present
        bl .serial__send_string

        ldr w10, [x2, SDMMC_CMD]      ; BootROM leaves SDMMC_CMD register
        orr w10, w10, 1 shl 31        ; pre-filled for CMD17, so I just
        str wzr, [x2, SDMMC_CMDARG]   ; change block address to 0
        str w10, [x2, SDMMC_CMD]      ; to read from the first block
        ldr w11, [x2, SDMMC_RINTSTS]
        tbz w11, 2, $ - 4             ; wait until command completed
        . . .
assembly
arm64
bare-metal
sdmmc
asked on Stack Overflow Mar 10, 2021 by Alexander Zhak • edited Mar 11, 2021 by Alexander Zhak

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0