[U-Boot] gen_atmel_mci freeze on at91sam9g45

eric cariat cariat.eric at gmail.com
Tue Dec 7 18:23:28 CET 2010


Hi Rheinard,

2010/12/5 Reinhard Meyer <u-boot at emk-elektronik.de>

> Dear eric cariat,
> > I'm currently working on a custom board with an at91sam9g45 : I followed
> the
> > instruction in README.atmel_mci. In U-boot, if I use the command mmcinfo,
> > the system hang. The uSD is working correctly with at91bootstrap and
> linux.
> > In U-boot everything seems fine, the card exchange a few command and
> > response, and then freeze on the command 55 51 (the first command that
> will
> > receive some data on DAT0 ) :
> >
> > U-Boot> mmcinfo
> > mci: bus_hz is 133333333, setting clock 150000 Hz, block size 512
> "setting clock" should read "requesting clock". 150000 is the clock a MMC
> card
> should be inquired with. Unfortunately the minimum clock obtainable is
> 260416,
> but that did not cause problems with SD cards so far...
> > mci: setting clock 260416 Hz, block size 512
> So the software sets it to the minimum-.
> > mci: bus_hz is 133333333, setting clock 0 Hz, block size 512
> > mci: setting clock 260416 Hz, block size 512
> > mci: bus_hz is 133333333, setting clock 260416 Hz, block size 512
> > mci: setting clock 260416 Hz, block size 512
>
> First make sure the clock values are correct: Assuming the system is
> running
> at 400MHz, this would make sense if the MCI is clocked by system clock / 3.
> Then the minimum clock would indeed be 260416.
>

Clock values are OK (running from 12 Mhz like the 9g45 eval kit), system
running at 400 Mhz.
260416 Hz is exactly what I probe on the hardware.


>
> Is the 9G45 (H)MCI is really identical to the 9260 MCI or are there subtle
> differences?
>

I checked the datasheet of the 9260, most register seems to be the same...
I suppose you have been testing the gen_atmel_mci on the 9260 ?

>
> > But if I add some printf to debug , just after the
> > mci_data_op=mci_data_read() in gen_atmel_mci, then everything is OK and I
> > can now use the uSD without any problem.
> > Here is where I add the printf, so uSD is correctly handled :
> >
> > diff -crbN u-boot-2010.09.orig/drivers/mmc/gen_atmel_mci.c
> > u-boot-2010.09/drivers/mmc/gen_atmel_mci.c
> > *** u-boot-2010.09.orig/drivers/mmc/gen_atmel_mci.c    2010-09-28
> > 23:20:55.000000000 +0200
> > --- u-boot-2010.09/drivers/mmc/gen_atmel_mci.c    2010-12-04
> > 17:52:59.092770689 +0100
> > ***************
> > *** 252,257 ****
> > --- 252,258 ----
> >               while (!status && word_count < (sys_blocksize / 4)) {
> >                   status = mci_data_op(mci, &dummy,
> >                       error_flags);
> > +                 printf("status=%x\n",status);
> >                   word_count++;
> >               }
> >               if (status) {
> >
>
> Have you tested whether a udelay() serves the same purpose? It would seem
> that there is
> an issue when mci_data_op() is called too frequently. However, quite the
> same code exists
> a few lines above and it did not hang there.
>
>
I added a udelay(1) and udelay(50) -> it freeze
If I put a udelay(100) -> everything is OK (same effect as printf)


> Is your data cache on?
>

I suppose it is enabled by default, so I added #define
CONFIG_SYS_NO_CP15_CACHE in my config file -> but that still freeze

>
> There are no timeouts coded in mci_data_read() and mci_data_write(), maybe
> it would be good
> to add some...
>
> I also cannot rule out that pre-initialisation of the MCI by the bootstrap
> code could leave
> some registers with values that the gen_atmel_mci driver does not reset.
> But then, a printf
> would unlikely fix the problem.
>
> Patches are always welcome ;)
>
> Best Regards,
> Reinhard
>
>
My observation are the following :

It seems that we are trying to read too many data byte : for ACMD 51 : the
data reply is not a full 512 bytes data packet, but only 8 bytes len
(checked with oscillo). Actually when in function mci_send_cmd() with ACMD
51, we first read the 8 "useful" byte ... then we try to "fill the rest of
block" => we try to read 512 - 8 = 504 more bytes  (which never comes on the
DAT0 )
as there are no more data we should exit from mci_data_read() with a timeout
error, but this never happen (I have to check error_flags about that)

