uSDHC bare metal driver

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

uSDHC bare metal driver

2,055 Views
ogj
Contributor IV

I am writing a bare metal uSDHC driver for the iMX6Q based on the SDK version and am having an issue with reading (haven't tried writing yet). I can send commands to the SDHC card and get the proper responses back, so sending commands is not an issue. I believe the code for setting up for the read is also correct including the setup for the adma2. I'm using a CMD17 (read single block) to try to read the MBR (sector 0) of a known good (16GB) SDCARD using a known good OTS board from Boundary Devices. I initialize the read buffer (512 bytes) with the value 0x5a to detect what is read. This is what I get back (buffer starts at 0x104098a0):

ogj_0-1610410722730.png

 

The 55 aa at the end is correct and some of the 00 bytes may be as well. Since none of the bytes are 0x5a, 512 bytes were read from somewhere.

Below is what the data should be:

ogj_1-1610410724065.jpeg

 

Here are the registers just before sending the command:

ogj_2-1610410724115.png

 

Below are the registers after the read (note that INT_STATUS has already been cleared):

ogj_3-1610410724162.png

 

In my setup I use three adma2 descriptors. The first one covers from the beginning of the buffer until the start of the first cache line. The read data is read into a separate uncached buffer (in DRAM), then copied into the real buffer. The second one is used to read in the rest of the data down to the last full 32 bytes (last full cache line). This data is read into physical memory, then the virtual memory is invalidated forcing the cache to be re-loaded. The third descriptor is used to read anything left over, and acts like the first one.

 The adma2 descriptors are set up (in uncached DRAM) in this example such that, the buffer was started on a cache line so only two of the descriptor are used (third one not needed). There doesn’t appear to be any descriptor errors (AMDA_ERR_STATUS = 0), and the addresses of the 2 descriptors used are 0x184000C0, and 0x184000C8. The ADMA_SYS_ADDR reg shows 0x184000D0 which shows that the 2 descriptors used were executed. No errors are reported in the INT_STATUS reg.

It has the appearance of some kind of timing issue or data not ready, card can send data fast enough (@25MHz). Both CIHB and CDIHB are checked as you can see in the attached code.

Any ideas where to start looking for errors as to why the data is incorrect?

 

Labels (1)
Tags (1)
0 Kudos
Reply
8 Replies

1,588 Views
npashi
Contributor III

Hi,

I'm working on a bare-metal uSDHC driver (written in rust) for the i.MX8M Nano and seem to be hit a technical snag. I was wondering if you'd be open to sharing your implementation as a quick reference or provide some pointers on what I might be missing.

-Nihal

Tags (1)
0 Kudos
Reply

1,575 Views
ogj
Contributor IV

What problem are you having?

0 Kudos
Reply

1,568 Views
npashi
Contributor III

When my uSDHC driver issues an sd-command (anything apart from a CMD0), I get a response but it contains errors and decoding the contents of interrupt status register for details gives me

  • Command index error: which means the response did not contain the command index the host sent.
  • Command end bit error: which occurs when detecting that the end field of a command response is 0.

I have double-checked the implementation (many times) but I cant seem to figure out what I am missing.

A quick overview of my implementation:

  1. enable uSDHC clock - (this includes enabling clock gates and clock-roots for the usdhc2 peripheral).
  2. set mux config for uSDHC2.
  3. initialize uSDHC. It fails here (more precisely - upon sending a CMD8, it returns the above error)
    1. from the debug log below, you can see that (among other things) we are able to reset the sd-host circuit and get a stable sd-clock

Here is the full debug log

-Nihal

0 Kudos
Reply

1,550 Views
ogj
Contributor IV

My first guess is your clock is too fast. During card identification, the card clock cannot exceed 400KHz. In my case I use 3.3V signaling and stick with cards not exceeding 64 GB. After card ID is done, the clock rate can be boosted to whatever (I use 50 MHz).

Send me a PM and I'll send you my driver.

0 Kudos
Reply

1,515 Views
npashi
Contributor III

During uSDHC initialization, I use an identification clock of 400Khz and a 3.3 volts setting. I'm currently testing an 8GB card.

Here is the list of steps in my initialization routine

  1. Reset the entire host controller by setting the RSTA bit. Just to be sure I also set the RSTC + RSTD bits
  2. set sd-clock to 400khz i.e. the prescaler field in the SYS_CTRL register is set to 0x20 and divisor field is set to 0xf.
  3. Note - I'm using PLL1_DIV2 as my source root clock i.e. SYSTEM_PLL1_DIV2_CLK or 800Mhz/2 for uSDHC2. (note: I have not configured the source clock, I use it as-is. I assume this is OK).
  4. enable relevant IRQ bits via the interrupt status enable register
  5. set the initialize active field in SYS_CTRL register and wait until it is cleared
  6. set the little-endian and four-bit wide fields in the PROT_CTRL register
  7. set data timeout value field in the SYS_CTRL to its maximum i.e. 0xf
  8. at this point, I assume the card is initialized
  9. and send CMD0 wait 2ms and send a CMD8
  10. It fails to initialize after CMD8 is sent. Looking at the command completion bit in the interrupt status register, we can conclude that a response was received but it contains errors.

For pinmux settings - I use the values from the imx8mn nano device-tree, as listed below

  • clock line     - <0xd4 0x33c 0x00 0x00 0x00 0x190>
  • cmd line       - <0xd8 0x340 0x00 0x00 0x00 0x1d0>
  • data0 line     - <0xdc 0x344 0x00 0x00 0x00 0x1d0>
  • data1 line     - <0xe0 0x348 0x00 0x00 0x00 0x1d0>
  • data2 line     - <0xe4 0x34c 0x00 0x00 0x00 0x1d0>
  • data3 line     - <0xe8 0x350 0x00 0x00 0x00 0x1d0>
  • cd line          - <0x38 0x2a0 0x00 0x01 0x00 0x1d0>;
  • reset line      - <0xec 0x354 0x00 0x05 0x00 0x41>;

with some modifications.

  • I have applied a drive strength of 6 instead of 1.
  • the reset line is set is set to GPIO output mode before setting the mux-modes and pad config for all the other pins. Once done, we clear it. If this is not done, we get a sd-timeout error instead of sd-command errors.
0 Kudos
Reply

2,048 Views
ogj
Contributor IV

The board I'm using has been in production several years so I think it's solid. I'm using the same pin settings that the company uses in their linux distro:

PAD_CTL_PUS_100K_PU |
PAD_CTL_ODE_DISABLED |
PAD_CTL_SPEED_MED |
PAD_CTL_DSE_38ohm |
PAD_CTL_HYS_ENABLED |
PAD_CTL_SRE_FAST;

I think the problem has to do more with the adma and/or cache issues. In the example above, the first adma descriptor is:

   LEN:   32

   ATT:  0x21

   ADDR:  0x18400080  (uncached DRAM)

 

The second one is:

   LEN:  480

   ATTR:  0x23

   ADDR:  0x104098C0

I don't flush the descriptors before the read because they are in uncached memory. My system is flat-mapped - virtual address = physical addr.

Right after the read, the 32 bytes in the uncached memory read all zeros (before the read all bytes were 0x5a) so something happened. After the read, the data from uncached memory is copied into the beginning of the data buffer (at 0x104098A0), then a dcache_invalidate is done over the part of the buffer in cached memory (starting at 0x1040_98C0) to update the virtual memory. However the data is already wrong at this point.

Don't know where to look for a solution.

 

0 Kudos
Reply

2,042 Views
igorpadykov
NXP Employee
NXP Employee

>The board I'm using has been in production several years so I think it's solid.

 

in such case one can try the same test in verified (working) software : uboot or

linux. For ADMA there is ERR004536 erratum

Chip Errata for the i.MX 6Dual/6Quad and i.MX 6DualPlus/6QuadPlus - IMX6DQCE

 

Best regards
igor

0 Kudos
Reply

2,053 Views
igorpadykov
NXP Employee
NXP Employee

Hi ogj

 

>Any ideas where to start looking for errors as to why the data is incorrect?

 

in general, it may be due to signal integrity issues as described for example on

https://community.nxp.com/t5/i-MX-Processors/eMMC-8GB-to-4GB-crash-on-linux-yocto-boot/m-p/373231

 

Best regards
igor

0 Kudos
Reply