raspberrypi/documentation

Help in porting an EMMC driver (for the rpi4) using `rust`

nihalpasham opened this issue · 1 comments

Hi,

New here (and to the raspberry-pi). I seem to have hit a wall and am hoping someone can shed light on what I'm missing here.

  1. Rust impl of SD/EMMC driver -
  2. C impl of driver -

Context: I'm working on porting an SD/EMMC driver written in C, managed to put together an initial implementation (i.e. port) but I cant seem to get it to work. I assumed the rpi4 would have sufficient documentation but I guess not (at least when it comes to the onboard SD/EMMC controllers).

So, here's what I've been able to gather. The rpi4 has 3 of them, SD/EMMC modules on-board

  • SDHOST: this is accessible via GPIO pins but isn't connected to the onboard micro-SD slot.
  • EMMC: accessible via GPIO pins but we cant use GPIO to connect to the on-board micro-SD slot. Although this interface can be routed to the dedicated pins used by the EMMC2 controller.
  • EMMC2: is a new piece of HW (on the rpi4) that doesn't appear on the GPIOs i.e. its the default MMC controller with dedicated pins connecting it to the micro-SD slot.

I'm using EMMC for my impl. The port sort of works i.e. I can

  • get a stable clock, reset the EMMC controller etc.
  • but fails when attempting to perform a full initialization
  • more specifically, it fails when I issue the very first command GO_IDLE_STATE (to an SDcard placed in the on-board microSD slot).
  • I get a command timeout and a command CRC error almost immediately and
  • the status register shows command line (i.e. CMD_INHIBIT) is busy throughout.

For now, I'm relying on print-f style debugging; as I was hoping to avoid a full debugging workflow (i.e. JTAG and all; assumed this was going to be a straightforward port but it didn't quite turn out that way). So, I'm hoping someone here who has more insight into the rpi and its inner workings can provide some pointers on what I'm missing here.

Notes:

  • I haven't been able to find a working bare-metal (EMMC/EMMC2) driver impl for the rpi4. The C driver I'm using has been known to work on rpi (1, 2 and 3) but hasn't been tested on rpi4. I'm assuming there's some little detail I'm missing here.
  • Additionally, issue #1209 has some commentary on switching to the legacy EMMC controller (at mmio address 0x7e300000). I tried setting bit 1 of addr 0x7e2000d0 but that didn't do much i.e. I get the same result with or without this setting.
  • I noticed that all 4-bytes addressed at 0x7e2000d0 are set to 0xFFFFFFFF.

Build steps:
Clone the rustBoot repo; compile, build and extract the kernel binary with a single command as follows (assuming you have rust nightly and aarch64-unknown-none-softfloat toolchain installed).

cargo xtask build rustBoot-only rpi4

This should produce a bare-metal binary that can be dropped onto an SD card. Here's the output I get when I compile and run the impl on real hardware (i.e. an rpi4)

[    0.000025] EMMC: reset card.

[W   0.000104] EMMC_CONTROL1, from emmc_reset2: 0x00000000
[    0.000709] EMMC: setting clock speed to 400000.

[    0.001284] Divisor = 105, Freq Set = 396825

[W   0.001814] EMMC_CONTROL1, from emmc_set_clock1: 0x000e6907
[W   0.002495] EMMC_CONTROL1::CLK_STABLE, from emmc_set_clock: 1
[W   0.003210] EMMC_CONTROL1, from emmc_set_clock2: 0x000e6907
[W   0.003903] from emmc_set_clock, set_clock_success

[W   0.004500] from_emmc_reset_card, interrupt: 0x00000000
[W   0.005138] from_emmc_reset_card, interrupt_en: 0x00000000
[W   0.005809] from_emmc_reset_card, interrupt_mask: 0x00000000
[W   0.006503] from_emmc_reset_card, interrupt_en: 0x37ff7fff
[W   0.007175] from_emmc_reset_card, interrupt_mask: 0x37ff7fff
[W   0.007868] from_emmc_reset_card, interrupt: 0x00000140

[W   0.008518] from emmc_reset, just before emmc_send_command:
[W   0.009201] from_emmc_send_command1, issue APP_CMD: false
[W   0.009863] from_emmc_send_command2
[W   0.010284] from emmc_wait_for_command, cmd_inhibit: false
[W   0.010955] from emmc_wait_for_command1, interrupt: 0x00000140
[W   0.011670] from emmc_wait_for_command1, int_error_mask: 0x017e8000
[W   0.012439] from emmc_wait_for_command1, interrupt & mask: 0x00000000
[W   0.013231] from emmc_wait_for_command, cmd_inhibit: false
[W   0.013902] from emmc_wait_for_command2, interrupt: 0x00000140
[W   0.014617] from emmc_wait_for_command2, int_error_mask: 0x017e8000
[W   0.015386] from emmc_wait_for_command2, interrupt & mask: 0x00000000
[W   0.016177] from_emmc_wait_for_command, td: 0
[    0.016708] EMMC: Sending command, CMD_NAME: "GO_IDLE_STATE", CMD_CODE: 0x00000000, CMD_ARG: 0x00000000

[W   0.017879] from_emmc_send_command_p, interrupt: 0x00000100
[W   0.018561] from emmc_send_command_p, cmd_inhibit: false
[W   0.019210] from_emmc_send_command_p, before wait_for_interrupt

[W   0.019947] from_emmc_wait_for_interrupt, interrupt_en: 0x37ff7fff
[W   0.020705] from_emmc_wait_for_interrupt, interrupt_mask: 0x37ff7fff
[W   0.021485] from_emmc_wait_for_interrupt, interrupt: 0x00038100
[W   0.022211] from_emmc_wait_for_interrupt, mask: 0x00000001, t_mask: 0x017e8001, int_error_mask: 0x017e8000
[W   0.023403] from_emmc_wait_for_interrupt, interrupt & t_mask: 0x00028000
[W   0.024226] from emmc_wait_for_interrupt, cmd_inhibit: true
[W   0.024909] from_emmc_wait_for_interrupt: td: 0
[W   0.025461] from_emmc_wait_for_interrupt, interrupt_en: 0x37ff7fff
[W   0.026219] from_emmc_wait_for_interrupt, interrupt_mask: 0x37ff7fff
[W   0.026999] from_emmc_wait_for_interrupt, ival: 0x00038100
[W   0.027671] from_emmc_wait_for_interrupt, ival & INT_CMD_TIMEOUT: 0x00010000
[W   0.028538] from_emmc_wait_for_interrupt, ival & INT_DATA_TIMEOUT: 0x00000000
[    0.029416] EMMC: Wait for interrupt MASK: 0x00000001, STATUS: 0x000f0001, iVAL: 0x00038100, RESP0: 0x00000000

[W   0.030665] from emmc_reset, emmc_send_command resp: EMMC_TIMEOUT

[    0.031420] from emmc_init, emmc_reset_card: EMMC_TIMEOUT
[    0.032081] failed to initialize EMMC2
[    0.032537] rpi4 version 0.1.0
[    0.032903] Booting on: Raspberry Pi 4
[    0.033358] Architectural timer resolution: 18 ns
[    0.033933] Drivers loaded:
[    0.034269]       1. BCM GPIO
[    0.034626]       2. BCM PL011 UART
[    0.035049] Chars written: 3265
[W   0.035430] wait duration smaller than architecturally supported, skipping
[    0.036273] waiting for 1 second
[  1.036802] read 20 blocks: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
....
....
.... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[ 1.369945] waiting for 1 second

This is not a documentation issue, the forums are the best place for this sort of question.