Doing a pause or printf in the while change the RXRDY flag (set to 1) and so
we exit from the while without any error... ( I could not understand why ?
). It seems that when we don't read the correct number of byte, the MCI
controller behave incorrectly (the status register seems to be incoherent)

Actually the driver set a block len of 512 byte only once (at
initialization) in the mode register (mr) in gen_atmel_mci:mci_set_mode().
So I suppose we need to change dynamically the block len for each command
(most command will use the 512 byte data block reply, but some (like ACMD51)
are using a specific len -> I think we don't need to change the block len in
the SDCard see comment [1] below )

So I made the following change, ( just for information ) :

diff -crbN u-boot-2010.09.orig/drivers/mmc/gen_atmel_mci.c
u-boot-2010.09/drivers/mmc/gen_atmel_mci.c
*** u-boot-2010.09.orig/drivers/mmc/gen_atmel_mci.c    2010-09-28
23:20:55.000000000 +0200
--- u-boot-2010.09/drivers/mmc/gen_atmel_mci.c    2010-12-07
18:14:05.956116190 +0100
***************
*** 174,179 ****
--- 174,180 ----
      u32 cmdr;
      u32 error_flags = 0;
      u32 status;
+     u32 mr;

      if (!initialized) {
          puts ("MCI not initialized!\n");
***************
*** 182,187 ****
--- 183,201 ----

      /* Figure out the transfer arguments */
      cmdr = mci_encode_cmd(cmd, data, &error_flags);
+     if (data)
+     {
+ #ifdef DEBUG
+         printf("data->blocksize = %d\n",data->blocksize);
+         printf(" mmc->write_bl_len = %d\n", mmc->write_bl_len);
+ #endif
+         /* get current mr register and change block size */
+         mr = readl(&mci->mr);
+         mr = mr & 0xffff;                   /* clear upper part */
+         mr = mr | (data->blocksize << 16);  /* set block size   */
+         writel( mr, &mci->mr);
+     }
+

      /* Send the command */
      writel(cmd->cmdarg, &mci->argr);
***************
*** 218,224 ****

          if (data->flags & MMC_DATA_READ) {
              mci_data_op = mci_data_read;
!             sys_blocksize = mmc->read_bl_len;
              ioptr = (u32*)data->dest;
          } else {
              mci_data_op = mci_data_write;
--- 232,239 ----

          if (data->flags & MMC_DATA_READ) {
              mci_data_op = mci_data_read;
!             /* sys_blocksize = mmc->read_bl_len; */
!             sys_blocksize = data->blocksize;
              ioptr = (u32*)data->dest;
          } else {
              mci_data_op = mci_data_write;

But this is not correct because it must be done only for specific command
(with a fixed data size  reply), Here, the "filling the rest of block" is
never used again -> the code is working using mmcinfo, rescan and fatls (I
d'ont need the printf or udelay anymore in the while loop), but
unfortunately If I remove all other debug information -> It freeze again !

So I suppose we have to modify the code for every command -> we need to know
if the data reply is a fixed size or if we have to fill the rest of loop (to
fill a 512 byte data packet). But the number of "data" byte reply for each
command is not really clear in the specification
("Simplified_Physical_Layer_Spec.pdf")
I don't know if there are some more documentation on that ...

I'm just thinking I have to check how this was done before gen_atmel_mci, in
an older U-Boot, maybe I can understand a little more...

I can see the gen_atmel_mci has been working on a V1.0 SDCARD :
http://www.mail-archive.com/u-boot@lists.denx.de/msg37774.html
so I checked with the V2.0 : I don't see any major difference (except a few
more register but SCR and ACMD51 are the same)

So I 'm not sure if I'm looking in the right direction ? am I missing
something about the length on data reply ?
just wanted to know what you think about all that ? any other advice ?

best regards,

Eric Cariat


For information I'm currently using an Sandisk 1 Gb uSD.


[1]  In
http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
pg 46 we can read for an other special function :
The block length is predefined to 512 bits and the use of SET_BLK_LEN
command is not necessary.
=> so we don't need to send BLK_LEN to the SDCard, but we need to inform the
at91 that the number of data will be 64 bytes, so it can calculate the CRC
and set it's flag according the new size.


More information about the U-Boot mailing list