public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [U-Boot-Users] drivers MMCplus for at91sam9x
@ 2008-04-08 14:32 Pierre Savary
  2008-04-09 17:49 ` Jean-Christophe PLAGNIOL-VILLARD
  2008-04-10 22:31 ` Ken.Fuchs at bench.com
  0 siblings, 2 replies; 39+ messages in thread
From: Pierre Savary @ 2008-04-08 14:32 UTC (permalink / raw)
  To: u-boot

Hi,
I use a MMCplus 4GB on my design (with at91sam9260). It's wired with 4 bits.
Currently U-boot (1.1.5) can't detect correctly the MMC and so I can't read
my Linux kernel Image on the ext3 part of this MMC. If I use MMC 1GB, it
works.
Somebody have already use it? Or somebody have already implemented the
ext_csd and high capacity with MMC on another platform?
I need help. Thanks in advance to help me.

Regards,

Pierre

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-08 14:32 [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary
@ 2008-04-09 17:49 ` Jean-Christophe PLAGNIOL-VILLARD
  2008-04-10 10:32   ` Pierre Savary
  2008-04-10 22:31 ` Ken.Fuchs at bench.com
  1 sibling, 1 reply; 39+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2008-04-09 17:49 UTC (permalink / raw)
  To: u-boot

On 16:32 Tue 08 Apr     , Pierre Savary wrote:
> Hi,
> I use a MMCplus 4GB on my design (with at91sam9260). It's wired with 4 bits.
> Currently U-boot (1.1.5) can't detect correctly the MMC and so I can't read
1.1.5 is really old please update to the curent RC

Best Regards,
J.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-09 17:49 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2008-04-10 10:32   ` Pierre Savary
  0 siblings, 0 replies; 39+ messages in thread
From: Pierre Savary @ 2008-04-10 10:32 UTC (permalink / raw)
  To: u-boot

I have already test it but the version of the MMC driver is the same... And
it's very difficult for me to update my own version to the current.
Thanks for your help

Pierre

-----Message d'origine-----
De?: u-boot-users-bounces at lists.sourceforge.net
[mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de
Jean-Christophe PLAGNIOL-VILLARD
Envoy??: mercredi 9 avril 2008 19:49
??: Pierre Savary
Cc?: u-boot-users at lists.sourceforge.net; 'Pierre Ossman'
Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x

On 16:32 Tue 08 Apr     , Pierre Savary wrote:
> Hi,
> I use a MMCplus 4GB on my design (with at91sam9260). It's wired with 4
bits.
> Currently U-boot (1.1.5) can't detect correctly the MMC and so I can't
read
1.1.5 is really old please update to the curent RC

Best Regards,
J.

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao
ne
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-08 14:32 [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary
  2008-04-09 17:49 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2008-04-10 22:31 ` Ken.Fuchs at bench.com
  2008-04-11  8:26   ` Pierre Savary
  2008-04-11 15:48   ` Pierre Ossman
  1 sibling, 2 replies; 39+ messages in thread
From: Ken.Fuchs at bench.com @ 2008-04-10 22:31 UTC (permalink / raw)
  To: u-boot

Pierre Savary wrote:

> I use a MMCplus 4GB on my design (with at91sam9260). It's 
> wired with 4 bits.

The MCI controller on the AT91SAM926x family does not support
MMCplus.  There is no way to support a 4 bit bus, since the
MCI controller supports only 1 bit to an MMC chip.  The MCI will
support a 4 bit SD chip, but I don't think it can be tricked
into working with a 4 bit MMC chip (at least not via software
alone).

The only reasonable solution is switching to a processor that
has MMCplus support.  Maybe Atmel has been working on one?

> Currently U-boot (1.1.5) can't detect correctly the MMC and 
> so I can't read my Linux kernel Image on the ext3 part of this
> MMC. If I use MMC 1GB, it works.

Did you add MMCplus commands to the MCI U-Boot driver?  You can
do this to the extent that these changes do not require the MCI
controller to be MMCplus compliant.  (The MCI U-Boot driver I'm
aware of contains no MMCplus support.)

I suggest that you use the u-boot sources available via git.
You will get very little support (if any) from the U-Boot ML for
two reasons:

1) U-Boot 1.1.5 is extremely old and no one on the list is
   interested in supporting it.

2) The version of U-Boot 1.1.5 you are using almost certainly
   has an Atmel patch applied to it that was never accepted
   into the "official" U-Boot tree.

However, ...

It appears that someone is working on the AT91SAM9260 within the
official U-Boot (git) tree, since the ./include/configs/at91sam9260ek.h
file is there.  Other file structures like ./cpu/arm926ejs/* seem to be
missing some drivers and other support files.  I know that the
AT91SAM926x specific U-Boot files were never an official part of
U-Boot, but that appears to be changing.  It is my understanding
that the AT91SAM926x support is being completely reworked and
integrated with the AT91CAP9 code that has been present in git
for over a month already.  The AT91CAP9 and AT91SAM926x are very
similar and should share a lot of code.

Even if the AT91SAM9260 is not quite ready, the AT91CAP9 code
should provide the basis of a current U-Boot for the AT91SAM926x
family.

> Somebody have already use it? Or somebody have already implemented
> the ext_csd and high capacity with MMC on another platform?

I know that the MCI controller can be used to access 1GB MMCplus chips,
but I'm not sure it can be used to access MMCplus chips larger than
that.
There may be a special MMCplus command that will allow larger chips to
be accessed.  Try looking for it in your MMCplus chip's manual.

Sincerely,

Ken Fuchs

> -----Original Message-----
> From: u-boot-users-bounces at lists.sourceforge.net 
> [mailto:u-boot-users-bounces at lists.sourceforge.net] On Behalf 
> Of Pierre Savary
> Sent: Tuesday, April 08, 2008 09:32
> To: u-boot-users at lists.sourceforge.net
> Cc: 'Pierre Ossman'
> Subject: [U-Boot-Users] drivers MMCplus for at91sam9x
> 
> 
> Hi,
> I use a MMCplus 4GB on my design (with at91sam9260). It's 
> wired with 4 bits.
> Currently U-boot (1.1.5) can't detect correctly the MMC and 
> so I can't read
> my Linux kernel Image on the ext3 part of this MMC. If I use 
> MMC 1GB, it
> works.
> Somebody have already use it? Or somebody have already implemented the
> ext_csd and high capacity with MMC on another platform?
> I need help. Thanks in advance to help me.
> 
> Regards,
> 
> Pierre
> 
> 
> --------------------------------------------------------------
> -----------
> This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
> Register now and save $200. Hurry, offer ends at 11:59 p.m., 
> Monday, April 7! Use priority code J8TLD2. 
> http://ad.doubleclick.net/clk;198757673;13503038;p?http://java
.sun.com/javaone
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-10 22:31 ` Ken.Fuchs at bench.com
@ 2008-04-11  8:26   ` Pierre Savary
  2008-04-11 15:48   ` Pierre Ossman
  1 sibling, 0 replies; 39+ messages in thread
From: Pierre Savary @ 2008-04-11  8:26 UTC (permalink / raw)
  To: u-boot

Thanks a lot for your help.
In fact it's not really important to support MMCplus, the main is to support
MMC v4 where the extended CSD is introduced. Moreover, it's not really
important if only one wire is used... I want only be able to read on a MMC
4Gb with my U-boot...

Thanks in advance

Pierre

-----Message d'origine-----
De?: u-boot-users-bounces at lists.sourceforge.net
[mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de
Ken.Fuchs at bench.com
Envoy??: vendredi 11 avril 2008 00:31
??: pierre.savary at kerlink.fr
Cc?: u-boot-users at lists.sourceforge.net; drzeus-mmc at drzeus.cx
Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x

Pierre Savary wrote:

> I use a MMCplus 4GB on my design (with at91sam9260). It's 
> wired with 4 bits.

The MCI controller on the AT91SAM926x family does not support
MMCplus.  There is no way to support a 4 bit bus, since the
MCI controller supports only 1 bit to an MMC chip.  The MCI will
support a 4 bit SD chip, but I don't think it can be tricked
into working with a 4 bit MMC chip (at least not via software
alone).

The only reasonable solution is switching to a processor that
has MMCplus support.  Maybe Atmel has been working on one?

> Currently U-boot (1.1.5) can't detect correctly the MMC and 
> so I can't read my Linux kernel Image on the ext3 part of this
> MMC. If I use MMC 1GB, it works.

Did you add MMCplus commands to the MCI U-Boot driver?  You can
do this to the extent that these changes do not require the MCI
controller to be MMCplus compliant.  (The MCI U-Boot driver I'm
aware of contains no MMCplus support.)

I suggest that you use the u-boot sources available via git.
You will get very little support (if any) from the U-Boot ML for
two reasons:

1) U-Boot 1.1.5 is extremely old and no one on the list is
   interested in supporting it.

2) The version of U-Boot 1.1.5 you are using almost certainly
   has an Atmel patch applied to it that was never accepted
   into the "official" U-Boot tree.

However, ...

It appears that someone is working on the AT91SAM9260 within the
official U-Boot (git) tree, since the ./include/configs/at91sam9260ek.h
file is there.  Other file structures like ./cpu/arm926ejs/* seem to be
missing some drivers and other support files.  I know that the
AT91SAM926x specific U-Boot files were never an official part of
U-Boot, but that appears to be changing.  It is my understanding
that the AT91SAM926x support is being completely reworked and
integrated with the AT91CAP9 code that has been present in git
for over a month already.  The AT91CAP9 and AT91SAM926x are very
similar and should share a lot of code.

Even if the AT91SAM9260 is not quite ready, the AT91CAP9 code
should provide the basis of a current U-Boot for the AT91SAM926x
family.

> Somebody have already use it? Or somebody have already implemented
> the ext_csd and high capacity with MMC on another platform?

I know that the MCI controller can be used to access 1GB MMCplus chips,
but I'm not sure it can be used to access MMCplus chips larger than
that.
There may be a special MMCplus command that will allow larger chips to
be accessed.  Try looking for it in your MMCplus chip's manual.

Sincerely,

Ken Fuchs

> -----Original Message-----
> From: u-boot-users-bounces at lists.sourceforge.net 
> [mailto:u-boot-users-bounces at lists.sourceforge.net] On Behalf 
> Of Pierre Savary
> Sent: Tuesday, April 08, 2008 09:32
> To: u-boot-users at lists.sourceforge.net
> Cc: 'Pierre Ossman'
> Subject: [U-Boot-Users] drivers MMCplus for at91sam9x
> 
> 
> Hi,
> I use a MMCplus 4GB on my design (with at91sam9260). It's 
> wired with 4 bits.
> Currently U-boot (1.1.5) can't detect correctly the MMC and 
> so I can't read
> my Linux kernel Image on the ext3 part of this MMC. If I use 
> MMC 1GB, it
> works.
> Somebody have already use it? Or somebody have already implemented the
> ext_csd and high capacity with MMC on another platform?
> I need help. Thanks in advance to help me.
> 
> Regards,
> 
> Pierre
> 
> 
> --------------------------------------------------------------
> -----------
> This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
> Register now and save $200. Hurry, offer ends at 11:59 p.m., 
> Monday, April 7! Use priority code J8TLD2. 
> http://ad.doubleclick.net/clk;198757673;13503038;p?http://java
.sun.com/javaone
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao
ne
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-10 22:31 ` Ken.Fuchs at bench.com
  2008-04-11  8:26   ` Pierre Savary
@ 2008-04-11 15:48   ` Pierre Ossman
  2008-04-11 18:54     ` Ken.Fuchs at bench.com
  1 sibling, 1 reply; 39+ messages in thread
From: Pierre Ossman @ 2008-04-11 15:48 UTC (permalink / raw)
  To: u-boot

On Thu, 10 Apr 2008 17:31:24 -0500
Ken.Fuchs at bench.com wrote:

> Pierre Savary wrote:
> 
> > I use a MMCplus 4GB on my design (with at91sam9260). It's 
> > wired with 4 bits.
> 
> The MCI controller on the AT91SAM926x family does not support
> MMCplus.  There is no way to support a 4 bit bus, since the
> MCI controller supports only 1 bit to an MMC chip.

Untrue. The hardware interface is identical for 4-bit SD and 4-bit MMC.
So if that part isn't working, it's because you either have a bug or
because you lack 4-bit MMC support entirely in u-boot.

> I know that the MCI controller can be used to access 1GB MMCplus chips,
> but I'm not sure it can be used to access MMCplus chips larger than
> that.
> There may be a special MMCplus command that will allow larger chips to
> be accessed.  Try looking for it in your MMCplus chip's manual.

All compliant cards above 2 GB require special handling. They use a
system identical to SDHC (except for the init). Check the specs (this
part is publicly available) or the Linux code.

On Fri, 11 Apr 2008 10:26:52 +0200
"Pierre Savary" <pierre.savary@kerlink.fr> wrote:

> Thanks a lot for your help.
> In fact it's not really important to support MMCplus, the main is to support
> MMC v4 where the extended CSD is introduced. Moreover, it's not really
> important if only one wire is used... I want only be able to read on a MMC
> 4Gb with my U-boot...

Just to avoid some more confusion, MMCplus is the marketing name of the
full size MMC cards since version 4. So when discussing technical
attributes, the MMCplus/MMCmobile distinction is not that useful.
It's better to just call them v4. :)

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-11 15:48   ` Pierre Ossman
@ 2008-04-11 18:54     ` Ken.Fuchs at bench.com
  2008-04-12  9:28       ` Pierre Ossman
  0 siblings, 1 reply; 39+ messages in thread
From: Ken.Fuchs at bench.com @ 2008-04-11 18:54 UTC (permalink / raw)
  To: u-boot

Pierre Ossman wrote:

> Ken Fuchs wrote:
> 
> > The MCI controller on the AT91SAM926x family does not support
> > MMCplus.  There is no way to support a 4 bit bus, since the
> > MCI controller supports only 1 bit to an MMC chip.
> 
> Untrue. The hardware interface is identical for 4-bit SD and 
> 4-bit MMC.
> So if that part isn't working, it's because you either have a bug or
> because you lack 4-bit MMC support entirely in u-boot.

The manual for the AT91SAM926x processors clearly states that the
MCI controller supports MMC 2.2.  I asked Atmel whether this controller
could support 4 bits to an MMC 4.x chip and they said _no_.   The answer
is supposedly from their engineering group in France.

4-bit MMC support can easily be added to U-Boot, but the MCI
controller is MMC 2.2, and this standard only allows for a 1-bit
bus to MMC, so I'm not sure you can make it work at all.  Atmel will
definitely not help you, since they guarantee only MMC 2.2 compliance
with the AT91SAM926x processor family.  Has this changed?

Pierre Ossman omitted the following part of my original response:

> > The MCI will
> > support a 4 bit SD chip, but I don't think it can be tricked
> > into working with a 4 bit MMC chip (at least not via software
> > alone).

How does one program the MCI controller to send 4 bit (parallel) data
an MMC 4.x chip, with or without telling it that it is communicating
to a 4-bit SD chip?  The only way to get 4 bits of data out of the MCI
is to tell it that it is connected to a SD (1.0) chip.  If you program
the MCI to communicate with an MMC chip, it will send data out only on
the low order bit.

If you have a way around this, please let us know what it is.

> All compliant cards above 2 GB require special handling. They use a
> system identical to SDHC (except for the init). Check the specs (this
> part is publicly available) or the Linux code.

Both ends of the communication link must considered.  It may not be
sufficient that the MMC chip is MMC 4.x; The fact that the MCI
controller is only MMC 2.2 or SD 1.0 compliant, may or may not impact
this special handling.

Sincerely,

Ken Fuchs

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-11 18:54     ` Ken.Fuchs at bench.com
@ 2008-04-12  9:28       ` Pierre Ossman
  2008-04-15 10:18         ` Pierre Savary
       [not found]         ` <-6021840981243159212@unknownmsgid>
  0 siblings, 2 replies; 39+ messages in thread
From: Pierre Ossman @ 2008-04-12  9:28 UTC (permalink / raw)
  To: u-boot

On Fri, 11 Apr 2008 13:54:13 -0500
Ken.Fuchs at bench.com wrote:

> 
> The manual for the AT91SAM926x processors clearly states that the
> MCI controller supports MMC 2.2.  I asked Atmel whether this controller
> could support 4 bits to an MMC 4.x chip and they said _no_.   The answer
> is supposedly from their engineering group in France.
> 

What they answered was if Atmel would support such a solution, not if
the hardware would.

> 
> How does one program the MCI controller to send 4 bit (parallel) data
> an MMC 4.x chip, with or without telling it that it is communicating
> to a 4-bit SD chip?  The only way to get 4 bits of data out of the MCI
> is to tell it that it is connected to a SD (1.0) chip.  If you program
> the MCI to communicate with an MMC chip, it will send data out only on
> the low order bit.

You tell it to use all four bits. That's it. The setting isn't MMC/SD,
it's 1-bit/4-bit.

> Both ends of the communication link must considered.  It may not be
> sufficient that the MMC chip is MMC 4.x; The fact that the MCI
> controller is only MMC 2.2 or SD 1.0 compliant, may or may not impact
> this special handling.

It does not in the slightest. Remember that these controllers are
extremely dumb. The low level behaviour of the protocol hasn't changed
since the very first specs, so only software needs to be changed to
support even the newest features.

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-12  9:28       ` Pierre Ossman
@ 2008-04-15 10:18         ` Pierre Savary
  2008-04-15 16:51           ` Ken.Fuchs at bench.com
       [not found]         ` <-6021840981243159212@unknownmsgid>
  1 sibling, 1 reply; 39+ messages in thread
From: Pierre Savary @ 2008-04-15 10:18 UTC (permalink / raw)
  To: u-boot

Then my MMC 4GB works with my Linux kernel but if I can't load my kernel
(located on the first part of this MMC) ... it's not really interesting :(

So, somebody does already use MMC v4 with U-boot???

Thanks in advance

Pierre

-----Message d'origine-----
De?: u-boot-users-bounces at lists.sourceforge.net
[mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de Pierre
Ossman
Envoy??: samedi 12 avril 2008 11:28
??: Ken.Fuchs at bench.com
Cc?: pierre.savary at kerlink.fr; u-boot-users at lists.sourceforge.net
Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x

On Fri, 11 Apr 2008 13:54:13 -0500
Ken.Fuchs at bench.com wrote:

> 
> The manual for the AT91SAM926x processors clearly states that the
> MCI controller supports MMC 2.2.  I asked Atmel whether this controller
> could support 4 bits to an MMC 4.x chip and they said _no_.   The answer
> is supposedly from their engineering group in France.
> 

What they answered was if Atmel would support such a solution, not if
the hardware would.

> 
> How does one program the MCI controller to send 4 bit (parallel) data
> an MMC 4.x chip, with or without telling it that it is communicating
> to a 4-bit SD chip?  The only way to get 4 bits of data out of the MCI
> is to tell it that it is connected to a SD (1.0) chip.  If you program
> the MCI to communicate with an MMC chip, it will send data out only on
> the low order bit.

You tell it to use all four bits. That's it. The setting isn't MMC/SD,
it's 1-bit/4-bit.

> Both ends of the communication link must considered.  It may not be
> sufficient that the MMC chip is MMC 4.x; The fact that the MCI
> controller is only MMC 2.2 or SD 1.0 compliant, may or may not impact
> this special handling.

It does not in the slightest. Remember that these controllers are
extremely dumb. The low level behaviour of the protocol hasn't changed
since the very first specs, so only software needs to be changed to
support even the newest features.

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao
ne
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-15 10:18         ` Pierre Savary
@ 2008-04-15 16:51           ` Ken.Fuchs at bench.com
  0 siblings, 0 replies; 39+ messages in thread
From: Ken.Fuchs at bench.com @ 2008-04-15 16:51 UTC (permalink / raw)
  To: u-boot

Pierre Savary wrote:

> Then my MMC 4GB works with my Linux kernel but if I can't 
> load my kernel
> (located on the first part of this MMC) ... it's not really 
> interesting :(

> So, somebody does already use MMC v4 with U-boot???

Assuming a AT91SAM926x MCI controller:

Probably.  Given an MMC v2.x compliant U-Boot driver, it
would be relatively easy to add support for an MMC v4.x chip.
If there is an MMC v4.x compliant Linux driver, it could be
ported to U-Boot (Many, if not most, U-Boot drivers are ports
from the corresponding Linux driver.)  Alternatively, if both
an MMC v2.x compliant U-Boot driver and MMC v4.x compliant Linux
driver exist, the port would be trivial; just copy the MMC v4.x
Linux code into the corresponding places in the MMC v2.2 U-Boot
driver until it supports your MMC v4.x chip.

Such an MMC v4.x U-Boot AT91SAM926x MCI driver should be able to
support any v4.x MMC chip, at least via a one bit MMC bus.  (I
remain unconvinced that the AT91SAM926x MCI controller can support
a 4 bit MMC bus; only a working MCI driver using a 4 bit MMC bus
verified by a logic analyzer or similar compliance/debugging device
would be convincing enough.)

If the Linux AT91SAM926x MCI driver supports a 4 bit MMC bus, then
the U-Boot AT91SAM926x MCI driver can borrow the Linux driver's
code and support a 4 bit bus also.

Sincerely,

Ken Fuchs

> -----Message d'origine-----
> De?: u-boot-users-bounces at lists.sourceforge.net
> [mailto:u-boot-users-bounces at lists.sourceforge.net] De la 
> part de Pierre
> Ossman
> Envoy??: samedi 12 avril 2008 11:28
> ??: Ken.Fuchs at bench.com
> Cc?: pierre.savary at kerlink.fr; u-boot-users at lists.sourceforge.net
> Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x
> 
> On Fri, 11 Apr 2008 13:54:13 -0500
> Ken.Fuchs at bench.com wrote:
> 
> > 
> > The manual for the AT91SAM926x processors clearly states that the
> > MCI controller supports MMC 2.2.  I asked Atmel whether 
> this controller
> > could support 4 bits to an MMC 4.x chip and they said _no_. 
>   The answer
> > is supposedly from their engineering group in France.
> > 
> 
> What they answered was if Atmel would support such a solution, not if
> the hardware would.
> 
> > 
> > How does one program the MCI controller to send 4 bit 
> (parallel) data
> > an MMC 4.x chip, with or without telling it that it is communicating
> > to a 4-bit SD chip?  The only way to get 4 bits of data out 
> of the MCI
> > is to tell it that it is connected to a SD (1.0) chip.  If 
> you program
> > the MCI to communicate with an MMC chip, it will send data 
> out only on
> > the low order bit.
> 
> You tell it to use all four bits. That's it. The setting isn't MMC/SD,
> it's 1-bit/4-bit.
> 
> > Both ends of the communication link must considered.  It may not be
> > sufficient that the MMC chip is MMC 4.x; The fact that the MCI
> > controller is only MMC 2.2 or SD 1.0 compliant, may or may 
> not impact
> > this special handling.
> 
> It does not in the slightest. Remember that these controllers are
> extremely dumb. The low level behaviour of the protocol hasn't changed
> since the very first specs, so only software needs to be changed to
> support even the newest features.
> 
> Rgds
> -- 
>      -- Pierre Ossman
> 
>   Linux kernel, MMC maintainer        http://www.kernel.org
>   PulseAudio, core developer          http://pulseaudio.org
>   rdesktop, core developer          http://www.rdesktop.org
> 
> --------------------------------------------------------------
> -----------
> This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
> Don't miss this year's exciting event. There's still time to 
> save $100. 
> Use priority code J8TL2D2. 
> http://ad.doubleclick.net/clk;198757673;13503038;p?http://java
.sun.com/javao
ne
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
       [not found]         ` <-6021840981243159212@unknownmsgid>
@ 2008-04-15 19:25           ` Andy Fleming
  2008-04-16  8:55             ` Pierre Savary
                               ` (2 more replies)
  0 siblings, 3 replies; 39+ messages in thread
From: Andy Fleming @ 2008-04-15 19:25 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 15, 2008 at 5:18 AM, Pierre Savary <pierre.savary@kerlink.fr> wrote:
> Then my MMC 4GB works with my Linux kernel but if I can't load my kernel
>  (located on the first part of this MMC) ... it's not really interesting :(
>
>  So, somebody does already use MMC v4 with U-boot???

I've got one that works.  However, I don't have a 4GB MMC card with
v4.  I thought I did, but it turned out the card just takes advantage
of the fact that older versions can address 4GB, even though the spec
says 2GB is the max.

However, I'm fairly confident in the code (it's been tested in
simulated environments, and reflects what the Linux code does).  I'm
currently working on bringing it forward to the top of tree (I started
it before drivers/ got rearranged).  I'm actually hoping to generalize
it some so we can share it between all MMC/SD users.

Andy

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-15 19:25           ` Andy Fleming
@ 2008-04-16  8:55             ` Pierre Savary
  2008-04-16 23:30             ` Ken.Fuchs at bench.com
  2008-04-22 11:55             ` Pierre Savary
  2 siblings, 0 replies; 39+ messages in thread
From: Pierre Savary @ 2008-04-16  8:55 UTC (permalink / raw)
  To: u-boot

Hi,
Perhaps that I could help you...? I could test it with many different MMC
(2GB, 4GB, 8GB) (Samsung and Micron). Could you share with me your source
code?
Thanks in advance for your help,

Best Regards

Pierre


-----Message d'origine-----
De?: u-boot-users-bounces at lists.sourceforge.net
[mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de Andy
Fleming
Envoy??: mardi 15 avril 2008 21:25
??: Pierre Savary
Cc?: u-boot-users at lists.sourceforge.net; drzeus-mmc at drzeus.cx
Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x

On Tue, Apr 15, 2008 at 5:18 AM, Pierre Savary <pierre.savary@kerlink.fr>
wrote:
> Then my MMC 4GB works with my Linux kernel but if I can't load my kernel
>  (located on the first part of this MMC) ... it's not really interesting
:(
>
>  So, somebody does already use MMC v4 with U-boot???

I've got one that works.  However, I don't have a 4GB MMC card with
v4.  I thought I did, but it turned out the card just takes advantage
of the fact that older versions can address 4GB, even though the spec
says 2GB is the max.

However, I'm fairly confident in the code (it's been tested in
simulated environments, and reflects what the Linux code does).  I'm
currently working on bringing it forward to the top of tree (I started
it before drivers/ got rearranged).  I'm actually hoping to generalize
it some so we can share it between all MMC/SD users.

Andy

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao
ne
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-15 19:25           ` Andy Fleming
  2008-04-16  8:55             ` Pierre Savary
@ 2008-04-16 23:30             ` Ken.Fuchs at bench.com
  2008-04-22 11:55             ` Pierre Savary
  2 siblings, 0 replies; 39+ messages in thread
From: Ken.Fuchs at bench.com @ 2008-04-16 23:30 UTC (permalink / raw)
  To: u-boot

Congratulations!  It will be great to have MMC v4.x support in U-Boot.

The following segment of code from
linux-2.6.25-rc9/drivers/mmc/host/at91_mci.c is confusing:

if (host->board->wire4) {
        if (cpu_is_at91sam9260() || cpu_is_at91sam9263())
                mmc->caps |= MMC_CAP_4_BIT_DATA;
        else
                dev_warn(&pdev->dev, "4 wire bus mode not supported"
                        " - using 1 wire\n");
}

This code seems to imply that MMC 4 bits works on the AT91SAM9260 and
AT91SAM9263, but not any of the others in this processor family,
possibly due to a hardware bug.  Any comments on why the Linux AT91 MCI
driver doesn't support an 4 bit MMC bus for all AT91SAM9 processors?

I mention this because it may impact the AT91 MCI U-Boot device driver.

Sincerely,

Ken Fuchs

> -----Original Message-----
> From: u-boot-users-bounces at lists.sourceforge.net 
> [mailto:u-boot-users-bounces at lists.sourceforge.net] On Behalf 
> Of Andy Fleming
> Sent: Tuesday, April 15, 2008 14:25
> To: Pierre Savary
> Cc: u-boot-users at lists.sourceforge.net; drzeus-mmc at drzeus.cx
> Subject: Re: [U-Boot-Users] drivers MMCplus for at91sam9x
> 
> 
> On Tue, Apr 15, 2008 at 5:18 AM, Pierre Savary 
> <pierre.savary@kerlink.fr> wrote:
> > Then my MMC 4GB works with my Linux kernel but if I can't 
> load my kernel
> >  (located on the first part of this MMC) ... it's not 
> really interesting :(
> >
> >  So, somebody does already use MMC v4 with U-boot???
> 
> I've got one that works.  However, I don't have a 4GB MMC card with
> v4.  I thought I did, but it turned out the card just takes advantage
> of the fact that older versions can address 4GB, even though the spec
> says 2GB is the max.
> 
> However, I'm fairly confident in the code (it's been tested in
> simulated environments, and reflects what the Linux code does).  I'm
> currently working on bringing it forward to the top of tree (I started
> it before drivers/ got rearranged).  I'm actually hoping to generalize
> it some so we can share it between all MMC/SD users.
> 
> Andy
> 
> --------------------------------------------------------------
> -----------
> This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
> Don't miss this year's exciting event. There's still time to 
> save $100. 
> Use priority code J8TL2D2. 
> http://ad.doubleclick.net/clk;198757673;13503038;p?http://java
.sun.com/javaone
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-15 19:25           ` Andy Fleming
  2008-04-16  8:55             ` Pierre Savary
  2008-04-16 23:30             ` Ken.Fuchs at bench.com
@ 2008-04-22 11:55             ` Pierre Savary
  2008-04-22 15:07               ` [U-Boot-Users] [PATCH] Add eSDHC driver Andy Fleming
  2 siblings, 1 reply; 39+ messages in thread
From: Pierre Savary @ 2008-04-22 11:55 UTC (permalink / raw)
  To: u-boot

Hi Andy,
Where could we find the driver that works with MMCv4 on at91sam9x?
Best regards

Pierre


-----Message d'origine-----
De?: u-boot-users-bounces at lists.sourceforge.net
[mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de Andy
Fleming
Envoy??: mardi 15 avril 2008 21:25
??: Pierre Savary
Cc?: u-boot-users at lists.sourceforge.net; drzeus-mmc at drzeus.cx
Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x

On Tue, Apr 15, 2008 at 5:18 AM, Pierre Savary <pierre.savary@kerlink.fr>
wrote:
> Then my MMC 4GB works with my Linux kernel but if I can't load my kernel
>  (located on the first part of this MMC) ... it's not really interesting
:(
>
>  So, somebody does already use MMC v4 with U-boot???

I've got one that works.  However, I don't have a 4GB MMC card with
v4.  I thought I did, but it turned out the card just takes advantage
of the fact that older versions can address 4GB, even though the spec
says 2GB is the max.

However, I'm fairly confident in the code (it's been tested in
simulated environments, and reflects what the Linux code does).  I'm
currently working on bringing it forward to the top of tree (I started
it before drivers/ got rearranged).  I'm actually hoping to generalize
it some so we can share it between all MMC/SD users.

Andy

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao
ne
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] [PATCH] Add eSDHC driver
  2008-04-22 11:55             ` Pierre Savary
@ 2008-04-22 15:07               ` Andy Fleming
  2008-04-22 16:53                 ` Anton Vorontsov
  2008-04-23 19:23                 ` Ken.Fuchs at bench.com
  0 siblings, 2 replies; 39+ messages in thread
From: Andy Fleming @ 2008-04-22 15:07 UTC (permalink / raw)
  To: u-boot

This is the SD/MMC controller on several of Freescale's more recent parts
---
> Hi Andy,
> Where could we find the driver that works with MMCv4 on at91sam9x?
> Best regards

Pierre, I don't have a driver that works on at91sam9x, I'm afraid.  I have
a driver that nearly works on an mpc837x.  However, some of it is certainly
right, and that may help you.  Also, some of it is wrong (I get intermittent
failures on MMC cards), and maybe someone will look at this driver, and see what
I'm doing wrong.


 Makefile                           |    2 +
 drivers/mmc/Makefile               |   46 ++
 drivers/mmc/fsl_esdhc.c            | 1111 ++++++++++++++++++++++++++++++++++++
 drivers/mmc/fsl_esdhc.h            |  208 +++++++
 include/asm-ppc/arch-mpc83xx/mmc.h |    1 +
 5 files changed, 1368 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mmc/Makefile
 create mode 100644 drivers/mmc/fsl_esdhc.c
 create mode 100644 drivers/mmc/fsl_esdhc.h
 create mode 100644 include/asm-ppc/arch-mpc83xx/mmc.h

diff --git a/Makefile b/Makefile
index e5b4210..cd614a5 100644
--- a/Makefile
+++ b/Makefile
@@ -214,6 +214,7 @@ LIBS += drivers/hwmon/libhwmon.a
 LIBS += drivers/i2c/libi2c.a
 LIBS += drivers/input/libinput.a
 LIBS += drivers/misc/libmisc.a
+LIBS += drivers/mmc/libmmc.a
 LIBS += drivers/mtd/libmtd.a
 LIBS += drivers/mtd/nand/libnand.a
 LIBS += drivers/mtd/nand_legacy/libnand_legacy.a
@@ -383,6 +384,7 @@ TAG_SUBDIRS += drivers/hwmon
 TAG_SUBDIRS += drivers/i2c
 TAG_SUBDIRS += drivers/input
 TAG_SUBDIRS += drivers/misc
+TAG_SUBDIRS += drivers/mmc
 TAG_SUBDIRS += drivers/mtd
 TAG_SUBDIRS += drivers/mtd/nand
 TAG_SUBDIRS += drivers/mtd/nand_legacy
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
new file mode 100644
index 0000000..06e4e88
--- /dev/null
+++ b/drivers/mmc/Makefile
@@ -0,0 +1,46 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB 	:= $(obj)libmmc.a
+
+COBJS-y += fsl_esdhc.o
+
+COBJS	:= $(COBJS-y)
+SRCS 	:= $(COBJS:.o=.c)
+OBJS 	:= $(addprefix $(obj),$(COBJS))
+
+all:	$(LIB)
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
new file mode 100644
index 0000000..29af92a
--- /dev/null
+++ b/drivers/mmc/fsl_esdhc.c
@@ -0,0 +1,1111 @@
+/*
+ * Copyright 2007, Freescale Semiconductor, Inc
+ * Andy Fleming
+ *
+ * Based vaguely on the pxa mmc code:
+ * (C) Copyright 2003
+ * Kyle Harris, Nexus Technologies, Inc. kharris at nexus-tech.net
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <mmc.h>
+#include <part.h>
+#include <malloc.h>
+#include <asm/io.h>
+
+#include "fsl_esdhc.h"
+
+#ifdef CONFIG_MMC
+DECLARE_GLOBAL_DATA_PTR;
+
+struct fsl_esdhc {
+	uint	dsaddr;
+	uint	blkattr;
+	uint	cmdarg;
+	uint	xfertyp;
+	uint	cmdrsp0;
+	uint	cmdrsp1;
+	uint	cmdrsp2;
+	uint	cmdrsp3;
+	uint	datport;
+	uint	prsstat;
+	uint	proctl;
+	uint	sysctl;
+	uint	irqstat;
+	uint	irqstaten;
+	uint	irqsigen;
+	uint	autoc12err;
+	uint	hostcapblt;
+	uint	wml;
+	char	reserved1[8];
+	uint	fevt;
+	char	reserved2[168];
+	uint	hostver;
+	char	reserved3[780];
+	uint	scr;
+};
+
+enum {
+	MMC_CMD_RSP_NONE,
+	MMC_CMD_R1 = 1,
+	MMC_CMD_R1b,
+	MMC_CMD_R2,
+	MMC_CMD_R3,
+	MMC_CMD_R4,
+	MMC_CMD_R5,
+	MMC_CMD_R5b,
+	MMC_CMD_R6,
+	MMC_CMD_R7
+};
+
+uint	xfertyps[] = {
+	XFERTYP_RSPTYP_NONE,
+	XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN,
+	XFERTYP_RSPTYP_48_BUSY | XFERTYP_CICEN | XFERTYP_CCCEN,
+	XFERTYP_RSPTYP_136 | XFERTYP_CCCEN,
+	XFERTYP_RSPTYP_48,
+	XFERTYP_RSPTYP_48,
+	XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN,
+	XFERTYP_RSPTYP_48_BUSY | XFERTYP_CICEN | XFERTYP_CCCEN,
+	XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN,
+	XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN
+};
+
+struct mmc {
+	volatile void *	regs;
+	uint version;
+	int high_capacity;
+	uint mode;
+	uint ocr;
+	uint scr[2];
+	uint csd[4];
+	char cid[16];
+	ushort rca;
+	uint tran_speed;
+	uint read_bl_len;
+	uint write_bl_len;
+	u64 capacity;
+	block_dev_desc_t block_dev;
+};
+
+static struct mmc *mmc_dev;
+
+block_dev_desc_t *mmc_get_dev(int dev)
+{
+	return (dev == 0) ? &mmc_dev->block_dev : NULL;
+}
+
+struct mmc_cmd {
+	ushort	cmdidx;
+	int	resp_type;
+	uint	cmdarg;
+	char	response[18];
+	uint	flags;
+};
+
+struct mmc_data {
+	char *	buffer;
+	uint	flags;
+	int	blocks;
+	int	blocksize;
+};
+
+/* Return the XFERTYP flags for a given command and data packet */
+uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	uint xfertyp = 0;
+
+	if (data) {
+		xfertyp |= XFERTYP_DPSEL | XFERTYP_DMAEN;
+
+		if (data->blocks > 1) {
+			xfertyp |= XFERTYP_MSBSEL;
+			xfertyp |= XFERTYP_BCEN;
+		}
+
+		if (data->flags & MMC_DATA_READ)
+			xfertyp |= XFERTYP_DTDSEL;
+	}
+
+	xfertyp |= xfertyps[cmd->resp_type];
+
+	return xfertyp;
+}
+
+
+/*
+ * Sends a command out on the bus.  Takes the mmc pointer,
+ * a command pointer, and an optional data pointer.
+ */
+static int
+mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	uint	xfertyp;
+	uint	irqstat;
+	volatile struct fsl_esdhc *regs = mmc->regs;
+
+	regs->irqstat = -1;
+
+	sync();
+
+	/* Wait for the bus to be idle */
+	while ((regs->prsstat & PRSSTAT_CICHB) ||
+			(regs->prsstat & PRSSTAT_CIDHB))
+		sync();
+
+	while (regs->prsstat & PRSSTAT_DLA)
+		sync();
+
+	/* Wait at least 8 SD clock cycles before the next command */
+	/*
+	 * Note: This is way more than 8 cycles, but 1ms seems to
+	 * resolve timing issues with some cards
+	 */
+	udelay(1000);
+
+	/* Set up for a data transfer if we have one */
+	if (data) {
+		uint wml_value;
+		int timeout;
+
+		wml_value = data->blocksize/4;
+
+		if (data->flags & MMC_DATA_READ) {
+			if (wml_value > 0x10)
+				wml_value = 0x10;
+
+			wml_value = 0x100000 | wml_value;
+		} else {
+			if (wml_value > 0x80)
+				wml_value = 0x80;
+
+			wml_value = wml_value << 16 | 0x10;
+		}
+
+		regs->dsaddr = (uint)data->buffer;
+
+		sync();
+
+		regs->wml = wml_value;
+
+		sync();
+
+		regs->blkattr = data->blocks << 16 | data->blocksize;
+
+		sync();
+
+		timeout = __ilog2(mmc->tran_speed/10);
+		timeout -= 13;
+
+		if (timeout > 14)
+			timeout = 14;
+
+		if (timeout < 0)
+			timeout = 0;
+
+		regs->sysctl &= ~0x000f0000;
+
+		sync();
+
+		regs->sysctl |= timeout << 16;
+
+		sync();
+	}
+
+	/* Figure out the transfer arguments */
+	xfertyp = esdhc_xfertyp(cmd, data);
+
+	/* Send the command */
+	regs->cmdarg = cmd->cmdarg;
+	sync();
+	regs->xfertyp = XFERTYP_CMD(cmd->cmdidx) | xfertyp;
+
+	sync();
+	/* Wait for the command to complete */
+	while (!(regs->irqstat & IRQSTAT_CC))
+		sync();
+
+	irqstat = regs->irqstat;
+
+	sync();
+
+	regs->irqstat = irqstat;
+
+	sync();
+
+	if (irqstat & CMD_ERR)
+		return COMM_ERR;
+
+	if (irqstat & IRQSTAT_CTOE)
+		return TIMEOUT;
+
+	/* Copy the response to the response buffer */
+	if (cmd->resp_type == MMC_CMD_R2) {
+		((uint *)(cmd->response))[0] =
+			(regs->cmdrsp3 << 8) | (regs->cmdrsp2 >> 24);
+		((uint *)(cmd->response))[1] =
+			(regs->cmdrsp2 << 8) | (regs->cmdrsp1 >> 24);
+		((uint *)(cmd->response))[2] =
+			(regs->cmdrsp1 << 8) | (regs->cmdrsp0 >> 24);
+		((uint *)(cmd->response))[3] = (regs->cmdrsp0 << 8);
+	} else
+		((uint *)(cmd->response))[0] = regs->cmdrsp0;
+
+	/* Wait until all of the blocks are transferred */
+	if (data) {
+		do {
+			irqstat = regs->irqstat;
+
+			if (irqstat & DATA_ERR)
+				return COMM_ERR;
+
+			if (irqstat & IRQSTAT_DTOE)
+				return TIMEOUT;
+			sync();
+		} while (!(irqstat & IRQSTAT_TC) &&
+				(regs->prsstat & PRSSTAT_DLA));
+	}
+
+	regs->irqstat = -1;
+	sync();
+
+	return 0;
+}
+
+void set_sysctl(struct mmc *mmc, int clock)
+{
+	int sdhc_clk = gd->sdhc_clk;
+	int div, pre_div;
+	volatile struct fsl_esdhc *regs = mmc->regs;
+	uint clk;
+
+	if (sdhc_clk / 16 > clock) {
+		for (pre_div = 2; pre_div < 256; pre_div *= 2)
+			if ((sdhc_clk / pre_div) <= (clock * 16))
+				break;
+	} else
+		pre_div = 2;
+
+	for (div = 1; div <= 16; div++)
+		if ((sdhc_clk / (div * pre_div)) <= clock)
+			break;
+
+	pre_div >>= 1;
+	div -= 1;
+
+	clk = (pre_div << 8) | (div << 4);
+	regs->sysctl &= ~0x0000fff0;
+	sync();
+	regs->sysctl |= clk;
+	sync();
+
+	udelay(10000);
+
+	regs->sysctl |= SYSCTL_PEREN;
+}
+
+
+int
+mmc_block_write(ulong dst, uchar *src, int len)
+{
+#warning write not yet implemented
+	return 0;
+}
+
+int mmc_set_blocklen(struct mmc *mmc, int len)
+{
+	struct mmc_cmd cmd;
+
+	cmd.cmdidx = SET_BLOCKLEN;
+	cmd.resp_type = MMC_CMD_R1;
+	cmd.cmdarg = len;
+	cmd.flags = 0;
+
+	return mmc_send_cmd(mmc, &cmd, NULL);
+}
+
+int
+mmc_read(ulong src, uchar *dst, int size)
+{
+	struct mmc_cmd cmd;
+	struct mmc_data data;
+	int err;
+	char * buffer;
+	int stoperr = 0;
+	struct mmc *mmc = mmc_dev;
+	int blklen = mmc->read_bl_len;
+	int startblock = src / blklen;
+	int endblock = (src + size - 1) / blklen;
+	int blkcnt = endblock - startblock + 1;
+
+	/* Make a buffer big enough to hold all the blocks we might read */
+	buffer = malloc(blkcnt * blklen);
+
+	if (!buffer) {
+		printf("Could not allocate buffer for MMC read!\n");
+		return -1;
+	}
+
+#warning deal with larger reads (more than 65536 blks) and partial block reads
+	/* We only support full block reads from the card */
+	err = mmc_set_blocklen(mmc, mmc->read_bl_len);
+
+	if (err)
+		return err;
+
+	if (blkcnt > 1)
+		cmd.cmdidx = READ_MULTIPLE_BLOCKS;
+	else
+		cmd.cmdidx = READ_SINGLE_BLOCK;
+
+	if (mmc->high_capacity)
+		cmd.cmdarg = startblock;
+	else
+		cmd.cmdarg = startblock * blklen;
+
+	cmd.resp_type = MMC_CMD_R1;
+	cmd.flags = 0;
+
+	data.buffer = buffer;
+	data.blocks = blkcnt;
+	data.blocksize = blklen;
+	data.flags = MMC_DATA_READ;
+
+	err = mmc_send_cmd(mmc, &cmd, &data);
+
+	if (blkcnt > 1) {
+		cmd.cmdidx = STOP_TRANSMISSION;
+		cmd.cmdarg = 0;
+		cmd.resp_type = MMC_CMD_R1b;
+		cmd.flags = 0;
+		stoperr = mmc_send_cmd(mmc, &cmd, NULL);
+	}
+
+
+	if (err)
+		return err;
+
+	memcpy(dst, buffer + (src & (blklen - 1)), size);
+
+	free(buffer);
+
+	return stoperr;
+}
+
+int
+mmc_write(uchar *src, ulong dst, int size)
+{
+	return 0;
+}
+
+ulong
+mmc_bread(int dev_num, ulong blknr, ulong blkcnt, void *dst)
+{
+	int err;
+	ulong src = blknr * mmc_dev->read_bl_len;
+
+	err = mmc_read(src, dst, blkcnt * mmc_dev->read_bl_len);
+
+	if (err) {
+		printf("block read failed: %d\n", err);
+		return 0;
+	}
+
+	return blkcnt;
+}
+
+int mmc_go_idle(struct mmc* mmc)
+{
+	struct mmc_cmd cmd;
+	int err;
+
+	udelay(1000);
+
+	cmd.cmdidx = GO_IDLE_STATE;
+	cmd.cmdarg = 0;
+	cmd.resp_type = MMC_CMD_RSP_NONE;
+	cmd.flags = 0;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	udelay(2000);
+
+	return 0;
+}
+
+int
+sd_send_op_cond(struct mmc *mmc)
+{
+	int timeout = 1000;
+	int err;
+	struct mmc_cmd cmd;
+
+	do {
+		cmd.cmdidx = APP_CMD;
+		cmd.resp_type = MMC_CMD_R1;
+		cmd.cmdarg = 0;
+		cmd.flags = 0;
+
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (err)
+			return err;
+
+		cmd.cmdidx = SD_SEND_OP_COND;
+		cmd.resp_type = MMC_CMD_R3;
+		cmd.cmdarg = 0xff8000;
+
+		if (mmc->version == SD_VERSION_2)
+			cmd.cmdarg |= 0x40000000;
+
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (err)
+			return err;
+
+		udelay(1000);
+	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
+
+	if (timeout <= 0)
+		return UNUSABLE_ERR;
+
+	if (mmc->version != SD_VERSION_2)
+		mmc->version = SD_VERSION_1_0;
+
+	mmc->ocr = ((uint *)(cmd.response))[0];
+
+	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
+	mmc->rca = 0;
+
+	return 0;
+}
+
+int mmc_send_op_cond(struct mmc *mmc)
+{
+	int timeout = 1000;
+	struct mmc_cmd cmd;
+	int err;
+
+	/* Some cards seem to need this */
+	mmc_go_idle(mmc);
+
+	do {
+		cmd.cmdidx = MMC_SEND_OP_COND;
+		cmd.resp_type = MMC_CMD_R3;
+		cmd.cmdarg = 0x40ff8000;
+		cmd.flags = 0;
+
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (err)
+			return err;
+
+		udelay(1000);
+	} while (!(cmd.response[0] & OCR_BUSY) && timeout--);
+
+	if (timeout <= 0)
+		return UNUSABLE_ERR;
+
+	mmc->version = MMC_VERSION_UNKNOWN;
+	mmc->ocr = ((uint *)(cmd.response))[0];
+
+	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
+	mmc->rca = 0;
+
+	return 0;
+}
+
+
+int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
+{
+	struct mmc_cmd cmd;
+	struct mmc_data data;
+	int err;
+
+	/* Get the Card Status Register */
+	cmd.cmdidx = SEND_EXT_CSD;
+	cmd.resp_type = MMC_CMD_R1;
+	cmd.cmdarg = 0;
+	cmd.flags = 0;
+
+	data.buffer = ext_csd;
+	data.blocks = 1;
+	data.blocksize = 512;
+	data.flags = MMC_DATA_READ;
+
+	err = mmc_send_cmd(mmc, &cmd, &data);
+
+	return err;
+}
+
+
+int mmc_change_freq(struct mmc *mmc)
+{
+	struct mmc_cmd cmd;
+	char ext_csd[512];
+	char cardtype;
+	int err;
+
+	mmc->mode = 0;
+
+	/* Only version 4 supports high-speed */
+	if (mmc->version < MMC_VERSION_4)
+		return 0;
+
+	mmc->mode |= MMC_MODE_4BIT;
+
+	err = mmc_send_ext_csd(mmc, ext_csd);
+
+	if (err)
+		return err;
+
+	if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215])
+		mmc->high_capacity = 1;
+
+	cardtype = ext_csd[196] & 0xf;
+
+	/* Set the card to use High Speed */
+	cmd.cmdidx = MMC_SWITCH;
+	cmd.resp_type = MMC_CMD_R1b;
+	cmd.cmdarg = 0x1b90100;
+	cmd.flags = 0;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	/* Now check to see that it worked */
+	err = mmc_send_ext_csd(mmc, ext_csd);
+
+	if (err)
+		return err;
+
+	/* No high-speed support */
+	if (!ext_csd[185])
+		return 0;
+
+	/* High Speed is set, there are two types: 52MHz and 26MHz */
+	if (cardtype & MMC_HS_52MHZ)
+		mmc->mode |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+	else
+		mmc->mode |= MMC_MODE_HS;
+
+	return 0;
+}
+
+int sd_change_freq(struct mmc *mmc)
+{
+	int err;
+	struct mmc_cmd cmd;
+	uint scr[2];
+	uint switch_status[16];
+	struct mmc_data data;
+	int timeout;
+
+	mmc->mode = 0;
+
+	/* Read the SCR to find out if this card supports higher speeds */
+	cmd.cmdidx = APP_CMD;
+	cmd.resp_type = MMC_CMD_R1;
+	cmd.cmdarg = mmc->rca << 16;
+	cmd.flags = 0;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	cmd.cmdidx = SEND_SCR;
+	cmd.resp_type = MMC_CMD_R1;
+	cmd.cmdarg = 0;
+	cmd.flags = 0;
+
+	timeout = 3;
+
+retry_scr:
+	data.buffer = (char *)&scr;
+	data.blocksize = 8;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+
+	err = mmc_send_cmd(mmc, &cmd, &data);
+
+	if (err) {
+		if (timeout--)
+			goto retry_scr;
+
+		return err;
+	}
+
+	mmc->scr[0] = scr[0];
+	mmc->scr[1] = scr[1];
+
+	switch ((mmc->scr[0] >> 24) & 0xf) {
+		case 0:
+			mmc->version = SD_VERSION_1_0;
+			break;
+		case 1:
+			mmc->version = SD_VERSION_1_10;
+			break;
+		case 2:
+			mmc->version = SD_VERSION_2;
+			break;
+		default:
+			mmc->version = SD_VERSION_1_0;
+			break;
+	}
+
+	/* Version 1.0 doesn't support switching */
+	if (mmc->version == SD_VERSION_1_0)
+		return 0;
+
+	timeout = 4;
+	while (timeout--) {
+		/* Switch the frequency */
+		cmd.cmdidx = SWITCH_FUNC;
+		cmd.resp_type = MMC_CMD_R1;
+		cmd.cmdarg = 0xfffff1;
+		cmd.flags = 0;
+
+		data.buffer = (char *)&switch_status;
+		data.blocksize = 64;
+		data.blocks = 1;
+		data.flags = MMC_DATA_READ;
+
+		err = mmc_send_cmd(mmc, &cmd, &data);
+
+		if (err)
+			return err;
+
+		/* The high-speed function is busy.  Try again */
+		if (!switch_status[7] & SD_HIGHSPEED_BUSY)
+			break;
+	}
+
+	if (mmc->scr[0] & SD_DATA_4BIT)
+		mmc->mode |= MMC_MODE_4BIT;
+
+	/* If high-speed isn't supported, we return */
+	if (!(switch_status[3] & SD_HIGHSPEED_SUPPORTED))
+		return 0;
+
+	cmd.cmdidx = SWITCH_FUNC;
+	cmd.resp_type = MMC_CMD_R1;
+	cmd.cmdarg = 0x80fffff1;
+	cmd.flags = 0;
+
+	data.buffer = (char *)&switch_status;
+	data.blocksize = 64;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+
+	err = mmc_send_cmd(mmc, &cmd, &data);
+
+	if (err)
+		return err;
+
+	if ((switch_status[4] & 0x0f000000) == 0x01000000)
+		mmc->mode |= MMC_MODE_HS;
+
+	return 0;
+}
+
+/* frequency bases */
+/* divided by 10 to be nice to platforms without floating point */
+int fbase[] = {
+	10000,
+	100000,
+	1000000,
+	10000000,
+};
+
+/* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
+ * to platforms without floating point.
+ */
+int multipliers[] = {
+	0,	/* reserved */
+	10,
+	12,
+	13,
+	15,
+	20,
+	25,
+	30,
+	35,
+	40,
+	45,
+	50,
+	55,
+	60,
+	70,
+	80,
+};
+
+
+int mmc_startup(struct mmc *mmc)
+{
+	int err;
+	uint mult, freq;
+	uint cmult, csize;
+	struct mmc_cmd cmd;
+	volatile struct fsl_esdhc *regs = mmc->regs;
+
+	/* Put the Card in Identify Mode */
+	cmd.cmdidx = ALL_SEND_CID;
+	cmd.resp_type = MMC_CMD_R2;
+	cmd.cmdarg = 0;
+	cmd.flags = 0;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	memcpy(mmc->cid, cmd.response, 16);
+
+	/*
+	 * For MMC cards, set the Relative Address.
+	 * For SD cards, get the Relatvie Address.
+	 * This also puts the cards into Standby State
+	 */
+	cmd.cmdidx = SEND_RELATIVE_ADDR;
+	cmd.cmdarg = mmc->rca << 16;
+	cmd.resp_type = MMC_CMD_R6;
+	cmd.flags = 0;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	if (IS_SD(mmc))
+		mmc->rca = (((uint *)(cmd.response))[0] >> 16) & 0xffff;
+
+	/* Get the Card-Specific Data */
+	cmd.cmdidx = SEND_CSD;
+	cmd.resp_type = MMC_CMD_R2;
+	cmd.cmdarg = mmc->rca << 16;
+	cmd.flags = 0;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	mmc->csd[0] = ((uint *)(cmd.response))[0];
+	mmc->csd[1] = ((uint *)(cmd.response))[1];
+	mmc->csd[2] = ((uint *)(cmd.response))[2];
+	mmc->csd[3] = ((uint *)(cmd.response))[3];
+
+	if (mmc->version == MMC_VERSION_UNKNOWN) {
+		int version = (cmd.response[0] >> 2) & 0xf;
+
+		switch (version) {
+			case 0:
+				mmc->version = MMC_VERSION_1_2;
+				break;
+			case 1:
+				mmc->version = MMC_VERSION_1_4;
+				break;
+			case 2:
+				mmc->version = MMC_VERSION_2_2;
+				break;
+			case 3:
+				mmc->version = MMC_VERSION_3;
+				break;
+			case 4:
+				mmc->version = MMC_VERSION_4;
+				break;
+			default:
+				mmc->version = MMC_VERSION_1_2;
+				break;
+		}
+	}
+
+	/* divide frequency by 10, since the mults are 10x bigger */
+	freq = fbase[(cmd.response[3] & 0x7)];
+	mult = multipliers[((cmd.response[3] >> 3) & 0xf)];
+
+	mmc->tran_speed = freq * mult;
+
+	mmc->read_bl_len = 1 << ((((uint *)(cmd.response))[1] >> 16) & 0xf);
+
+	if (IS_SD(mmc))
+		mmc->write_bl_len = mmc->read_bl_len;
+	else
+		mmc->write_bl_len = 1 << ((((uint *)(cmd.response))[3] >> 22) & 0xf);
+
+	csize = (mmc->csd[1] & 0x3ff) << 2 | (mmc->csd[2] & 0xc0000000) >> 30;
+	cmult = (mmc->csd[2] & 0x00038000) >> 15;
+
+	mmc->capacity = (csize + 1) << (cmult + 2);
+	mmc->capacity *= mmc->read_bl_len;
+
+	if (mmc->read_bl_len > 512)
+		mmc->read_bl_len = 512;
+
+	if (mmc->write_bl_len > 512)
+		mmc->write_bl_len = 512;
+
+	/* Select the card, and put it into Transfer Mode */
+	cmd.cmdidx = SELECT_CARD;
+	cmd.resp_type = MMC_CMD_R1b;
+	cmd.cmdarg = mmc->rca << 16;
+	cmd.flags = 0;
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	if (IS_SD(mmc))
+		err = sd_change_freq(mmc);
+	else
+		err = mmc_change_freq(mmc);
+
+	if (err)
+		return err;
+
+	if (IS_SD(mmc)) {
+		if (mmc->mode & MMC_MODE_4BIT) {
+			cmd.cmdidx = APP_CMD;
+			cmd.resp_type = MMC_CMD_R1;
+			cmd.cmdarg = mmc->rca << 16;
+			cmd.flags = 0;
+
+			err = mmc_send_cmd(mmc, &cmd, NULL);
+			if (err)
+				return err;
+
+			cmd.cmdidx = SET_BUS_WIDTH;
+			cmd.resp_type = MMC_CMD_R1;
+			cmd.cmdarg = 2;
+			cmd.flags = 0;
+			err = mmc_send_cmd(mmc, &cmd, NULL);
+			if (err)
+				return err;
+
+			regs->proctl |= PROCTL_DTW_4;
+		}
+
+		if (mmc->mode & MMC_MODE_HS)
+			set_sysctl(mmc, 50000000);
+		else
+			set_sysctl(mmc, 25000000);
+	} else {
+		if (mmc->mode & MMC_MODE_4BIT) {
+			/* Set the card to use 4 bit*/
+			cmd.cmdidx = MMC_SWITCH;
+			cmd.resp_type = MMC_CMD_R1b;
+			cmd.cmdarg = 0x1b70100;
+			cmd.flags = 0;
+
+			err = mmc_send_cmd(mmc, &cmd, NULL);
+
+			if (err)
+				return err;
+
+			regs->proctl |= PROCTL_DTW_4;
+		} else if (mmc->mode & MMC_MODE_8BIT) {
+			/* Set the card to use 8 bit*/
+			cmd.cmdidx = MMC_SWITCH;
+			cmd.resp_type = MMC_CMD_R1b;
+			cmd.cmdarg = 0x1b70200;
+			cmd.flags = 0;
+
+			err = mmc_send_cmd(mmc, &cmd, NULL);
+
+			if (err)
+				return err;
+			
+			regs->proctl |= PROCTL_DTW_8;
+		}
+
+		if (mmc->mode & MMC_MODE_HS) {
+			if (mmc->mode & MMC_MODE_HS_52MHz)
+				set_sysctl(mmc, 52000000);
+			else
+				set_sysctl(mmc, 26000000);
+		} else
+			set_sysctl(mmc, 20000000);
+	}
+
+	/* fill in device description */
+	mmc->block_dev.if_type = IF_TYPE_MMC;
+	mmc->block_dev.part_type = PART_TYPE_DOS;
+	mmc->block_dev.dev = 0;
+	mmc->block_dev.lun = 0;
+	mmc->block_dev.type = 0;
+	mmc->block_dev.blksz = mmc->read_bl_len;
+	mmc->block_dev.lba = mmc->capacity/mmc->read_bl_len;
+	sprintf(mmc->block_dev.vendor,"Man %02x%02x%02x Snr %02x%02x%02x%02x",
+			mmc->cid[0], mmc->cid[1], mmc->cid[2],
+			mmc->cid[9], mmc->cid[10], mmc->cid[11], mmc->cid[12]);
+	sprintf(mmc->block_dev.product,"%c%c%c%c%c", mmc->cid[3],
+			mmc->cid[4], mmc->cid[5], mmc->cid[6], mmc->cid[7]);
+	sprintf(mmc->block_dev.revision,"%d.%d", mmc->cid[8] >> 4,
+			mmc->cid[8] & 0xf);
+	mmc->block_dev.removable = 1;
+	mmc->block_dev.block_read = mmc_bread;
+
+	init_part(&mmc->block_dev);
+
+	return 0;
+}
+
+int mmc_send_if_cond(struct mmc *mmc)
+{
+	struct mmc_cmd cmd;
+	int err;
+
+	cmd.cmdidx = SEND_IF_COND;
+	cmd.cmdarg = 0x1aa;
+	cmd.resp_type = MMC_CMD_R7;
+	cmd.flags = 0;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	if (((uint *)(cmd.response))[0] != 0x1aa)
+		return UNUSABLE_ERR;
+	else
+		mmc->version = SD_VERSION_2;
+
+	return 0;
+}
+
+int
+mmc_init(int verbose)
+{
+	volatile immap_t *im = (immap_t *) CFG_IMMR;
+	struct fsl_esdhc *regs = (struct fsl_esdhc *)&im->sdhc;
+	int timeout = 1000;
+	struct mmc *mmc;
+	int err;
+
+	mmc = malloc(sizeof(struct mmc));
+
+	mmc->regs = regs;
+
+	if (mmc_dev)
+		free(mmc_dev);
+
+	mmc_dev = mmc;
+
+	regs->sysctl = SYSCTL_HCKEN | SYSCTL_IPGEN;
+
+	/* Set the clock speed */
+	set_sysctl(mmc, 400000);
+
+	/* Disable the BRR and BWR bits in IRQSTAT */
+	regs->irqstaten &= ~(IRQSTATEN_BRR | IRQSTATEN_BWR);
+
+	/* Put the PROCTL reg back to the default */
+	regs->proctl = PROCTL_INIT;
+
+	while (!(regs->prsstat & PRSSTAT_CINS) && timeout--)
+		udelay(1000);
+
+	if (timeout <= 0)
+		return NO_CARD_ERR;
+
+	/* Reset the Card */
+	err = mmc_go_idle(mmc);
+
+	if (err)
+		return err;
+
+	/* Test for SD version 2 */
+	err = mmc_send_if_cond(mmc);
+
+	/* If we got an error other than timeout, we bail */
+	if (err && err != TIMEOUT)
+		return err;
+
+	/* Now try to get the SD card's operating condition */
+	err = sd_send_op_cond(mmc);
+
+	/* If the command timed out, we check for an MMC card */
+	if (err == TIMEOUT) {
+		err = mmc_send_op_cond(mmc);
+
+		if (err) {
+			printf("Card did not respond to voltage select!\n");
+			return UNUSABLE_ERR;
+		}
+	}
+
+	err = mmc_startup(mmc);
+
+	if (err)
+		printf("Returning with err %d\n", err);
+
+	return err;
+}
+
+int
+mmc2info(ulong addr)
+{
+	/* Hmm... */
+	return 0;
+}
+
+static void print_mmcinfo(struct mmc *mmc)
+{
+	printf("Manufacturer: %x\n", mmc->cid[0] >> 24);
+	printf("OEM: %x\n", (mmc->cid[0] >> 8) & 0xffff);
+	printf("Name: %c%c%c%c%c\n", mmc->cid[0] & 0xff,
+			(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
+			(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
+
+	printf("Tran Speed: %d\n", mmc->tran_speed);
+	printf("Rd Block Len: %d\n", mmc->read_bl_len);
+
+	printf("%s version %d.%d\n", IS_SD(mmc) ? "SD" : "MMC",
+			(mmc->version >> 4) & 0xf, mmc->version & 0xf);
+
+	printf("High Capacity: %s\n", mmc->high_capacity ? "Yes" : "No");
+	printf("Capacity: %d\n", mmc->capacity);
+
+	printf("Bus Width: %d-bit\n", (mmc->mode & MMC_MODE_4BIT) ? 4 :
+			(mmc->mode & MMC_MODE_8BIT) ? 8 : 1);
+}
+
+int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	if (mmc_dev)
+		print_mmcinfo(mmc_dev);
+	else
+		printf("Call mmcinit first\n");
+
+	return 0;
+}
+
+U_BOOT_CMD(mmcinfo, 1, 0, do_mmcinfo, "mmcinfo -- display MMC info\n", NULL);
+
+#endif	/* CONFIG_MMC */
diff --git a/drivers/mmc/fsl_esdhc.h b/drivers/mmc/fsl_esdhc.h
new file mode 100644
index 0000000..cf5f2d1
--- /dev/null
+++ b/drivers/mmc/fsl_esdhc.h
@@ -0,0 +1,208 @@
+/*
+ * FSL SD/MMC Defines
+ *-------------------------------------------------------------------
+ *
+ * Copyright 2007-2008, Freescale Semiconductor, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *-------------------------------------------------------------------
+ *
+ */
+
+#ifndef  __FSL_ESDHC_H__
+#define	__FSL_ESDHC_H__
+
+#define SD_VERSION_SD	0x20000
+#define SD_VERSION_2	(SD_VERSION_SD | 0x20)
+#define SD_VERSION_1_0	(SD_VERSION_SD | 0x10)
+#define SD_VERSION_1_10	(SD_VERSION_SD | 0x1a)
+#define MMC_VERSION_MMC		0x10000
+#define MMC_VERSION_UNKNOWN	(MMC_VERSION_MMC)
+#define MMC_VERSION_1_2		(MMC_VERSION_MMC | 0x12)
+#define MMC_VERSION_1_4		(MMC_VERSION_MMC | 0x14)
+#define MMC_VERSION_2_2		(MMC_VERSION_MMC | 0x22)
+#define MMC_VERSION_3		(MMC_VERSION_MMC | 0x30)
+#define MMC_VERSION_4		(MMC_VERSION_MMC | 0x40)
+
+#define MMC_MODE_HS		0x001
+#define MMC_MODE_HS_52MHz	0x010
+#define MMC_MODE_4BIT		0x100
+#define MMC_MODE_8BIT		0x200
+
+#define SD_DATA_4BIT	0x00040000
+
+#define IS_SD(x) (mmc->version & SD_VERSION_SD)
+
+#define MMC_DATA_READ		1
+#define MMC_DATA_WRITE		2
+
+#define NO_CARD_ERR		-16 /* No SD/MMC card inserted */
+#define UNUSABLE_ERR		-17 /* Unusable Card */
+#define COMM_ERR		-18 /* Communications Error */
+#define TIMEOUT			-19
+
+#define GO_IDLE_STATE		0x0
+#define SEND_IF_COND		(8)
+
+#define APP_CMD			(55)
+
+#define MMC_SEND_OP_COND	(1)
+
+#define SD_SEND_OP_COND		(41)
+
+#define ALL_SEND_CID		(2)
+
+#define SEND_RELATIVE_ADDR	(3)
+
+#define SELECT_CARD		(7)
+
+#define SEND_SCR		(51)
+
+#define SEND_EXT_CSD		(8)
+
+#define SEND_CSD		(9)
+
+#define SEND_STATUS		(13)
+
+#define SWITCH_FUNC		(6)
+#define MMC_SWITCH		(6)
+
+#define SET_BUS_WIDTH		(6)
+
+#define STOP_TRANSMISSION	(12)
+
+#define SET_BLOCKLEN		(16)
+
+#define READ_SINGLE_BLOCK	(17)
+#define READ_MULTIPLE_BLOCKS	(18)
+
+#define SD_HIGHSPEED_BUSY	0x00020000
+#define SD_HIGHSPEED_SUPPORTED	0x00020000
+
+#define MMC_HS_TIMING		0x00000100
+#define MMC_HS_52MHZ		0x2
+
+#define OCR_BUSY	0x80
+#define OCR_HCS		0x40000000
+
+/* FSL eSDHC-specific constants */
+#define SYSCTL			0x0002e02c
+#define SYSCTL_INITA		0x08000000
+#define SYSCTL_PEREN		0x00000004
+#define SYSCTL_HCKEN		0x00000002
+#define SYSCTL_IPGEN		0x00000001
+
+#define IRQSTAT			0x0002e030
+#define IRQSTAT_DMAE		(0x10000000)
+#define IRQSTAT_AC12E		(0x01000000)
+#define IRQSTAT_DEBE		(0x00400000)
+#define IRQSTAT_DCE		(0x00200000)
+#define IRQSTAT_DTOE		(0x00100000)
+#define IRQSTAT_CIE		(0x00080000)
+#define IRQSTAT_CEBE		(0x00040000)
+#define IRQSTAT_CCE		(0x00020000)
+#define IRQSTAT_CTOE		(0x00010000)
+#define IRQSTAT_CINT		(0x00000100)
+#define IRQSTAT_CRM		(0x00000080)
+#define IRQSTAT_CINS		(0x00000040)
+#define IRQSTAT_BRR		(0x00000020)
+#define IRQSTAT_BWR		(0x00000010)
+#define IRQSTAT_DINT		(0x00000008)
+#define IRQSTAT_BGE		(0x00000004)
+#define IRQSTAT_TC		(0x00000002)
+#define IRQSTAT_CC		(0x00000001)
+
+#define CMD_ERR		(IRQSTAT_CIE | IRQSTAT_CEBE | IRQSTAT_CCE)
+#define DATA_ERR	(IRQSTAT_DEBE | IRQSTAT_DCE | IRQSTAT_DTOE)
+
+#define IRQSTATEN		0x0002e034
+#define IRQSTATEN_DMAE		(0x10000000)
+#define IRQSTATEN_AC12E		(0x01000000)
+#define IRQSTATEN_DEBE		(0x00400000)
+#define IRQSTATEN_DCE		(0x00200000)
+#define IRQSTATEN_DTOE		(0x00100000)
+#define IRQSTATEN_CIE		(0x00080000)
+#define IRQSTATEN_CEBE		(0x00040000)
+#define IRQSTATEN_CCE		(0x00020000)
+#define IRQSTATEN_CTOE		(0x00010000)
+#define IRQSTATEN_CINT		(0x00000100)
+#define IRQSTATEN_CRM		(0x00000080)
+#define IRQSTATEN_CINS		(0x00000040)
+#define IRQSTATEN_BRR		(0x00000020)
+#define IRQSTATEN_BWR		(0x00000010)
+#define IRQSTATEN_DINT		(0x00000008)
+#define IRQSTATEN_BGE		(0x00000004)
+#define IRQSTATEN_TC		(0x00000002)
+#define IRQSTATEN_CC		(0x00000001)
+
+#define PRSSTAT			0x0002e024
+#define PRSSTAT_CLSL		(0x00800000)
+#define PRSSTAT_WPSPL		(0x00080000)
+#define PRSSTAT_CDPL		(0x00040000)
+#define PRSSTAT_CINS		(0x00010000)
+#define PRSSTAT_BREN		(0x00000800)
+#define PRSSTAT_DLA		(0x00000004)
+#define PRSSTAT_CICHB		(0x00000002)
+#define PRSSTAT_CIDHB		(0x00000001)
+
+#define PROCTL			0x0002e028
+#define PROCTL_INIT		0x00000020
+#define PROCTL_DTW_4		0x00000002
+#define PROCTL_DTW_8		0x00000004
+
+#define CMDARG			0x0002e008
+
+#define XFERTYP			0x0002e00c
+#define XFERTYP_CMD(x)		((x & 0x3f) << 24)
+#define XFERTYP_CMDTYP_NORMAL	0x0
+#define XFERTYP_CMDTYP_SUSPEND	0x00400000
+#define XFERTYP_CMDTYP_RESUME	0x00800000
+#define XFERTYP_CMDTYP_ABORT	0x00c00000
+#define XFERTYP_DPSEL		0x00200000
+#define XFERTYP_CICEN		0x00100000
+#define XFERTYP_CCCEN		0x00080000
+#define XFERTYP_RSPTYP_NONE	0
+#define XFERTYP_RSPTYP_136	0x00010000
+#define XFERTYP_RSPTYP_48	0x00020000
+#define XFERTYP_RSPTYP_48_BUSY	0x00030000
+#define XFERTYP_MSBSEL		0x00000020
+#define XFERTYP_DTDSEL		0x00000010
+#define XFERTYP_AC12EN		0x00000004
+#define XFERTYP_BCEN		0x00000002
+#define XFERTYP_DMAEN		0x00000001
+
+#define CINS_TIMEOUT		1000
+
+#define DSADDR		0x2e004
+
+#define CMDRSP0		0x2e010
+#define CMDRSP1		0x2e014
+#define CMDRSP2		0x2e018
+#define CMDRSP3		0x2e01c
+
+#define DATPORT		0x2e020
+
+#define WML		0x2e044
+#define WML_WRITE	0x00010000
+
+#define BLKATTR		0x2e004
+#define BLKATTR_CNT(x)	((x & 0xffff) << 16)
+#define BLKATTR_SIZE(x)	(x & 0x1fff)
+#define MAX_BLK_CNT	0x7fff	/* so malloc will have enough room with 32M */
+
+
+#endif  /* __FSL_ESDHC_H__ */
diff --git a/include/asm-ppc/arch-mpc83xx/mmc.h b/include/asm-ppc/arch-mpc83xx/mmc.h
new file mode 100644
index 0000000..d5034f4
--- /dev/null
+++ b/include/asm-ppc/arch-mpc83xx/mmc.h
@@ -0,0 +1 @@
+/* Stub file to satisfy odd requirement for <arch/mmc.h> */
-- 
1.5.4.GIT

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [U-Boot-Users] [PATCH] Add eSDHC driver
  2008-04-22 15:07               ` [U-Boot-Users] [PATCH] Add eSDHC driver Andy Fleming
@ 2008-04-22 16:53                 ` Anton Vorontsov
  2008-04-23 19:23                 ` Ken.Fuchs at bench.com
  1 sibling, 0 replies; 39+ messages in thread
From: Anton Vorontsov @ 2008-04-22 16:53 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 22, 2008 at 10:07:46AM -0500, Andy Fleming wrote:
> This is the SD/MMC controller on several of Freescale's more recent parts

Cool. Is there Linux version pending? Does anybody working on it yet?

Thanks.

-- 
Anton Vorontsov
email: cbouatmailru at gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] [PATCH] Add eSDHC driver
  2008-04-22 15:07               ` [U-Boot-Users] [PATCH] Add eSDHC driver Andy Fleming
  2008-04-22 16:53                 ` Anton Vorontsov
@ 2008-04-23 19:23                 ` Ken.Fuchs at bench.com
  2008-04-24  6:24                   ` Pierre Savary
  1 sibling, 1 reply; 39+ messages in thread
From: Ken.Fuchs at bench.com @ 2008-04-23 19:23 UTC (permalink / raw)
  To: u-boot

> Pierre Savary wrote:

> >Where could we find the driver that works with MMCv4 on at91sam9x?

Andy Fleming wrote:

> Pierre, I don't have a driver that works on at91sam9x, I'm 
> afraid.

Here's an MMC v2.x AT91SAM9260 patch for Atmel modified u-boot 1.1.5.
You will need to define GPIO pins for other AT91SAM9 processors, etc.

If you really need an MMC v4.x AT91SAM9 MCI driver for 1.1.5 fast, you
probably could cut and paste the v4.x code you need from Andy's MMC
driver
into the MMC v2.x MCI driver this patch provides.

BTW, if anyone knows why MMC 4 bit is disabled for AT91SAM9261 in the
MCI Linux driver, I'd like to hear the reasons why.

--- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) ---

diff -burN u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c
u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c
--- u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c	2007-08-21
17:06:36.000000000 +0200
+++ u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c
2007-08-23 08:37:42.000000000 +0200
@@ -109,6 +109,24 @@
 }
 
 
+#ifdef CONFIG_MMC
+#if (CONFIG_COMMANDS & CFG_CMD_MMC)
+int AT91F_MMC_Hardware_Init(void)
+{
+	AT91C_BASE_PIOA->PIO_ASR = (1 << 8 );		/* periph A
select register */
+	AT91C_BASE_PIOA->PIO_BSR |= 0x3B;			/*
periph B select register */
+	AT91C_BASE_PIOA->PIO_PDR |= 0x13B;			/* PIO
disable register */
+	AT91C_BASE_PIOA->PIO_PPUDR |= 0x13B;		/* Pull up
disable register */
+
+	AT91C_BASE_PMC->PMC_PCER = (1 << 9);
+}
+#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */
+#endif /* CONFIG_MMC */
+
+
+
+
+
 #ifdef CONFIG_DRIVER_ETHER
 #if (CONFIG_COMMANDS & CFG_CMD_NET)
 
diff -burN u-boot-1.1.5/common/cmd_nvedit.c
u-boot-1.1.5.klk/common/cmd_nvedit.c
--- u-boot-1.1.5/common/cmd_nvedit.c	2006-10-20 17:54:33.000000000
+0200
+++ u-boot-1.1.5.klk/common/cmd_nvedit.c	2007-08-23
09:26:18.000000000 +0200
@@ -530,6 +530,7 @@
 	return (-1);
 }
 
+#ifndef CFG_ENV_IS_NOWHERE
 #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \
     ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \
       (CFG_CMD_ENV|CFG_CMD_FLASH)) || \
@@ -544,7 +545,7 @@
 	return (saveenv() ? 1 : 0);
 }
 
-
+#endif
 #endif
 
 
@@ -587,7 +588,7 @@
 	"setenv name\n"
 	"    - delete environment variable 'name'\n"
 );
-
+#ifndef CFG_ENV_IS_NOWHERE
 #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \
     ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \
       (CFG_CMD_ENV|CFG_CMD_FLASH)) || \
@@ -600,6 +601,7 @@
 );
 
 #endif	/* CFG_CMD_ENV */
+#endif	
 
 #if (CONFIG_COMMANDS & CFG_CMD_ASKENV)
 
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c
u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c
--- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c	1970-01-01
01:00:00.000000000 +0100
+++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c
2007-08-23 09:45:46.000000000 +0200
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+
+#ifdef CONFIG_MMC
+
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+//#include <asm/arch/clk.h>
+//#include <asm/arch/memory-map.h>
+#include <asm/arch/hardware.h>	//klk
+
+#include "atmel_mci.h"
+#undef DEBUG
+#ifdef DEBUG
+#define pr_debug(fmt, args...) printf(fmt, ##args)
+#else
+#define pr_debug(...) do { } while(0)
+#endif
+
+#ifndef CFG_MMC_CLK_OD
+#define CFG_MMC_CLK_OD		375000
+#endif
+
+#ifndef CFG_MMC_CLK_PP
+#define CFG_MMC_CLK_PP		20000000
+#endif
+
+#ifndef CFG_MMC_OP_COND
+#define CFG_MMC_OP_COND		0x00100000
+#endif
+
+#define MMC_DEFAULT_BLKLEN	512
+#define MMC_DEFAULT_RCA		1
+
+static unsigned int mmc_rca;
+static int mmc_card_is_sd;
+static block_dev_desc_t mmc_blkdev;
+
+block_dev_desc_t *mmc_get_dev(int dev)
+{
+	return &mmc_blkdev;
+}
+
+static void mci_set_mode(unsigned long hz, unsigned long blklen)
+{
+	unsigned long bus_hz;
+	unsigned long clkdiv;
+
+	// bus_hz = get_mci_clk_rate();
+	bus_hz = AT91C_MASTER_CLOCK;
+	clkdiv = (bus_hz / hz) / 2 - 1;
+
+	pr_debug("mmc: setting clock %lu Hz, block size %lu\n",
+		 hz, blklen);
+
+	if (clkdiv & ~255UL) {
+		clkdiv = 255;
+		pr_debug("mmc: clock %lu too low; setting CLKDIV to
255\n",
+			hz);
+	}
+
+	blklen &= 0xfffc;
+	mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv)
+			 | MMCI_BF(BLKLEN, blklen)
+			 | MMCI_BIT(RDPROOF)
+			 | MMCI_BIT(WRPROOF)));
+}
+
+#define RESP_NO_CRC	1
+#define R1		MMCI_BF(RSPTYP, 1)
+#define R2		MMCI_BF(RSPTYP, 2)
+#define R3		(R1 | RESP_NO_CRC)
+#define R6		R1
+#define NID		MMCI_BF(MAXLAT, 0)
+#define NCR		MMCI_BF(MAXLAT, 1)
+#define TRCMD_START	MMCI_BF(TRCMD, 1)
+#define TRDIR_READ	MMCI_BF(TRDIR, 1)
+#define TRTYP_BLOCK	MMCI_BF(TRTYP, 0)
+#define INIT_CMD	MMCI_BF(SPCMD, 1)
+#define OPEN_DRAIN	MMCI_BF(OPDCMD, 1)
+
+#define ERROR_FLAGS	(MMCI_BIT(DTOE)			\
+			 | MMCI_BIT(RDIRE)		\
+			 | MMCI_BIT(RENDE)		\
+			 | MMCI_BIT(RINDE)		\
+			 | MMCI_BIT(RTOE))
+
+static int
+mmc_cmd(unsigned long cmd, unsigned long arg,
+	void *resp, unsigned long flags)
+{
+	unsigned long *response = resp;
+	int i, response_words = 0;
+	unsigned long error_flags;
+	u32 status;
+
+	AT91F_MMC_Hardware_Init();
+	
+	pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n",
+		 cmd, arg, flags);
+
+	error_flags = ERROR_FLAGS;
+	if (!(flags & RESP_NO_CRC))
+		error_flags |= MMCI_BIT(RCRCE);
+
+	flags &= ~MMCI_BF(CMDNB, ~0UL);
+
+	if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_48_BIT_RESP)
+		response_words = 1;
+	else if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_136_BIT_RESP)
+		response_words = 4;
+
+	mmci_writel(ARGR, arg);
+	mmci_writel(CMDR, cmd | flags);
+	do {
+		udelay(40);
+		status = mmci_readl(SR);
+	} while (!(status & MMCI_BIT(CMDRDY)));
+
+	pr_debug("mmc: status 0x%08lx\n", status);
+
+	if (status & ERROR_FLAGS) {
+		pr_debug("mmc: command %lu failed (status: 0x%08lx)\n",
+		       cmd, status);
+		return -EIO;
+	}
+
+	if (response_words)
+		pr_debug("mmc: response:");
+
+	for (i = 0; i < response_words; i++) {
+		response[i] = mmci_readl(RSPR);
+		pr_debug(" %08lx", response[i]);
+	}
+	pr_debug("\n");
+
+	return 0;
+}
+
+static int mmc_acmd(unsigned long cmd, unsigned long arg,
+		    void *resp, unsigned long flags)
+{
+	unsigned long aresp[4];
+	int ret;
+
+	/*
+	 * Seems like the APP_CMD part of an ACMD has 64 cycles max
+	 * latency even though the ACMD part doesn't. This isn't
+	 * entirely clear in the SD Card spec, but some cards refuse
+	 * to work if we attempt to use 5 cycles max latency here...
+	 */
+	ret = mmc_cmd(MMC_CMD_APP_CMD, 0, aresp,
+		      R1 | NCR | (flags & OPEN_DRAIN));
+	if (ret)
+		return ret;
+	if ((aresp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) !=
R1_APP_CMD)
+		return -ENODEV;
+
+	ret = mmc_cmd(cmd, arg, resp, flags);
+	return ret;
+}
+
+static unsigned long
+mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
+	  unsigned long *buffer)
+{
+	int ret, i = 0;
+	unsigned long resp[4];
+	unsigned long card_status, data;
+	unsigned long wordcount;
+	u32 status;
+
+	if (blkcnt == 0)
+		return 0;
+
+	pr_debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n",
+		 dev, start, blkcnt);
+
+	/* Put the device into Transfer state */
+	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	if (ret) goto fail;
+
+	/* Set block length */
+	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	if (ret) goto fail;
+
+	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
+
+	for (i = 0; i < blkcnt; i++, start++) {
+		ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK,
+			      start * mmc_blkdev.blksz, resp,
+			      (R1 | NCR | TRCMD_START | TRDIR_READ
+			       | TRTYP_BLOCK));
+		if (ret) goto fail;
+
+		ret = -EIO;
+		wordcount = 0;
+		do {
+			do {
+				status = mmci_readl(SR);
+				if (status & (ERROR_FLAGS |
MMCI_BIT(OVRE)))
+					goto fail;
+			} while (!(status & MMCI_BIT(RXRDY)));
+
+			if (status & MMCI_BIT(RXRDY)) {
+				data = mmci_readl(RDR);
+				/* pr_debug("%x\n", data); */
+				*buffer++ = data;
+				wordcount++;
+			}
+		} while(wordcount < (mmc_blkdev.blksz / 4));
+
+		pr_debug("mmc: read %u words, waiting for BLKE\n",
wordcount);
+
+		do {
+			status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(BLKE)));
+
+		putc('.');
+	}
+
+out:
+	/* Put the device back into Standby state */
+	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	return i;
+
+fail:
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread failed, card status = %08x\n",
card_status);
+	goto out;
+}
+
+static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp)
+{
+	cid->mid = resp[0] >> 24;
+	cid->oid = (resp[0] >> 8) & 0xffff;
+	cid->pnm[0] = resp[0];
+	cid->pnm[1] = resp[1] >> 24;
+	cid->pnm[2] = resp[1] >> 16;
+	cid->pnm[3] = resp[1] >> 8;
+	cid->pnm[4] = resp[1];
+	cid->pnm[5] = resp[2] >> 24;
+	cid->pnm[6] = 0;
+	cid->prv = resp[2] >> 16;
+	cid->psn = (resp[2] << 16) | (resp[3] >> 16);
+	cid->mdt = resp[3] >> 8;
+}
+
+static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp)
+{
+	cid->mid = resp[0] >> 24;
+	cid->oid = (resp[0] >> 8) & 0xffff;
+	cid->pnm[0] = resp[0];
+	cid->pnm[1] = resp[1] >> 24;
+	cid->pnm[2] = resp[1] >> 16;
+	cid->pnm[3] = resp[1] >> 8;
+	cid->pnm[4] = resp[1];
+	cid->pnm[5] = 0;
+	cid->pnm[6] = 0;
+	cid->prv = resp[2] >> 24;
+	cid->psn = (resp[2] << 8) | (resp[3] >> 24);
+	cid->mdt = (resp[3] >> 8) & 0x0fff;
+}
+
+static void mmc_dump_cid(const struct mmc_cid *cid)
+{
+	printf("Manufacturer ID:       %02lX\n", cid->mid);
+	printf("OEM/Application ID:    %04lX\n", cid->oid);
+	printf("Product name:          %s\n", cid->pnm);
+	printf("Product Revision:      %lu.%lu\n",
+	       cid->prv >> 4, cid->prv & 0x0f);
+	printf("Product Serial Number: %lu\n", cid->psn);
+	printf("Manufacturing Date:    %02lu/%02lu\n",
+	       cid->mdt >> 4, cid->mdt & 0x0f);
+}
+
+static void mmc_dump_csd(const struct mmc_csd *csd)
+{
+	unsigned long *csd_raw = (unsigned long *)csd;
+	pr_debug("CSD data: %08lx %08lx %08lx %08lx\n",
+	       csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]);
+	pr_debug("CSD structure version:   1.%u\n", csd->csd_structure);
+	pr_debug("MMC System Spec version: %u\n", csd->spec_vers);
+	pr_debug("Card command classes:    %03x\n", csd->ccc);
+	pr_debug("Read block length:       %u\n", 1 <<
csd->read_bl_len);
+	if (csd->read_bl_partial)
+		puts("Supports partial reads\n");
+	else
+		puts("Does not support partial reads\n");
+	pr_debug("Write block length:      %u\n", 1 <<
csd->write_bl_len);
+	if (csd->write_bl_partial)
+		puts("Supports partial writes\n");
+	else
+		puts("Does not support partial writes\n");
+	if (csd->wp_grp_enable)
+		pr_debug("Supports group WP:      %u\n",
csd->wp_grp_size + 1);
+	else
+		puts("Does not support group WP\n");
+	pr_debug("Card capacity:		%u bytes\n",
+	       (csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) *
+	       (1 << csd->read_bl_len));
+	pr_debug("File format:            %u/%u\n",
+	       csd->file_format_grp, csd->file_format);
+	puts("Write protection:        ");
+	if (csd->perm_write_protect)
+		puts(" permanent");
+	if (csd->tmp_write_protect)
+		puts(" temporary");
+	putc('\n');
+}
+
+static int mmc_idle_cards(void)
+{
+	int ret;
+
+	/* Reset and initialize all cards */
+	ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0);
+	
+	if (ret)
+		return ret;
+	pr_debug(" ret: %i\n",ret);
+	/* Keep the bus idle for 74 clock cycles */
+	return mmc_cmd(0, 0, NULL, INIT_CMD);
+}
+
+static int sd_init_card(struct mmc_cid *cid, int verbose)
+{
+	unsigned long resp[4];
+	int i, ret = 0;
+
+	mmc_idle_cards();
+	for (i = 0; i < 1000; i++) {
+		ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND,
CFG_MMC_OP_COND,
+			       resp, R3 | NID);
+		if (ret || (resp[0] & 0x80000000))
+			break;
+		ret = -ETIMEDOUT;
+	}
+
+	if (ret)
+		return ret;
+
+	ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID);
+	if (ret)
+		return ret;
+	sd_parse_cid(cid, resp);
+	if (verbose)
+		mmc_dump_cid(cid);
+
+	/* Get RCA of the card that responded */
+	ret = mmc_cmd(MMC_CMD_SD_SEND_RELATIVE_ADDR, 0, resp, R6 | NCR);
+	if (ret)
+		return ret;
+
+	mmc_rca = resp[0] >> 16;
+	if (verbose)
+		pr_debug("SD Card detected (RCA %u)\n", mmc_rca);
+	mmc_card_is_sd = 1;
+	return 0;
+}
+
+static int mmc_init_card(struct mmc_cid *cid, int verbose)
+{
+	unsigned long resp[4];
+	int i, ret = 0;
+
+	mmc_idle_cards();
+
+	for (i = 0; i < 1000; i++) {
+		ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND,
resp,
+			      R3 | NID | OPEN_DRAIN);
+		if (ret || (resp[0] & 0x80000000))
+		{
+			break;
+		}
+		ret = -ETIMEDOUT;
+	}
+	pr_debug("4\n");
+	pr_debug("ret : %i\n",ret);
+	if (ret)
+		return ret;
+	pr_debug("5\n");
+	/* Get CID of all cards. FIXME: Support more than one card */
+	ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID |
OPEN_DRAIN);
+	if (ret)
+		return ret;
+	mmc_parse_cid(cid, resp);
+	if (verbose)
+		mmc_dump_cid(cid);
+
+	/* Set Relative Address of the card that responded */
+	ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp,
+		      R1 | NCR | OPEN_DRAIN);
+	return ret;
+}
+
+static void mci_set_data_timeout(struct mmc_csd *csd)
+{
+	static const unsigned int dtomul_to_shift[] = {
+		0, 4, 7, 8, 10, 12, 16, 20,
+	};
+	static const unsigned int taac_exp[] = {
+		1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
+	};
+	static const unsigned int taac_mant[] = {
+		0,  10, 12, 13, 15, 60, 25, 30,
+		35, 40, 45, 50, 55, 60, 70, 80,
+	};
+	unsigned int timeout_ns, timeout_clks;
+	unsigned int e, m;
+	unsigned int dtocyc, dtomul;
+	unsigned int shift;
+	u32 dtor;
+
+	e = csd->taac & 0x07;
+	m = (csd->taac >> 3) & 0x0f;
+
+	timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10;
+	timeout_clks = csd->nsac * 100;
+
+	timeout_clks += (((timeout_ns + 9) / 10)
+			 * ((CFG_MMC_CLK_PP + 99999) / 100000) + 9999) /
10000;
+	if (!mmc_card_is_sd)
+		timeout_clks *= 10;
+	else
+		timeout_clks *= 100;
+
+	dtocyc = timeout_clks;
+	dtomul = 0;
+	while (dtocyc > 15 && dtomul < 8) {
+		dtomul++;
+		shift = dtomul_to_shift[dtomul];
+		dtocyc = (timeout_clks + (1 << shift) - 1) >> shift;
+	}
+
+	if (dtomul >= 8) {
+		dtomul = 7;
+		dtocyc = 15;
+		puts("Warning: Using maximum data timeout\n");
+	}
+
+	dtor = (MMCI_BF(DTOMUL, dtomul)
+		| MMCI_BF(DTOCYC, dtocyc));
+	mmci_writel(DTOR, dtor);
+
+	pr_debug("mmc: Using %u cycles data timeout (DTOR=0x%x)\n",
+	       dtocyc << shift, dtor);
+}
+
+int mmc_init(int verbose)
+{
+	struct mmc_cid cid;
+	struct mmc_csd csd;
+	unsigned int max_blksz;
+	int ret,aux;
+	
+	AT91F_MMC_Hardware_Init();
+	
+	pr_debug("0\n");
+	/* Initialize controller */
+	mmci_writel(CR, MMCI_BIT(SWRST));
+	mmci_writel(CR, MMCI_BIT(MCIEN));
+	mmci_writel(DTOR, 0x5f);
+	mmci_writel(IDR, ~0UL);
+	mmci_writel(SDCR, 0x1);
+	mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+/* 	//mmci_writel(CR, MMCI_BIT(SWRST));
+	mmci_writel(CR, 0x00000001);
+	mmci_writel(DTOR, 0x0000007F);
+	mmci_writel(IDR, 0xFFFFFFFF);
+	mmci_writel(SDCR, 0x00000001);
+	//mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+	mmci_writel(MR, 0x02009B4A); */
+
+	pr_debug("1\n");
+	
+	mmc_card_is_sd = 0;
+
+	ret = sd_init_card(&cid, verbose);
+	if (ret) {
+		mmc_rca = MMC_DEFAULT_RCA;
+		ret = mmc_init_card(&cid, verbose);
+	}
+	pr_debug("6\n");
+	if (ret)
+		return ret;
+	pr_debug("7\n");
+	/* Get CSD from the card */
+	ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &csd, R2 | NCR);
+	if (ret)
+		return ret;
+	if (verbose)
+		mmc_dump_csd(&csd);
+
+	mci_set_data_timeout(&csd);
+
+	/* Initialize the blockdev structure */
+	mmc_blkdev.if_type = IF_TYPE_MMC;
+	mmc_blkdev.part_type = PART_TYPE_DOS;
+	mmc_blkdev.block_read = mmc_bread;
+	sprintf((char *)mmc_blkdev.vendor,
+		"Man %02x%04x Snr %08x",
+		cid.mid, cid.oid, cid.psn);
+	strncpy((char *)mmc_blkdev.product, cid.pnm,
+		sizeof(mmc_blkdev.product));
+	sprintf((char *)mmc_blkdev.revision, "%x %x",
+		cid.prv >> 4, cid.prv & 0x0f);
+
+	/*
+	 * If we can't use 512 byte blocks, refuse to deal with the
+	 * card. Tons of code elsewhere seems to depend on this.
+	 */
+	max_blksz = 1 << csd.read_bl_len;
+	// if (max_blksz < 512 || (max_blksz > 512 &&
!csd.read_bl_partial)) {
+		// pr_debug("Card does not support 512 byte reads,
aborting.\n");
+		// return -ENODEV;
+	// }
+	mmc_blkdev.blksz = 512;
+	mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult +
2));
+
+	mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz);
+
+#if 0
+	if (fat_register_device(&mmc_blkdev, 1))
+		pr_debug("Could not register MMC fat device\n");
+#else
+	init_part(&mmc_blkdev);
+#endif
+
+	return 0;
+}
+
+int mmc_read(ulong src, uchar *dst, int size)
+{
+	return -ENOSYS;
+}
+
+int mmc_write(uchar *src, ulong dst, int size)
+{
+	return -ENOSYS;
+}
+
+int mmc2info(ulong addr)
+{
+	return 0;
+}
+
+#endif /* CONFIG_MMC */
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h
u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h
--- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h	1970-01-01
01:00:00.000000000 +0100
+++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h
2007-08-17 10:43:17.000000000 +0200
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __CPU_AT32AP_ATMEL_MCI_H__
+#define __CPU_AT32AP_ATMEL_MCI_H__
+
+/* Atmel MultiMedia Card Interface (MCI) registers */
+#define MMCI_CR					0x0000
+#define MMCI_MR					0x0004
+#define MMCI_DTOR				0x0008
+#define MMCI_SDCR				0x000c
+#define MMCI_ARGR				0x0010
+#define MMCI_CMDR				0x0014
+#define MMCI_RSPR				0x0020
+#define MMCI_RSPR1				0x0024
+#define MMCI_RSPR2				0x0028
+#define MMCI_RSPR3				0x002c
+#define MMCI_RDR				0x0030
+#define MMCI_TDR				0x0034
+#define MMCI_SR					0x0040
+#define MMCI_IER				0x0044
+#define MMCI_IDR				0x0048
+#define MMCI_IMR				0x004c
+
+/* Bitfields in CR */
+#define MMCI_MCIEN_OFFSET			0
+#define MMCI_MCIEN_SIZE				1
+#define MMCI_MCIDIS_OFFSET			1
+#define MMCI_MCIDIS_SIZE			1
+#define MMCI_PWSEN_OFFSET			2
+#define MMCI_PWSEN_SIZE				1
+#define MMCI_PWSDIS_OFFSET			3
+#define MMCI_PWSDIS_SIZE			1
+#define MMCI_SWRST_OFFSET			7
+#define MMCI_SWRST_SIZE				1
+
+/* Bitfields in MR */
+#define MMCI_CLKDIV_OFFSET			0
+#define MMCI_CLKDIV_SIZE			8
+#define MMCI_PWSDIV_OFFSET			8
+#define MMCI_PWSDIV_SIZE			3
+#define MMCI_RDPROOF_OFFSET			11
+#define MMCI_RDPROOF_SIZE			1
+#define MMCI_WRPROOF_OFFSET			12
+#define MMCI_WRPROOF_SIZE			1
+#define MMCI_PDCPADV_OFFSET			14
+#define MMCI_PDCPADV_SIZE			1
+#define MMCI_PDCMODE_OFFSET			15
+#define MMCI_PDCMODE_SIZE			1
+#define MMCI_BLKLEN_OFFSET			16
+#define MMCI_BLKLEN_SIZE			16
+
+/* Bitfields in DTOR */
+#define MMCI_DTOCYC_OFFSET			0
+#define MMCI_DTOCYC_SIZE			4
+#define MMCI_DTOMUL_OFFSET			4
+#define MMCI_DTOMUL_SIZE			3
+
+/* Bitfields in SDCR */
+#define MMCI_SCDSEL_OFFSET			0
+#define MMCI_SCDSEL_SIZE			4
+#define MMCI_SCDBUS_OFFSET			7
+#define MMCI_SCDBUS_SIZE			1
+
+/* Bitfields in ARGR */
+#define MMCI_ARG_OFFSET				0
+#define MMCI_ARG_SIZE				32
+
+/* Bitfields in CMDR */
+#define MMCI_CMDNB_OFFSET			0
+#define MMCI_CMDNB_SIZE				6
+#define MMCI_RSPTYP_OFFSET			6
+#define MMCI_RSPTYP_SIZE			2
+#define MMCI_SPCMD_OFFSET			8
+#define MMCI_SPCMD_SIZE				3
+#define MMCI_OPDCMD_OFFSET			11
+#define MMCI_OPDCMD_SIZE			1
+#define MMCI_MAXLAT_OFFSET			12
+#define MMCI_MAXLAT_SIZE			1
+#define MMCI_TRCMD_OFFSET			16
+#define MMCI_TRCMD_SIZE				2
+#define MMCI_TRDIR_OFFSET			18
+#define MMCI_TRDIR_SIZE				1
+#define MMCI_TRTYP_OFFSET			19
+#define MMCI_TRTYP_SIZE				2
+
+/* Bitfields in RSPRx */
+#define MMCI_RSP_OFFSET				0
+#define MMCI_RSP_SIZE				32
+
+/* Bitfields in SR/IER/IDR/IMR */
+#define MMCI_CMDRDY_OFFSET			0
+#define MMCI_CMDRDY_SIZE			1
+#define MMCI_RXRDY_OFFSET			1
+#define MMCI_RXRDY_SIZE				1
+#define MMCI_TXRDY_OFFSET			2
+#define MMCI_TXRDY_SIZE				1
+#define MMCI_BLKE_OFFSET			3
+#define MMCI_BLKE_SIZE				1
+#define MMCI_DTIP_OFFSET			4
+#define MMCI_DTIP_SIZE				1
+#define MMCI_NOTBUSY_OFFSET			5
+#define MMCI_NOTBUSY_SIZE			1
+#define MMCI_ENDRX_OFFSET			6
+#define MMCI_ENDRX_SIZE				1
+#define MMCI_ENDTX_OFFSET			7
+#define MMCI_ENDTX_SIZE				1
+#define MMCI_RXBUFF_OFFSET			14
+#define MMCI_RXBUFF_SIZE			1
+#define MMCI_TXBUFE_OFFSET			15
+#define MMCI_TXBUFE_SIZE			1
+#define MMCI_RINDE_OFFSET			16
+#define MMCI_RINDE_SIZE				1
+#define MMCI_RDIRE_OFFSET			17
+#define MMCI_RDIRE_SIZE				1
+#define MMCI_RCRCE_OFFSET			18
+#define MMCI_RCRCE_SIZE				1
+#define MMCI_RENDE_OFFSET			19
+#define MMCI_RENDE_SIZE				1
+#define MMCI_RTOE_OFFSET			20
+#define MMCI_RTOE_SIZE				1
+#define MMCI_DCRCE_OFFSET			21
+#define MMCI_DCRCE_SIZE				1
+#define MMCI_DTOE_OFFSET			22
+#define MMCI_DTOE_SIZE				1
+#define MMCI_OVRE_OFFSET			30
+#define MMCI_OVRE_SIZE				1
+#define MMCI_UNRE_OFFSET			31
+#define MMCI_UNRE_SIZE				1
+
+/* Constants for DTOMUL */
+#define MMCI_DTOMUL_1_CYCLE			0
+#define MMCI_DTOMUL_16_CYCLES			1
+#define MMCI_DTOMUL_128_CYCLES			2
+#define MMCI_DTOMUL_256_CYCLES			3
+#define MMCI_DTOMUL_1024_CYCLES			4
+#define MMCI_DTOMUL_4096_CYCLES			5
+#define MMCI_DTOMUL_65536_CYCLES		6
+#define MMCI_DTOMUL_1048576_CYCLES		7
+
+/* Constants for RSPTYP */
+#define MMCI_RSPTYP_NO_RESP			0
+#define MMCI_RSPTYP_48_BIT_RESP			1
+#define MMCI_RSPTYP_136_BIT_RESP		2
+
+/* Constants for SPCMD */
+#define MMCI_SPCMD_NO_SPEC_CMD			0
+#define MMCI_SPCMD_INIT_CMD			1
+#define MMCI_SPCMD_SYNC_CMD			2
+#define MMCI_SPCMD_INT_CMD			4
+#define MMCI_SPCMD_INT_RESP			5
+
+/* Constants for TRCMD */
+#define MMCI_TRCMD_NO_TRANS			0
+#define MMCI_TRCMD_START_TRANS			1
+#define MMCI_TRCMD_STOP_TRANS			2
+
+/* Constants for TRTYP */
+#define MMCI_TRTYP_BLOCK			0
+#define MMCI_TRTYP_MULTI_BLOCK			1
+#define MMCI_TRTYP_STREAM			2
+
+/* Bit manipulation macros */
+#define MMCI_BIT(name)					\
+	(1 << MMCI_##name##_OFFSET)
+#define MMCI_BF(name,value)				\
+	(((value) & ((1 << MMCI_##name##_SIZE) - 1))	\
+	 << MMCI_##name##_OFFSET)
+#define MMCI_BFEXT(name,value)				\
+	(((value) >> MMCI_##name##_OFFSET)\
+	 & ((1 << MMCI_##name##_SIZE) - 1))
+#define MMCI_BFINS(name,value,old)			\
+	(((old) & ~(((1 << MMCI_##name##_SIZE) - 1)	\
+		    << MMCI_##name##_OFFSET))		\
+	 | MMCI_BF(name,value))
+
+/* Register access macros */
+#define mmci_readl(reg)					\
+	readl((void *)MMCI_BASE + MMCI_##reg)
+#define mmci_writel(reg,value)				\
+	writel((value), (void *)MMCI_BASE + MMCI_##reg)
+	
+#endif /* __CPU_AT32AP_ATMEL_MCI_H__ */
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk
u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk
--- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk	2007-08-21
17:06:35.000000000 +0200
+++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk
2007-08-16 13:34:14.000000000 +0200
@@ -19,10 +19,10 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 # MA 02111-1307 USA
-#
+#PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,)
 
 PLATFORM_RELFLAGS += -fno-strict-aliasing  -fno-common -ffixed-r8
-PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,)
+PLATFORM_RELFLAGS += $(call cc-option,)
 
 PLATFORM_CPPFLAGS += -march=armv5te
 PLATFORM_CPPFLAGS += $(call cc-option,-mtune=arm926ejs,)
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile
u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile
--- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile	2007-08-21
17:06:36.000000000 +0200
+++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile	2007-08-23
09:14:21.000000000 +0200
@@ -26,8 +26,8 @@
 LIB	= lib$(SOC).a
 
 
-OBJS	= serial.o interrupts.o usb_ohci.o lcd.o ether.o spi.o
-SOBJS   = 
+OBJS	= serial.o interrupts.o usb_ohci.o ether.o spi.o
+SOBJS   = atmel_mci.o
 
 all:	.depend $(LIB)
 
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c
u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c
--- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c	2007-08-21
17:06:35.000000000 +0200
+++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c	2007-08-23
10:36:47.000000000 +0200
@@ -184,6 +184,20 @@
 {
   unsigned int timeout;
   
+#ifdef CONFIG_AT91SAM9260EK
+  /* Configure PIO controllers to periph mode */
+  AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, // PIO controller base address
+		      ((unsigned int) AT91C_PA1_SPI0_MOSI) |
+		      ((unsigned int) AT91C_PA3_SPI0_NPCS0) |
+		      ((unsigned int) AT91C_PA0_SPI0_MISO) |
+		      ((unsigned int) AT91C_PA2_SPI0_SPCK), /*
Peripheral A */
+		      0); /* Peripheral B */
+  /* Configure PIO controllers to periph mode */
+  AT91F_PIO_CfgPeriph(AT91C_BASE_PIOC, /* PIO controller base address
*/
+		      0, /* Peripheral A */
+		      ((unsigned int) AT91C_PC11_SPI0_NPCS1)); /*
Peripheral B */
+#endif
+  
   pDesc->state = BUSY;
   
   /* Disable PDC TX and RX channels */
diff -burN u-boot-1.1.5/cpu/arm926ejs/config.mk
u-boot-1.1.5.klk/cpu/arm926ejs/config.mk
--- u-boot-1.1.5/cpu/arm926ejs/config.mk	2006-10-20
17:54:33.000000000 +0200
+++ u-boot-1.1.5.klk/cpu/arm926ejs/config.mk	2007-08-16
13:34:42.000000000 +0200
@@ -20,10 +20,10 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 # MA 02111-1307 USA
 #
-
-PLATFORM_RELFLAGS += -fno-strict-aliasing  -fno-common -ffixed-r8 \
-	-msoft-float
-
+#
+#PLATFORM_RELFLAGS += -fno-strict-aliasing  -fno-common -ffixed-r8 \
+#	-msoft-float
+PLATFORM_RELFLAGS += -fno-strict-aliasing  -fno-common -ffixed-r8
 PLATFORM_CPPFLAGS += -march=armv4
 #
========================================================================
=
 #
diff -burN u-boot-1.1.5/disk/part.c u-boot-1.1.5.klk/disk/part.c
--- u-boot-1.1.5/disk/part.c	2006-10-20 17:54:33.000000000 +0200
+++ u-boot-1.1.5.klk/disk/part.c	2007-08-23 08:29:56.000000000
+0200
@@ -36,6 +36,7 @@
 #if ((CONFIG_COMMANDS & CFG_CMD_IDE)	|| \
      (CONFIG_COMMANDS & CFG_CMD_SCSI)	|| \
      (CONFIG_COMMANDS & CFG_CMD_USB)	|| \
+	 (CONFIG_COMMANDS & CFG_CMD_MMC)	|| \
      defined(CONFIG_MMC) || \
      defined(CONFIG_SYSTEMACE) )
 
@@ -126,6 +127,8 @@
 #if ((CONFIG_COMMANDS & CFG_CMD_IDE)	|| \
      (CONFIG_COMMANDS & CFG_CMD_SCSI)	|| \
      (CONFIG_COMMANDS & CFG_CMD_USB)	|| \
+	 (CONFIG_COMMANDS & CFG_CMD_MMC)	|| \
+     defined(CONFIG_MMC) || \
      defined(CONFIG_SYSTEMACE)          )
 
 #if defined(CONFIG_MAC_PARTITION) || \
diff -burN u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h
u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h
--- u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h	1970-01-01
01:00:00.000000000 +0100
+++ u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h
2007-08-17 10:44:42.000000000 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __ASM_AVR32_MMC_H
+#define __ASM_AVR32_MMC_H
+
+struct mmc_cid {
+	unsigned long psn;
+	unsigned short oid;
+	unsigned char mid;
+	unsigned char prv;
+	unsigned char mdt;
+	char pnm[7];
+};
+
+struct mmc_csd
+{
+	u8	csd_structure:2,
+		spec_vers:4,
+		rsvd1:2;
+	u8	taac;
+	u8	nsac;
+	u8	tran_speed;
+	u16	ccc:12,
+		read_bl_len:4;
+	u64	read_bl_partial:1,
+		write_blk_misalign:1,
+		read_blk_misalign:1,
+		dsr_imp:1,
+		rsvd2:2,
+		c_size:12,
+		vdd_r_curr_min:3,
+		vdd_r_curr_max:3,
+		vdd_w_curr_min:3,
+		vdd_w_curr_max:3,
+		c_size_mult:3,
+		sector_size:5,
+		erase_grp_size:5,
+		wp_grp_size:5,
+		wp_grp_enable:1,
+		default_ecc:2,
+		r2w_factor:3,
+		write_bl_len:4,
+		write_bl_partial:1,
+		rsvd3:5;
+	u8	file_format_grp:1,
+		copy:1,
+		perm_write_protect:1,
+		tmp_write_protect:1,
+		file_format:2,
+		ecc:2;
+	u8	crc:7;
+	u8	one:1;
+};
+
+/* MMC Command numbers */
+#define MMC_CMD_GO_IDLE_STATE		0
+#define MMC_CMD_SEND_OP_COND		1
+#define MMC_CMD_ALL_SEND_CID 		2
+#define MMC_CMD_SET_RELATIVE_ADDR	3
+#define MMC_CMD_SD_SEND_RELATIVE_ADDR	3
+#define MMC_CMD_SET_DSR			4
+#define MMC_CMD_SELECT_CARD		7
+#define MMC_CMD_SEND_CSD 		9
+#define MMC_CMD_SEND_CID 		10
+#define MMC_CMD_SEND_STATUS		13
+#define MMC_CMD_SET_BLOCKLEN		16
+#define MMC_CMD_READ_SINGLE_BLOCK	17
+#define MMC_CMD_READ_MULTIPLE_BLOCK	18
+#define MMC_CMD_WRITE_BLOCK		24
+#define MMC_CMD_APP_CMD			55
+
+#define MMC_ACMD_SD_SEND_OP_COND	41
+
+#define R1_ILLEGAL_COMMAND		(1 << 22)
+#define R1_APP_CMD			(1 << 5)
+
+#endif /* __ASM_AVR32_MMC_H */
diff -burN u-boot-1.1.5/include/configs/at91sam9260ek.h
u-boot-1.1.5.klk/include/configs/at91sam9260ek.h
--- u-boot-1.1.5/include/configs/at91sam9260ek.h	2007-08-21
17:06:36.000000000 +0200
+++ u-boot-1.1.5.klk/include/configs/at91sam9260ek.h	2007-08-23
10:51:43.000000000 +0200
@@ -88,6 +88,8 @@
                         CFG_CMD_FLASH | \
 			CFG_CMD_AUTOSCRIPT | \
                         CFG_CMD_NAND | \
+						CFG_CMD_MMC | \
+						CFG_CMD_EXT2 | \
                         CFG_CMD_FAT ) & \
 		      ~(CFG_CMD_BDI | \
 			CFG_CMD_IMLS | \
@@ -225,6 +227,7 @@
 #undef  CFG_ENV_IS_IN_FLASH
 #define	CFG_ENV_IS_IN_DATAFLASH         1
 #undef CFG_ENV_IS_IN_NAND              
+#undef CFG_ENV_IS_NOWHERE
 
 /*#define CONFIG_MTD_DEBUG		1
 #define CONFIG_MTD_DEBUG_VERBOSE	MTD_DEBUG_LEVEL3
@@ -241,6 +244,10 @@
 #define CFG_ENV_SIZE			0x4000  /* 0x8000 */
 #endif
 
+#ifdef CFG_ENV_IS_NOWHERE
+#define CFG_ENV_SIZE			0x4000
+#endif
+
 #ifdef CFG_ENV_IS_IN_FLASH
 #ifdef CONFIG_BOOTBINFUNC
 #define CFG_ENV_ADDR			(PHYS_FLASH_1 + 0x60000)  /*
after u-boot.bin */
@@ -257,6 +264,10 @@
 #define CONFIG_DOS_PARTITION	        1
 #define LITTLEENDIAN 			1
 
+/* MMC */
+#define CONFIG_MMC		1
+#define MMCI_BASE		0xFFFA8000
+
 #define CFG_LOAD_ADDR		0x23f00000  /* default load address */
 
 #ifdef CONFIG_BOOTBINFUNC

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] [PATCH] Add eSDHC driver
  2008-04-23 19:23                 ` Ken.Fuchs at bench.com
@ 2008-04-24  6:24                   ` Pierre Savary
  2008-04-29 19:45                     ` [U-Boot-Users] drivers MMCplus for at91sam9x Ken.Fuchs at bench.com
  0 siblings, 1 reply; 39+ messages in thread
From: Pierre Savary @ 2008-04-24  6:24 UTC (permalink / raw)
  To: u-boot

Thanks for that... but it's my own patch ;)

Pierre


-----Message d'origine-----
De?: u-boot-users-bounces at lists.sourceforge.net
[mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de
Ken.Fuchs at bench.com
Envoy??: mercredi 23 avril 2008 21:23
??: pierre.savary at kerlink.fr
Cc?: u-boot-users at lists.sourceforge.net; afleming at freescale.com;
drzeus-mmc at drzeus.cx
Objet?: Re: [U-Boot-Users] [PATCH] Add eSDHC driver

> Pierre Savary wrote:

> >Where could we find the driver that works with MMCv4 on at91sam9x?

Andy Fleming wrote:

> Pierre, I don't have a driver that works on at91sam9x, I'm 
> afraid.

Here's an MMC v2.x AT91SAM9260 patch for Atmel modified u-boot 1.1.5.
You will need to define GPIO pins for other AT91SAM9 processors, etc.

If you really need an MMC v4.x AT91SAM9 MCI driver for 1.1.5 fast, you
probably could cut and paste the v4.x code you need from Andy's MMC
driver
into the MMC v2.x MCI driver this patch provides.

BTW, if anyone knows why MMC 4 bit is disabled for AT91SAM9261 in the
MCI Linux driver, I'd like to hear the reasons why.

--- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) ---

diff -burN u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c
u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c
--- u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c	2007-08-21
17:06:36.000000000 +0200
+++ u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c
2007-08-23 08:37:42.000000000 +0200
@@ -109,6 +109,24 @@
 }
 
 
+#ifdef CONFIG_MMC
+#if (CONFIG_COMMANDS & CFG_CMD_MMC)
+int AT91F_MMC_Hardware_Init(void)
+{
+	AT91C_BASE_PIOA->PIO_ASR = (1 << 8 );		/* periph A
select register */
+	AT91C_BASE_PIOA->PIO_BSR |= 0x3B;			/*
periph B select register */
+	AT91C_BASE_PIOA->PIO_PDR |= 0x13B;			/* PIO
disable register */
+	AT91C_BASE_PIOA->PIO_PPUDR |= 0x13B;		/* Pull up
disable register */
+
+	AT91C_BASE_PMC->PMC_PCER = (1 << 9);
+}
+#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */
+#endif /* CONFIG_MMC */
+
+
+
+
+
 #ifdef CONFIG_DRIVER_ETHER
 #if (CONFIG_COMMANDS & CFG_CMD_NET)
 
diff -burN u-boot-1.1.5/common/cmd_nvedit.c
u-boot-1.1.5.klk/common/cmd_nvedit.c
--- u-boot-1.1.5/common/cmd_nvedit.c	2006-10-20 17:54:33.000000000
+0200
+++ u-boot-1.1.5.klk/common/cmd_nvedit.c	2007-08-23
09:26:18.000000000 +0200
@@ -530,6 +530,7 @@
 	return (-1);
 }
 
