Skip to contentSkip to conversation

drivers MMCplus for at91sam9x

U-Boot-Users New Pierre Savary 13 participants 39 messages Apr 8, 2008 – May 8, 2008 2 messages not in the archive

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

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

#1 lore raw
Quoted 3 lines · Pierre Savary

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.

#2 lore raw

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

Quoted 2 lines · Pierre Savary

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

bits.

Quoted 1 line

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

#3 lore raw
In reply to Pierre Savary
Quoted 2 lines · Pierre Savary

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?

Quoted 3 lines

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.

Quoted 2 lines

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

Quoted 27 lines

-----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

Quoted 6 lines

--------------------------------------------------------------
-----------
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

#4 lore raw

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

Quoted 2 lines · Pierre Savary

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?

Quoted 3 lines

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.

Quoted 2 lines

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

Quoted 27 lines

-----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

Quoted 6 lines

--------------------------------------------------------------
-----------
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

#5 lore raw
In reply to Ken.Fuchs at bench.com
Quoted 8 lines · On Thu, 10 Apr 2008 17:31:24 -0500 Ken.Fuchs at bench.com wrote:
Quoted 2 lines · Pierre Savary

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.

Quoted 5 lines

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.

Quoted 5 lines · On Fri, 11 Apr 2008 10:26:52 +0200 "Pierre Savary" <[email protected]>…

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

Signature · 5 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org
#6 lore raw
Quoted 10 lines · Pierre Ossman
Quoted 3 lines · Ken Fuchs

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:

Quoted 4 lines
Quoted 4 lines

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.

Quoted 3 lines

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

#7 lore raw
Quoted 6 lines · 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.

Quoted 7 lines

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.

Quoted 4 lines

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

Signature · 5 lines
     -- Pierre Ossman

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

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

Quoted 6 lines · 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.

Quoted 7 lines

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.

Quoted 4 lines

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

Signature · 16 lines
     -- 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
#9 lore raw
Quoted 6 lines · Pierre Savary

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

Quoted 44 lines

-----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

Quoted 3 lines · 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

Quoted 1 line

could support 4 bits to an MMC 4.x chip and they said _no_.

The answer

Quoted 2 lines

is supposedly from their engineering group in France.

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

Quoted 2 lines

How does one program the MCI controller to send 4 bit

(parallel) data

Quoted 2 lines

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

Quoted 1 line

is to tell it that it is connected to a SD (1.0) chip. If

you program

Quoted 1 line

the MCI to communicate with an MMC chip, it will send data

out only on

Quoted 1 line

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.

Quoted 3 lines

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

Quoted 22 lines
Quoted 1 line

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

Signature · 13 lines
     -- 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

A message that is not in the archive (sent off-list or not yet received): -6021840981243159212@unknownmsgid

#11 lore raw
Quoted 4 lines · Pierre Savary

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

#12 lore raw

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

Quoted 2 lines · Pierre Savary

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

:(

Quoted 2 lines

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

#13 lore raw
In reply to Andy Fleming

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

Quoted 32 lines

-----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

Quoted 1 line · Pierre Savary

Then my MMC 4GB works with my Linux kernel but if I can't

load my kernel

Quoted 1 line

(located on the first part of this MMC) ... it's not

really interesting :(

Quoted 2 lines

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

Quoted 7 lines

--------------------------------------------------------------
-----------
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

#14 lore raw
In reply to Andy Fleming

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

Quoted 2 lines · Pierre Savary

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

:(

Quoted 2 lines

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

#15 lore raw

PATCH 1/1 Add eSDHC driver

This is the SD/MMC controller on several of Freescale's more recent parts
---

Quoted 3 lines

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
Makefile +2 -0
index e5b4210..cd614a5 100644
@@ -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
drivers/mmc/Makefile new file +46 -0

46 lines not on this page · raw message

drivers/mmc/fsl_esdhc.c new file +1111 -0

1,111 lines not on this page · raw message

drivers/mmc/fsl_esdhc.h new file +208 -0

208 lines not on this page · raw message

include/asm-ppc/arch-mpc83xx/mmc.h new file +1 -0
new file mode 100644
index 0000000..d5034f4
@@ -0,0 +1 @@
+/* Stub file to satisfy odd requirement for <arch/mmc.h> */
Signature · 1 line
1.5.4.GIT
#16 lore raw

PATCH 1/1 Add eSDHC driver

Quoted 1 line · Andy Fleming

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.

Signature · 3 lines
Anton Vorontsov
email: cbouatmailru at gmail.com
irc://irc.freenode.net/bd2
#17 lore raw

PATCH 1/1 Add eSDHC driver

In reply to Andy Fleming
Quoted 3 lines
Quoted 1 line · Pierre Savary

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

Quoted 2 lines · Andy Fleming

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
#
========================================================================
=
#

disk/part.c +0 -0
diff -burN u-boot-1.1.5/disk/part.c u-boot-1.1.5.klk/disk/part.c

+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

#18 lore raw

PATCH 1/1 Add eSDHC driver

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

Quoted 3 lines
Quoted 1 line · Pierre Savary

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

Quoted 2 lines · Andy Fleming

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
#
========================================================================
=
#

disk/part.c +0 -0
diff -burN u-boot-1.1.5/disk/part.c u-boot-1.1.5.klk/disk/part.c

+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
[email protected]
https://lists.sourceforge.net/lists/listinfo/u-boot-users

#19 lore raw

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

Quoted 1 line
Quoted 1 line

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

Quoted 3 lines · Pierre Savary

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

arm926ejs/at91sam926x/atmel_mci.c +24 -1
Index: cpu/arm926ejs/at91sam926x/atmel_mci.c
===================================================================
@@ -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

asm-arm/arch-at91sam926x/mmc.h +103 -0

103 lines not on this page · raw message

svn diff -r21 include/configs/at91sam9261ek.h

configs/at91sam9261ek.h +13 -3
Index: include/configs/at91sam9261ek.h
===================================================================
@@ -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

at91sam9261ek/at91sam9261ek.c +11 -2
Index: board/at91sam9261ek/at91sam9261ek.c
===================================================================
@@ -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;
}

#20 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

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:

cfi_flash.c +1 -1
diff -u -r1.1.1.2.2.2 cfi_flash.c
@@ -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

#21 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

Quoted 5 lines · In message <[email protected]> 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

Signature · 5 lines
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
#22 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

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

Quoted 17 lines · Wolfgang Denk
Quoted 5 lines · In message <[email protected]> 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

#23 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

Quoted 28 lines · Adrian Filipi
Quoted 5 lines · Wolfgang Denk
Quoted 4 lines · In message <[email protected]> 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;".

Quoted 8 lines

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.

Review

Quoted 3 lines
(quoted diff) +0 -0
 	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

A message that is not in the archive (sent off-list or not yet received): [email protected]

#25 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

Quoted 55 lines · Adrian Filipi
Quoted 38 lines · Jerry Van Baren
Quoted 27 lines · Adrian Filipi
Quoted 8 lines · Wolfgang Denk

In message <[email protected]> you

Quoted 6 lines · 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;".

Quoted 8 lines

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.

Quoted 7 lines

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,

Quoted 9 lines

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.

Quoted 4 lines

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.

#26 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

Quoted 4 lines

[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

#27 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

Quoted 2 lines · Joakim Tjernlund

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

#28 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

Quoted 8 lines · Scott Wood
Quoted 2 lines · Joakim Tjernlund

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.

Quoted 2 lines

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

Quoted 4 lines

-Scott

#29 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

Quoted 3 lines · In message <[email protected]> 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

Signature · 5 lines
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.
#30 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

In reply to Joakim Tjernlund
Quoted 6 lines · Joakim Tjernlund
Quoted 4 lines · Scott Wood
Quoted 2 lines · Joakim Tjernlund

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

Quoted 7 lines
Quoted 4 lines

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.

Quoted 1 line

Anyway, just have a look at ucc_geth

Do I have to? :-)

Quoted 2 lines

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.

Quoted 3 lines
Quoted 1 line

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.

Quoted 1 line

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

#31 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

Quoted 12 lines · Scott Wood
Quoted 11 lines · Joakim Tjernlund
Quoted 8 lines · Scott Wood
Quoted 2 lines · Joakim Tjernlund

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.

Quoted 5 lines
Quoted 2 lines

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

Quoted 4 lines
Quoted 2 lines

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

#32 lore raw

[U-Boot-Users] PPC sync/eieio (was cfi_flash.c and lost volatile qualifier)

In reply to Joakim Tjernlund
Quoted 7 lines · Joakim Tjernlund
Quoted 2 lines

[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

#33 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

In reply to Jerry Van Baren
Quoted 4 lines · In message <[email protected]> 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

Signature · 5 lines
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
#34 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

Quoted 5 lines · Wolfgang Denk
Quoted 3 lines · In message <[email protected]> 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.

Quoted 7 lines

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

#35 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

In reply to Adrian Filipi

cfi_flash.c line 467

Quoted 9 lines · Adrian Filipi

diff -u -r1.1.1.2.2.2 cfi_flash.c

cfi_flash.c +1 -1
@@ -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

#36 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

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

Quoted 25 lines · Haavard Skinnemoen

cfi_flash.c line 467

Quoted 9 lines · Adrian Filipi

diff -u -r1.1.1.2.2.2 cfi_flash.c

cfi_flash.c +1 -1
@@ -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

#37 lore raw

[U-Boot-Users] cfi_flash.c and lost volatile qualifier

Quoted 5 lines · Adrian Filipi

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

#38 lore raw
In reply to Ken.Fuchs at bench.com

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

Quoted 1 line
Quoted 1 line

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

Quoted 3 lines · Pierre Savary

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

arm926ejs/at91sam926x/atmel_mci.c +24 -1
Index: cpu/arm926ejs/at91sam926x/atmel_mci.c
===================================================================
@@ -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

asm-arm/arch-at91sam926x/mmc.h +103 -0

103 lines not on this page · raw message

svn diff -r21 include/configs/at91sam9261ek.h

configs/at91sam9261ek.h +13 -3
Index: include/configs/at91sam9261ek.h
===================================================================
@@ -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

at91sam9261ek/at91sam9261ek.c +11 -2
Index: board/at91sam9261ek/at91sam9261ek.c
===================================================================
@@ -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
[email protected]
https://lists.sourceforge.net/lists/listinfo/u-boot-users

#39 lore raw
Quoted 1 line · Pierre Savary

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.

Quoted 1 line

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

asm-arm/arch-at91sam926x/at91sam9261.h +0 -0
Index: include/asm-arm/arch-at91sam926x/at91sam9261.h
===================================================================
@@ -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 */

#40 lore raw
In reply to Pierre Savary
Quoted 1 line · Pierre Savary

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

cmd_mmc.c +15 -3
Index: common/cmd_mmc.c
===================================================================
@@ -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 */