rust-embedded/rust-raspberrypi-OS-tutorials

Question - help, porting an EMMC driver over to `rust`

nihalpasham opened this issue · 1 comments

Hi,

Firstly, thank you for putting this repo together. Its been quite useful. I just wanted to check to see if someone's already solved this problem.

Context: I'm working on porting a SD/EMMC driver written in C, managed to put together an initial implementation but I seem to have hit a roadblock. I assumed the rpi4 would have sufficient documentation but I guess not (at least when it comes to the onboard SD/EMMC controllers). Rpi4 has 3 of them usually referred to as

  • 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.
  • EMMC2: the 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.

So, the port works so far in as 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 a CMD to an SDcard in the on-board microSD slot.
  • I get a command timeout and command CRC error almost immediately.

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), assuming this was going to be a straightforward port but it didn't quite turn out that way (I'm quite sure I'm missing something). So, I'm hoping someone here has more insight into the rpi and its inner workings; if yes, would appreciate it if you provide some pointers on what I'm missing here.

Here's the output you should get when you compile and run the impl on real hardware (i.e. rpi4)

[    0.001629] EMMC: reset card.

[W   0.001984] EMMC_CONTROL1, from emmc_reset2: 0
[    0.002550] EMMC: setting clock speed to 400000.

[    0.003124] Divisor = 105, Freq Set = 396825

[W   0.003653] EMMC_CONTROL1, from emmc_set_clock1: 944391
[W   0.004291] EMMC_CONTROL1::CLK_STABLE, from emmc_set_clock: 1
[W   0.005007] EMMC_CONTROL1, from emmc_set_clock2: 944391
[W   0.005657] from emmc_set_clock, set_clock_success
[W   0.006242] from_emmc_reset_card, interrupt: 0x00000000
[W   0.006881] from_emmc_reset_card, interrupt_en: 0x00000000
[W   0.007552] from_emmc_reset_card, interrupt_mask: 0x00000000
[W   0.008246] from_emmc_reset_card, interrupt_en: 0x37ff7fff
[W   0.008918] from_emmc_reset_card, interrupt_mask: 0x37ff7fff
[W   0.009611] from_emmc_reset_card, interrupt: 0x00000140
[W   0.010250] from emmc_reset, just before emmc_send_command:
[W   0.010933] from_emmc_send_command1, false
[W   0.011432] from_emmc_send_command2
[W   0.011854] from emmc_wait_for_command, cmd_inhibit: false
[W   0.012525] from emmc_wait_for_command1, interrupt: 0x00000140
[W   0.013239] from emmc_wait_for_command1, int_error_mask: 0x017e8000
[W   0.014009] from emmc_wait_for_command1, interrupt & mask: 0x00000000
[W   0.014800] from emmc_wait_for_command, cmd_inhibit: false
[W   0.015471] from emmc_wait_for_command2, interrupt: 0x00000140
[W   0.016186] from emmc_wait_for_command2, int_error_mask: 0x017e8000
[W   0.016955] from emmc_wait_for_command2, interrupt & mask: 0x00000000
[W   0.017746] from_emmc_wait_for_command, td: 0
[    0.018277] EMMC: Sending command, CMD_NAME: "GO_IDLE_STATE", CMD_CODE: 0x00000000, CMD_ARG: 0x00000000

[W   0.019448] from_emmc_send_command_p, interrupt: 0x00000100
[W   0.020130] from_emmc_send_command_p, before wait_for_interrupt

[W   0.020867] from_emmc_wait_for_interrupt, interrupt_en: 0x37ff7fff
[W   0.021625] from_emmc_wait_for_interrupt, interrupt_mask: 0x37ff7fff
[W   0.022405] from_emmc_wait_for_interrupt, interrupt: 0x00038100
[W   0.023131] from_emmc_wait_for_interrupt, mask: 0x00000001, t_mask: 0x017e8001, int_error_mask: 0x017e8000
[W   0.024322] from_emmc_wait_for_interrupt, interrupt & t_mask: 0x00028000
[W   0.025146] from_emmc_wait_for_interrupt: td: 0
[W   0.025698] from_emmc_wait_for_interrupt, interrupt_en: 0x37ff7fff
[W   0.026456] from_emmc_wait_for_interrupt, interrupt_mask: 0x37ff7fff
[W   0.027236] from_emmc_wait_for_interrupt, ival: 0x00038100
[W   0.027908] from_emmc_wait_for_interrupt, ival & INT_CMD_TIMEOUT: 0x00010000
[W   0.028775] from_emmc_wait_for_interrupt, ival & INT_DATA_TIMEOUT: 0x00000000
[    0.029653] EMMC: Wait for interrupt MASK: 0x00000001, STATUS: 0x000f0001, iVAL: 0x00038100, RESP0: 0x00000000

[W   0.030902] from emmc_reset, emmc_send_command resp: EMMC_TIMEOUT
[    0.031646] from emmc_init, emmc_reset_card: EMMC_TIMEOUT
[    0.032307] failed to initialize EMMC2
[    0.032763] rpi4 version 0.1.0
[    0.033129] Booting on: Raspberry Pi 4
[    0.033584] Architectural timer resolution: 18 ns
[    0.034159] Drivers loaded:
[    0.034494]       1. BCM GPIO
[    0.034852]       2. BCM PL011 UART
[    0.035275] Chars written: 3287
[W   0.035656] wait duration smaller than architecturally supported, skipping
[    0.036499] waiting for 1 second
[    1.037147] 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

Forgot to mention, you can compile, build and extract the kernel binary with a single command -

cargo xtask build rustBoot-only rpi4 

which you can then drop onto an SD card.