+#ifndef CFG_ENV_IS_NOWHERE
 #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \
     ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \
       (CFG_CMD_ENV|CFG_CMD_FLASH)) || \
@@ -544,7 +545,7 @@
 	return (saveenv() ? 1 : 0);
 }
 
-
+#endif
 #endif
 
 
@@ -587,7 +588,7 @@
 	"setenv name\n"
 	"    - delete environment variable 'name'\n"
 );
-
+#ifndef CFG_ENV_IS_NOWHERE
 #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \
     ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \
       (CFG_CMD_ENV|CFG_CMD_FLASH)) || \
@@ -600,6 +601,7 @@
 );
 
 #endif	/* CFG_CMD_ENV */
+#endif	
 
 #if (CONFIG_COMMANDS & CFG_CMD_ASKENV)
 
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c
u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c
--- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c	1970-01-01
01:00:00.000000000 +0100
+++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c
2007-08-23 09:45:46.000000000 +0200
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+
+#ifdef CONFIG_MMC
+
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+//#include <asm/arch/clk.h>
+//#include <asm/arch/memory-map.h>
+#include <asm/arch/hardware.h>	//klk
+
+#include "atmel_mci.h"
+#undef DEBUG
+#ifdef DEBUG
+#define pr_debug(fmt, args...) printf(fmt, ##args)
+#else
+#define pr_debug(...) do { } while(0)
+#endif
+
+#ifndef CFG_MMC_CLK_OD
+#define CFG_MMC_CLK_OD		375000
+#endif
+
+#ifndef CFG_MMC_CLK_PP
+#define CFG_MMC_CLK_PP		20000000
+#endif
+
+#ifndef CFG_MMC_OP_COND
+#define CFG_MMC_OP_COND		0x00100000
+#endif
+
+#define MMC_DEFAULT_BLKLEN	512
+#define MMC_DEFAULT_RCA		1
+
+static unsigned int mmc_rca;
+static int mmc_card_is_sd;
+static block_dev_desc_t mmc_blkdev;
+
+block_dev_desc_t *mmc_get_dev(int dev)
+{
+	return &mmc_blkdev;
+}
+
+static void mci_set_mode(unsigned long hz, unsigned long blklen)
+{
+	unsigned long bus_hz;
+	unsigned long clkdiv;
+
+	// bus_hz = get_mci_clk_rate();
+	bus_hz = AT91C_MASTER_CLOCK;
+	clkdiv = (bus_hz / hz) / 2 - 1;
+
+	pr_debug("mmc: setting clock %lu Hz, block size %lu\n",
+		 hz, blklen);
+
+	if (clkdiv & ~255UL) {
+		clkdiv = 255;
+		pr_debug("mmc: clock %lu too low; setting CLKDIV to
255\n",
+			hz);
+	}
+
+	blklen &= 0xfffc;
+	mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv)
+			 | MMCI_BF(BLKLEN, blklen)
+			 | MMCI_BIT(RDPROOF)
+			 | MMCI_BIT(WRPROOF)));
+}
+
+#define RESP_NO_CRC	1
+#define R1		MMCI_BF(RSPTYP, 1)
+#define R2		MMCI_BF(RSPTYP, 2)
+#define R3		(R1 | RESP_NO_CRC)
+#define R6		R1
+#define NID		MMCI_BF(MAXLAT, 0)
+#define NCR		MMCI_BF(MAXLAT, 1)
+#define TRCMD_START	MMCI_BF(TRCMD, 1)
+#define TRDIR_READ	MMCI_BF(TRDIR, 1)
+#define TRTYP_BLOCK	MMCI_BF(TRTYP, 0)
+#define INIT_CMD	MMCI_BF(SPCMD, 1)
+#define OPEN_DRAIN	MMCI_BF(OPDCMD, 1)
+
+#define ERROR_FLAGS	(MMCI_BIT(DTOE)			\
+			 | MMCI_BIT(RDIRE)		\
+			 | MMCI_BIT(RENDE)		\
+			 | MMCI_BIT(RINDE)		\
+			 | MMCI_BIT(RTOE))
+
+static int
+mmc_cmd(unsigned long cmd, unsigned long arg,
+	void *resp, unsigned long flags)
+{
+	unsigned long *response = resp;
+	int i, response_words = 0;
+	unsigned long error_flags;
+	u32 status;
+
+	AT91F_MMC_Hardware_Init();
+	
+	pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n",
+		 cmd, arg, flags);
+
+	error_flags = ERROR_FLAGS;
+	if (!(flags & RESP_NO_CRC))
+		error_flags |= MMCI_BIT(RCRCE);
+
+	flags &= ~MMCI_BF(CMDNB, ~0UL);
+
+	if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_48_BIT_RESP)
+		response_words = 1;
+	else if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_136_BIT_RESP)
+		response_words = 4;
+
+	mmci_writel(ARGR, arg);
+	mmci_writel(CMDR, cmd | flags);
+	do {
+		udelay(40);
+		status = mmci_readl(SR);
+	} while (!(status & MMCI_BIT(CMDRDY)));
+
+	pr_debug("mmc: status 0x%08lx\n", status);
+
+	if (status & ERROR_FLAGS) {
+		pr_debug("mmc: command %lu failed (status: 0x%08lx)\n",
+		       cmd, status);
+		return -EIO;
+	}
+
+	if (response_words)
+		pr_debug("mmc: response:");
+
+	for (i = 0; i < response_words; i++) {
+		response[i] = mmci_readl(RSPR);
+		pr_debug(" %08lx", response[i]);
+	}
+	pr_debug("\n");
+
+	return 0;
+}
+
+static int mmc_acmd(unsigned long cmd, unsigned long arg,
+		    void *resp, unsigned long flags)
+{
+	unsigned long aresp[4];
+	int ret;
+
+	/*
+	 * Seems like the APP_CMD part of an ACMD has 64 cycles max
+	 * latency even though the ACMD part doesn't. This isn't
+	 * entirely clear in the SD Card spec, but some cards refuse
+	 * to work if we attempt to use 5 cycles max latency here...
+	 */
+	ret = mmc_cmd(MMC_CMD_APP_CMD, 0, aresp,
+		      R1 | NCR | (flags & OPEN_DRAIN));
+	if (ret)
+		return ret;
+	if ((aresp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) !=
R1_APP_CMD)
+		return -ENODEV;
+
+	ret = mmc_cmd(cmd, arg, resp, flags);
+	return ret;
+}
+
+static unsigned long
+mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
+	  unsigned long *buffer)
+{
+	int ret, i = 0;
+	unsigned long resp[4];
+	unsigned long card_status, data;
+	unsigned long wordcount;
+	u32 status;
+
+	if (blkcnt == 0)
+		return 0;
+
+	pr_debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n",
+		 dev, start, blkcnt);
+
+	/* Put the device into Transfer state */
+	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	if (ret) goto fail;
+
+	/* Set block length */
+	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	if (ret) goto fail;
+
+	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
+
+	for (i = 0; i < blkcnt; i++, start++) {
+		ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK,
+			      start * mmc_blkdev.blksz, resp,
+			      (R1 | NCR | TRCMD_START | TRDIR_READ
+			       | TRTYP_BLOCK));
+		if (ret) goto fail;
+
+		ret = -EIO;
+		wordcount = 0;
+		do {
+			do {
+				status = mmci_readl(SR);
+				if (status & (ERROR_FLAGS |
MMCI_BIT(OVRE)))
+					goto fail;
+			} while (!(status & MMCI_BIT(RXRDY)));
+
+			if (status & MMCI_BIT(RXRDY)) {
+				data = mmci_readl(RDR);
+				/* pr_debug("%x\n", data); */
+				*buffer++ = data;
+				wordcount++;
+			}
+		} while(wordcount < (mmc_blkdev.blksz / 4));
+
+		pr_debug("mmc: read %u words, waiting for BLKE\n",
wordcount);
+
+		do {
+			status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(BLKE)));
+
+		putc('.');
+	}
+
+out:
+	/* Put the device back into Standby state */
+	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	return i;
+
+fail:
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread failed, card status = %08x\n",
card_status);
+	goto out;
+}
+
+static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp)
+{
+	cid->mid = resp[0] >> 24;
+	cid->oid = (resp[0] >> 8) & 0xffff;
+	cid->pnm[0] = resp[0];
+	cid->pnm[1] = resp[1] >> 24;
+	cid->pnm[2] = resp[1] >> 16;
+	cid->pnm[3] = resp[1] >> 8;
+	cid->pnm[4] = resp[1];
+	cid->pnm[5] = resp[2] >> 24;
+	cid->pnm[6] = 0;
+	cid->prv = resp[2] >> 16;
+	cid->psn = (resp[2] << 16) | (resp[3] >> 16);
+	cid->mdt = resp[3] >> 8;
+}
+
+static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp)
+{
+	cid->mid = resp[0] >> 24;
+	cid->oid = (resp[0] >> 8) & 0xffff;
+	cid->pnm[0] = resp[0];
+	cid->pnm[1] = resp[1] >> 24;
+	cid->pnm[2] = resp[1] >> 16;
+	cid->pnm[3] = resp[1] >> 8;
+	cid->pnm[4] = resp[1];
+	cid->pnm[5] = 0;
+	cid->pnm[6] = 0;
+	cid->prv = resp[2] >> 24;
+	cid->psn = (resp[2] << 8) | (resp[3] >> 24);
+	cid->mdt = (resp[3] >> 8) & 0x0fff;
+}
+
+static void mmc_dump_cid(const struct mmc_cid *cid)
+{
+	printf("Manufacturer ID:       %02lX\n", cid->mid);
+	printf("OEM/Application ID:    %04lX\n", cid->oid);
+	printf("Product name:          %s\n", cid->pnm);
+	printf("Product Revision:      %lu.%lu\n",
+	       cid->prv >> 4, cid->prv & 0x0f);
+	printf("Product Serial Number: %lu\n", cid->psn);
+	printf("Manufacturing Date:    %02lu/%02lu\n",
+	       cid->mdt >> 4, cid->mdt & 0x0f);
+}
+
+static void mmc_dump_csd(const struct mmc_csd *csd)
+{
+	unsigned long *csd_raw = (unsigned long *)csd;
+	pr_debug("CSD data: %08lx %08lx %08lx %08lx\n",
+	       csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]);
+	pr_debug("CSD structure version:   1.%u\n", csd->csd_structure);
+	pr_debug("MMC System Spec version: %u\n", csd->spec_vers);
+	pr_debug("Card command classes:    %03x\n", csd->ccc);
+	pr_debug("Read block length:       %u\n", 1 <<
csd->read_bl_len);
+	if (csd->read_bl_partial)
+		puts("Supports partial reads\n");
+	else
+		puts("Does not support partial reads\n");
+	pr_debug("Write block length:      %u\n", 1 <<
csd->write_bl_len);
+	if (csd->write_bl_partial)
+		puts("Supports partial writes\n");
+	else
+		puts("Does not support partial writes\n");
+	if (csd->wp_grp_enable)
+		pr_debug("Supports group WP:      %u\n",
csd->wp_grp_size + 1);
+	else
+		puts("Does not support group WP\n");
+	pr_debug("Card capacity:		%u bytes\n",
+	       (csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) *
+	       (1 << csd->read_bl_len));
+	pr_debug("File format:            %u/%u\n",
+	       csd->file_format_grp, csd->file_format);
+	puts("Write protection:        ");
+	if (csd->perm_write_protect)
+		puts(" permanent");
+	if (csd->tmp_write_protect)
+		puts(" temporary");
+	putc('\n');
+}
+
+static int mmc_idle_cards(void)
+{
+	int ret;
+
+	/* Reset and initialize all cards */
+	ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0);
+	
+	if (ret)
+		return ret;
+	pr_debug(" ret: %i\n",ret);
+	/* Keep the bus idle for 74 clock cycles */
+	return mmc_cmd(0, 0, NULL, INIT_CMD);
+}
+
+static int sd_init_card(struct mmc_cid *cid, int verbose)
+{
+	unsigned long resp[4];
+	int i, ret = 0;
+
+	mmc_idle_cards();
+	for (i = 0; i < 1000; i++) {
+		ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND,
CFG_MMC_OP_COND,
+			       resp, R3 | NID);
+		if (ret || (resp[0] & 0x80000000))
+			break;
+		ret = -ETIMEDOUT;
+	}
+
+	if (ret)
+		return ret;
+
+	ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID);
+	if (ret)
+		return ret;
+	sd_parse_cid(cid, resp);
+	if (verbose)
+		mmc_dump_cid(cid);
+
+	/* Get RCA of the card that responded */
+	ret = mmc_cmd(MMC_CMD_SD_SEND_RELATIVE_ADDR, 0, resp, R6 | NCR);
+	if (ret)
+		return ret;
+
+	mmc_rca = resp[0] >> 16;
+	if (verbose)
+		pr_debug("SD Card detected (RCA %u)\n", mmc_rca);
+	mmc_card_is_sd = 1;
+	return 0;
+}
+
+static int mmc_init_card(struct mmc_cid *cid, int verbose)
+{
+	unsigned long resp[4];
+	int i, ret = 0;
+
+	mmc_idle_cards();
+
+	for (i = 0; i < 1000; i++) {
+		ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND,
resp,
+			      R3 | NID | OPEN_DRAIN);
+		if (ret || (resp[0] & 0x80000000))
+		{
+			break;
+		}
+		ret = -ETIMEDOUT;
+	}
+	pr_debug("4\n");
+	pr_debug("ret : %i\n",ret);
+	if (ret)
+		return ret;
+	pr_debug("5\n");
+	/* Get CID of all cards. FIXME: Support more than one card */
+	ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID |
OPEN_DRAIN);
+	if (ret)
+		return ret;
+	mmc_parse_cid(cid, resp);
+	if (verbose)
+		mmc_dump_cid(cid);
+
+	/* Set Relative Address of the card that responded */
+	ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp,
+		      R1 | NCR | OPEN_DRAIN);
+	return ret;
+}
+
+static void mci_set_data_timeout(struct mmc_csd *csd)
+{
+	static const unsigned int dtomul_to_shift[] = {
+		0, 4, 7, 8, 10, 12, 16, 20,
+	};
+	static const unsigned int taac_exp[] = {
+		1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
+	};
+	static const unsigned int taac_mant[] = {
+		0,  10, 12, 13, 15, 60, 25, 30,
+		35, 40, 45, 50, 55, 60, 70, 80,
+	};
+	unsigned int timeout_ns, timeout_clks;
+	unsigned int e, m;
+	unsigned int dtocyc, dtomul;
+	unsigned int shift;
+	u32 dtor;
+
+	e = csd->taac & 0x07;
+	m = (csd->taac >> 3) & 0x0f;
+
+	timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10;
+	timeout_clks = csd->nsac * 100;
+
+	timeout_clks += (((timeout_ns + 9) / 10)
+			 * ((CFG_MMC_CLK_PP + 99999) / 100000) + 9999) /
10000;
+	if (!mmc_card_is_sd)
+		timeout_clks *= 10;
+	else
+		timeout_clks *= 100;
+
+	dtocyc = timeout_clks;
+	dtomul = 0;
+	while (dtocyc > 15 && dtomul < 8) {
+		dtomul++;
+		shift = dtomul_to_shift[dtomul];
+		dtocyc = (timeout_clks + (1 << shift) - 1) >> shift;
+	}
+
+	if (dtomul >= 8) {
+		dtomul = 7;
+		dtocyc = 15;
+		puts("Warning: Using maximum data timeout\n");
+	}
+
+	dtor = (MMCI_BF(DTOMUL, dtomul)
+		| MMCI_BF(DTOCYC, dtocyc));
+	mmci_writel(DTOR, dtor);
+
+	pr_debug("mmc: Using %u cycles data timeout (DTOR=0x%x)\n",
+	       dtocyc << shift, dtor);
+}
+
+int mmc_init(int verbose)
+{
+	struct mmc_cid cid;
+	struct mmc_csd csd;
+	unsigned int max_blksz;
+	int ret,aux;
+	
+	AT91F_MMC_Hardware_Init();
+	
+	pr_debug("0\n");
+	/* Initialize controller */
+	mmci_writel(CR, MMCI_BIT(SWRST));
+	mmci_writel(CR, MMCI_BIT(MCIEN));
+	mmci_writel(DTOR, 0x5f);
+	mmci_writel(IDR, ~0UL);
+	mmci_writel(SDCR, 0x1);
+	mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+/* 	//mmci_writel(CR, MMCI_BIT(SWRST));
+	mmci_writel(CR, 0x00000001);
+	mmci_writel(DTOR, 0x0000007F);
+	mmci_writel(IDR, 0xFFFFFFFF);
+	mmci_writel(SDCR, 0x00000001);
+	//mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+	mmci_writel(MR, 0x02009B4A); */
+
+	pr_debug("1\n");
+	
+	mmc_card_is_sd = 0;
+
+	ret = sd_init_card(&cid, verbose);
+	if (ret) {
+		mmc_rca = MMC_DEFAULT_RCA;
+		ret = mmc_init_card(&cid, verbose);
+	}
+	pr_debug("6\n");
+	if (ret)
+		return ret;
+	pr_debug("7\n");
+	/* Get CSD from the card */
+	ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &csd, R2 | NCR);
+	if (ret)
+		return ret;
+	if (verbose)
+		mmc_dump_csd(&csd);
+
+	mci_set_data_timeout(&csd);
+
+	/* Initialize the blockdev structure */
+	mmc_blkdev.if_type = IF_TYPE_MMC;
+	mmc_blkdev.part_type = PART_TYPE_DOS;
+	mmc_blkdev.block_read = mmc_bread;
+	sprintf((char *)mmc_blkdev.vendor,
+		"Man %02x%04x Snr %08x",
+		cid.mid, cid.oid, cid.psn);
+	strncpy((char *)mmc_blkdev.product, cid.pnm,
+		sizeof(mmc_blkdev.product));
+	sprintf((char *)mmc_blkdev.revision, "%x %x",
+		cid.prv >> 4, cid.prv & 0x0f);
+
+	/*
+	 * If we can't use 512 byte blocks, refuse to deal with the
+	 * card. Tons of code elsewhere seems to depend on this.
+	 */
+	max_blksz = 1 << csd.read_bl_len;
+	// if (max_blksz < 512 || (max_blksz > 512 &&
!csd.read_bl_partial)) {
+		// pr_debug("Card does not support 512 byte reads,
aborting.\n");
+		// return -ENODEV;
+	// }
+	mmc_blkdev.blksz = 512;
+	mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult +
2));
+
+	mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz);
+
+#if 0
+	if (fat_register_device(&mmc_blkdev, 1))
+		pr_debug("Could not register MMC fat device\n");
+#else
+	init_part(&mmc_blkdev);
+#endif
+
+	return 0;
+}
+
+int mmc_read(ulong src, uchar *dst, int size)
+{
+	return -ENOSYS;
+}
+
+int mmc_write(uchar *src, ulong dst, int size)
+{
+	return -ENOSYS;
+}
+
+int mmc2info(ulong addr)
+{
+	return 0;
+}
+
+#endif /* CONFIG_MMC */
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h
u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h
--- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h	1970-01-01
01:00:00.000000000 +0100
+++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h
2007-08-17 10:43:17.000000000 +0200
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __CPU_AT32AP_ATMEL_MCI_H__
+#define __CPU_AT32AP_ATMEL_MCI_H__
+
+/* Atmel MultiMedia Card Interface (MCI) registers */
+#define MMCI_CR					0x0000
+#define MMCI_MR					0x0004
+#define MMCI_DTOR				0x0008
+#define MMCI_SDCR				0x000c
+#define MMCI_ARGR				0x0010
+#define MMCI_CMDR				0x0014
+#define MMCI_RSPR				0x0020
+#define MMCI_RSPR1				0x0024
+#define MMCI_RSPR2				0x0028
+#define MMCI_RSPR3				0x002c
+#define MMCI_RDR				0x0030
+#define MMCI_TDR				0x0034
+#define MMCI_SR					0x0040
+#define MMCI_IER				0x0044
+#define MMCI_IDR				0x0048
+#define MMCI_IMR				0x004c
+
+/* Bitfields in CR */
+#define MMCI_MCIEN_OFFSET			0
+#define MMCI_MCIEN_SIZE				1
+#define MMCI_MCIDIS_OFFSET			1
+#define MMCI_MCIDIS_SIZE			1
+#define MMCI_PWSEN_OFFSET			2
+#define MMCI_PWSEN_SIZE				1
+#define MMCI_PWSDIS_OFFSET			3
+#define MMCI_PWSDIS_SIZE			1
+#define MMCI_SWRST_OFFSET			7
+#define MMCI_SWRST_SIZE				1
+
+/* Bitfields in MR */
+#define MMCI_CLKDIV_OFFSET			0
+#define MMCI_CLKDIV_SIZE			8
+#define MMCI_PWSDIV_OFFSET			8
+#define MMCI_PWSDIV_SIZE			3
+#define MMCI_RDPROOF_OFFSET			11
+#define MMCI_RDPROOF_SIZE			1
+#define MMCI_WRPROOF_OFFSET			12
+#define MMCI_WRPROOF_SIZE			1
+#define MMCI_PDCPADV_OFFSET			14
+#define MMCI_PDCPADV_SIZE			1
+#define MMCI_PDCMODE_OFFSET			15
+#define MMCI_PDCMODE_SIZE			1
+#define MMCI_BLKLEN_OFFSET			16
+#define MMCI_BLKLEN_SIZE			16
+
+/* Bitfields in DTOR */
+#define MMCI_DTOCYC_OFFSET			0
+#define MMCI_DTOCYC_SIZE			4
+#define MMCI_DTOMUL_OFFSET			4
+#define MMCI_DTOMUL_SIZE			3
+
+/* Bitfields in SDCR */
+#define MMCI_SCDSEL_OFFSET			0
+#define MMCI_SCDSEL_SIZE			4
+#define MMCI_SCDBUS_OFFSET			7
+#define MMCI_SCDBUS_SIZE			1
+
+/* Bitfields in ARGR */
+#define MMCI_ARG_OFFSET				0
+#define MMCI_ARG_SIZE				32
+
+/* Bitfields in CMDR */
+#define MMCI_CMDNB_OFFSET			0
+#define MMCI_CMDNB_SIZE				6
+#define MMCI_RSPTYP_OFFSET			6
+#define MMCI_RSPTYP_SIZE			2
+#define MMCI_SPCMD_OFFSET			8
+#define MMCI_SPCMD_SIZE				3
+#define MMCI_OPDCMD_OFFSET			11
+#define MMCI_OPDCMD_SIZE			1
+#define MMCI_MAXLAT_OFFSET			12
+#define MMCI_MAXLAT_SIZE			1
+#define MMCI_TRCMD_OFFSET			16
+#define MMCI_TRCMD_SIZE				2
+#define MMCI_TRDIR_OFFSET			18
+#define MMCI_TRDIR_SIZE				1
+#define MMCI_TRTYP_OFFSET			19
+#define MMCI_TRTYP_SIZE				2
+
+/* Bitfields in RSPRx */
+#define MMCI_RSP_OFFSET				0
+#define MMCI_RSP_SIZE				32
+
+/* Bitfields in SR/IER/IDR/IMR */
+#define MMCI_CMDRDY_OFFSET			0
+#define MMCI_CMDRDY_SIZE			1
+#define MMCI_RXRDY_OFFSET			1
+#define MMCI_RXRDY_SIZE				1
+#define MMCI_TXRDY_OFFSET			2
+#define MMCI_TXRDY_SIZE				1
+#define MMCI_BLKE_OFFSET			3
+#define MMCI_BLKE_SIZE				1
+#define MMCI_DTIP_OFFSET			4
+#define MMCI_DTIP_SIZE				1
+#define MMCI_NOTBUSY_OFFSET			5
+#define MMCI_NOTBUSY_SIZE			1
+#define MMCI_ENDRX_OFFSET			6
+#define MMCI_ENDRX_SIZE				1
+#define MMCI_ENDTX_OFFSET			7
+#define MMCI_ENDTX_SIZE				1
+#define MMCI_RXBUFF_OFFSET			14
+#define MMCI_RXBUFF_SIZE			1
+#define MMCI_TXBUFE_OFFSET			15
+#define MMCI_TXBUFE_SIZE			1
+#define MMCI_RINDE_OFFSET			16
+#define MMCI_RINDE_SIZE				1
+#define MMCI_RDIRE_OFFSET			17
+#define MMCI_RDIRE_SIZE				1
+#define MMCI_RCRCE_OFFSET			18
+#define MMCI_RCRCE_SIZE				1
+#define MMCI_RENDE_OFFSET			19
+#define MMCI_RENDE_SIZE				1
+#define MMCI_RTOE_OFFSET			20
+#define MMCI_RTOE_SIZE				1
+#define MMCI_DCRCE_OFFSET			21
+#define MMCI_DCRCE_SIZE				1
+#define MMCI_DTOE_OFFSET			22
+#define MMCI_DTOE_SIZE				1
+#define MMCI_OVRE_OFFSET			30
+#define MMCI_OVRE_SIZE				1
+#define MMCI_UNRE_OFFSET			31
+#define MMCI_UNRE_SIZE				1
+
+/* Constants for DTOMUL */
+#define MMCI_DTOMUL_1_CYCLE			0
+#define MMCI_DTOMUL_16_CYCLES			1
+#define MMCI_DTOMUL_128_CYCLES			2
+#define MMCI_DTOMUL_256_CYCLES			3
+#define MMCI_DTOMUL_1024_CYCLES			4
+#define MMCI_DTOMUL_4096_CYCLES			5
+#define MMCI_DTOMUL_65536_CYCLES		6
+#define MMCI_DTOMUL_1048576_CYCLES		7
+
+/* Constants for RSPTYP */
+#define MMCI_RSPTYP_NO_RESP			0
+#define MMCI_RSPTYP_48_BIT_RESP			1
+#define MMCI_RSPTYP_136_BIT_RESP		2
+
+/* Constants for SPCMD */
+#define MMCI_SPCMD_NO_SPEC_CMD			0
+#define MMCI_SPCMD_INIT_CMD			1
+#define MMCI_SPCMD_SYNC_CMD			2
+#define MMCI_SPCMD_INT_CMD			4
+#define MMCI_SPCMD_INT_RESP			5
+
+/* Constants for TRCMD */
+#define MMCI_TRCMD_NO_TRANS			0
+#define MMCI_TRCMD_START_TRANS			1
+#define MMCI_TRCMD_STOP_TRANS			2
+
+/* Constants for TRTYP */
+#define MMCI_TRTYP_BLOCK			0
+#define MMCI_TRTYP_MULTI_BLOCK			1
+#define MMCI_TRTYP_STREAM			2
+
+/* Bit manipulation macros */
+#define MMCI_BIT(name)					\
+	(1 << MMCI_##name##_OFFSET)
+#define MMCI_BF(name,value)				\
+	(((value) & ((1 << MMCI_##name##_SIZE) - 1))	\
+	 << MMCI_##name##_OFFSET)
+#define MMCI_BFEXT(name,value)				\
+	(((value) >> MMCI_##name##_OFFSET)\
+	 & ((1 << MMCI_##name##_SIZE) - 1))
+#define MMCI_BFINS(name,value,old)			\
+	(((old) & ~(((1 << MMCI_##name##_SIZE) - 1)	\
+		    << MMCI_##name##_OFFSET))		\
+	 | MMCI_BF(name,value))
+
+/* Register access macros */
+#define mmci_readl(reg)					\
+	readl((void *)MMCI_BASE + MMCI_##reg)
+#define mmci_writel(reg,value)				\
+	writel((value), (void *)MMCI_BASE + MMCI_##reg)
+	
+#endif /* __CPU_AT32AP_ATMEL_MCI_H__ */
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk
u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk
--- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk	2007-08-21
17:06:35.000000000 +0200
+++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk
2007-08-16 13:34:14.000000000 +0200
@@ -19,10 +19,10 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 # MA 02111-1307 USA
-#
+#PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,)
 
 PLATFORM_RELFLAGS += -fno-strict-aliasing  -fno-common -ffixed-r8
-PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,)
+PLATFORM_RELFLAGS += $(call cc-option,)
 
 PLATFORM_CPPFLAGS += -march=armv5te
 PLATFORM_CPPFLAGS += $(call cc-option,-mtune=arm926ejs,)
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile
u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile
--- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile	2007-08-21
17:06:36.000000000 +0200
+++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile	2007-08-23
09:14:21.000000000 +0200
@@ -26,8 +26,8 @@
 LIB	= lib$(SOC).a
 
 
-OBJS	= serial.o interrupts.o usb_ohci.o lcd.o ether.o spi.o
-SOBJS   = 
+OBJS	= serial.o interrupts.o usb_ohci.o ether.o spi.o
+SOBJS   = atmel_mci.o
 
 all:	.depend $(LIB)
 
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c
u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c
--- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c	2007-08-21
17:06:35.000000000 +0200
+++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c	2007-08-23
10:36:47.000000000 +0200
@@ -184,6 +184,20 @@
 {
   unsigned int timeout;
   
+#ifdef CONFIG_AT91SAM9260EK
+  /* Configure PIO controllers to periph mode */
+  AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, // PIO controller base address
+		      ((unsigned int) AT91C_PA1_SPI0_MOSI) |
+		      ((unsigned int) AT91C_PA3_SPI0_NPCS0) |
+		      ((unsigned int) AT91C_PA0_SPI0_MISO) |
+		      ((unsigned int) AT91C_PA2_SPI0_SPCK), /*
Peripheral A */
+		      0); /* Peripheral B */
+  /* Configure PIO controllers to periph mode */
+  AT91F_PIO_CfgPeriph(AT91C_BASE_PIOC, /* PIO controller base address
*/
+		      0, /* Peripheral A */
+		      ((unsigned int) AT91C_PC11_SPI0_NPCS1)); /*
Peripheral B */
+#endif
+  
   pDesc->state = BUSY;
   
   /* Disable PDC TX and RX channels */
diff -burN u-boot-1.1.5/cpu/arm926ejs/config.mk
u-boot-1.1.5.klk/cpu/arm926ejs/config.mk
--- u-boot-1.1.5/cpu/arm926ejs/config.mk	2006-10-20
17:54:33.000000000 +0200
+++ u-boot-1.1.5.klk/cpu/arm926ejs/config.mk	2007-08-16
13:34:42.000000000 +0200
@@ -20,10 +20,10 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 # MA 02111-1307 USA
 #
-
-PLATFORM_RELFLAGS += -fno-strict-aliasing  -fno-common -ffixed-r8 \
-	-msoft-float
-
+#
+#PLATFORM_RELFLAGS += -fno-strict-aliasing  -fno-common -ffixed-r8 \
+#	-msoft-float
+PLATFORM_RELFLAGS += -fno-strict-aliasing  -fno-common -ffixed-r8
 PLATFORM_CPPFLAGS += -march=armv4
 #
========================================================================
=
 #
diff -burN u-boot-1.1.5/disk/part.c u-boot-1.1.5.klk/disk/part.c
--- u-boot-1.1.5/disk/part.c	2006-10-20 17:54:33.000000000 +0200
+++ u-boot-1.1.5.klk/disk/part.c	2007-08-23 08:29:56.000000000
+0200
@@ -36,6 +36,7 @@
 #if ((CONFIG_COMMANDS & CFG_CMD_IDE)	|| \
      (CONFIG_COMMANDS & CFG_CMD_SCSI)	|| \
      (CONFIG_COMMANDS & CFG_CMD_USB)	|| \
+	 (CONFIG_COMMANDS & CFG_CMD_MMC)	|| \
      defined(CONFIG_MMC) || \
      defined(CONFIG_SYSTEMACE) )
 
@@ -126,6 +127,8 @@
 #if ((CONFIG_COMMANDS & CFG_CMD_IDE)	|| \
      (CONFIG_COMMANDS & CFG_CMD_SCSI)	|| \
      (CONFIG_COMMANDS & CFG_CMD_USB)	|| \
+	 (CONFIG_COMMANDS & CFG_CMD_MMC)	|| \
+     defined(CONFIG_MMC) || \
      defined(CONFIG_SYSTEMACE)          )
 
 #if defined(CONFIG_MAC_PARTITION) || \
diff -burN u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h
u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h
--- u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h	1970-01-01
01:00:00.000000000 +0100
+++ u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h
2007-08-17 10:44:42.000000000 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __ASM_AVR32_MMC_H
+#define __ASM_AVR32_MMC_H
+
+struct mmc_cid {
+	unsigned long psn;
+	unsigned short oid;
+	unsigned char mid;
+	unsigned char prv;
+	unsigned char mdt;
+	char pnm[7];
+};
+
+struct mmc_csd
+{
+	u8	csd_structure:2,
+		spec_vers:4,
+		rsvd1:2;
+	u8	taac;
+	u8	nsac;
+	u8	tran_speed;
+	u16	ccc:12,
+		read_bl_len:4;
+	u64	read_bl_partial:1,
+		write_blk_misalign:1,
+		read_blk_misalign:1,
+		dsr_imp:1,
+		rsvd2:2,
+		c_size:12,
+		vdd_r_curr_min:3,
+		vdd_r_curr_max:3,
+		vdd_w_curr_min:3,
+		vdd_w_curr_max:3,
+		c_size_mult:3,
+		sector_size:5,
+		erase_grp_size:5,
+		wp_grp_size:5,
+		wp_grp_enable:1,
+		default_ecc:2,
+		r2w_factor:3,
+		write_bl_len:4,
+		write_bl_partial:1,
+		rsvd3:5;
+	u8	file_format_grp:1,
+		copy:1,
+		perm_write_protect:1,
+		tmp_write_protect:1,
+		file_format:2,
+		ecc:2;
+	u8	crc:7;
+	u8	one:1;
+};
+
+/* MMC Command numbers */
+#define MMC_CMD_GO_IDLE_STATE		0
+#define MMC_CMD_SEND_OP_COND		1
+#define MMC_CMD_ALL_SEND_CID 		2
+#define MMC_CMD_SET_RELATIVE_ADDR	3
+#define MMC_CMD_SD_SEND_RELATIVE_ADDR	3
+#define MMC_CMD_SET_DSR			4
+#define MMC_CMD_SELECT_CARD		7
+#define MMC_CMD_SEND_CSD 		9
+#define MMC_CMD_SEND_CID 		10
+#define MMC_CMD_SEND_STATUS		13
+#define MMC_CMD_SET_BLOCKLEN		16
+#define MMC_CMD_READ_SINGLE_BLOCK	17
+#define MMC_CMD_READ_MULTIPLE_BLOCK	18
+#define MMC_CMD_WRITE_BLOCK		24
+#define MMC_CMD_APP_CMD			55
+
+#define MMC_ACMD_SD_SEND_OP_COND	41
+
+#define R1_ILLEGAL_COMMAND		(1 << 22)
+#define R1_APP_CMD			(1 << 5)
+
+#endif /* __ASM_AVR32_MMC_H */
diff -burN u-boot-1.1.5/include/configs/at91sam9260ek.h
u-boot-1.1.5.klk/include/configs/at91sam9260ek.h
--- u-boot-1.1.5/include/configs/at91sam9260ek.h	2007-08-21
17:06:36.000000000 +0200
+++ u-boot-1.1.5.klk/include/configs/at91sam9260ek.h	2007-08-23
10:51:43.000000000 +0200
@@ -88,6 +88,8 @@
                         CFG_CMD_FLASH | \
 			CFG_CMD_AUTOSCRIPT | \
                         CFG_CMD_NAND | \
+						CFG_CMD_MMC | \
+						CFG_CMD_EXT2 | \
                         CFG_CMD_FAT ) & \
 		      ~(CFG_CMD_BDI | \
 			CFG_CMD_IMLS | \
@@ -225,6 +227,7 @@
 #undef  CFG_ENV_IS_IN_FLASH
 #define	CFG_ENV_IS_IN_DATAFLASH         1
 #undef CFG_ENV_IS_IN_NAND              
+#undef CFG_ENV_IS_NOWHERE
 
 /*#define CONFIG_MTD_DEBUG		1
 #define CONFIG_MTD_DEBUG_VERBOSE	MTD_DEBUG_LEVEL3
@@ -241,6 +244,10 @@
 #define CFG_ENV_SIZE			0x4000  /* 0x8000 */
 #endif
 
+#ifdef CFG_ENV_IS_NOWHERE
+#define CFG_ENV_SIZE			0x4000
+#endif
+
 #ifdef CFG_ENV_IS_IN_FLASH
 #ifdef CONFIG_BOOTBINFUNC
 #define CFG_ENV_ADDR			(PHYS_FLASH_1 + 0x60000)  /*
after u-boot.bin */
@@ -257,6 +264,10 @@
 #define CONFIG_DOS_PARTITION	        1
 #define LITTLEENDIAN 			1
 
+/* MMC */
+#define CONFIG_MMC		1
+#define MMCI_BASE		0xFFFA8000
+
 #define CFG_LOAD_ADDR		0x23f00000  /* default load address */
 
 #ifdef CONFIG_BOOTBINFUNC

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao
ne
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-24  6:24                   ` Pierre Savary
@ 2008-04-29 19:45                     ` Ken.Fuchs at bench.com
  2008-04-29 20:20                       ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Adrian Filipi
  2008-04-30 14:20                       ` [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary
  0 siblings, 2 replies; 39+ messages in thread
From: Ken.Fuchs at bench.com @ 2008-04-29 19:45 UTC (permalink / raw)
  To: u-boot

I posted the following patch under a different subject line:
Re: [U-Boot-Users] [PATCH] Add eSDHC driver

> > --- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) ---

Pierre Savary wrote:

> Thanks for that... but it's my own patch ;)
> 
> Pierre

===========================================================

Pierre, I hope you like this patch better. :)

The following MMC v4 patch is for u-boot-1.1.5_atmel_1.2.
To the AT91SAM9261 MCI device driver it adds support for
MMC v4.x chips (MoviNAND in particular).
  
The u-boot_at91sam9260_mmc.patch, previously send to this
thread 23 April 2008 must be applied to
u-boot-1.1.5_atmel_1.2, prior to applying the patch below.

The patch includes lines "/* Ignore */".  These are
simply place holders for code that was not relevant
to the MCI driver or MMC code. 

The patch is actually of four individual source files.
Please let me know of any serious problems applying the
patch.  It should apply cleanly, but I didn't verify this.

The MCI MMC v4 features contained in this patch work perfectly
on our AT91SAM9261 board, except that I never got MMC 4 bit
bus working (that code is omitted from this patch).  Anyone
know why the AT91SAM9261-EK doesn't appear to support 4 bit MMC?

This patch may not work on AT91SAM9261-EK, since we modified
the AT91SAM9261-EK board definitions rather than creating a
new configuration and files for our board.

Sincerely,

Ken Fuchs

u-boot-at91sam9261-mmc-v4.patch
===============================

svn diff -r21 cpu/arm926ejs/at91sam926x/atmel_mci.c
Index: cpu/arm926ejs/at91sam926x/atmel_mci.c
===================================================================
--- cpu/arm926ejs/at91sam926x/atmel_mci.c	(revision 21)
+++ cpu/arm926ejs/at91sam926x/atmel_mci.c	(working copy)
@@ -1,4 +1,8 @@
 /*
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Added MMC v4.x (MoviNAND) support
+ *
  * Copyright (C) 2004-2006 Atmel Corporation
  *
  * See file CREDITS for list of people who contributed to this
@@ -34,21 +38,43 @@
 #include <asm/arch/hardware.h>	//klk
 
 #include "atmel_mci.h"
-#undef DEBUG
+
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
+#if     0
+#define DEBUG
+#else   /* 0 */
+#undef  DEBUG   /* kf - was #undef */
+#endif  /* 0 */
+
 #ifdef DEBUG
 #define pr_debug(fmt, args...) printf(fmt, ##args)
 #else
 #define pr_debug(...) do { } while(0)
 #endif
 
+#undef  CFG_MMC_CLK_OD
+#define CFG_MMC_CLK_OD		375000
+
 #ifndef CFG_MMC_CLK_OD
 #define CFG_MMC_CLK_OD		375000
 #endif
 
+#undef  CFG_MMC_CLK_PP
+#define CFG_MMC_CLK_PP		20000000
+
 #ifndef CFG_MMC_CLK_PP
 #define CFG_MMC_CLK_PP		20000000
 #endif
 
+#undef  CFG_MMC_OP_COND
+#define CFG_MMC_OP_COND		0x80ff8000
+/*                              0x80ff8080 works with 30+ sec. power
off req */
+/*                              0x00800000 works better, but write
forever?  */
+/*                              0x00100000 works with 30+ sec. power
off req */
+
 #ifndef CFG_MMC_OP_COND
 #define CFG_MMC_OP_COND		0x00100000
 #endif
@@ -74,8 +100,13 @@
 	bus_hz = AT91C_MASTER_CLOCK;
 	clkdiv = (bus_hz / hz) / 2 - 1;
 
+#if     1
+	printf("mmc: setting clock %lu Hz, block size %lu\n",
+		 hz, blklen);
+#else   /* 1 */
 	pr_debug("mmc: setting clock %lu Hz, block size %lu\n",
 		 hz, blklen);
+#endif  /* 1 */
 
 	if (clkdiv & ~255UL) {
 		clkdiv = 255;
@@ -84,10 +115,17 @@
 	}
 
 	blklen &= 0xfffc;
+
+#if     1   /* AT91SAM9261 does not have RDPROOF and WRPROOF fields. */
 	mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv)
+			 | MMCI_BF(BLKLEN, blklen)));
+#else   /* 1 */
+	mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv)
 			 | MMCI_BF(BLKLEN, blklen)
 			 | MMCI_BIT(RDPROOF)
 			 | MMCI_BIT(WRPROOF)));
+#endif  /* 1 */
+
 }
 
 #define RESP_NO_CRC	1
@@ -99,6 +137,7 @@
 #define NCR		MMCI_BF(MAXLAT, 1)
 #define TRCMD_START	MMCI_BF(TRCMD, 1)
 #define TRDIR_READ	MMCI_BF(TRDIR, 1)
+#define TRDIR_WRITE	MMCI_BF(TRDIR, 0)
 #define TRTYP_BLOCK	MMCI_BF(TRTYP, 0)
 #define INIT_CMD	MMCI_BF(SPCMD, 1)
 #define OPEN_DRAIN	MMCI_BF(OPDCMD, 1)
@@ -109,6 +148,20 @@
 			 | MMCI_BIT(RINDE)		\
 			 | MMCI_BIT(RTOE))
 
+#if     0
+#define DEBUG
+#else   /* 0 */
+#undef  DEBUG   /* kf - was #undef */
+#endif  /* 0 */
+
+#undef pr_debug
+
+#ifdef DEBUG
+#define pr_debug(fmt, args...) printf(fmt, ##args)
+#else
+#define pr_debug(...) do { } while(0)
+#endif
+
 static int
 mmc_cmd(unsigned long cmd, unsigned long arg,
 	void *resp, unsigned long flags)
@@ -117,7 +170,9 @@
 	int i, response_words = 0;
 	unsigned long error_flags;
 	u32 status;
-
+#if     1
+	pr_debug("mmc_cmd: entry\n");
+#endif  /* 1 */
 	AT91F_MMC_Hardware_Init();
 	
 	pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n",
@@ -161,12 +216,28 @@
 	return 0;
 }
 
+#if     0
+#define DEBUG
+#else   /* 0 */
+#undef  DEBUG   /* kf - was #undef */
+#endif  /* 0 */
+
+#undef pr_debug
+
+#ifdef DEBUG
+#define pr_debug(fmt, args...) printf(fmt, ##args)
+#else
+#define pr_debug(...) do { } while(0)
+#endif
+
 static int mmc_acmd(unsigned long cmd, unsigned long arg,
 		    void *resp, unsigned long flags)
 {
 	unsigned long aresp[4];
 	int ret;
 
+	pr_debug("mmc_acmd: entry\n");
+
 	/*
 	 * Seems like the APP_CMD part of an ACMD has 64 cycles max
 	 * latency even though the ACMD part doesn't. This isn't
@@ -184,7 +255,16 @@
 	return ret;
 }
 
-static unsigned long
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
+unsigned long
 mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
 	  unsigned long *buffer)
 {
@@ -193,7 +273,14 @@
 	unsigned long card_status, data;
 	unsigned long wordcount;
 	u32 status;
+	unsigned long *bufaddr;
 
+	pr_debug("mmc_bread: entry\n");
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n", ret,
card_status);
+
+	bufaddr = buffer;
+
 	if (blkcnt == 0)
 		return 0;
 
@@ -202,10 +289,16 @@
 
 	/* Put the device into Transfer state */
 	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n",
+		 ret, card_status);
 	if (ret) goto fail;
 
 	/* Set block length */
 	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n",
+		 ret, card_status);
 	if (ret) goto fail;
 
 	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
@@ -228,7 +321,6 @@
 
 			if (status & MMCI_BIT(RXRDY)) {
 				data = mmci_readl(RDR);
-				/* pr_debug("%x\n", data); */
 				*buffer++ = data;
 				wordcount++;
 			}
@@ -240,12 +332,68 @@
 			status = mmci_readl(SR);
 		} while (!(status & MMCI_BIT(BLKE)));
 
-		putc('.');
+		mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+			&card_status, R1 | NCR);
+		pr_debug("mmc: bread ret = %d, card status = %08x\n",
+			ret, card_status);
+
+		if (i % 0x800 == 0x7ff) {
+		        putc('.');  /* Display '.', after each MB
xfer'ed */ 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+               }
+
+#if     0
+		buffer = bufaddr;
+		wordcount = 0;
+		do {
+		        if (wordcount % 8 == 0) {
+			        pr_debug("\n%06lx:", 4 * wordcount);
+			}
+			pr_debug(" %08lx", *buffer++);
+			wordcount++;
+		} while (4 * wordcount < mmc_blkdev.blksz);
+		pr_debug("\n");
+#endif  /* 0 */
+
 	}
 
 out:
 	/* Put the device back into Standby state */
 	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n", ret,
card_status);
+	if (i >= 0x7ff) {
+	         putc('\n');
+	}
 	return i;
 
 fail:
@@ -254,8 +402,329 @@
 	goto out;
 }
 
+unsigned long
+mmc_bwrite(int dev, unsigned long start, lbaint_t blkcnt,
+	  unsigned long *buffer)
+{
+	int ret, i = 0;
+	unsigned long resp[4];
+	unsigned long card_status, data;
+	unsigned long wordcount;
+	u32 status;
+	unsigned long *bufaddr;
+
+	pr_debug("mmc_bwrite: entry\n");
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("en mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+
+	bufaddr = buffer;
+
+	if (blkcnt == 0)
+		return 0;
+
+	pr_debug("mmc_bwrite: dev %d, start %lx, blkcnt %lx\n",
+		 dev, start, blkcnt);
+
+	/* Put the device into Transfer state */
+	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("sc mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+
+	/* Set block length */
+	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("bl mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+
+	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
+
+	for (i = 0; i < blkcnt; i++, start++) {
+		ret = mmc_cmd(MMC_CMD_WRITE_BLOCK,
+			      start * mmc_blkdev.blksz, resp,
+			      (R1 | NCR | TRCMD_START | TRDIR_WRITE
+			       | TRTYP_BLOCK));
+		if (ret) goto fail;
+
+		ret = -EIO;
+		wordcount = 0;
+		do {
+			do {
+				status = mmci_readl(SR);
+				if (status & (ERROR_FLAGS |
MMCI_BIT(UNRE)))
+					goto fail;
+			} while (!(status & MMCI_BIT(TXRDY)));
+
+			if (status & MMCI_BIT(TXRDY)) {
+			        data = *buffer++;
+				mmci_writel(TDR, data);
+				wordcount++;
+			}
+		} while(wordcount < (mmc_blkdev.blksz / 4));
+
+		pr_debug("mmc: write %u words, waiting for BLKE\n",
wordcount);
+
+		do {
+			status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(BLKE)));
+
+		do {
+		        mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+				&card_status, R1 | NCR);
+			if ((card_status & 0x00000100) != 0x00000100) {
+#if     0
+			        printf("lp mmc: bwrite ret = %d, ",
ret);
+				printf("card status = %08x\n",
card_status);
+#endif  /* 0 */
+			} else {
+			        pr_debug("lp mmc: bwrite ret = %d, ",
ret);
+				pr_debug("card status = %08x\n",
card_status);
+			}
+		} while ((card_status & 0x00000100) != 0x00000100);
+
+		if (i % 0x800 == 0x7ff) {
+		         putc('.');  /* Display '.', after each MB
xfer'ed */ 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+		}
+
+#if     0
+		ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION,
+			      0, resp,
+			      R1 | NCR);
+		mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+			&card_status, R1 | NCR);
+		pr_debug("st mmc: bwrite ret = %d, card status =
%08x\n",
+			 ret, card_status);
+		if (ret) goto fail;
+#endif  /* 0 */
+
+	}
+
+out:
+#if     0
+	ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION,
+		      0, resp,
+		      R1 | NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("st mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+#endif  /* 0 */
+
+	/* Put the device back into Standby state */
+	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("dc mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (i >= 0x7ff) {
+	         putc('\n');
+	}
+	return i;
+
+fail:
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("fa mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	goto out;
+}
+
+   /* Hangs - did not attempt to debug */
+/* MMC Multiple Block Write - mmc_mbwrite() */
+unsigned long
+mmc_mbwrite(int dev, unsigned long start, lbaint_t blkcnt,
+	  unsigned long *buffer)
+{
+	int ret, i = 0;
+	unsigned long resp[4];
+	unsigned long card_status, data;
+	unsigned long wordcount;
+	u32 status;
+	unsigned long *bufaddr;
+
+	pr_debug("mmc_bwrite: entry\n");
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("en mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+
+	bufaddr = buffer;
+
+	if (blkcnt == 0)
+		return 0;
+
+	if (blkcnt > 0xffff) {  /* Exceeds length supported by MoviNAND.
*/
+	        return -1;
+	}
+
+	pr_debug("mmc_mbwrite: dev %d, start %lx, blkcnt %lx\n",
+		 dev, start, blkcnt);
+
+	/* Put the device into Transfer state */
+	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("sc mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (ret) goto fail;
+
+	/* Set block length */
+	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("bl mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (ret) goto fail;
+
+	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
+
+	ret = mmc_cmd(MMC_CMD_SET_BLOCK_COUNT,
+		      blkcnt, resp,
+		      R1 | NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("bc mmc: mbwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+
+	ret = mmc_cmd(MMC_CMD_WRITE_MULTIPLE_BLOCK,
+		      start * mmc_blkdev.blksz, resp,
+		      (R1 | NCR | TRCMD_START | TRDIR_WRITE |
TRTYP_BLOCK));
+	if (ret) goto fail;
+
+	for (i = 0; i < blkcnt; i++, start++) {
+
+		ret = -EIO;
+		wordcount = 0;
+		do {
+			do {
+				status = mmci_readl(SR);
+				if (status & (ERROR_FLAGS |
MMCI_BIT(UNRE)))
+					goto fail;
+			} while (!(status & MMCI_BIT(TXRDY)));
+
+			if (status & MMCI_BIT(TXRDY)) {
+			        data = *buffer++;
+				mmci_writel(TDR, data);
+				wordcount++;
+			}
+		} while(wordcount < (mmc_blkdev.blksz / 4));
+
+#if     1
+		pr_debug("mmc: write %u words, waiting for BLKE\n",
wordcount);
+
+		do {
+			status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(BLKE)));
+#endif  /* 0 */
+
+		do {
+		        mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+				&card_status, R1 | NCR);
+			if ((card_status & 0x00000100) != 0x00000100) {
+#if     0
+			        printf("lp mmc: mbwrite ret = %d, ",
ret);
+				printf("card status = %08x\n",
card_status);
+#endif  /* 0 */
+			} else {
+			        pr_debug("lp mmc: mbwrite ret = %d, ",
ret);
+				pr_debug("card status = %08x\n",
card_status);
+			}
+		} while ((card_status & 0x00000100) != 0x00000100);
+
+		if (i % 0x800 == 0x7ff) {
+		         putc('.');  /* Display '.', after each MB
xfer'ed */ 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+		}
+	}
+
+out:
+#if     0
+	ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION,
+		      0, resp,
+		      R1 | NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("st mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (ret) goto fail;
+#endif  /* 0 */
+
+	/* Put the device back into Standby state */
+	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("dc mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (i >= 0x7ff) {
+	         putc('\n');
+	}
+	return i;
+
+fail:
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("fa mmc: mbwrite failed, card status = %08x\n",
card_status);
+	goto out;
+}
+
 static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp)
 {
+	pr_debug("mmc_parse_cid: entry\n");
+
 	cid->mid = resp[0] >> 24;
 	cid->oid = (resp[0] >> 8) & 0xffff;
 	cid->pnm[0] = resp[0];
@@ -272,6 +741,8 @@
 
 static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp)
 {
+	pr_debug("sd_parse_cid: entry\n");
+
 	cid->mid = resp[0] >> 24;
 	cid->oid = (resp[0] >> 8) & 0xffff;
 	cid->pnm[0] = resp[0];
@@ -288,6 +759,8 @@
 
 static void mmc_dump_cid(const struct mmc_cid *cid)
 {
+	pr_debug("mmc_dump_cid: entry\n");
+
 	printf("Manufacturer ID:       %02lX\n", cid->mid);
 	printf("OEM/Application ID:    %04lX\n", cid->oid);
 	printf("Product name:          %s\n", cid->pnm);
@@ -301,6 +774,9 @@
 static void mmc_dump_csd(const struct mmc_csd *csd)
 {
 	unsigned long *csd_raw = (unsigned long *)csd;
+
+	pr_debug("mmc_dump_csd: entry\n");
+
 	pr_debug("CSD data: %08lx %08lx %08lx %08lx\n",
 	       csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]);
 	pr_debug("CSD structure version:   1.%u\n", csd->csd_structure);
@@ -337,6 +813,8 @@
 {
 	int ret;
 
+	pr_debug("mmc_idle_cards: entry\n");
+
 	/* Reset and initialize all cards */
 	ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0);
 	
@@ -352,6 +830,8 @@
 	unsigned long resp[4];
 	int i, ret = 0;
 
+	pr_debug("sd_init_card: entry\n");
+
 	mmc_idle_cards();
 	for (i = 0; i < 1000; i++) {
 		ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND,
CFG_MMC_OP_COND,
@@ -387,10 +867,40 @@
 {
 	unsigned long resp[4];
 	int i, ret = 0;
+	u32 status;
 
+	pr_debug("mmc_init_card: entry\n");
+
 	mmc_idle_cards();
 
+	/* MoviNAND initialization */
 	for (i = 0; i < 1000; i++) {
+	        mmci_writel(ARGR, 0xFFFFFFFF);
+		mmci_writel(CMDR, 0x0018113F);
+		do {
+		        status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(CMDRDY)));
+	}
+        /* Getting the OCR value seems to prevent marginal chips from
*/
+        /* working@all, whereas they would work fine after waiting
*/
+        /* a full minute or more with the power off prior to booting.
*/
+        /* Our marginal chips have date codes 0716 and 0728.
*/
+#if     0   
+	for (i = 0; i < 1000; i++) {
+	  /* Request OCR value to determine chip's supported volt. */
+		ret = mmc_cmd(MMC_CMD_SEND_OP_COND, 0, resp,
+			      R3 | NID | OPEN_DRAIN);
+		if (ret || (resp[0] & 0x80000000))
+		{
+			break;
+		}
+		ret = -ETIMEDOUT;
+	}
+	if (ret) {
+		return ret;
+	}
+#endif  /* 0 */
+	for (i = 0; i < 1000; i++) {
 		ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND,
resp,
 			      R3 | NID | OPEN_DRAIN);
 		if (ret || (resp[0] & 0x80000000))
@@ -399,13 +909,35 @@
 		}
 		ret = -ETIMEDOUT;
 	}
+        pr_debug("Step 4: ret = 0x%lx\n", ret);
+	pr_debug("MMC_CMD_SEND_OP_COND = 0x%lx\n",
MMC_CMD_SEND_OP_COND);
+        pr_debug("CFG_MMC_OP_COND = 0x%lx\n", CFG_MMC_OP_COND);
+        pr_debug("resp[0] = 0x%lx\n", resp[0]);
+        pr_debug("resp[1] = 0x%lx\n", resp[1]);
+        pr_debug("resp[2] = 0x%lx\n", resp[2]);
+        pr_debug("resp[3] = 0x%lx\n", resp[3]);
+        pr_debug("R3 = 0x%lx\n", R3);
+        pr_debug("NID = 0x%lx\n", NID);
+        pr_debug("OPEN_DRAIN = 0x%lx\n", OPEN_DRAIN);
+
 	pr_debug("4\n");
 	pr_debug("ret : %i\n",ret);
+
+	pr_debug("MCI_MR = 0x%08lx\n", mmci_readl(MR));
+	pr_debug("MCI_DTOR = 0x%08lx\n", mmci_readl(DTOR));
+	pr_debug("MCI_SDCR = 0x%08lx\n", mmci_readl(SDCR));
+	pr_debug("MCI_ARGR = 0x%08lx\n", mmci_readl(ARGR));
+	/* RSPR */
+	/* RDR */
+	pr_debug("MCI_SR = 0x%08lx\n", mmci_readl(SR));
+	pr_debug("MCI_IMR = 0x%08lx\n", mmci_readl(IMR));
+
 	if (ret)
 		return ret;
 	pr_debug("5\n");
 	/* Get CID of all cards. FIXME: Support more than one card */
 	ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID |
OPEN_DRAIN);
+	pr_debug("ALL_SEND_CID ret: 0x%08lx\n", ret);
 	if (ret)
 		return ret;
 	mmc_parse_cid(cid, resp);
@@ -415,6 +947,7 @@
 	/* Set Relative Address of the card that responded */
 	ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp,
 		      R1 | NCR | OPEN_DRAIN);
+	pr_debug("SET_RELATIVE_ADDR ret: 0x%08lx\n", ret);
 	return ret;
 }
 
@@ -471,23 +1004,42 @@
 	       dtocyc << shift, dtor);
 }
 
+#define DEFAULT_SECTOR_SIZE 512
+
 int mmc_init(int verbose)
 {
 	struct mmc_cid cid;
 	struct mmc_csd csd;
 	unsigned int max_blksz;
 	int ret,aux;
+	unsigned char buffer[DEFAULT_SECTOR_SIZE];
 	
+	pr_debug("mmc_init: entry\n");
+	pr_debug("mmc_init: verbose = 0x%08lx\n", verbose);
+
 	AT91F_MMC_Hardware_Init();
 	
 	pr_debug("0\n");
 	/* Initialize controller */
 	mmci_writel(CR, MMCI_BIT(SWRST));
 	mmci_writel(CR, MMCI_BIT(MCIEN));
+
+	pr_debug("MCI_MR = 0x%08lx\n", mmci_readl(MR));
+	pr_debug("MCI_DTOR = 0x%08lx\n", mmci_readl(DTOR));
+	pr_debug("MCI_SDCR = 0x%08lx\n", mmci_readl(SDCR));
+	pr_debug("MCI_ARGR = 0x%08lx\n", mmci_readl(ARGR));
+	/* RSPR */
+	/* RDR */
+	pr_debug("MCI_SR = 0x%08lx\n", mmci_readl(SR));
+	pr_debug("MCI_IMR = 0x%08lx\n", mmci_readl(IMR));
+
 	mmci_writel(DTOR, 0x5f);
 	mmci_writel(IDR, ~0UL);
 	mmci_writel(SDCR, 0x1);
 	mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+#if     0
+	mmci_writel(MR, 0x02009B4A);
+#endif  /* 0 */
 /* 	//mmci_writel(CR, MMCI_BIT(SWRST));
 	mmci_writel(CR, 0x00000001);
 	mmci_writel(DTOR, 0x0000007F);
@@ -502,6 +1054,7 @@
 
 	ret = sd_init_card(&cid, verbose);
 	if (ret) {
+	  	pr_debug("Not SDCard, try MMC\n");
 		mmc_rca = MMC_DEFAULT_RCA;
 		ret = mmc_init_card(&cid, verbose);
 	}
@@ -545,6 +1098,20 @@
 	mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz);
 
 #if 0
+	mmc_bread(mmc_blkdev.dev, 1024, 1, (ulong *)buffer);
+        buffer[0] = 0x00; buffer[1] = 0x11;
+        buffer[2] = 0x22; buffer[3] = 0x33;
+        buffer[4] = 0x44; buffer[5] = 0x55;
+        buffer[6] = 0x66; buffer[7] = 0x77;
+        buffer[504] = 0x88; buffer[505] = 0x99;
+        buffer[506] = 0xaa; buffer[507] = 0xbb;
+        buffer[508] = 0xcc; buffer[509] = 0xdd;
+        buffer[510] = 0xee; buffer[511] = 0xff;
+	mmc_bwrite(mmc_blkdev.dev, 1024, 1, (ulong *)buffer); 
+	mmc_bread(mmc_blkdev.dev, 1024, 1, (ulong *)buffer);
+#endif  /* 0 */
+
+#if 0
 	if (fat_register_device(&mmc_blkdev, 1))
 		pr_debug("Could not register MMC fat device\n");
 #else
@@ -556,16 +1123,22 @@
 
 int mmc_read(ulong src, uchar *dst, int size)
 {
+	pr_debug("mmc_read: entry\n");
+
 	return -ENOSYS;
 }
 
 int mmc_write(uchar *src, ulong dst, int size)
 {
+	pr_debug("mmc_write: entry\n");
+
 	return -ENOSYS;
 }
 
 int mmc2info(ulong addr)
 {
+	pr_debug("mmc2info: entry\n");
+
 	return 0;
 }
 
svn diff -r21 include/asm-arm/arch-at91sam926x/mmc.h
Index: include/asm-arm/arch-at91sam926x/mmc.h
===================================================================
--- include/asm-arm/arch-at91sam926x/mmc.h	(revision 0)
+++ include/asm-arm/arch-at91sam926x/mmc.h	(revision 50)
@@ -0,0 +1,103 @@
+/*
+ * (C) Copyright 2007
+ * Benchmark Electronics, Inc.
+ * Added MMC v4.x (MoviNAND) support
+ *
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __ASM_AT91SAM926X_MMC_H
+#define __ASM_AT91SAM926X_MMC_H
+
+struct mmc_cid {
+	unsigned long psn;
+	unsigned short oid;
+	unsigned char mid;
+	unsigned char prv;
+	unsigned char mdt;
+	char pnm[7];
+};
+
+struct mmc_csd
+{
+	u8	csd_structure:2,
+		spec_vers:4,
+		rsvd1:2;
+	u8	taac;
+	u8	nsac;
+	u8	tran_speed;
+	u16	ccc:12,
+		read_bl_len:4;
+	u64	read_bl_partial:1,
+		write_blk_misalign:1,
+		read_blk_misalign:1,
+		dsr_imp:1,
+		rsvd2:2,
+		c_size:12,
+		vdd_r_curr_min:3,
+		vdd_r_curr_max:3,
+		vdd_w_curr_min:3,
+		vdd_w_curr_max:3,
+		c_size_mult:3,
+		sector_size:5,
+		erase_grp_size:5,
+		wp_grp_size:5,
+		wp_grp_enable:1,
+		default_ecc:2,
+		r2w_factor:3,
+		write_bl_len:4,
+		write_bl_partial:1,
+		rsvd3:5;
+	u8	file_format_grp:1,
+		copy:1,
+		perm_write_protect:1,
+		tmp_write_protect:1,
+		file_format:2,
+		ecc:2;
+	u8	crc:7;
+	u8	one:1;
+};
+
+/* MMC Command numbers */
+#define MMC_CMD_GO_IDLE_STATE		0
+#define MMC_CMD_SEND_OP_COND		1
+#define MMC_CMD_ALL_SEND_CID 		2
+#define MMC_CMD_SET_RELATIVE_ADDR	3
+#define MMC_CMD_SD_SEND_RELATIVE_ADDR	3
+#define MMC_CMD_SET_DSR			4
+#define MMC_CMD_SELECT_CARD		7
+#define MMC_CMD_SEND_CSD 		9
+#define MMC_CMD_SEND_CID 		10
+#define MMC_CMD_STOP_TRANSMISSION	12
+#define MMC_CMD_SEND_STATUS		13
+#define MMC_CMD_SET_BLOCKLEN		16
+#define MMC_CMD_READ_SINGLE_BLOCK	17
+#define MMC_CMD_READ_MULTIPLE_BLOCK	18
+#define MMC_CMD_SET_BLOCK_COUNT		23
+#define MMC_CMD_WRITE_BLOCK		24
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK	25
+#define MMC_CMD_APP_CMD			55
+
+#define MMC_ACMD_SD_SEND_OP_COND	41
+
+#define R1_ILLEGAL_COMMAND		(1 << 22)
+#define R1_APP_CMD			(1 << 5)
+
+#endif /* __ASM_AT91SAM926X_MMC_H */

svn diff -r21 include/configs/at91sam9261ek.h
Index: include/configs/at91sam9261ek.h
===================================================================
--- include/configs/at91sam9261ek.h	(revision 21)
+++ include/configs/at91sam9261ek.h	(working copy)
@@ -1,4 +1,8 @@
 /*
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Added MMC v4.x (MoviNAND) support
+ *
  * (C) Copyright 2005
  * M. Amine SAYA ATMEL Rousset, France.
  *
@@ -95,18 +99,24 @@
 /* SPI */
 #define CONFIG_SPI
 
+/* kf - define hush (from busy box) command line interface & options */
+#define CFG_HUSH_PARSER
+#define CFG_PROMPT_HUSH_PS2     "> "
+#define CFG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
 #define CONFIG_COMMANDS		\
 		       ((CONFIG_CMD_DFL	| \
                         CFG_CMD_NET | \
                         CFG_CMD_ENV | \
                         CFG_CMD_USB | \
                         CFG_CMD_FLASH | \
-			CFG_CMD_NAND | \
+                        CFG_CMD_MMC | \
+                        CFG_CMD_EXT2 | \
+                        CFG_CMD_FAT | \
 			CFG_CMD_AUTOSCRIPT | \
-                        CFG_CMD_FAT | \
                         CFG_CMD_NFS | \
                         CFG_CMD_SPI | \
-                        CFG_CMD_U | \
 			CFG_CMD_IMI | \
                         CFG_CMD_PING ) & \
 		      ~(CFG_CMD_BDI | \
@@ -296,8 +306,12 @@
 #define CFG_FLASH_ERASE_TOUT		(2*CFG_HZ) /* Timeout for Flash
Erase */
 #define CFG_FLASH_WRITE_TOUT		(2*CFG_HZ) /* Timeout for Flash
Write */
 
+#undef  CFG_ENV_IS_IN_FLASH
 #define	CFG_ENV_IS_IN_DATAFLASH         1
-#undef  CFG_ENV_IS_IN_FLASH
+#if     0
+#undef  CFG_ENV_IS_IN_NAND
+#endif  /* 0 - kf */
+#undef  CFG_ENV_IS_NOWHERE
 
 #ifdef CFG_ENV_IS_IN_DATAFLASH
 #define CFG_ENV_OFFSET			0x4000
@@ -305,6 +319,10 @@
 #define CFG_ENV_SIZE			0x4000  /* 0x8000 */
 #endif
 
+#ifdef CFG_ENV_IS_NOWHERE
+#define CFG_ENV_SIZE			0x4000
+#endif
+
 #ifdef CFG_ENV_IS_IN_FLASH
 #ifdef CONFIG_BOOTBINFUNC
 #define CFG_ENV_ADDR			(PHYS_FLASH_1 + 0x60000)  /*
after u-boot.bin */
@@ -316,6 +334,9 @@
 #endif
 
 /* Add LCD stuff */
+/* Ignore */
+/* Ignore */
+
 #if 0  /* No LCD */
 #define  CONFIG_LCD
 /* #undef  CONFIG_LCD_LOGO */
@@ -333,8 +354,21 @@
 #define CONFIG_DOS_PARTITION	        1
 #define LITTLEENDIAN 			1
 
-#define CFG_LOAD_ADDR		0x23f00000  /* default load address */
+/* Add FAT filesystem configuration, other than CFG_CMD_FAT */
+#define CONFIG_SUPPORT_VFAT
 
+/* MMC */
+#define CONFIG_MMC		1
+#define MMCI_BASE		0xFFFA8000  /* (void *)AT91C_BASE_MCI */
+/* MMC - kf - slow down speed for debug from 20000000 Hz down to ...
*/
+/* However, tweaking this value here causes all code to be compiled,
*/
+/* so we shall change the value only where needed - in atmel_mci.c.
*/
+#define CFG_MMC_CLK_PP          20000000
+
+#define CFG_LOAD_ADDR		0x23f00000  /* default load address   */
+
+#define CFG_BOOTM_LEN           0x02100000  /* 33MB uncompressed max.
*/
+
 #ifdef CONFIG_BOOTBINFUNC
 #define CFG_BOOT_SIZE		0x00 /* 0 KBytes */
 #define CFG_U_BOOT_BASE		PHYS_FLASH_1

svn diff -r21 board/at91sam9261ek/at91sam9261ek.c
Index: board/at91sam9261ek/at91sam9261ek.c
===================================================================
--- board/at91sam9261ek/at91sam9261ek.c	(revision 21)
+++ board/at91sam9261ek/at91sam9261ek.c	(working copy)
@@ -1,4 +1,8 @@
 /*
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Added specific AT91SAM9261 board support
+ *
  * (C) Copyright 2005
  * M. Amine SAYA ATMEL Rousset, France.
  * Added AT91SAM9261EK support.
@@ -28,12 +32,19 @@
 
 #include <common.h>
 #include <asm/arch/hardware.h>
+#include <asm/arch-at91sam926x/at91sam9261.h>
 
 #include <net.h>
 
 extern void AT91F_Spi1Init (void);
 extern void gpio_init(void);
 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
 /*
------------------------------------------------------------------------
- */
 /*
  * Miscelaneous platform dependent initialisations
@@ -107,7 +118,8 @@
   *AT91C_PMC_PCER |= 1 << AT91C_ID_US0;	/* enable clock */
 #endif
   
-#ifdef CONFIG_USART1
+#if     1
+  /* #ifdef CONFIG_USART1 */
   *AT91C_PIOB_PDR = AT91C_PC12_TXD1 | AT91C_PC13_RXD1;
   *AT91C_PMC_PCER |= 1 << AT91C_ID_US1;	/* enable clock */
 #endif
@@ -118,6 +130,41 @@
 #endif
 }
 
+#ifdef CONFIG_MMC
+#if (CONFIG_COMMANDS & CFG_CMD_MMC)
+int AT91F_MMC_Hardware_Init(void)
+{
+#if     0
+	printf("AT91F_MMC_Hardware_Init: entry\n");
+#endif  /* 0 */
+
+        AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,
+			    0,                   /*  <- Peripheral A */
+			    (AT91C_PA0_MCDA0 |    /*  MMC NAND MCDA0  */
+			     AT91C_PA1_MCCDA |    /*  MMC NAND MCCDA  */
+			     AT91C_PA2_MCCK  |    /*  MMC NAND MCCK   */
+			     AT91C_PA4_MCDA1 |    /*  MMC NAND MCDA1  */
+			     AT91C_PA5_MCDA2 |    /*  MMC NAND MCDA2  */
+			     AT91C_PA6_MCDA3 |    /*  MMC NAND MCDA3  */
+			     0));                 /*  <- Peripheral B */
+
+#if     1
+	/* Pull up disable register */
+	AT91C_BASE_PIOA->PIO_PPUDR |=
+	        AT91C_PA0_MCDA0 |    /*  MMC NAND MCDA0  */
+	        AT91C_PA1_MCCDA |    /*  MMC NAND MCCDA  */
+	        AT91C_PA2_MCCK  |    /*  MMC NAND MCCK   */
+	        AT91C_PA4_MCDA1 |    /*  MMC NAND MCDA1  */
+	        AT91C_PA5_MCDA2 |    /*  MMC NAND MCDA2  */
+	        AT91C_PA6_MCDA3;     /*  MMC NAND MCDA3  */
+#endif  /* 0 */
+
+	AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_MCI);
+}
+#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */
+#endif /* CONFIG_MMC */
+
+
 int dram_init (void)
 {
   DECLARE_GLOBAL_DATA_PTR;
@@ -148,5 +195,35 @@
 
   gpio_init();
 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
   return 0;
 }

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-29 19:45                     ` [U-Boot-Users] drivers MMCplus for at91sam9x Ken.Fuchs at bench.com
@ 2008-04-29 20:20                       ` Adrian Filipi
  2008-04-29 20:43                         ` Wolfgang Denk
  2008-05-08 11:17                         ` Haavard Skinnemoen
  2008-04-30 14:20                       ` [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary
  1 sibling, 2 replies; 39+ messages in thread
From: Adrian Filipi @ 2008-04-29 20:20 UTC (permalink / raw)
  To: u-boot

hi folks,

 	I've come across a case on one of our PXA250 boards where the 
flash was getting corrupted when using the 1.3.2 version of cfi_flash.c, 
while the 1.2.0 version worked just fine.

 	Here's what happens:

 	1. Reprogram uboot.
 	2. Compare uboot in flash against uboot in DRAM.
 	3. Either run "reset" or press the reset button.
 	4. Compare the flash and DRAM, as well as a new copy
 	   of uboot re-read from CF for good measure.

 	At this point the low byte in the word at offset 0x554 has switched 
from a 0x30 to a 0x10.  This is the only change in the flash.  The new 
value is always the same.

 	I narrowed down the source of the problem to the loss of the 
volatile qualifier on the addr pointer in flash_write_cmd().  Adding the 
qualifier gets rid of the corruption.  In the older 1.2.0 sources, addr was 
declared as "volatile cfiptr_t addr;".

 	Has anyone else seen this?  It seems like the safe thing to do is 
to restore the qualifier in general.

 	Below is a diff, of the change for the 1.3.2. sources:

diff -u -r1.1.1.2.2.2 cfi_flash.c
--- cfi_flash.c	23 Apr 2008 17:02:47 -0000	1.1.1.2.2.2
+++ cfi_flash.c	29 Apr 2008 18:55:47 -0000
@@ -464,7 +464,7 @@
  			     uint offset, uchar cmd)
  {

-	void *addr;
+	void *volatile addr;
  	cfiword_t cword;

  	addr = flash_map (info, sect, offset);

 	Adrian
--
Linux Software Engineer | EuroTech, Inc. | www.eurotech-inc.com

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-29 20:20                       ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Adrian Filipi
@ 2008-04-29 20:43                         ` Wolfgang Denk
  2008-04-29 21:10                           ` Adrian Filipi
  2008-05-08 11:17                         ` Haavard Skinnemoen
  1 sibling, 1 reply; 39+ messages in thread
From: Wolfgang Denk @ 2008-04-29 20:43 UTC (permalink / raw)
  To: u-boot

In message <alpine.DEB.1.10.0804291604250.32753@pmy.adscville> you wrote:
> 
>  	I narrowed down the source of the problem to the loss of the 
> volatile qualifier on the addr pointer in flash_write_cmd().  Adding the 
> qualifier gets rid of the corruption.  In the older 1.2.0 sources, addr was 
> declared as "volatile cfiptr_t addr;".

The volatile should not be needed - the CFI driver should use correct
accessor macros instead. See
Documentation/volatile-considered-harmful.txt in your Linux kernel
source tree...

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
No one wants war.
	-- Kirk, "Errand of Mercy", stardate 3201.7

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-29 20:43                         ` Wolfgang Denk
@ 2008-04-29 21:10                           ` Adrian Filipi
  2008-04-29 21:16                             ` Jerry Van Baren
  0 siblings, 1 reply; 39+ messages in thread
From: Adrian Filipi @ 2008-04-29 21:10 UTC (permalink / raw)
  To: u-boot


 	Sure, reducing the reliance on volatile is a good idea, but I'm at 
a loss for anything better to do.

 	I'm seeing a real problem that is only fixed by qualifying the 
container of the pointer as volatile, i.e. "void *volatile".  "volatile 
void *" has no effect as expected given that the read/write accessors are 
used now.

 	The old data type was essentially "volatile void *volatile addr" 
and the new type is simply "void *addr".  I seem to need at least "void 
*volatile addr" for things to work.

 	Note, I'm only seeing this problem on our PXA250 boards.

 	Adrian
--
Linux Software Engineer | EuroTech, Inc. | www.eurotech-inc.com

On Tue, 29 Apr 2008, Wolfgang Denk wrote:

> In message <alpine.DEB.1.10.0804291604250.32753@pmy.adscville> you wrote:
>>
>>  	I narrowed down the source of the problem to the loss of the
>> volatile qualifier on the addr pointer in flash_write_cmd().  Adding the
>> qualifier gets rid of the corruption.  In the older 1.2.0 sources, addr was
>> declared as "volatile cfiptr_t addr;".
>
> The volatile should not be needed - the CFI driver should use correct
> accessor macros instead. See
> Documentation/volatile-considered-harmful.txt in your Linux kernel
> source tree...
>
> Best regards,
>
> Wolfgang Denk
>
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-29 21:10                           ` Adrian Filipi
@ 2008-04-29 21:16                             ` Jerry Van Baren
       [not found]                               ` <alpine.DEB.1.10.0804300949360.13610@pmy.adscville>
  0 siblings, 1 reply; 39+ messages in thread
From: Jerry Van Baren @ 2008-04-29 21:16 UTC (permalink / raw)
  To: u-boot

Adrian Filipi wrote:
> On Tue, 29 Apr 2008, Wolfgang Denk wrote:
> 
>> In message <alpine.DEB.1.10.0804291604250.32753@pmy.adscville> you wrote:
>>>  	I narrowed down the source of the problem to the loss of the
>>> volatile qualifier on the addr pointer in flash_write_cmd().  Adding the
>>> qualifier gets rid of the corruption.  In the older 1.2.0 sources, addr was
>>> declared as "volatile cfiptr_t addr;".
>> The volatile should not be needed - the CFI driver should use correct
>> accessor macros instead. See
>> Documentation/volatile-considered-harmful.txt in your Linux kernel
>> source tree...
>>
>> Best regards,
>>
>> Wolfgang Denk
> 
>  	Sure, reducing the reliance on volatile is a good idea, but I'm at 
> a loss for anything better to do.
> 
>  	I'm seeing a real problem that is only fixed by qualifying the 
> container of the pointer as volatile, i.e. "void *volatile".  "volatile 
> void *" has no effect as expected given that the read/write accessors are 
> used now.
> 
>  	The old data type was essentially "volatile void *volatile addr" 
> and the new type is simply "void *addr".  I seem to need at least "void 
> *volatile addr" for things to work.
> 
>  	Note, I'm only seeing this problem on our PXA250 boards.
> 
>  	Adrian

Hi Adrian,

Please bottom post.

It may be useful to disassemble cfi_flash.o file (objdump -S) and see 
what the two different configurations of flash_write_cmd() get turned 
into in assembly.

Best regards,
gvb

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-29 19:45                     ` [U-Boot-Users] drivers MMCplus for at91sam9x Ken.Fuchs at bench.com
  2008-04-29 20:20                       ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Adrian Filipi
@ 2008-04-30 14:20                       ` Pierre Savary
  2008-04-30 16:25                         ` Ken.Fuchs at bench.com
  2008-04-30 20:31                         ` Ken.Fuchs at bench.com
  1 sibling, 2 replies; 39+ messages in thread
From: Pierre Savary @ 2008-04-30 14:20 UTC (permalink / raw)
  To: u-boot

Hi Ken,
Thanks a lot for your patch. I will test it next week. Have you ever tested
your U-Boot with 4GB or 8GB moviNAND?
Thanks in advance

Pierre

-----Message d'origine-----
De?: u-boot-users-bounces at lists.sourceforge.net
[mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de
Ken.Fuchs at bench.com
Envoy??: mardi 29 avril 2008 21:46
??: pierre.savary at kerlink.fr
Cc?: u-boot-users at lists.sourceforge.net; afleming at freescale.com;
abo at kerlink.fr; drzeus-mmc at drzeus.cx
Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x

I posted the following patch under a different subject line:
Re: [U-Boot-Users] [PATCH] Add eSDHC driver

> > --- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) ---

Pierre Savary wrote:

> Thanks for that... but it's my own patch ;)
> 
> Pierre

===========================================================

Pierre, I hope you like this patch better. :)

The following MMC v4 patch is for u-boot-1.1.5_atmel_1.2.
To the AT91SAM9261 MCI device driver it adds support for
MMC v4.x chips (MoviNAND in particular).
  
The u-boot_at91sam9260_mmc.patch, previously send to this
thread 23 April 2008 must be applied to
u-boot-1.1.5_atmel_1.2, prior to applying the patch below.

The patch includes lines "/* Ignore */".  These are
simply place holders for code that was not relevant
to the MCI driver or MMC code. 

The patch is actually of four individual source files.
Please let me know of any serious problems applying the
patch.  It should apply cleanly, but I didn't verify this.

The MCI MMC v4 features contained in this patch work perfectly
on our AT91SAM9261 board, except that I never got MMC 4 bit
bus working (that code is omitted from this patch).  Anyone
know why the AT91SAM9261-EK doesn't appear to support 4 bit MMC?

This patch may not work on AT91SAM9261-EK, since we modified
the AT91SAM9261-EK board definitions rather than creating a
new configuration and files for our board.

Sincerely,

Ken Fuchs

u-boot-at91sam9261-mmc-v4.patch
===============================

svn diff -r21 cpu/arm926ejs/at91sam926x/atmel_mci.c
Index: cpu/arm926ejs/at91sam926x/atmel_mci.c
===================================================================
--- cpu/arm926ejs/at91sam926x/atmel_mci.c	(revision 21)
+++ cpu/arm926ejs/at91sam926x/atmel_mci.c	(working copy)
@@ -1,4 +1,8 @@
 /*
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Added MMC v4.x (MoviNAND) support
+ *
  * Copyright (C) 2004-2006 Atmel Corporation
  *
  * See file CREDITS for list of people who contributed to this
@@ -34,21 +38,43 @@
 #include <asm/arch/hardware.h>	//klk
 
 #include "atmel_mci.h"
-#undef DEBUG
+
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
+#if     0
+#define DEBUG
+#else   /* 0 */
+#undef  DEBUG   /* kf - was #undef */
+#endif  /* 0 */
+
 #ifdef DEBUG
 #define pr_debug(fmt, args...) printf(fmt, ##args)
 #else
 #define pr_debug(...) do { } while(0)
 #endif
 
+#undef  CFG_MMC_CLK_OD
+#define CFG_MMC_CLK_OD		375000
+
 #ifndef CFG_MMC_CLK_OD
 #define CFG_MMC_CLK_OD		375000
 #endif
 
+#undef  CFG_MMC_CLK_PP
+#define CFG_MMC_CLK_PP		20000000
+
 #ifndef CFG_MMC_CLK_PP
 #define CFG_MMC_CLK_PP		20000000
 #endif
 
+#undef  CFG_MMC_OP_COND
+#define CFG_MMC_OP_COND		0x80ff8000
+/*                              0x80ff8080 works with 30+ sec. power
off req */
+/*                              0x00800000 works better, but write
forever?  */
+/*                              0x00100000 works with 30+ sec. power
off req */
+
 #ifndef CFG_MMC_OP_COND
 #define CFG_MMC_OP_COND		0x00100000
 #endif
@@ -74,8 +100,13 @@
 	bus_hz = AT91C_MASTER_CLOCK;
 	clkdiv = (bus_hz / hz) / 2 - 1;
 
+#if     1
+	printf("mmc: setting clock %lu Hz, block size %lu\n",
+		 hz, blklen);
+#else   /* 1 */
 	pr_debug("mmc: setting clock %lu Hz, block size %lu\n",
 		 hz, blklen);
+#endif  /* 1 */
 
 	if (clkdiv & ~255UL) {
 		clkdiv = 255;
@@ -84,10 +115,17 @@
 	}
 
 	blklen &= 0xfffc;
+
+#if     1   /* AT91SAM9261 does not have RDPROOF and WRPROOF fields. */
 	mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv)
+			 | MMCI_BF(BLKLEN, blklen)));
+#else   /* 1 */
+	mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv)
 			 | MMCI_BF(BLKLEN, blklen)
 			 | MMCI_BIT(RDPROOF)
 			 | MMCI_BIT(WRPROOF)));
+#endif  /* 1 */
+
 }
 
 #define RESP_NO_CRC	1
@@ -99,6 +137,7 @@
 #define NCR		MMCI_BF(MAXLAT, 1)
 #define TRCMD_START	MMCI_BF(TRCMD, 1)
 #define TRDIR_READ	MMCI_BF(TRDIR, 1)
+#define TRDIR_WRITE	MMCI_BF(TRDIR, 0)
 #define TRTYP_BLOCK	MMCI_BF(TRTYP, 0)
 #define INIT_CMD	MMCI_BF(SPCMD, 1)
 #define OPEN_DRAIN	MMCI_BF(OPDCMD, 1)
@@ -109,6 +148,20 @@
 			 | MMCI_BIT(RINDE)		\
 			 | MMCI_BIT(RTOE))
 
+#if     0
+#define DEBUG
+#else   /* 0 */
+#undef  DEBUG   /* kf - was #undef */
+#endif  /* 0 */
+
+#undef pr_debug
+
+#ifdef DEBUG
+#define pr_debug(fmt, args...) printf(fmt, ##args)
+#else
+#define pr_debug(...) do { } while(0)
+#endif
+
 static int
 mmc_cmd(unsigned long cmd, unsigned long arg,
 	void *resp, unsigned long flags)
@@ -117,7 +170,9 @@
 	int i, response_words = 0;
 	unsigned long error_flags;
 	u32 status;
-
+#if     1
+	pr_debug("mmc_cmd: entry\n");
+#endif  /* 1 */
 	AT91F_MMC_Hardware_Init();
 	
 	pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n",
@@ -161,12 +216,28 @@
 	return 0;
 }
 
+#if     0
+#define DEBUG
+#else   /* 0 */
+#undef  DEBUG   /* kf - was #undef */
+#endif  /* 0 */
+
+#undef pr_debug
+
+#ifdef DEBUG
+#define pr_debug(fmt, args...) printf(fmt, ##args)
+#else
+#define pr_debug(...) do { } while(0)
+#endif
+
 static int mmc_acmd(unsigned long cmd, unsigned long arg,
 		    void *resp, unsigned long flags)
 {
 	unsigned long aresp[4];
 	int ret;
 
+	pr_debug("mmc_acmd: entry\n");
+
 	/*
 	 * Seems like the APP_CMD part of an ACMD has 64 cycles max
 	 * latency even though the ACMD part doesn't. This isn't
@@ -184,7 +255,16 @@
 	return ret;
 }
 
-static unsigned long
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
+unsigned long
 mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
 	  unsigned long *buffer)
 {
@@ -193,7 +273,14 @@
 	unsigned long card_status, data;
 	unsigned long wordcount;
 	u32 status;
+	unsigned long *bufaddr;
 
+	pr_debug("mmc_bread: entry\n");
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n", ret,
card_status);
+
+	bufaddr = buffer;
+
 	if (blkcnt == 0)
 		return 0;
 
@@ -202,10 +289,16 @@
 
 	/* Put the device into Transfer state */
 	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n",
+		 ret, card_status);
 	if (ret) goto fail;
 
 	/* Set block length */
 	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n",
+		 ret, card_status);
 	if (ret) goto fail;
 
 	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
@@ -228,7 +321,6 @@
 
 			if (status & MMCI_BIT(RXRDY)) {
 				data = mmci_readl(RDR);
-				/* pr_debug("%x\n", data); */
 				*buffer++ = data;
 				wordcount++;
 			}
@@ -240,12 +332,68 @@
 			status = mmci_readl(SR);
 		} while (!(status & MMCI_BIT(BLKE)));
 
-		putc('.');
+		mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+			&card_status, R1 | NCR);
+		pr_debug("mmc: bread ret = %d, card status = %08x\n",
+			ret, card_status);
+
+		if (i % 0x800 == 0x7ff) {
+		        putc('.');  /* Display '.', after each MB
xfer'ed */ 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+               }
+
+#if     0
+		buffer = bufaddr;
+		wordcount = 0;
+		do {
+		        if (wordcount % 8 == 0) {
+			        pr_debug("\n%06lx:", 4 * wordcount);
+			}
+			pr_debug(" %08lx", *buffer++);
+			wordcount++;
+		} while (4 * wordcount < mmc_blkdev.blksz);
+		pr_debug("\n");
+#endif  /* 0 */
+
 	}
 
 out:
 	/* Put the device back into Standby state */
 	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("mmc: bread ret = %d, card status = %08x\n", ret,
card_status);
+	if (i >= 0x7ff) {
+	         putc('\n');
+	}
 	return i;
 
 fail:
@@ -254,8 +402,329 @@
 	goto out;
 }
 
+unsigned long
+mmc_bwrite(int dev, unsigned long start, lbaint_t blkcnt,
+	  unsigned long *buffer)
+{
+	int ret, i = 0;
+	unsigned long resp[4];
+	unsigned long card_status, data;
+	unsigned long wordcount;
+	u32 status;
+	unsigned long *bufaddr;
+
+	pr_debug("mmc_bwrite: entry\n");
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("en mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+
+	bufaddr = buffer;
+
+	if (blkcnt == 0)
+		return 0;
+
+	pr_debug("mmc_bwrite: dev %d, start %lx, blkcnt %lx\n",
+		 dev, start, blkcnt);
+
+	/* Put the device into Transfer state */
+	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("sc mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+
+	/* Set block length */
+	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("bl mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+
+	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
+
+	for (i = 0; i < blkcnt; i++, start++) {
+		ret = mmc_cmd(MMC_CMD_WRITE_BLOCK,
+			      start * mmc_blkdev.blksz, resp,
+			      (R1 | NCR | TRCMD_START | TRDIR_WRITE
+			       | TRTYP_BLOCK));
+		if (ret) goto fail;
+
+		ret = -EIO;
+		wordcount = 0;
+		do {
+			do {
+				status = mmci_readl(SR);
+				if (status & (ERROR_FLAGS |
MMCI_BIT(UNRE)))
+					goto fail;
+			} while (!(status & MMCI_BIT(TXRDY)));
+
+			if (status & MMCI_BIT(TXRDY)) {
+			        data = *buffer++;
+				mmci_writel(TDR, data);
+				wordcount++;
+			}
+		} while(wordcount < (mmc_blkdev.blksz / 4));
+
+		pr_debug("mmc: write %u words, waiting for BLKE\n",
wordcount);
+
+		do {
+			status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(BLKE)));
+
+		do {
+		        mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+				&card_status, R1 | NCR);
+			if ((card_status & 0x00000100) != 0x00000100) {
+#if     0
+			        printf("lp mmc: bwrite ret = %d, ",
ret);
+				printf("card status = %08x\n",
card_status);
+#endif  /* 0 */
+			} else {
+			        pr_debug("lp mmc: bwrite ret = %d, ",
ret);
+				pr_debug("card status = %08x\n",
card_status);
+			}
+		} while ((card_status & 0x00000100) != 0x00000100);
+
+		if (i % 0x800 == 0x7ff) {
+		         putc('.');  /* Display '.', after each MB
xfer'ed */ 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+		}
+
+#if     0
+		ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION,
+			      0, resp,
+			      R1 | NCR);
+		mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+			&card_status, R1 | NCR);
+		pr_debug("st mmc: bwrite ret = %d, card status =
%08x\n",
+			 ret, card_status);
+		if (ret) goto fail;
+#endif  /* 0 */
+
+	}
+
+out:
+#if     0
+	ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION,
+		      0, resp,
+		      R1 | NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("st mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+#endif  /* 0 */
+
+	/* Put the device back into Standby state */
+	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("dc mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (i >= 0x7ff) {
+	         putc('\n');
+	}
+	return i;
+
+fail:
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("fa mmc: bwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	goto out;
+}
+
+   /* Hangs - did not attempt to debug */
+/* MMC Multiple Block Write - mmc_mbwrite() */
+unsigned long
+mmc_mbwrite(int dev, unsigned long start, lbaint_t blkcnt,
+	  unsigned long *buffer)
+{
+	int ret, i = 0;
+	unsigned long resp[4];
+	unsigned long card_status, data;
+	unsigned long wordcount;
+	u32 status;
+	unsigned long *bufaddr;
+
+	pr_debug("mmc_bwrite: entry\n");
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("en mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+
+	bufaddr = buffer;
+
+	if (blkcnt == 0)
+		return 0;
+
+	if (blkcnt > 0xffff) {  /* Exceeds length supported by MoviNAND.
*/
+	        return -1;
+	}
+
+	pr_debug("mmc_mbwrite: dev %d, start %lx, blkcnt %lx\n",
+		 dev, start, blkcnt);
+
+	/* Put the device into Transfer state */
+	ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("sc mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (ret) goto fail;
+
+	/* Set block length */
+	ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 |
NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("bl mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (ret) goto fail;
+
+	pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
+
+	ret = mmc_cmd(MMC_CMD_SET_BLOCK_COUNT,
+		      blkcnt, resp,
+		      R1 | NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("bc mmc: mbwrite ret = %d, card status = %08x\n",
+		 ret, card_status);
+	if (ret) goto fail;
+
+	ret = mmc_cmd(MMC_CMD_WRITE_MULTIPLE_BLOCK,
+		      start * mmc_blkdev.blksz, resp,
+		      (R1 | NCR | TRCMD_START | TRDIR_WRITE |
TRTYP_BLOCK));
+	if (ret) goto fail;
+
+	for (i = 0; i < blkcnt; i++, start++) {
+
+		ret = -EIO;
+		wordcount = 0;
+		do {
+			do {
+				status = mmci_readl(SR);
+				if (status & (ERROR_FLAGS |
MMCI_BIT(UNRE)))
+					goto fail;
+			} while (!(status & MMCI_BIT(TXRDY)));
+
+			if (status & MMCI_BIT(TXRDY)) {
+			        data = *buffer++;
+				mmci_writel(TDR, data);
+				wordcount++;
+			}
+		} while(wordcount < (mmc_blkdev.blksz / 4));
+
+#if     1
+		pr_debug("mmc: write %u words, waiting for BLKE\n",
wordcount);
+
+		do {
+			status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(BLKE)));
+#endif  /* 0 */
+
+		do {
+		        mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16,
+				&card_status, R1 | NCR);
+			if ((card_status & 0x00000100) != 0x00000100) {
+#if     0
+			        printf("lp mmc: mbwrite ret = %d, ",
ret);
+				printf("card status = %08x\n",
card_status);
+#endif  /* 0 */
+			} else {
+			        pr_debug("lp mmc: mbwrite ret = %d, ",
ret);
+				pr_debug("card status = %08x\n",
card_status);
+			}
+		} while ((card_status & 0x00000100) != 0x00000100);
+
+		if (i % 0x800 == 0x7ff) {
+		         putc('.');  /* Display '.', after each MB
xfer'ed */ 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+		}
+	}
+
+out:
+#if     0
+	ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION,
+		      0, resp,
+		      R1 | NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("st mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (ret) goto fail;
+#endif  /* 0 */
+
+	/* Put the device back into Standby state */
+	mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("dc mmc: mbwrite ret = %d, card status = %08x\n",
+	       ret, card_status);
+	if (i >= 0x7ff) {
+	         putc('\n');
+	}
+	return i;
+
+fail:
+	mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 |
NCR);
+	pr_debug("fa mmc: mbwrite failed, card status = %08x\n",
card_status);
+	goto out;
+}
+
 static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp)
 {
+	pr_debug("mmc_parse_cid: entry\n");
+
 	cid->mid = resp[0] >> 24;
 	cid->oid = (resp[0] >> 8) & 0xffff;
 	cid->pnm[0] = resp[0];
@@ -272,6 +741,8 @@
 
 static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp)
 {
+	pr_debug("sd_parse_cid: entry\n");
+
 	cid->mid = resp[0] >> 24;
 	cid->oid = (resp[0] >> 8) & 0xffff;
 	cid->pnm[0] = resp[0];
@@ -288,6 +759,8 @@
 
 static void mmc_dump_cid(const struct mmc_cid *cid)
 {
+	pr_debug("mmc_dump_cid: entry\n");
+
 	printf("Manufacturer ID:       %02lX\n", cid->mid);
 	printf("OEM/Application ID:    %04lX\n", cid->oid);
 	printf("Product name:          %s\n", cid->pnm);
@@ -301,6 +774,9 @@
 static void mmc_dump_csd(const struct mmc_csd *csd)
 {
 	unsigned long *csd_raw = (unsigned long *)csd;
+
+	pr_debug("mmc_dump_csd: entry\n");
+
 	pr_debug("CSD data: %08lx %08lx %08lx %08lx\n",
 	       csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]);
 	pr_debug("CSD structure version:   1.%u\n", csd->csd_structure);
@@ -337,6 +813,8 @@
 {
 	int ret;
 
+	pr_debug("mmc_idle_cards: entry\n");
+
 	/* Reset and initialize all cards */
 	ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0);
 	
@@ -352,6 +830,8 @@
 	unsigned long resp[4];
 	int i, ret = 0;
 
+	pr_debug("sd_init_card: entry\n");
+
 	mmc_idle_cards();
 	for (i = 0; i < 1000; i++) {
 		ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND,
CFG_MMC_OP_COND,
@@ -387,10 +867,40 @@
 {
 	unsigned long resp[4];
 	int i, ret = 0;
+	u32 status;
 
+	pr_debug("mmc_init_card: entry\n");
+
 	mmc_idle_cards();
 
+	/* MoviNAND initialization */
 	for (i = 0; i < 1000; i++) {
+	        mmci_writel(ARGR, 0xFFFFFFFF);
+		mmci_writel(CMDR, 0x0018113F);
+		do {
+		        status = mmci_readl(SR);
+		} while (!(status & MMCI_BIT(CMDRDY)));
+	}
+        /* Getting the OCR value seems to prevent marginal chips from
*/
+        /* working@all, whereas they would work fine after waiting
*/
+        /* a full minute or more with the power off prior to booting.
*/
+        /* Our marginal chips have date codes 0716 and 0728.
*/
+#if     0   
+	for (i = 0; i < 1000; i++) {
+	  /* Request OCR value to determine chip's supported volt. */
+		ret = mmc_cmd(MMC_CMD_SEND_OP_COND, 0, resp,
+			      R3 | NID | OPEN_DRAIN);
+		if (ret || (resp[0] & 0x80000000))
+		{
+			break;
+		}
+		ret = -ETIMEDOUT;
+	}
+	if (ret) {
+		return ret;
+	}
+#endif  /* 0 */
+	for (i = 0; i < 1000; i++) {
 		ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND,
resp,
 			      R3 | NID | OPEN_DRAIN);
 		if (ret || (resp[0] & 0x80000000))
@@ -399,13 +909,35 @@
 		}
 		ret = -ETIMEDOUT;
 	}
+        pr_debug("Step 4: ret = 0x%lx\n", ret);
+	pr_debug("MMC_CMD_SEND_OP_COND = 0x%lx\n",
MMC_CMD_SEND_OP_COND);
+        pr_debug("CFG_MMC_OP_COND = 0x%lx\n", CFG_MMC_OP_COND);
+        pr_debug("resp[0] = 0x%lx\n", resp[0]);
+        pr_debug("resp[1] = 0x%lx\n", resp[1]);
+        pr_debug("resp[2] = 0x%lx\n", resp[2]);
+        pr_debug("resp[3] = 0x%lx\n", resp[3]);
+        pr_debug("R3 = 0x%lx\n", R3);
+        pr_debug("NID = 0x%lx\n", NID);
+        pr_debug("OPEN_DRAIN = 0x%lx\n", OPEN_DRAIN);
+
 	pr_debug("4\n");
 	pr_debug("ret : %i\n",ret);
+
+	pr_debug("MCI_MR = 0x%08lx\n", mmci_readl(MR));
+	pr_debug("MCI_DTOR = 0x%08lx\n", mmci_readl(DTOR));
+	pr_debug("MCI_SDCR = 0x%08lx\n", mmci_readl(SDCR));
+	pr_debug("MCI_ARGR = 0x%08lx\n", mmci_readl(ARGR));
+	/* RSPR */
+	/* RDR */
+	pr_debug("MCI_SR = 0x%08lx\n", mmci_readl(SR));
+	pr_debug("MCI_IMR = 0x%08lx\n", mmci_readl(IMR));
+
 	if (ret)
 		return ret;
 	pr_debug("5\n");
 	/* Get CID of all cards. FIXME: Support more than one card */
 	ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID |
OPEN_DRAIN);
+	pr_debug("ALL_SEND_CID ret: 0x%08lx\n", ret);
 	if (ret)
 		return ret;
 	mmc_parse_cid(cid, resp);
@@ -415,6 +947,7 @@
 	/* Set Relative Address of the card that responded */
 	ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp,
 		      R1 | NCR | OPEN_DRAIN);
+	pr_debug("SET_RELATIVE_ADDR ret: 0x%08lx\n", ret);
 	return ret;
 }
 
@@ -471,23 +1004,42 @@
 	       dtocyc << shift, dtor);
 }
 
+#define DEFAULT_SECTOR_SIZE 512
+
 int mmc_init(int verbose)
 {
 	struct mmc_cid cid;
 	struct mmc_csd csd;
 	unsigned int max_blksz;
 	int ret,aux;
+	unsigned char buffer[DEFAULT_SECTOR_SIZE];
 	
+	pr_debug("mmc_init: entry\n");
+	pr_debug("mmc_init: verbose = 0x%08lx\n", verbose);
+
 	AT91F_MMC_Hardware_Init();
 	
 	pr_debug("0\n");
 	/* Initialize controller */
 	mmci_writel(CR, MMCI_BIT(SWRST));
 	mmci_writel(CR, MMCI_BIT(MCIEN));
+
+	pr_debug("MCI_MR = 0x%08lx\n", mmci_readl(MR));
+	pr_debug("MCI_DTOR = 0x%08lx\n", mmci_readl(DTOR));
+	pr_debug("MCI_SDCR = 0x%08lx\n", mmci_readl(SDCR));
+	pr_debug("MCI_ARGR = 0x%08lx\n", mmci_readl(ARGR));
+	/* RSPR */
+	/* RDR */
+	pr_debug("MCI_SR = 0x%08lx\n", mmci_readl(SR));
+	pr_debug("MCI_IMR = 0x%08lx\n", mmci_readl(IMR));
+
 	mmci_writel(DTOR, 0x5f);
 	mmci_writel(IDR, ~0UL);
 	mmci_writel(SDCR, 0x1);
 	mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+#if     0
+	mmci_writel(MR, 0x02009B4A);
+#endif  /* 0 */
 /* 	//mmci_writel(CR, MMCI_BIT(SWRST));
 	mmci_writel(CR, 0x00000001);
 	mmci_writel(DTOR, 0x0000007F);
@@ -502,6 +1054,7 @@
 
 	ret = sd_init_card(&cid, verbose);
 	if (ret) {
+	  	pr_debug("Not SDCard, try MMC\n");
 		mmc_rca = MMC_DEFAULT_RCA;
 		ret = mmc_init_card(&cid, verbose);
 	}
@@ -545,6 +1098,20 @@
 	mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz);
 
 #if 0
+	mmc_bread(mmc_blkdev.dev, 1024, 1, (ulong *)buffer);
+        buffer[0] = 0x00; buffer[1] = 0x11;
+        buffer[2] = 0x22; buffer[3] = 0x33;
+        buffer[4] = 0x44; buffer[5] = 0x55;
+        buffer[6] = 0x66; buffer[7] = 0x77;
+        buffer[504] = 0x88; buffer[505] = 0x99;
+        buffer[506] = 0xaa; buffer[507] = 0xbb;
+        buffer[508] = 0xcc; buffer[509] = 0xdd;
+        buffer[510] = 0xee; buffer[511] = 0xff;
+	mmc_bwrite(mmc_blkdev.dev, 1024, 1, (ulong *)buffer); 
+	mmc_bread(mmc_blkdev.dev, 1024, 1, (ulong *)buffer);
+#endif  /* 0 */
+
+#if 0
 	if (fat_register_device(&mmc_blkdev, 1))
 		pr_debug("Could not register MMC fat device\n");
 #else
@@ -556,16 +1123,22 @@
 
 int mmc_read(ulong src, uchar *dst, int size)
 {
+	pr_debug("mmc_read: entry\n");
+
 	return -ENOSYS;
 }
 
 int mmc_write(uchar *src, ulong dst, int size)
 {
+	pr_debug("mmc_write: entry\n");
+
 	return -ENOSYS;
 }
 
 int mmc2info(ulong addr)
 {
+	pr_debug("mmc2info: entry\n");
+
 	return 0;
 }
 
svn diff -r21 include/asm-arm/arch-at91sam926x/mmc.h
Index: include/asm-arm/arch-at91sam926x/mmc.h
===================================================================
--- include/asm-arm/arch-at91sam926x/mmc.h	(revision 0)
+++ include/asm-arm/arch-at91sam926x/mmc.h	(revision 50)
@@ -0,0 +1,103 @@
+/*
+ * (C) Copyright 2007
+ * Benchmark Electronics, Inc.
+ * Added MMC v4.x (MoviNAND) support
+ *
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __ASM_AT91SAM926X_MMC_H
+#define __ASM_AT91SAM926X_MMC_H
+
+struct mmc_cid {
+	unsigned long psn;
+	unsigned short oid;
+	unsigned char mid;
+	unsigned char prv;
+	unsigned char mdt;
+	char pnm[7];
+};
+
+struct mmc_csd
+{
+	u8	csd_structure:2,
+		spec_vers:4,
+		rsvd1:2;
+	u8	taac;
+	u8	nsac;
+	u8	tran_speed;
+	u16	ccc:12,
+		read_bl_len:4;
+	u64	read_bl_partial:1,
+		write_blk_misalign:1,
+		read_blk_misalign:1,
+		dsr_imp:1,
+		rsvd2:2,
+		c_size:12,
+		vdd_r_curr_min:3,
+		vdd_r_curr_max:3,
+		vdd_w_curr_min:3,
+		vdd_w_curr_max:3,
+		c_size_mult:3,
+		sector_size:5,
+		erase_grp_size:5,
+		wp_grp_size:5,
+		wp_grp_enable:1,
+		default_ecc:2,
+		r2w_factor:3,
+		write_bl_len:4,
+		write_bl_partial:1,
+		rsvd3:5;
+	u8	file_format_grp:1,
+		copy:1,
+		perm_write_protect:1,
+		tmp_write_protect:1,
+		file_format:2,
+		ecc:2;
+	u8	crc:7;
+	u8	one:1;
+};
+
+/* MMC Command numbers */
+#define MMC_CMD_GO_IDLE_STATE		0
+#define MMC_CMD_SEND_OP_COND		1
+#define MMC_CMD_ALL_SEND_CID 		2
+#define MMC_CMD_SET_RELATIVE_ADDR	3
+#define MMC_CMD_SD_SEND_RELATIVE_ADDR	3
+#define MMC_CMD_SET_DSR			4
+#define MMC_CMD_SELECT_CARD		7
+#define MMC_CMD_SEND_CSD 		9
+#define MMC_CMD_SEND_CID 		10
+#define MMC_CMD_STOP_TRANSMISSION	12
+#define MMC_CMD_SEND_STATUS		13
+#define MMC_CMD_SET_BLOCKLEN		16
+#define MMC_CMD_READ_SINGLE_BLOCK	17
+#define MMC_CMD_READ_MULTIPLE_BLOCK	18
+#define MMC_CMD_SET_BLOCK_COUNT		23
+#define MMC_CMD_WRITE_BLOCK		24
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK	25
+#define MMC_CMD_APP_CMD			55
+
+#define MMC_ACMD_SD_SEND_OP_COND	41
+
+#define R1_ILLEGAL_COMMAND		(1 << 22)
+#define R1_APP_CMD			(1 << 5)
+
+#endif /* __ASM_AT91SAM926X_MMC_H */

svn diff -r21 include/configs/at91sam9261ek.h
Index: include/configs/at91sam9261ek.h
===================================================================
--- include/configs/at91sam9261ek.h	(revision 21)
+++ include/configs/at91sam9261ek.h	(working copy)
@@ -1,4 +1,8 @@
 /*
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Added MMC v4.x (MoviNAND) support
+ *
  * (C) Copyright 2005
  * M. Amine SAYA ATMEL Rousset, France.
  *
@@ -95,18 +99,24 @@
 /* SPI */
 #define CONFIG_SPI
 
+/* kf - define hush (from busy box) command line interface & options */
+#define CFG_HUSH_PARSER
+#define CFG_PROMPT_HUSH_PS2     "> "
+#define CFG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
 #define CONFIG_COMMANDS		\
 		       ((CONFIG_CMD_DFL	| \
                         CFG_CMD_NET | \
                         CFG_CMD_ENV | \
                         CFG_CMD_USB | \
                         CFG_CMD_FLASH | \
-			CFG_CMD_NAND | \
+                        CFG_CMD_MMC | \
+                        CFG_CMD_EXT2 | \
+                        CFG_CMD_FAT | \
 			CFG_CMD_AUTOSCRIPT | \
-                        CFG_CMD_FAT | \
                         CFG_CMD_NFS | \
                         CFG_CMD_SPI | \
-                        CFG_CMD_U | \
 			CFG_CMD_IMI | \
                         CFG_CMD_PING ) & \
 		      ~(CFG_CMD_BDI | \
@@ -296,8 +306,12 @@
 #define CFG_FLASH_ERASE_TOUT		(2*CFG_HZ) /* Timeout for Flash
Erase */
 #define CFG_FLASH_WRITE_TOUT		(2*CFG_HZ) /* Timeout for Flash
Write */
 
+#undef  CFG_ENV_IS_IN_FLASH
 #define	CFG_ENV_IS_IN_DATAFLASH         1
-#undef  CFG_ENV_IS_IN_FLASH
+#if     0
+#undef  CFG_ENV_IS_IN_NAND
+#endif  /* 0 - kf */
+#undef  CFG_ENV_IS_NOWHERE
 
 #ifdef CFG_ENV_IS_IN_DATAFLASH
 #define CFG_ENV_OFFSET			0x4000
@@ -305,6 +319,10 @@
 #define CFG_ENV_SIZE			0x4000  /* 0x8000 */
 #endif
 
+#ifdef CFG_ENV_IS_NOWHERE
+#define CFG_ENV_SIZE			0x4000
+#endif
+
 #ifdef CFG_ENV_IS_IN_FLASH
 #ifdef CONFIG_BOOTBINFUNC
 #define CFG_ENV_ADDR			(PHYS_FLASH_1 + 0x60000)  /*
after u-boot.bin */
@@ -316,6 +334,9 @@
 #endif
 
 /* Add LCD stuff */
+/* Ignore */
+/* Ignore */
+
 #if 0  /* No LCD */
 #define  CONFIG_LCD
 /* #undef  CONFIG_LCD_LOGO */
@@ -333,8 +354,21 @@
 #define CONFIG_DOS_PARTITION	        1
 #define LITTLEENDIAN 			1
 
-#define CFG_LOAD_ADDR		0x23f00000  /* default load address */
+/* Add FAT filesystem configuration, other than CFG_CMD_FAT */
+#define CONFIG_SUPPORT_VFAT
 
+/* MMC */
+#define CONFIG_MMC		1
+#define MMCI_BASE		0xFFFA8000  /* (void *)AT91C_BASE_MCI */
+/* MMC - kf - slow down speed for debug from 20000000 Hz down to ...
*/
+/* However, tweaking this value here causes all code to be compiled,
*/
+/* so we shall change the value only where needed - in atmel_mci.c.
*/
+#define CFG_MMC_CLK_PP          20000000
+
+#define CFG_LOAD_ADDR		0x23f00000  /* default load address   */
+
+#define CFG_BOOTM_LEN           0x02100000  /* 33MB uncompressed max.
*/
+
 #ifdef CONFIG_BOOTBINFUNC
 #define CFG_BOOT_SIZE		0x00 /* 0 KBytes */
 #define CFG_U_BOOT_BASE		PHYS_FLASH_1

svn diff -r21 board/at91sam9261ek/at91sam9261ek.c
Index: board/at91sam9261ek/at91sam9261ek.c
===================================================================
--- board/at91sam9261ek/at91sam9261ek.c	(revision 21)
+++ board/at91sam9261ek/at91sam9261ek.c	(working copy)
@@ -1,4 +1,8 @@
 /*
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Added specific AT91SAM9261 board support
+ *
  * (C) Copyright 2005
  * M. Amine SAYA ATMEL Rousset, France.
  * Added AT91SAM9261EK support.
@@ -28,12 +32,19 @@
 
 #include <common.h>
 #include <asm/arch/hardware.h>
+#include <asm/arch-at91sam926x/at91sam9261.h>
 
 #include <net.h>
 
 extern void AT91F_Spi1Init (void);
 extern void gpio_init(void);
 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
 /*
------------------------------------------------------------------------
- */
 /*
  * Miscelaneous platform dependent initialisations
@@ -107,7 +118,8 @@
   *AT91C_PMC_PCER |= 1 << AT91C_ID_US0;	/* enable clock */
 #endif
   
-#ifdef CONFIG_USART1
+#if     1
+  /* #ifdef CONFIG_USART1 */
   *AT91C_PIOB_PDR = AT91C_PC12_TXD1 | AT91C_PC13_RXD1;
   *AT91C_PMC_PCER |= 1 << AT91C_ID_US1;	/* enable clock */
 #endif
@@ -118,6 +130,41 @@
 #endif
 }
 
+#ifdef CONFIG_MMC
+#if (CONFIG_COMMANDS & CFG_CMD_MMC)
+int AT91F_MMC_Hardware_Init(void)
+{
+#if     0
+	printf("AT91F_MMC_Hardware_Init: entry\n");
+#endif  /* 0 */
+
+        AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,
+			    0,                   /*  <- Peripheral A */
+			    (AT91C_PA0_MCDA0 |    /*  MMC NAND MCDA0  */
+			     AT91C_PA1_MCCDA |    /*  MMC NAND MCCDA  */
+			     AT91C_PA2_MCCK  |    /*  MMC NAND MCCK   */
+			     AT91C_PA4_MCDA1 |    /*  MMC NAND MCDA1  */
+			     AT91C_PA5_MCDA2 |    /*  MMC NAND MCDA2  */
+			     AT91C_PA6_MCDA3 |    /*  MMC NAND MCDA3  */
+			     0));                 /*  <- Peripheral B */
+
+#if     1
+	/* Pull up disable register */
+	AT91C_BASE_PIOA->PIO_PPUDR |=
+	        AT91C_PA0_MCDA0 |    /*  MMC NAND MCDA0  */
+	        AT91C_PA1_MCCDA |    /*  MMC NAND MCCDA  */
+	        AT91C_PA2_MCCK  |    /*  MMC NAND MCCK   */
+	        AT91C_PA4_MCDA1 |    /*  MMC NAND MCDA1  */
+	        AT91C_PA5_MCDA2 |    /*  MMC NAND MCDA2  */
+	        AT91C_PA6_MCDA3;     /*  MMC NAND MCDA3  */
+#endif  /* 0 */
+
+	AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_MCI);
+}
+#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */
+#endif /* CONFIG_MMC */
+
+
 int dram_init (void)
 {
   DECLARE_GLOBAL_DATA_PTR;
@@ -148,5 +195,35 @@
 
   gpio_init();
 
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+/* Ignore */
+
   return 0;
 }

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao
ne
_______________________________________________
U-Boot-Users mailing list
U-Boot-Users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/u-boot-users

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
       [not found]                               ` <alpine.DEB.1.10.0804300949360.13610@pmy.adscville>
@ 2008-04-30 14:43                                 ` Jerry Van Baren
  2008-04-30 15:11                                   ` Joakim Tjernlund
  2008-04-30 15:38                                   ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Wolfgang Denk
  0 siblings, 2 replies; 39+ messages in thread
From: Jerry Van Baren @ 2008-04-30 14:43 UTC (permalink / raw)
  To: u-boot

Adrian Filipi wrote:
> On Tue, 29 Apr 2008, Jerry Van Baren wrote:
> 
>> Adrian Filipi wrote:
>>> On Tue, 29 Apr 2008, Wolfgang Denk wrote:
>>>
>>>> In message <alpine.DEB.1.10.0804291604250.32753@pmy.adscville> you 
>>>> wrote:
>>>>>      I narrowed down the source of the problem to the loss of the
>>>>> volatile qualifier on the addr pointer in flash_write_cmd().  
>>>>> Adding the
>>>>> qualifier gets rid of the corruption.  In the older 1.2.0 sources, 
>>>>> addr was
>>>>> declared as "volatile cfiptr_t addr;".
>>>> The volatile should not be needed - the CFI driver should use correct
>>>> accessor macros instead. See
>>>> Documentation/volatile-considered-harmful.txt in your Linux kernel
>>>> source tree...
>>>>
>>>> Best regards,
>>>>
>>>> Wolfgang Denk
>>>
>>>      Sure, reducing the reliance on volatile is a good idea, but I'm 
>>> at a loss for anything better to do.
>>>
>>>      I'm seeing a real problem that is only fixed by qualifying the 
>>> container of the pointer as volatile, i.e. "void *volatile".  
>>> "volatile void *" has no effect as expected given that the read/write 
>>> accessors are used now.
>>>
>>>      The old data type was essentially "volatile void *volatile addr" 
>>> and the new type is simply "void *addr".  I seem to need at least 
>>> "void *volatile addr" for things to work.
>>>
>>>      Note, I'm only seeing this problem on our PXA250 boards.
>>>
>>>      Adrian
>>
>> Hi Adrian,
>>
>> Please bottom post.
>>
>> It may be useful to disassemble cfi_flash.o file (objdump -S) and see 
>> what the two different configurations of flash_write_cmd() get turned 
>> into in assembly.
>>
>> Best regards,
>> gvb
>>
> 
>     I've attached the assembler output as well as the diff to the 
> version with volatile added.  I don't see anything incriminating.
> Instead of using a register, the variable is read from its location on 
> the stack.
> 
>     I'm having a hard time seeing how flash could get corrupted by this 
> code.  It's happening during initialization.
> 
>     Adrian

I'm not an ARMexpert, but if that were a PowerPC CPU, I would *strongly* 
suspect that the bus interface unit is rearranging the bus operations 
going to memory (e.g. moving a read ahead of a write or re-ordering the 
writes).  The result is that the write command/data sequence to the 
flash gets buggered by the re-ordering.

Per my theory, by putting in the "volatile", you force extra reads on 
the bus which forces the bus interface unit to flush out the flash write 
sequence in the right order.  The fix is totally unrelated the the 
problem, other than as an unrecognized side effect it "fixes" the problem.

The solution in the PowerPC world is to add a "eieio" or "sync" 
instruction[1] appropriately[2], which prevents the bus interface unit 
from reordering the memory operations.

Your task is to dig into the PXA250 manual to (a) figure out what syncs 
you need and (b) figure out why the bus interface is doing you in. 
Alternatively, (c) show that I don't know what I'm talking about. 
Obviously, (a) gets you the best results, so lets root for that. ;-)

HTH,
gvb

[1] Sync is a big hammer, eieio is a medium size hammer.  Don't use 
both, PPC people will know you don't know what you are doing.  ;-)

[2] The flash command sequence order is critical (e.g. the 55s and AAs). 
  The actual data sequence is not critical.  The observed problem is in 
flash_write_cmd() that is writing the command sequence.  Hmmmmm.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-30 14:43                                 ` Jerry Van Baren
@ 2008-04-30 15:11                                   ` Joakim Tjernlund
  2008-04-30 15:21                                     ` Scott Wood
  2008-04-30 15:35                                     ` [U-Boot-Users] PPC sync/eieio (was cfi_flash.c and lost volatile qualifier) Jerry Van Baren
  2008-04-30 15:38                                   ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Wolfgang Denk
  1 sibling, 2 replies; 39+ messages in thread
From: Joakim Tjernlund @ 2008-04-30 15:11 UTC (permalink / raw)
  To: u-boot


> 
> [1] Sync is a big hammer, eieio is a medium size hammer.  Don't use 
> both, PPC people will know you don't know what you are doing.  ;-)

Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all
SOC drivers are encouraged to use them. What a waste :(

 Jocke

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-30 15:11                                   ` Joakim Tjernlund
@ 2008-04-30 15:21                                     ` Scott Wood
  2008-04-30 15:34                                       ` Joakim Tjernlund
  2008-04-30 15:35                                     ` [U-Boot-Users] PPC sync/eieio (was cfi_flash.c and lost volatile qualifier) Jerry Van Baren
  1 sibling, 1 reply; 39+ messages in thread
From: Scott Wood @ 2008-04-30 15:21 UTC (permalink / raw)
  To: u-boot

On Wed, Apr 30, 2008 at 05:11:09PM +0200, Joakim Tjernlund wrote:
> Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all
> SOC drivers are encouraged to use them. What a waste :(

sync is needed in some of the cases, to sync I/O accesses with DMA buffer
accesses.  Ideally, we could trust the driver writers to put
synchronization in where needed, but it seems Linux has too much x86
heritage for that.

There should at least be raw alternatives, though...

-Scott

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-30 15:21                                     ` Scott Wood
@ 2008-04-30 15:34                                       ` Joakim Tjernlund
  2008-04-30 15:41                                         ` Wolfgang Denk
  2008-04-30 16:02                                         ` Scott Wood
  0 siblings, 2 replies; 39+ messages in thread
From: Joakim Tjernlund @ 2008-04-30 15:34 UTC (permalink / raw)
  To: u-boot


On Wed, 2008-04-30 at 10:21 -0500, Scott Wood wrote:
> On Wed, Apr 30, 2008 at 05:11:09PM +0200, Joakim Tjernlund wrote:
> > Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all
> > SOC drivers are encouraged to use them. What a waste :(
> 
> sync is needed in some of the cases, to sync I/O accesses with DMA buffer
> accesses.  Ideally, we could trust the driver writers to put
> synchronization in where needed, but it seems Linux has too much x86
> heritage for that.

Perhaps, is sync needed in this case for non-smp too? or is eieio
enough?
Anyway, just have a look at ucc_geth and you will see that
most such accesses are just about getting the endian right.

> 
> There should at least be raw alternatives, though...

There need be a get-the-endian-right-but-no-sync. After all
2.4 managed well without using the in/out be() functions.

 Jocke
> 
> -Scott
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] PPC sync/eieio (was cfi_flash.c and lost volatile qualifier)
  2008-04-30 15:11                                   ` Joakim Tjernlund
  2008-04-30 15:21                                     ` Scott Wood
@ 2008-04-30 15:35                                     ` Jerry Van Baren
  1 sibling, 0 replies; 39+ messages in thread
From: Jerry Van Baren @ 2008-04-30 15:35 UTC (permalink / raw)
  To: u-boot

Joakim Tjernlund wrote:
>> [1] Sync is a big hammer, eieio is a medium size hammer.  Don't use 
>> both, PPC people will know you don't know what you are doing.  ;-)
> 
> Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all
> SOC drivers are encouraged to use them. What a waste :(
> 
>  Jocke

Well, I was a little terse because I was cross-applying PPC instructions 
in a ARM discussion.  Personally, I prefer to use sync vs. eieio.  The 
size of the hammer isn't that different, I don't believe.  The advantage 
of sync is that it flushes the read/write operation out on the bus 
*now*.  When I'm writing to hardware to control the hardware, *now* is 
what I want.

The eieio merely guarantees the preceding operations will go out on the 
bus before following bus operations.  The preceding operations could be 
hung up in the bus interface unit *indefinitely* if no "following" bus 
operations occur.  This is an unlikely occurrence, but could be the 
result of running out of cache in a tight loop.

For instance, if you do a write to a hardware register, a eieio, and 
then wait in a tight loop until time goes by (reading the decrementer 
register) followed by another write, the write1/delay/write2 sequence 
could actually be delay/write1/write2.  Note that the order of the 
writes on the bus is correct per the eieio, but it isn't what the 
hardware *needed*.

Illustration - what you did in code and intended to occur:
   write1 (eieio)
   delay
   write2 (eieio)

What actually may happen on the bus:
   delay
   write1 (eieio)
   write2 (eieio)

By using a sync, you guarantee the write isn't delayed:
   write1 (sync)
   delay
   write2 (sync)

Disclaimer: the above explanation is from my fertile imagination.  It 
may or may not happen and *will* happen differently on different PPC 
processors.  For instance, the eieio instruction is actually a NOP in 
the 603e core because it doesn't reorder bus operations, but it *does* 
have a BIU that can buffer and delay the bus operations, causing the 
above timing problem.

I contend using the "sync" instruction will always work correctly and 
the "eieio" instruction is at best a false economy and at worst a lot of 
very difficult, mysterious bugs to find, so I'm in agreement with the 
linux in_bex/out_bex recommendation.

Side note: I don't know if I communicated it properly, but when you see 
"eieio ; sync" or "sync ; eieio", you know the author of that code 
doesn't understand sync and eieio.  "isync ; sync" is occasionally a 
valid combination, but I don't believe it is necessary other than when 
called for by the Users Manual in conjunction with writing to special 
purpose registers.

Best regards,
gvb

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-30 14:43                                 ` Jerry Van Baren
  2008-04-30 15:11                                   ` Joakim Tjernlund
@ 2008-04-30 15:38                                   ` Wolfgang Denk
  2008-04-30 15:51                                     ` Jerry Van Baren
  1 sibling, 1 reply; 39+ messages in thread
From: Wolfgang Denk @ 2008-04-30 15:38 UTC (permalink / raw)
  To: u-boot

In message <48188584.3060109@ge.com> you wrote:
>
> The solution in the PowerPC world is to add a "eieio" or "sync" 
> instruction[1] appropriately[2], which prevents the bus interface unit 
> from reordering the memory operations.

No, the solution for ALL architectures  is  to  use  the  appropriate
accessor  macros which take care of such things (and probably contain
calls like sync or similar).

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Unix: Some say the learning curve is steep,  but  you  only  have  to
climb it once.                                      - Karl Lehenbauer

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-30 15:34                                       ` Joakim Tjernlund
@ 2008-04-30 15:41                                         ` Wolfgang Denk
  2008-04-30 16:02                                         ` Scott Wood
  1 sibling, 0 replies; 39+ messages in thread
From: Wolfgang Denk @ 2008-04-30 15:41 UTC (permalink / raw)
  To: u-boot

In message <1209569696.16926.53.camel@gentoo-jocke.transmode.se> you wrote:
> 
> There need be a get-the-endian-right-but-no-sync. After all
> 2.4 managed well without using the in/out be() functions.

Yes, but try building it with a recent version of  GCC  and  run  the
code  on  some  PPC  systems.  There  may  be some nasty surprises. I
remember that we had to fix a couple of drivers  in  our  old  2.4.25
kernel.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
As a general rule, the freedom of any people can  be  judged  by  the
volume of their laughter.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-30 15:38                                   ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Wolfgang Denk
@ 2008-04-30 15:51                                     ` Jerry Van Baren
  0 siblings, 0 replies; 39+ messages in thread
From: Jerry Van Baren @ 2008-04-30 15:51 UTC (permalink / raw)
  To: u-boot

Wolfgang Denk wrote:
> In message <48188584.3060109@ge.com> you wrote:
>> The solution in the PowerPC world is to add a "eieio" or "sync" 
>> instruction[1] appropriately[2], which prevents the bus interface unit 
>> from reordering the memory operations.
> 
> No, the solution for ALL architectures  is  to  use  the  appropriate
> accessor  macros which take care of such things (and probably contain
> calls like sync or similar).
> 
> Best regards,
> 
> Wolfgang Denk

Agreed.

If my theory is correct, Adrian has turned up a problem with the ARM 
configuration that apparently only shows up for the PXA250.  Or I'm 
blowing smoke - nothing to see, move along.

The hairs on the back of my neck say it is a sync/bus interface unit 
problem.

I don't know if it is significant, not being very intimately familiar 
with ARM (and, in particular, the PXA250), but my quick grep turns up 
./include/asm-arm/io.h and a quick browsing shows no syncs.  The hairs 
on the back of my neck are starting to ache.  ;-)

static inline void sync(void)
{
}

#define __arch_getb(a)                  (*(volatile unsigned char *)(a))

gvb

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-30 15:34                                       ` Joakim Tjernlund
  2008-04-30 15:41                                         ` Wolfgang Denk
@ 2008-04-30 16:02                                         ` Scott Wood
  2008-04-30 16:11                                           ` Joakim Tjernlund
  1 sibling, 1 reply; 39+ messages in thread
From: Scott Wood @ 2008-04-30 16:02 UTC (permalink / raw)
  To: u-boot

On Wed, Apr 30, 2008 at 05:34:56PM +0200, Joakim Tjernlund wrote:
> 
> On Wed, 2008-04-30 at 10:21 -0500, Scott Wood wrote:
> > On Wed, Apr 30, 2008 at 05:11:09PM +0200, Joakim Tjernlund wrote:
> > > Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all
> > > SOC drivers are encouraged to use them. What a waste :(
> > 
> > sync is needed in some of the cases, to sync I/O accesses with DMA buffer
> > accesses.  Ideally, we could trust the driver writers to put
> > synchronization in where needed, but it seems Linux has too much x86
> > heritage for that.
> 
> Perhaps, is sync needed in this case for non-smp too? or is eieio
> enough?

Yes, sync is needed -- eieio doesn't order between stores to cacheable
memory and stores to cache-inhibited memory.

> Anyway, just have a look at ucc_geth 

Do I have to? :-)

> and you will see that most such accesses are just about getting the
> endian right.

If you mean the descriptor accesses, ordering is relevant there as well.

> > There should at least be raw alternatives, though...
> 
> There need be a get-the-endian-right-but-no-sync.

Agreed.  There's cpu_to_be32, etc., but that doesn't fit well with
load/store endian-swapping instructions.

> After all 2.4 managed well without using the in/out be() functions.

I see in/out_be32() in 2.4...  and the significant chunks of code that
use volatile pointers instead, I wouldn't consider to be managing "well";
they just happen to work most of the time.

-Scott

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-30 16:02                                         ` Scott Wood
@ 2008-04-30 16:11                                           ` Joakim Tjernlund
  0 siblings, 0 replies; 39+ messages in thread
From: Joakim Tjernlund @ 2008-04-30 16:11 UTC (permalink / raw)
  To: u-boot


On Wed, 2008-04-30 at 11:02 -0500, Scott Wood wrote:
> On Wed, Apr 30, 2008 at 05:34:56PM +0200, Joakim Tjernlund wrote:
> > 
> > On Wed, 2008-04-30 at 10:21 -0500, Scott Wood wrote:
> > > On Wed, Apr 30, 2008 at 05:11:09PM +0200, Joakim Tjernlund wrote:
> > > > Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all
> > > > SOC drivers are encouraged to use them. What a waste :(
> > > 
> > > sync is needed in some of the cases, to sync I/O accesses with DMA buffer
> > > accesses.  Ideally, we could trust the driver writers to put
> > > synchronization in where needed, but it seems Linux has too much x86
> > > heritage for that.
> > 
> > Perhaps, is sync needed in this case for non-smp too? or is eieio
> > enough?
> 
> Yes, sync is needed -- eieio doesn't order between stores to cacheable
> memory and stores to cache-inhibited memory.

OK, thanks

> 
> > Anyway, just have a look at ucc_geth 
> 
> Do I have to? :-)

Yes, it needs a little love here and there :)
Especially Timur, his little "rename the tx/rx clock" trick
costed me a few days :)

 Jocke

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-30 14:20                       ` [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary
@ 2008-04-30 16:25                         ` Ken.Fuchs at bench.com
  2008-04-30 20:31                         ` Ken.Fuchs at bench.com
  1 sibling, 0 replies; 39+ messages in thread
From: Ken.Fuchs at bench.com @ 2008-04-30 16:25 UTC (permalink / raw)
  To: u-boot

Pierre Savary wrote:

> Thanks a lot for your patch. I will test it next week.

Sorry, that patch was manually constructed.  I forgot about 
include/asm-arm/arch-at91sam926x/at91sam9261.h which includes
the pin definitions used by the MCI controller.  An ancillary
patch for this file is appended below.  Of course it is useful
only for AT91SAM9261 based boards.

Note that Atmel used different conventions for defining
AT91SAM9261 and AT91SAM9260/AT91SAM9263 hardware (at least
for GPIO pin) definitions.  This will cause problems in
applying the previously posted u-boot-at91sam9261-mmc-v4.patch
for boards not based on the AT91SAM9261 (i.e.
AT91SAM9260/AT91SAM9263).

Note that I added the MMC v4.x code without access to the spec.
All I had was a MoviNAND manual, which assumes access to the
MMC v4.x spec.  (Note that the final CMD1 arg. is the correct
and recommended value for MoviNAND chips by their field eng.)
The patch included a lot of commented out (/* */ & '#if 0')
code used to help me understand MMC v4.x, at least well enough
to get the MoviNAND working reliably.

I never did get multi-block read or write working; The code
for it is included in the previous sent patch.  As I mentioned
before, I also didn't get 4 bit MMC working, but the code for
that is _not_ included in the patch anyway.

The Linux MMC code enables 4 bit for AT91SAM9260/AT91SAM9263
and only 1 bit for AT91SAM9261.  Does anyone know why?
I'd really like to get 4 bit transfers working on the 9261
via U-Boot.

I may try to put together a better patch using an earlier
version of my U-Boot code as a basis.  I'm not so sure my
previously sent patch will apply as cleanly as I had thought.

> Have you ever tested your U-Boot with 4GB or 8GB moviNAND?

No.

Sincerely,

Ken Fuchs

u-boot-at9261-mci-gpio-pins.patch
=================================

svn diff -r21 
Index: include/asm-arm/arch-at91sam926x/at91sam9261.h
===================================================================
--- include/asm-arm/arch-at91sam926x/at91sam9261.h	(revision 21)
+++ include/asm-arm/arch-at91sam926x/at91sam9261.h	(working copy)
@@ -17,6 +17,10 @@
  * Generated           : AT91 SW Application Group  03/30/2005
(17:05:06)
  * 
  *
------------------------------------------------------------------------
----
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Added numerous GPIO pin definitions for custom AT91SAM9261 board.
+ *
 */
 #ifndef AT91SAM9261_H
 #define AT91SAM9261_H
@@ -1330,8 +1334,10 @@
 /*
************************************************************************
***** */
 #define AT91C_PIO_PA0        ((unsigned int) 1 <<  0) /* Pin Controlled
by PA0 */
 #define AT91C_PA0_MISO0    ((unsigned int) AT91C_PIO_PA0) /*  SPI0
Master In Slave */
+#define AT91C_PA0_MCDA0    ((unsigned int) AT91C_PIO_PA0) /*  MMC NAND
MCDA0 */
 #define AT91C_PIO_PA1        ((unsigned int) 1 <<  1) /* Pin Controlled
by PA1 */
 #define AT91C_PA1_MOSI0    ((unsigned int) AT91C_PIO_PA1) /*  SPI0
Master Out Slave */
+#define AT91C_PA1_MCCDA    ((unsigned int) AT91C_PIO_PA1) /*  MMC NAND
MCCDA */
 #define AT91C_PIO_PA10       ((unsigned int) 1 << 10) /* Pin Controlled
by PA10 */
 #define AT91C_PA10_DTXD     ((unsigned int) AT91C_PIO_PA10) /*  DBGU
Debug Transmit Data */
 #define AT91C_PA10_LFON    ((unsigned int) AT91C_PIO_PA10)
@@ -1346,6 +1352,7 @@
 #define AT91C_PA16_NPCS15  ((unsigned int) AT91C_PIO_PA16) /* GPIO:
SPI1 CS5 */
 #define AT91C_PIO_PA2        ((unsigned int) 1 <<  2) /* Pin Controlled
by PA2 */
 #define AT91C_PA2_SPCK0    ((unsigned int) AT91C_PIO_PA2) /*  SPI0
Serial Clock */
+#define AT91C_PA2_MCCK     ((unsigned int) AT91C_PIO_PA2) /*  MMC NAND
MCCK  */
 #define AT91C_PIO_PA23       ((unsigned int) 1 << 23) /* Pin Controlled
by PA23 */
 #define AT91C_PA23_NPCS14  ((unsigned int) AT91C_PIO_PA23) /* GPIO:
SPI1 CS4 */
 #define AT91C_PIO_PA24       ((unsigned int) 1 << 24) /* Pin Controlled
by PA24 */
@@ -1358,10 +1365,13 @@
 #define AT91C_PA3_NPCS00   ((unsigned int) AT91C_PIO_PA3) /*  SPI0
Peripheral Chip Select 0 */
 #define AT91C_PIO_PA4        ((unsigned int) 1 <<  4) /* Pin Controlled
by PA4 */
 #define AT91C_PA4_NPCS01   ((unsigned int) AT91C_PIO_PA4) /*  SPI0
Peripheral Chip Select 1 */
+#define AT91C_PA4_MCDA1    ((unsigned int) AT91C_PIO_PA4) /*  MMC NAND
MCDA1 */
 #define AT91C_PIO_PA5        ((unsigned int) 1 <<  5) /* Pin Controlled
by PA5 */
 #define AT91C_PA5_NPCS02   ((unsigned int) AT91C_PIO_PA5) /*  SPI0
Peripheral Chip Select 2 */
+#define AT91C_PA5_MCDA2    ((unsigned int) AT91C_PIO_PA5) /*  MMC NAND
MCDA2 */
 #define AT91C_PIO_PA6        ((unsigned int) 1 <<  6) /* Pin Controlled
by PA6 */
 #define AT91C_PA6_NPCS03   ((unsigned int) AT91C_PIO_PA6) /*  SPI0
Peripheral Chip Select 3 */
+#define AT91C_PA6_MCDA3    ((unsigned int) AT91C_PIO_PA6) /*  MMC NAND
MCDA3 */
 #define AT91C_PIO_PA9        ((unsigned int) 1 <<  9) /* Pin Controlled
by PA9  */
 #define AT91C_PA9_DRXD     ((unsigned int) AT91C_PIO_PA9) /*  DBGU
Debug Receive Data */
 #define AT91C_PIO_PB0        ((unsigned int) 1 <<  0) /* Pin Controlled
by PB0 */

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] drivers MMCplus for at91sam9x
  2008-04-30 14:20                       ` [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary
  2008-04-30 16:25                         ` Ken.Fuchs at bench.com
@ 2008-04-30 20:31                         ` Ken.Fuchs at bench.com
  1 sibling, 0 replies; 39+ messages in thread
From: Ken.Fuchs at bench.com @ 2008-04-30 20:31 UTC (permalink / raw)
  To: u-boot

Pierre Savary wrote:

> Thanks a lot for your patch. I will test it next week.

I found it useful to modify common/cmd_mmc.c drastically
to facilitate easier testing of the AT91SAM9 MCI driver.
It replaces mmcinit with "mmc init" and adds raw read
("mmc read") and write ("mmc write") functions.
To use it, just apply the (ancillary) patch below.

Sincerely,

Ken Fuchs

------

u-boot-at91sam9261-cmd-mmc-for-testing.patch
============================================

svn diff -r21 common/cmd_mmc.c
Index: common/cmd_mmc.c
===================================================================
--- common/cmd_mmc.c	(revision 21)
+++ common/cmd_mmc.c	(working copy)
@@ -1,4 +1,8 @@
 /*
+ * (C) Copyright 2007-2008
+ * Benchmark Electronics, Inc.
+ * Split mmcinit into mmc init, mmc read and mmc write
+ *
  * (C) Copyright 2003
  * Kyle Harris, kharris at nexus-tech.net
  *
@@ -28,19 +32,100 @@
 
 #include <mmc.h>
 
+static unsigned int subcmd;
+static unsigned int bstart;
+static unsigned int noblocks;
+static unsigned int address;
+
 int do_mmc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-	if (mmc_init (1) != 0) {
-		printf ("No MMC card found\n");
-		return 1;
+        unsigned int compblocks;
+
+	if ((flag & CMD_FLAG_REPEAT) == 0) {
+	        if (argc >= 2) {
+		        if ((argv[1][0] == 'I' && argv[1][1] == 'N'
+			     && argv[1][2] == 'I' && argv[1][3] == 'T')
||
+			    (argv[1][0] == 'i' && argv[1][1] == 'n'
+			     && argv[1][2] == 'i' && argv[1][3] == 't'))
{
+			        subcmd = 0; /* init */
+			} else if ((argv[1][0] == 'R') ||
+			    (argv[1][0] == 'r')) {
+			        subcmd = 1; /* block read */
+			} else if ((argv[1][0] == 'W') ||
+			    (argv[1][0] == 'w')) {
+			        subcmd = 2; /* block write */
+			} else if ((argv[1][0] == 'M') ||
+			    (argv[1][0] == 'm')) {
+			        subcmd = 3; /* multiple block write */
+			} else {
+			        printf("Subcommand must be ");
+				printf("init, r[ead] or w[rite]\n");
+				return 1;
+			}
+		}
+		if (argc >= 3) {
+			bstart = simple_strtoul(argv[2], NULL, 16);
+		}
+		if (argc >= 4) {
+			noblocks = simple_strtoul(argv[3], NULL, 16);
+		}
+		if (argc >= 5) {
+			address = simple_strtoul(argv[4], NULL, 16);
+		}
 	}
-	return 0;
+	switch (subcmd) {
+	case 0:
+	        if (mmc_init(1) != 0) {
+		        printf ("No MMC card found\n");
+			return 1;
+		}
+		return 0;
+		break;
+	case 1:
+	        compblocks = mmc_bread(0, bstart, noblocks, (ulong
*)address);
+	        if (compblocks < noblocks) {
+		        printf("Error reading block#: 0x%08lx\n",
+			       bstart + compblocks);
+		}
+		break;
+	case 2:
+	        compblocks =
+		        mmc_bwrite(0, bstart, noblocks, (ulong
*)address);
+	        if (compblocks < noblocks) {
+		        printf("Error writing block#: 0x%08lx\n",
+			       bstart + compblocks);
+		}
+		break;
+	case 3:
+	        compblocks =
+		        mmc_mbwrite(0, bstart, noblocks, (ulong
*)address);
+	        if (compblocks < noblocks) {
+		        printf("Error writing block#: 0x%08lx\n",
+			       bstart + compblocks);
+		}
+		break;
+	}
 }
 
 U_BOOT_CMD(
-	mmcinit,	1,	0,	do_mmc,
-	"mmcinit - init mmc card\n",
-	NULL
+	mmc,	5,	1,	do_mmc,
+	"mmc     - init, read & write to the MMC NAND device\n",
+	"\n\nmmc init - initialize the MMC NAND device\n"
+	"\nmmc r <block#> <#blocks> <address> - block read MMC NAND
blocks\n"
+	"        <block#>   - starting block # (hexidecimal) to read\n"
+	"        <#blocks>  - no. of (512) blocks (hexidecimal) to
read\n"
+        "        <address>   - SDRAM/SRAM address (hex.) for read
data\n"
+	"\nmmc w <block#> <#blocks> <address> - block write MMC NAND
blocks\n"
+	"        <block#>   - starting block # (hexidecimal) to write\n"
+	"        <#blocks>  - no. of (512) blocks (hexidecimal) to
write\n"
+        "        <address>   - SDRAM/SRAM address (hex.) of data to
write\n"
+#if     0   /* Not working yet, so documentation is removed. */
+	"\nmmc m <block#> <#blocks> <address> - multiple block write
mode\n"
+	"        <block#>   - starting block # (hexidecimal) to write\n"
+	"        <#blocks>  - no. of (512) blocks (hexidecimal) to
write\n"
+        "        <address>   - SDRAM/SRAM address (hex.) of data to
write\n"
+#endif  /* 0 */
+        "\nA period (.) is displayed after each full MB is read or
written.\n"
 );
 
 #endif	/* CFG_CMD_MMC */

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-04-29 20:20                       ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Adrian Filipi
  2008-04-29 20:43                         ` Wolfgang Denk
@ 2008-05-08 11:17                         ` Haavard Skinnemoen
  2008-05-08 14:05                           ` Adrian Filipi
  1 sibling, 1 reply; 39+ messages in thread
From: Haavard Skinnemoen @ 2008-05-08 11:17 UTC (permalink / raw)
  To: u-boot

Adrian Filipi <adrian.filipi@eurotech.com> wrote:
> diff -u -r1.1.1.2.2.2 cfi_flash.c
> --- cfi_flash.c	23 Apr 2008 17:02:47 -0000	1.1.1.2.2.2
> +++ cfi_flash.c	29 Apr 2008 18:55:47 -0000
> @@ -464,7 +464,7 @@
>   			     uint offset, uchar cmd)
>   {
> 
> -	void *addr;
> +	void *volatile addr;

That looks bogus. It makes the pointer itself volatile, not whatever it
points to. All accesses through addr is performed by appropriate I/O
accessors, so no volatile should be needed, and certainly not one that
affects the pointer itself.

I suspect the change adds a few extra memory accesses (probably to the
stack) so that any memory ordering problems just happen to go away.

flash_write_cmd() calls sync() after writing the command to the flash,
so any memory ordering issues should have been taken care of. However,
sync() does nothing on ARM. Maybe it should do something?

Haavard

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-05-08 11:17                         ` Haavard Skinnemoen
@ 2008-05-08 14:05                           ` Adrian Filipi
  2008-05-08 16:27                             ` Haavard Skinnemoen
  0 siblings, 1 reply; 39+ messages in thread
From: Adrian Filipi @ 2008-05-08 14:05 UTC (permalink / raw)
  To: u-boot


 	Yeah, I agree it's bogus for the pointer to be volatile.  There 
shouldn't be anything unusual about that.

 	The assembler does show several additional memory accesses, so I 
think your theory is right.  I'm at a loss for what to to on the sync().

 	Adrian
--
Linux Software Engineer | EuroTech, Inc. | www.eurotech-inc.com

On Thu, 8 May 2008, Haavard Skinnemoen wrote:

> Adrian Filipi <adrian.filipi@eurotech.com> wrote:
>> diff -u -r1.1.1.2.2.2 cfi_flash.c
>> --- cfi_flash.c	23 Apr 2008 17:02:47 -0000	1.1.1.2.2.2
>> +++ cfi_flash.c	29 Apr 2008 18:55:47 -0000
>> @@ -464,7 +464,7 @@
>>   			     uint offset, uchar cmd)
>>   {
>>
>> -	void *addr;
>> +	void *volatile addr;
>
> That looks bogus. It makes the pointer itself volatile, not whatever it
> points to. All accesses through addr is performed by appropriate I/O
> accessors, so no volatile should be needed, and certainly not one that
> affects the pointer itself.
>
> I suspect the change adds a few extra memory accesses (probably to the
> stack) so that any memory ordering problems just happen to go away.
>
> flash_write_cmd() calls sync() after writing the command to the flash,
> so any memory ordering issues should have been taken care of. However,
> sync() does nothing on ARM. Maybe it should do something?
>
> Haavard
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [U-Boot-Users] cfi_flash.c and lost volatile qualifier
  2008-05-08 14:05                           ` Adrian Filipi
@ 2008-05-08 16:27                             ` Haavard Skinnemoen
  0 siblings, 0 replies; 39+ messages in thread
From: Haavard Skinnemoen @ 2008-05-08 16:27 UTC (permalink / raw)
  To: u-boot

Adrian Filipi <adrian.filipi@eurotech.com> wrote:
>  	Yeah, I agree it's bogus for the pointer to be volatile.  There 
> shouldn't be anything unusual about that.
> 
>  	The assembler does show several additional memory accesses, so I 
> think your theory is right.  I'm at a loss for what to to on the sync().

I'm at a loss too, I'm afraid...I don't really know PXA.

Linux seems to put an mb() after every write to the flash, so perhaps
include/asm-arm/system.h on Linux can provide some hints?

In any case, sync() should probably expand to at least a compiler
barrier on all architectures...though I'm not sure if it will make a
difference in this particular case.

Haavard

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2008-05-08 16:27 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-08 14:32 [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary
2008-04-09 17:49 ` Jean-Christophe PLAGNIOL-VILLARD
2008-04-10 10:32   ` Pierre Savary
2008-04-10 22:31 ` Ken.Fuchs at bench.com
2008-04-11  8:26   ` Pierre Savary
2008-04-11 15:48   ` Pierre Ossman
2008-04-11 18:54     ` Ken.Fuchs at bench.com
2008-04-12  9:28       ` Pierre Ossman
2008-04-15 10:18         ` Pierre Savary
2008-04-15 16:51           ` Ken.Fuchs at bench.com
     [not found]         ` <-6021840981243159212@unknownmsgid>
2008-04-15 19:25           ` Andy Fleming
2008-04-16  8:55             ` Pierre Savary
2008-04-16 23:30             ` Ken.Fuchs at bench.com
2008-04-22 11:55             ` Pierre Savary
2008-04-22 15:07               ` [U-Boot-Users] [PATCH] Add eSDHC driver Andy Fleming
2008-04-22 16:53                 ` Anton Vorontsov
2008-04-23 19:23                 ` Ken.Fuchs at bench.com
2008-04-24  6:24                   ` Pierre Savary
2008-04-29 19:45                     ` [U-Boot-Users] drivers MMCplus for at91sam9x Ken.Fuchs at bench.com
2008-04-29 20:20                       ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Adrian Filipi
2008-04-29 20:43                         ` Wolfgang Denk
2008-04-29 21:10                           ` Adrian Filipi
2008-04-29 21:16                             ` Jerry Van Baren
     [not found]                               ` <alpine.DEB.1.10.0804300949360.13610@pmy.adscville>
2008-04-30 14:43                                 ` Jerry Van Baren
2008-04-30 15:11                                   ` Joakim Tjernlund
2008-04-30 15:21                                     ` Scott Wood
2008-04-30 15:34                                       ` Joakim Tjernlund
2008-04-30 15:41                                         ` Wolfgang Denk
2008-04-30 16:02                                         ` Scott Wood
2008-04-30 16:11                                           ` Joakim Tjernlund
2008-04-30 15:35                                     ` [U-Boot-Users] PPC sync/eieio (was cfi_flash.c and lost volatile qualifier) Jerry Van Baren
2008-04-30 15:38                                   ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Wolfgang Denk
2008-04-30 15:51                                     ` Jerry Van Baren
2008-05-08 11:17                         ` Haavard Skinnemoen
2008-05-08 14:05                           ` Adrian Filipi
2008-05-08 16:27                             ` Haavard Skinnemoen
2008-04-30 14:20                       ` [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary
2008-04-30 16:25                         ` Ken.Fuchs at bench.com
2008-04-30 20:31                         ` Ken.Fuchs at bench.com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox