* [U-Boot-Users] drivers MMCplus for at91sam9x @ 2008-04-08 14:32 Pierre Savary 2008-04-09 17:49 ` Jean-Christophe PLAGNIOL-VILLARD 2008-04-10 22:31 ` Ken.Fuchs at bench.com 0 siblings, 2 replies; 39+ messages in thread From: Pierre Savary @ 2008-04-08 14:32 UTC (permalink / raw) To: u-boot Hi, I use a MMCplus 4GB on my design (with at91sam9260). It's wired with 4 bits. Currently U-boot (1.1.5) can't detect correctly the MMC and so I can't read my Linux kernel Image on the ext3 part of this MMC. If I use MMC 1GB, it works. Somebody have already use it? Or somebody have already implemented the ext_csd and high capacity with MMC on another platform? I need help. Thanks in advance to help me. Regards, Pierre ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-08 14:32 [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary @ 2008-04-09 17:49 ` Jean-Christophe PLAGNIOL-VILLARD 2008-04-10 10:32 ` Pierre Savary 2008-04-10 22:31 ` Ken.Fuchs at bench.com 1 sibling, 1 reply; 39+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2008-04-09 17:49 UTC (permalink / raw) To: u-boot On 16:32 Tue 08 Apr , Pierre Savary wrote: > Hi, > I use a MMCplus 4GB on my design (with at91sam9260). It's wired with 4 bits. > Currently U-boot (1.1.5) can't detect correctly the MMC and so I can't read 1.1.5 is really old please update to the curent RC Best Regards, J. ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-09 17:49 ` Jean-Christophe PLAGNIOL-VILLARD @ 2008-04-10 10:32 ` Pierre Savary 0 siblings, 0 replies; 39+ messages in thread From: Pierre Savary @ 2008-04-10 10:32 UTC (permalink / raw) To: u-boot I have already test it but the version of the MMC driver is the same... And it's very difficult for me to update my own version to the current. Thanks for your help Pierre -----Message d'origine----- De?: u-boot-users-bounces at lists.sourceforge.net [mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de Jean-Christophe PLAGNIOL-VILLARD Envoy??: mercredi 9 avril 2008 19:49 ??: Pierre Savary Cc?: u-boot-users at lists.sourceforge.net; 'Pierre Ossman' Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x On 16:32 Tue 08 Apr , Pierre Savary wrote: > Hi, > I use a MMCplus 4GB on my design (with at91sam9260). It's wired with 4 bits. > Currently U-boot (1.1.5) can't detect correctly the MMC and so I can't read 1.1.5 is really old please update to the curent RC Best Regards, J. ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao ne _______________________________________________ U-Boot-Users mailing list U-Boot-Users at lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-08 14:32 [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary 2008-04-09 17:49 ` Jean-Christophe PLAGNIOL-VILLARD @ 2008-04-10 22:31 ` Ken.Fuchs at bench.com 2008-04-11 8:26 ` Pierre Savary 2008-04-11 15:48 ` Pierre Ossman 1 sibling, 2 replies; 39+ messages in thread From: Ken.Fuchs at bench.com @ 2008-04-10 22:31 UTC (permalink / raw) To: u-boot Pierre Savary wrote: > I use a MMCplus 4GB on my design (with at91sam9260). It's > wired with 4 bits. The MCI controller on the AT91SAM926x family does not support MMCplus. There is no way to support a 4 bit bus, since the MCI controller supports only 1 bit to an MMC chip. The MCI will support a 4 bit SD chip, but I don't think it can be tricked into working with a 4 bit MMC chip (at least not via software alone). The only reasonable solution is switching to a processor that has MMCplus support. Maybe Atmel has been working on one? > Currently U-boot (1.1.5) can't detect correctly the MMC and > so I can't read my Linux kernel Image on the ext3 part of this > MMC. If I use MMC 1GB, it works. Did you add MMCplus commands to the MCI U-Boot driver? You can do this to the extent that these changes do not require the MCI controller to be MMCplus compliant. (The MCI U-Boot driver I'm aware of contains no MMCplus support.) I suggest that you use the u-boot sources available via git. You will get very little support (if any) from the U-Boot ML for two reasons: 1) U-Boot 1.1.5 is extremely old and no one on the list is interested in supporting it. 2) The version of U-Boot 1.1.5 you are using almost certainly has an Atmel patch applied to it that was never accepted into the "official" U-Boot tree. However, ... It appears that someone is working on the AT91SAM9260 within the official U-Boot (git) tree, since the ./include/configs/at91sam9260ek.h file is there. Other file structures like ./cpu/arm926ejs/* seem to be missing some drivers and other support files. I know that the AT91SAM926x specific U-Boot files were never an official part of U-Boot, but that appears to be changing. It is my understanding that the AT91SAM926x support is being completely reworked and integrated with the AT91CAP9 code that has been present in git for over a month already. The AT91CAP9 and AT91SAM926x are very similar and should share a lot of code. Even if the AT91SAM9260 is not quite ready, the AT91CAP9 code should provide the basis of a current U-Boot for the AT91SAM926x family. > Somebody have already use it? Or somebody have already implemented > the ext_csd and high capacity with MMC on another platform? I know that the MCI controller can be used to access 1GB MMCplus chips, but I'm not sure it can be used to access MMCplus chips larger than that. There may be a special MMCplus command that will allow larger chips to be accessed. Try looking for it in your MMCplus chip's manual. Sincerely, Ken Fuchs > -----Original Message----- > From: u-boot-users-bounces at lists.sourceforge.net > [mailto:u-boot-users-bounces at lists.sourceforge.net] On Behalf > Of Pierre Savary > Sent: Tuesday, April 08, 2008 09:32 > To: u-boot-users at lists.sourceforge.net > Cc: 'Pierre Ossman' > Subject: [U-Boot-Users] drivers MMCplus for at91sam9x > > > Hi, > I use a MMCplus 4GB on my design (with at91sam9260). It's > wired with 4 bits. > Currently U-boot (1.1.5) can't detect correctly the MMC and > so I can't read > my Linux kernel Image on the ext3 part of this MMC. If I use > MMC 1GB, it > works. > Somebody have already use it? Or somebody have already implemented the > ext_csd and high capacity with MMC on another platform? > I need help. Thanks in advance to help me. > > Regards, > > Pierre > > > -------------------------------------------------------------- > ----------- > This SF.net email is sponsored by the 2008 JavaOne(SM) Conference > Register now and save $200. Hurry, offer ends at 11:59 p.m., > Monday, April 7! Use priority code J8TLD2. > http://ad.doubleclick.net/clk;198757673;13503038;p?http://java .sun.com/javaone _______________________________________________ U-Boot-Users mailing list U-Boot-Users at lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-10 22:31 ` Ken.Fuchs at bench.com @ 2008-04-11 8:26 ` Pierre Savary 2008-04-11 15:48 ` Pierre Ossman 1 sibling, 0 replies; 39+ messages in thread From: Pierre Savary @ 2008-04-11 8:26 UTC (permalink / raw) To: u-boot Thanks a lot for your help. In fact it's not really important to support MMCplus, the main is to support MMC v4 where the extended CSD is introduced. Moreover, it's not really important if only one wire is used... I want only be able to read on a MMC 4Gb with my U-boot... Thanks in advance Pierre -----Message d'origine----- De?: u-boot-users-bounces at lists.sourceforge.net [mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de Ken.Fuchs at bench.com Envoy??: vendredi 11 avril 2008 00:31 ??: pierre.savary at kerlink.fr Cc?: u-boot-users at lists.sourceforge.net; drzeus-mmc at drzeus.cx Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary wrote: > I use a MMCplus 4GB on my design (with at91sam9260). It's > wired with 4 bits. The MCI controller on the AT91SAM926x family does not support MMCplus. There is no way to support a 4 bit bus, since the MCI controller supports only 1 bit to an MMC chip. The MCI will support a 4 bit SD chip, but I don't think it can be tricked into working with a 4 bit MMC chip (at least not via software alone). The only reasonable solution is switching to a processor that has MMCplus support. Maybe Atmel has been working on one? > Currently U-boot (1.1.5) can't detect correctly the MMC and > so I can't read my Linux kernel Image on the ext3 part of this > MMC. If I use MMC 1GB, it works. Did you add MMCplus commands to the MCI U-Boot driver? You can do this to the extent that these changes do not require the MCI controller to be MMCplus compliant. (The MCI U-Boot driver I'm aware of contains no MMCplus support.) I suggest that you use the u-boot sources available via git. You will get very little support (if any) from the U-Boot ML for two reasons: 1) U-Boot 1.1.5 is extremely old and no one on the list is interested in supporting it. 2) The version of U-Boot 1.1.5 you are using almost certainly has an Atmel patch applied to it that was never accepted into the "official" U-Boot tree. However, ... It appears that someone is working on the AT91SAM9260 within the official U-Boot (git) tree, since the ./include/configs/at91sam9260ek.h file is there. Other file structures like ./cpu/arm926ejs/* seem to be missing some drivers and other support files. I know that the AT91SAM926x specific U-Boot files were never an official part of U-Boot, but that appears to be changing. It is my understanding that the AT91SAM926x support is being completely reworked and integrated with the AT91CAP9 code that has been present in git for over a month already. The AT91CAP9 and AT91SAM926x are very similar and should share a lot of code. Even if the AT91SAM9260 is not quite ready, the AT91CAP9 code should provide the basis of a current U-Boot for the AT91SAM926x family. > Somebody have already use it? Or somebody have already implemented > the ext_csd and high capacity with MMC on another platform? I know that the MCI controller can be used to access 1GB MMCplus chips, but I'm not sure it can be used to access MMCplus chips larger than that. There may be a special MMCplus command that will allow larger chips to be accessed. Try looking for it in your MMCplus chip's manual. Sincerely, Ken Fuchs > -----Original Message----- > From: u-boot-users-bounces at lists.sourceforge.net > [mailto:u-boot-users-bounces at lists.sourceforge.net] On Behalf > Of Pierre Savary > Sent: Tuesday, April 08, 2008 09:32 > To: u-boot-users at lists.sourceforge.net > Cc: 'Pierre Ossman' > Subject: [U-Boot-Users] drivers MMCplus for at91sam9x > > > Hi, > I use a MMCplus 4GB on my design (with at91sam9260). It's > wired with 4 bits. > Currently U-boot (1.1.5) can't detect correctly the MMC and > so I can't read > my Linux kernel Image on the ext3 part of this MMC. If I use > MMC 1GB, it > works. > Somebody have already use it? Or somebody have already implemented the > ext_csd and high capacity with MMC on another platform? > I need help. Thanks in advance to help me. > > Regards, > > Pierre > > > -------------------------------------------------------------- > ----------- > This SF.net email is sponsored by the 2008 JavaOne(SM) Conference > Register now and save $200. Hurry, offer ends at 11:59 p.m., > Monday, April 7! Use priority code J8TLD2. > http://ad.doubleclick.net/clk;198757673;13503038;p?http://java .sun.com/javaone _______________________________________________ U-Boot-Users mailing list U-Boot-Users at lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao ne _______________________________________________ U-Boot-Users mailing list U-Boot-Users at lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-10 22:31 ` Ken.Fuchs at bench.com 2008-04-11 8:26 ` Pierre Savary @ 2008-04-11 15:48 ` Pierre Ossman 2008-04-11 18:54 ` Ken.Fuchs at bench.com 1 sibling, 1 reply; 39+ messages in thread From: Pierre Ossman @ 2008-04-11 15:48 UTC (permalink / raw) To: u-boot On Thu, 10 Apr 2008 17:31:24 -0500 Ken.Fuchs at bench.com wrote: > Pierre Savary wrote: > > > I use a MMCplus 4GB on my design (with at91sam9260). It's > > wired with 4 bits. > > The MCI controller on the AT91SAM926x family does not support > MMCplus. There is no way to support a 4 bit bus, since the > MCI controller supports only 1 bit to an MMC chip. Untrue. The hardware interface is identical for 4-bit SD and 4-bit MMC. So if that part isn't working, it's because you either have a bug or because you lack 4-bit MMC support entirely in u-boot. > I know that the MCI controller can be used to access 1GB MMCplus chips, > but I'm not sure it can be used to access MMCplus chips larger than > that. > There may be a special MMCplus command that will allow larger chips to > be accessed. Try looking for it in your MMCplus chip's manual. All compliant cards above 2 GB require special handling. They use a system identical to SDHC (except for the init). Check the specs (this part is publicly available) or the Linux code. On Fri, 11 Apr 2008 10:26:52 +0200 "Pierre Savary" <pierre.savary@kerlink.fr> wrote: > Thanks a lot for your help. > In fact it's not really important to support MMCplus, the main is to support > MMC v4 where the extended CSD is introduced. Moreover, it's not really > important if only one wire is used... I want only be able to read on a MMC > 4Gb with my U-boot... Just to avoid some more confusion, MMCplus is the marketing name of the full size MMC cards since version 4. So when discussing technical attributes, the MMCplus/MMCmobile distinction is not that useful. It's better to just call them v4. :) Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-11 15:48 ` Pierre Ossman @ 2008-04-11 18:54 ` Ken.Fuchs at bench.com 2008-04-12 9:28 ` Pierre Ossman 0 siblings, 1 reply; 39+ messages in thread From: Ken.Fuchs at bench.com @ 2008-04-11 18:54 UTC (permalink / raw) To: u-boot Pierre Ossman wrote: > Ken Fuchs wrote: > > > The MCI controller on the AT91SAM926x family does not support > > MMCplus. There is no way to support a 4 bit bus, since the > > MCI controller supports only 1 bit to an MMC chip. > > Untrue. The hardware interface is identical for 4-bit SD and > 4-bit MMC. > So if that part isn't working, it's because you either have a bug or > because you lack 4-bit MMC support entirely in u-boot. The manual for the AT91SAM926x processors clearly states that the MCI controller supports MMC 2.2. I asked Atmel whether this controller could support 4 bits to an MMC 4.x chip and they said _no_. The answer is supposedly from their engineering group in France. 4-bit MMC support can easily be added to U-Boot, but the MCI controller is MMC 2.2, and this standard only allows for a 1-bit bus to MMC, so I'm not sure you can make it work at all. Atmel will definitely not help you, since they guarantee only MMC 2.2 compliance with the AT91SAM926x processor family. Has this changed? Pierre Ossman omitted the following part of my original response: > > The MCI will > > support a 4 bit SD chip, but I don't think it can be tricked > > into working with a 4 bit MMC chip (at least not via software > > alone). How does one program the MCI controller to send 4 bit (parallel) data an MMC 4.x chip, with or without telling it that it is communicating to a 4-bit SD chip? The only way to get 4 bits of data out of the MCI is to tell it that it is connected to a SD (1.0) chip. If you program the MCI to communicate with an MMC chip, it will send data out only on the low order bit. If you have a way around this, please let us know what it is. > All compliant cards above 2 GB require special handling. They use a > system identical to SDHC (except for the init). Check the specs (this > part is publicly available) or the Linux code. Both ends of the communication link must considered. It may not be sufficient that the MMC chip is MMC 4.x; The fact that the MCI controller is only MMC 2.2 or SD 1.0 compliant, may or may not impact this special handling. Sincerely, Ken Fuchs ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-11 18:54 ` Ken.Fuchs at bench.com @ 2008-04-12 9:28 ` Pierre Ossman 2008-04-15 10:18 ` Pierre Savary [not found] ` <-6021840981243159212@unknownmsgid> 0 siblings, 2 replies; 39+ messages in thread From: Pierre Ossman @ 2008-04-12 9:28 UTC (permalink / raw) To: u-boot On Fri, 11 Apr 2008 13:54:13 -0500 Ken.Fuchs at bench.com wrote: > > The manual for the AT91SAM926x processors clearly states that the > MCI controller supports MMC 2.2. I asked Atmel whether this controller > could support 4 bits to an MMC 4.x chip and they said _no_. The answer > is supposedly from their engineering group in France. > What they answered was if Atmel would support such a solution, not if the hardware would. > > How does one program the MCI controller to send 4 bit (parallel) data > an MMC 4.x chip, with or without telling it that it is communicating > to a 4-bit SD chip? The only way to get 4 bits of data out of the MCI > is to tell it that it is connected to a SD (1.0) chip. If you program > the MCI to communicate with an MMC chip, it will send data out only on > the low order bit. You tell it to use all four bits. That's it. The setting isn't MMC/SD, it's 1-bit/4-bit. > Both ends of the communication link must considered. It may not be > sufficient that the MMC chip is MMC 4.x; The fact that the MCI > controller is only MMC 2.2 or SD 1.0 compliant, may or may not impact > this special handling. It does not in the slightest. Remember that these controllers are extremely dumb. The low level behaviour of the protocol hasn't changed since the very first specs, so only software needs to be changed to support even the newest features. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-12 9:28 ` Pierre Ossman @ 2008-04-15 10:18 ` Pierre Savary 2008-04-15 16:51 ` Ken.Fuchs at bench.com [not found] ` <-6021840981243159212@unknownmsgid> 1 sibling, 1 reply; 39+ messages in thread From: Pierre Savary @ 2008-04-15 10:18 UTC (permalink / raw) To: u-boot Then my MMC 4GB works with my Linux kernel but if I can't load my kernel (located on the first part of this MMC) ... it's not really interesting :( So, somebody does already use MMC v4 with U-boot??? Thanks in advance Pierre -----Message d'origine----- De?: u-boot-users-bounces at lists.sourceforge.net [mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de Pierre Ossman Envoy??: samedi 12 avril 2008 11:28 ??: Ken.Fuchs at bench.com Cc?: pierre.savary at kerlink.fr; u-boot-users at lists.sourceforge.net Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x On Fri, 11 Apr 2008 13:54:13 -0500 Ken.Fuchs at bench.com wrote: > > The manual for the AT91SAM926x processors clearly states that the > MCI controller supports MMC 2.2. I asked Atmel whether this controller > could support 4 bits to an MMC 4.x chip and they said _no_. The answer > is supposedly from their engineering group in France. > What they answered was if Atmel would support such a solution, not if the hardware would. > > How does one program the MCI controller to send 4 bit (parallel) data > an MMC 4.x chip, with or without telling it that it is communicating > to a 4-bit SD chip? The only way to get 4 bits of data out of the MCI > is to tell it that it is connected to a SD (1.0) chip. If you program > the MCI to communicate with an MMC chip, it will send data out only on > the low order bit. You tell it to use all four bits. That's it. The setting isn't MMC/SD, it's 1-bit/4-bit. > Both ends of the communication link must considered. It may not be > sufficient that the MMC chip is MMC 4.x; The fact that the MCI > controller is only MMC 2.2 or SD 1.0 compliant, may or may not impact > this special handling. It does not in the slightest. Remember that these controllers are extremely dumb. The low level behaviour of the protocol hasn't changed since the very first specs, so only software needs to be changed to support even the newest features. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao ne _______________________________________________ U-Boot-Users mailing list U-Boot-Users at lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-15 10:18 ` Pierre Savary @ 2008-04-15 16:51 ` Ken.Fuchs at bench.com 0 siblings, 0 replies; 39+ messages in thread From: Ken.Fuchs at bench.com @ 2008-04-15 16:51 UTC (permalink / raw) To: u-boot Pierre Savary wrote: > Then my MMC 4GB works with my Linux kernel but if I can't > load my kernel > (located on the first part of this MMC) ... it's not really > interesting :( > So, somebody does already use MMC v4 with U-boot??? Assuming a AT91SAM926x MCI controller: Probably. Given an MMC v2.x compliant U-Boot driver, it would be relatively easy to add support for an MMC v4.x chip. If there is an MMC v4.x compliant Linux driver, it could be ported to U-Boot (Many, if not most, U-Boot drivers are ports from the corresponding Linux driver.) Alternatively, if both an MMC v2.x compliant U-Boot driver and MMC v4.x compliant Linux driver exist, the port would be trivial; just copy the MMC v4.x Linux code into the corresponding places in the MMC v2.2 U-Boot driver until it supports your MMC v4.x chip. Such an MMC v4.x U-Boot AT91SAM926x MCI driver should be able to support any v4.x MMC chip, at least via a one bit MMC bus. (I remain unconvinced that the AT91SAM926x MCI controller can support a 4 bit MMC bus; only a working MCI driver using a 4 bit MMC bus verified by a logic analyzer or similar compliance/debugging device would be convincing enough.) If the Linux AT91SAM926x MCI driver supports a 4 bit MMC bus, then the U-Boot AT91SAM926x MCI driver can borrow the Linux driver's code and support a 4 bit bus also. Sincerely, Ken Fuchs > -----Message d'origine----- > De?: u-boot-users-bounces at lists.sourceforge.net > [mailto:u-boot-users-bounces at lists.sourceforge.net] De la > part de Pierre > Ossman > Envoy??: samedi 12 avril 2008 11:28 > ??: Ken.Fuchs at bench.com > Cc?: pierre.savary at kerlink.fr; u-boot-users at lists.sourceforge.net > Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x > > On Fri, 11 Apr 2008 13:54:13 -0500 > Ken.Fuchs at bench.com wrote: > > > > > The manual for the AT91SAM926x processors clearly states that the > > MCI controller supports MMC 2.2. I asked Atmel whether > this controller > > could support 4 bits to an MMC 4.x chip and they said _no_. > The answer > > is supposedly from their engineering group in France. > > > > What they answered was if Atmel would support such a solution, not if > the hardware would. > > > > > How does one program the MCI controller to send 4 bit > (parallel) data > > an MMC 4.x chip, with or without telling it that it is communicating > > to a 4-bit SD chip? The only way to get 4 bits of data out > of the MCI > > is to tell it that it is connected to a SD (1.0) chip. If > you program > > the MCI to communicate with an MMC chip, it will send data > out only on > > the low order bit. > > You tell it to use all four bits. That's it. The setting isn't MMC/SD, > it's 1-bit/4-bit. > > > Both ends of the communication link must considered. It may not be > > sufficient that the MMC chip is MMC 4.x; The fact that the MCI > > controller is only MMC 2.2 or SD 1.0 compliant, may or may > not impact > > this special handling. > > It does not in the slightest. Remember that these controllers are > extremely dumb. The low level behaviour of the protocol hasn't changed > since the very first specs, so only software needs to be changed to > support even the newest features. > > Rgds > -- > -- Pierre Ossman > > Linux kernel, MMC maintainer http://www.kernel.org > PulseAudio, core developer http://pulseaudio.org > rdesktop, core developer http://www.rdesktop.org > > -------------------------------------------------------------- > ----------- > This SF.net email is sponsored by the 2008 JavaOne(SM) Conference > Don't miss this year's exciting event. There's still time to > save $100. > Use priority code J8TL2D2. > http://ad.doubleclick.net/clk;198757673;13503038;p?http://java .sun.com/javao ne _______________________________________________ U-Boot-Users mailing list U-Boot-Users at lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ^ permalink raw reply [flat|nested] 39+ messages in thread
[parent not found: <-6021840981243159212@unknownmsgid>]
* [U-Boot-Users] drivers MMCplus for at91sam9x [not found] ` <-6021840981243159212@unknownmsgid> @ 2008-04-15 19:25 ` Andy Fleming 2008-04-16 8:55 ` Pierre Savary ` (2 more replies) 0 siblings, 3 replies; 39+ messages in thread From: Andy Fleming @ 2008-04-15 19:25 UTC (permalink / raw) To: u-boot On Tue, Apr 15, 2008 at 5:18 AM, Pierre Savary <pierre.savary@kerlink.fr> wrote: > Then my MMC 4GB works with my Linux kernel but if I can't load my kernel > (located on the first part of this MMC) ... it's not really interesting :( > > So, somebody does already use MMC v4 with U-boot??? I've got one that works. However, I don't have a 4GB MMC card with v4. I thought I did, but it turned out the card just takes advantage of the fact that older versions can address 4GB, even though the spec says 2GB is the max. However, I'm fairly confident in the code (it's been tested in simulated environments, and reflects what the Linux code does). I'm currently working on bringing it forward to the top of tree (I started it before drivers/ got rearranged). I'm actually hoping to generalize it some so we can share it between all MMC/SD users. Andy ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-15 19:25 ` Andy Fleming @ 2008-04-16 8:55 ` Pierre Savary 2008-04-16 23:30 ` Ken.Fuchs at bench.com 2008-04-22 11:55 ` Pierre Savary 2 siblings, 0 replies; 39+ messages in thread From: Pierre Savary @ 2008-04-16 8:55 UTC (permalink / raw) To: u-boot Hi, Perhaps that I could help you...? I could test it with many different MMC (2GB, 4GB, 8GB) (Samsung and Micron). Could you share with me your source code? Thanks in advance for your help, Best Regards Pierre -----Message d'origine----- De?: u-boot-users-bounces at lists.sourceforge.net [mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de Andy Fleming Envoy??: mardi 15 avril 2008 21:25 ??: Pierre Savary Cc?: u-boot-users at lists.sourceforge.net; drzeus-mmc at drzeus.cx Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x On Tue, Apr 15, 2008 at 5:18 AM, Pierre Savary <pierre.savary@kerlink.fr> wrote: > Then my MMC 4GB works with my Linux kernel but if I can't load my kernel > (located on the first part of this MMC) ... it's not really interesting :( > > So, somebody does already use MMC v4 with U-boot??? I've got one that works. However, I don't have a 4GB MMC card with v4. I thought I did, but it turned out the card just takes advantage of the fact that older versions can address 4GB, even though the spec says 2GB is the max. However, I'm fairly confident in the code (it's been tested in simulated environments, and reflects what the Linux code does). I'm currently working on bringing it forward to the top of tree (I started it before drivers/ got rearranged). I'm actually hoping to generalize it some so we can share it between all MMC/SD users. Andy ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao ne _______________________________________________ U-Boot-Users mailing list U-Boot-Users at lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-15 19:25 ` Andy Fleming 2008-04-16 8:55 ` Pierre Savary @ 2008-04-16 23:30 ` Ken.Fuchs at bench.com 2008-04-22 11:55 ` Pierre Savary 2 siblings, 0 replies; 39+ messages in thread From: Ken.Fuchs at bench.com @ 2008-04-16 23:30 UTC (permalink / raw) To: u-boot Congratulations! It will be great to have MMC v4.x support in U-Boot. The following segment of code from linux-2.6.25-rc9/drivers/mmc/host/at91_mci.c is confusing: if (host->board->wire4) { if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) mmc->caps |= MMC_CAP_4_BIT_DATA; else dev_warn(&pdev->dev, "4 wire bus mode not supported" " - using 1 wire\n"); } This code seems to imply that MMC 4 bits works on the AT91SAM9260 and AT91SAM9263, but not any of the others in this processor family, possibly due to a hardware bug. Any comments on why the Linux AT91 MCI driver doesn't support an 4 bit MMC bus for all AT91SAM9 processors? I mention this because it may impact the AT91 MCI U-Boot device driver. Sincerely, Ken Fuchs > -----Original Message----- > From: u-boot-users-bounces at lists.sourceforge.net > [mailto:u-boot-users-bounces at lists.sourceforge.net] On Behalf > Of Andy Fleming > Sent: Tuesday, April 15, 2008 14:25 > To: Pierre Savary > Cc: u-boot-users at lists.sourceforge.net; drzeus-mmc at drzeus.cx > Subject: Re: [U-Boot-Users] drivers MMCplus for at91sam9x > > > On Tue, Apr 15, 2008 at 5:18 AM, Pierre Savary > <pierre.savary@kerlink.fr> wrote: > > Then my MMC 4GB works with my Linux kernel but if I can't > load my kernel > > (located on the first part of this MMC) ... it's not > really interesting :( > > > > So, somebody does already use MMC v4 with U-boot??? > > I've got one that works. However, I don't have a 4GB MMC card with > v4. I thought I did, but it turned out the card just takes advantage > of the fact that older versions can address 4GB, even though the spec > says 2GB is the max. > > However, I'm fairly confident in the code (it's been tested in > simulated environments, and reflects what the Linux code does). I'm > currently working on bringing it forward to the top of tree (I started > it before drivers/ got rearranged). I'm actually hoping to generalize > it some so we can share it between all MMC/SD users. > > Andy > > -------------------------------------------------------------- > ----------- > This SF.net email is sponsored by the 2008 JavaOne(SM) Conference > Don't miss this year's exciting event. There's still time to > save $100. > Use priority code J8TL2D2. > http://ad.doubleclick.net/clk;198757673;13503038;p?http://java .sun.com/javaone _______________________________________________ U-Boot-Users mailing list U-Boot-Users at lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-15 19:25 ` Andy Fleming 2008-04-16 8:55 ` Pierre Savary 2008-04-16 23:30 ` Ken.Fuchs at bench.com @ 2008-04-22 11:55 ` Pierre Savary 2008-04-22 15:07 ` [U-Boot-Users] [PATCH] Add eSDHC driver Andy Fleming 2 siblings, 1 reply; 39+ messages in thread From: Pierre Savary @ 2008-04-22 11:55 UTC (permalink / raw) To: u-boot Hi Andy, Where could we find the driver that works with MMCv4 on at91sam9x? Best regards Pierre -----Message d'origine----- De?: u-boot-users-bounces at lists.sourceforge.net [mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de Andy Fleming Envoy??: mardi 15 avril 2008 21:25 ??: Pierre Savary Cc?: u-boot-users at lists.sourceforge.net; drzeus-mmc at drzeus.cx Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x On Tue, Apr 15, 2008 at 5:18 AM, Pierre Savary <pierre.savary@kerlink.fr> wrote: > Then my MMC 4GB works with my Linux kernel but if I can't load my kernel > (located on the first part of this MMC) ... it's not really interesting :( > > So, somebody does already use MMC v4 with U-boot??? I've got one that works. However, I don't have a 4GB MMC card with v4. I thought I did, but it turned out the card just takes advantage of the fact that older versions can address 4GB, even though the spec says 2GB is the max. However, I'm fairly confident in the code (it's been tested in simulated environments, and reflects what the Linux code does). I'm currently working on bringing it forward to the top of tree (I started it before drivers/ got rearranged). I'm actually hoping to generalize it some so we can share it between all MMC/SD users. Andy ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao ne _______________________________________________ U-Boot-Users mailing list U-Boot-Users at lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] [PATCH] Add eSDHC driver 2008-04-22 11:55 ` Pierre Savary @ 2008-04-22 15:07 ` Andy Fleming 2008-04-22 16:53 ` Anton Vorontsov 2008-04-23 19:23 ` Ken.Fuchs at bench.com 0 siblings, 2 replies; 39+ messages in thread From: Andy Fleming @ 2008-04-22 15:07 UTC (permalink / raw) To: u-boot This is the SD/MMC controller on several of Freescale's more recent parts --- > Hi Andy, > Where could we find the driver that works with MMCv4 on at91sam9x? > Best regards Pierre, I don't have a driver that works on at91sam9x, I'm afraid. I have a driver that nearly works on an mpc837x. However, some of it is certainly right, and that may help you. Also, some of it is wrong (I get intermittent failures on MMC cards), and maybe someone will look at this driver, and see what I'm doing wrong. Makefile | 2 + drivers/mmc/Makefile | 46 ++ drivers/mmc/fsl_esdhc.c | 1111 ++++++++++++++++++++++++++++++++++++ drivers/mmc/fsl_esdhc.h | 208 +++++++ include/asm-ppc/arch-mpc83xx/mmc.h | 1 + 5 files changed, 1368 insertions(+), 0 deletions(-) create mode 100644 drivers/mmc/Makefile create mode 100644 drivers/mmc/fsl_esdhc.c create mode 100644 drivers/mmc/fsl_esdhc.h create mode 100644 include/asm-ppc/arch-mpc83xx/mmc.h diff --git a/Makefile b/Makefile index e5b4210..cd614a5 100644 --- a/Makefile +++ b/Makefile @@ -214,6 +214,7 @@ LIBS += drivers/hwmon/libhwmon.a LIBS += drivers/i2c/libi2c.a LIBS += drivers/input/libinput.a LIBS += drivers/misc/libmisc.a +LIBS += drivers/mmc/libmmc.a LIBS += drivers/mtd/libmtd.a LIBS += drivers/mtd/nand/libnand.a LIBS += drivers/mtd/nand_legacy/libnand_legacy.a @@ -383,6 +384,7 @@ TAG_SUBDIRS += drivers/hwmon TAG_SUBDIRS += drivers/i2c TAG_SUBDIRS += drivers/input TAG_SUBDIRS += drivers/misc +TAG_SUBDIRS += drivers/mmc TAG_SUBDIRS += drivers/mtd TAG_SUBDIRS += drivers/mtd/nand TAG_SUBDIRS += drivers/mtd/nand_legacy diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile new file mode 100644 index 0000000..06e4e88 --- /dev/null +++ b/drivers/mmc/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd at denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB := $(obj)libmmc.a + +COBJS-y += fsl_esdhc.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c new file mode 100644 index 0000000..29af92a --- /dev/null +++ b/drivers/mmc/fsl_esdhc.c @@ -0,0 +1,1111 @@ +/* + * Copyright 2007, Freescale Semiconductor, Inc + * Andy Fleming + * + * Based vaguely on the pxa mmc code: + * (C) Copyright 2003 + * Kyle Harris, Nexus Technologies, Inc. kharris at nexus-tech.net + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> +#include <common.h> +#include <command.h> +#include <mmc.h> +#include <part.h> +#include <malloc.h> +#include <asm/io.h> + +#include "fsl_esdhc.h" + +#ifdef CONFIG_MMC +DECLARE_GLOBAL_DATA_PTR; + +struct fsl_esdhc { + uint dsaddr; + uint blkattr; + uint cmdarg; + uint xfertyp; + uint cmdrsp0; + uint cmdrsp1; + uint cmdrsp2; + uint cmdrsp3; + uint datport; + uint prsstat; + uint proctl; + uint sysctl; + uint irqstat; + uint irqstaten; + uint irqsigen; + uint autoc12err; + uint hostcapblt; + uint wml; + char reserved1[8]; + uint fevt; + char reserved2[168]; + uint hostver; + char reserved3[780]; + uint scr; +}; + +enum { + MMC_CMD_RSP_NONE, + MMC_CMD_R1 = 1, + MMC_CMD_R1b, + MMC_CMD_R2, + MMC_CMD_R3, + MMC_CMD_R4, + MMC_CMD_R5, + MMC_CMD_R5b, + MMC_CMD_R6, + MMC_CMD_R7 +}; + +uint xfertyps[] = { + XFERTYP_RSPTYP_NONE, + XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN, + XFERTYP_RSPTYP_48_BUSY | XFERTYP_CICEN | XFERTYP_CCCEN, + XFERTYP_RSPTYP_136 | XFERTYP_CCCEN, + XFERTYP_RSPTYP_48, + XFERTYP_RSPTYP_48, + XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN, + XFERTYP_RSPTYP_48_BUSY | XFERTYP_CICEN | XFERTYP_CCCEN, + XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN, + XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN +}; + +struct mmc { + volatile void * regs; + uint version; + int high_capacity; + uint mode; + uint ocr; + uint scr[2]; + uint csd[4]; + char cid[16]; + ushort rca; + uint tran_speed; + uint read_bl_len; + uint write_bl_len; + u64 capacity; + block_dev_desc_t block_dev; +}; + +static struct mmc *mmc_dev; + +block_dev_desc_t *mmc_get_dev(int dev) +{ + return (dev == 0) ? &mmc_dev->block_dev : NULL; +} + +struct mmc_cmd { + ushort cmdidx; + int resp_type; + uint cmdarg; + char response[18]; + uint flags; +}; + +struct mmc_data { + char * buffer; + uint flags; + int blocks; + int blocksize; +}; + +/* Return the XFERTYP flags for a given command and data packet */ +uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) +{ + uint xfertyp = 0; + + if (data) { + xfertyp |= XFERTYP_DPSEL | XFERTYP_DMAEN; + + if (data->blocks > 1) { + xfertyp |= XFERTYP_MSBSEL; + xfertyp |= XFERTYP_BCEN; + } + + if (data->flags & MMC_DATA_READ) + xfertyp |= XFERTYP_DTDSEL; + } + + xfertyp |= xfertyps[cmd->resp_type]; + + return xfertyp; +} + + +/* + * Sends a command out on the bus. Takes the mmc pointer, + * a command pointer, and an optional data pointer. + */ +static int +mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +{ + uint xfertyp; + uint irqstat; + volatile struct fsl_esdhc *regs = mmc->regs; + + regs->irqstat = -1; + + sync(); + + /* Wait for the bus to be idle */ + while ((regs->prsstat & PRSSTAT_CICHB) || + (regs->prsstat & PRSSTAT_CIDHB)) + sync(); + + while (regs->prsstat & PRSSTAT_DLA) + sync(); + + /* Wait at least 8 SD clock cycles before the next command */ + /* + * Note: This is way more than 8 cycles, but 1ms seems to + * resolve timing issues with some cards + */ + udelay(1000); + + /* Set up for a data transfer if we have one */ + if (data) { + uint wml_value; + int timeout; + + wml_value = data->blocksize/4; + + if (data->flags & MMC_DATA_READ) { + if (wml_value > 0x10) + wml_value = 0x10; + + wml_value = 0x100000 | wml_value; + } else { + if (wml_value > 0x80) + wml_value = 0x80; + + wml_value = wml_value << 16 | 0x10; + } + + regs->dsaddr = (uint)data->buffer; + + sync(); + + regs->wml = wml_value; + + sync(); + + regs->blkattr = data->blocks << 16 | data->blocksize; + + sync(); + + timeout = __ilog2(mmc->tran_speed/10); + timeout -= 13; + + if (timeout > 14) + timeout = 14; + + if (timeout < 0) + timeout = 0; + + regs->sysctl &= ~0x000f0000; + + sync(); + + regs->sysctl |= timeout << 16; + + sync(); + } + + /* Figure out the transfer arguments */ + xfertyp = esdhc_xfertyp(cmd, data); + + /* Send the command */ + regs->cmdarg = cmd->cmdarg; + sync(); + regs->xfertyp = XFERTYP_CMD(cmd->cmdidx) | xfertyp; + + sync(); + /* Wait for the command to complete */ + while (!(regs->irqstat & IRQSTAT_CC)) + sync(); + + irqstat = regs->irqstat; + + sync(); + + regs->irqstat = irqstat; + + sync(); + + if (irqstat & CMD_ERR) + return COMM_ERR; + + if (irqstat & IRQSTAT_CTOE) + return TIMEOUT; + + /* Copy the response to the response buffer */ + if (cmd->resp_type == MMC_CMD_R2) { + ((uint *)(cmd->response))[0] = + (regs->cmdrsp3 << 8) | (regs->cmdrsp2 >> 24); + ((uint *)(cmd->response))[1] = + (regs->cmdrsp2 << 8) | (regs->cmdrsp1 >> 24); + ((uint *)(cmd->response))[2] = + (regs->cmdrsp1 << 8) | (regs->cmdrsp0 >> 24); + ((uint *)(cmd->response))[3] = (regs->cmdrsp0 << 8); + } else + ((uint *)(cmd->response))[0] = regs->cmdrsp0; + + /* Wait until all of the blocks are transferred */ + if (data) { + do { + irqstat = regs->irqstat; + + if (irqstat & DATA_ERR) + return COMM_ERR; + + if (irqstat & IRQSTAT_DTOE) + return TIMEOUT; + sync(); + } while (!(irqstat & IRQSTAT_TC) && + (regs->prsstat & PRSSTAT_DLA)); + } + + regs->irqstat = -1; + sync(); + + return 0; +} + +void set_sysctl(struct mmc *mmc, int clock) +{ + int sdhc_clk = gd->sdhc_clk; + int div, pre_div; + volatile struct fsl_esdhc *regs = mmc->regs; + uint clk; + + if (sdhc_clk / 16 > clock) { + for (pre_div = 2; pre_div < 256; pre_div *= 2) + if ((sdhc_clk / pre_div) <= (clock * 16)) + break; + } else + pre_div = 2; + + for (div = 1; div <= 16; div++) + if ((sdhc_clk / (div * pre_div)) <= clock) + break; + + pre_div >>= 1; + div -= 1; + + clk = (pre_div << 8) | (div << 4); + regs->sysctl &= ~0x0000fff0; + sync(); + regs->sysctl |= clk; + sync(); + + udelay(10000); + + regs->sysctl |= SYSCTL_PEREN; +} + + +int +mmc_block_write(ulong dst, uchar *src, int len) +{ +#warning write not yet implemented + return 0; +} + +int mmc_set_blocklen(struct mmc *mmc, int len) +{ + struct mmc_cmd cmd; + + cmd.cmdidx = SET_BLOCKLEN; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = len; + cmd.flags = 0; + + return mmc_send_cmd(mmc, &cmd, NULL); +} + +int +mmc_read(ulong src, uchar *dst, int size) +{ + struct mmc_cmd cmd; + struct mmc_data data; + int err; + char * buffer; + int stoperr = 0; + struct mmc *mmc = mmc_dev; + int blklen = mmc->read_bl_len; + int startblock = src / blklen; + int endblock = (src + size - 1) / blklen; + int blkcnt = endblock - startblock + 1; + + /* Make a buffer big enough to hold all the blocks we might read */ + buffer = malloc(blkcnt * blklen); + + if (!buffer) { + printf("Could not allocate buffer for MMC read!\n"); + return -1; + } + +#warning deal with larger reads (more than 65536 blks) and partial block reads + /* We only support full block reads from the card */ + err = mmc_set_blocklen(mmc, mmc->read_bl_len); + + if (err) + return err; + + if (blkcnt > 1) + cmd.cmdidx = READ_MULTIPLE_BLOCKS; + else + cmd.cmdidx = READ_SINGLE_BLOCK; + + if (mmc->high_capacity) + cmd.cmdarg = startblock; + else + cmd.cmdarg = startblock * blklen; + + cmd.resp_type = MMC_CMD_R1; + cmd.flags = 0; + + data.buffer = buffer; + data.blocks = blkcnt; + data.blocksize = blklen; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + + if (blkcnt > 1) { + cmd.cmdidx = STOP_TRANSMISSION; + cmd.cmdarg = 0; + cmd.resp_type = MMC_CMD_R1b; + cmd.flags = 0; + stoperr = mmc_send_cmd(mmc, &cmd, NULL); + } + + + if (err) + return err; + + memcpy(dst, buffer + (src & (blklen - 1)), size); + + free(buffer); + + return stoperr; +} + +int +mmc_write(uchar *src, ulong dst, int size) +{ + return 0; +} + +ulong +mmc_bread(int dev_num, ulong blknr, ulong blkcnt, void *dst) +{ + int err; + ulong src = blknr * mmc_dev->read_bl_len; + + err = mmc_read(src, dst, blkcnt * mmc_dev->read_bl_len); + + if (err) { + printf("block read failed: %d\n", err); + return 0; + } + + return blkcnt; +} + +int mmc_go_idle(struct mmc* mmc) +{ + struct mmc_cmd cmd; + int err; + + udelay(1000); + + cmd.cmdidx = GO_IDLE_STATE; + cmd.cmdarg = 0; + cmd.resp_type = MMC_CMD_RSP_NONE; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + udelay(2000); + + return 0; +} + +int +sd_send_op_cond(struct mmc *mmc) +{ + int timeout = 1000; + int err; + struct mmc_cmd cmd; + + do { + cmd.cmdidx = APP_CMD; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 0; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + cmd.cmdidx = SD_SEND_OP_COND; + cmd.resp_type = MMC_CMD_R3; + cmd.cmdarg = 0xff8000; + + if (mmc->version == SD_VERSION_2) + cmd.cmdarg |= 0x40000000; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + udelay(1000); + } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--); + + if (timeout <= 0) + return UNUSABLE_ERR; + + if (mmc->version != SD_VERSION_2) + mmc->version = SD_VERSION_1_0; + + mmc->ocr = ((uint *)(cmd.response))[0]; + + mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); + mmc->rca = 0; + + return 0; +} + +int mmc_send_op_cond(struct mmc *mmc) +{ + int timeout = 1000; + struct mmc_cmd cmd; + int err; + + /* Some cards seem to need this */ + mmc_go_idle(mmc); + + do { + cmd.cmdidx = MMC_SEND_OP_COND; + cmd.resp_type = MMC_CMD_R3; + cmd.cmdarg = 0x40ff8000; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + udelay(1000); + } while (!(cmd.response[0] & OCR_BUSY) && timeout--); + + if (timeout <= 0) + return UNUSABLE_ERR; + + mmc->version = MMC_VERSION_UNKNOWN; + mmc->ocr = ((uint *)(cmd.response))[0]; + + mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); + mmc->rca = 0; + + return 0; +} + + +int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd) +{ + struct mmc_cmd cmd; + struct mmc_data data; + int err; + + /* Get the Card Status Register */ + cmd.cmdidx = SEND_EXT_CSD; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 0; + cmd.flags = 0; + + data.buffer = ext_csd; + data.blocks = 1; + data.blocksize = 512; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + + return err; +} + + +int mmc_change_freq(struct mmc *mmc) +{ + struct mmc_cmd cmd; + char ext_csd[512]; + char cardtype; + int err; + + mmc->mode = 0; + + /* Only version 4 supports high-speed */ + if (mmc->version < MMC_VERSION_4) + return 0; + + mmc->mode |= MMC_MODE_4BIT; + + err = mmc_send_ext_csd(mmc, ext_csd); + + if (err) + return err; + + if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215]) + mmc->high_capacity = 1; + + cardtype = ext_csd[196] & 0xf; + + /* Set the card to use High Speed */ + cmd.cmdidx = MMC_SWITCH; + cmd.resp_type = MMC_CMD_R1b; + cmd.cmdarg = 0x1b90100; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + /* Now check to see that it worked */ + err = mmc_send_ext_csd(mmc, ext_csd); + + if (err) + return err; + + /* No high-speed support */ + if (!ext_csd[185]) + return 0; + + /* High Speed is set, there are two types: 52MHz and 26MHz */ + if (cardtype & MMC_HS_52MHZ) + mmc->mode |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + else + mmc->mode |= MMC_MODE_HS; + + return 0; +} + +int sd_change_freq(struct mmc *mmc) +{ + int err; + struct mmc_cmd cmd; + uint scr[2]; + uint switch_status[16]; + struct mmc_data data; + int timeout; + + mmc->mode = 0; + + /* Read the SCR to find out if this card supports higher speeds */ + cmd.cmdidx = APP_CMD; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = mmc->rca << 16; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + cmd.cmdidx = SEND_SCR; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 0; + cmd.flags = 0; + + timeout = 3; + +retry_scr: + data.buffer = (char *)&scr; + data.blocksize = 8; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + + if (err) { + if (timeout--) + goto retry_scr; + + return err; + } + + mmc->scr[0] = scr[0]; + mmc->scr[1] = scr[1]; + + switch ((mmc->scr[0] >> 24) & 0xf) { + case 0: + mmc->version = SD_VERSION_1_0; + break; + case 1: + mmc->version = SD_VERSION_1_10; + break; + case 2: + mmc->version = SD_VERSION_2; + break; + default: + mmc->version = SD_VERSION_1_0; + break; + } + + /* Version 1.0 doesn't support switching */ + if (mmc->version == SD_VERSION_1_0) + return 0; + + timeout = 4; + while (timeout--) { + /* Switch the frequency */ + cmd.cmdidx = SWITCH_FUNC; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 0xfffff1; + cmd.flags = 0; + + data.buffer = (char *)&switch_status; + data.blocksize = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + + if (err) + return err; + + /* The high-speed function is busy. Try again */ + if (!switch_status[7] & SD_HIGHSPEED_BUSY) + break; + } + + if (mmc->scr[0] & SD_DATA_4BIT) + mmc->mode |= MMC_MODE_4BIT; + + /* If high-speed isn't supported, we return */ + if (!(switch_status[3] & SD_HIGHSPEED_SUPPORTED)) + return 0; + + cmd.cmdidx = SWITCH_FUNC; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 0x80fffff1; + cmd.flags = 0; + + data.buffer = (char *)&switch_status; + data.blocksize = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + + if (err) + return err; + + if ((switch_status[4] & 0x0f000000) == 0x01000000) + mmc->mode |= MMC_MODE_HS; + + return 0; +} + +/* frequency bases */ +/* divided by 10 to be nice to platforms without floating point */ +int fbase[] = { + 10000, + 100000, + 1000000, + 10000000, +}; + +/* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice + * to platforms without floating point. + */ +int multipliers[] = { + 0, /* reserved */ + 10, + 12, + 13, + 15, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 55, + 60, + 70, + 80, +}; + + +int mmc_startup(struct mmc *mmc) +{ + int err; + uint mult, freq; + uint cmult, csize; + struct mmc_cmd cmd; + volatile struct fsl_esdhc *regs = mmc->regs; + + /* Put the Card in Identify Mode */ + cmd.cmdidx = ALL_SEND_CID; + cmd.resp_type = MMC_CMD_R2; + cmd.cmdarg = 0; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + memcpy(mmc->cid, cmd.response, 16); + + /* + * For MMC cards, set the Relative Address. + * For SD cards, get the Relatvie Address. + * This also puts the cards into Standby State + */ + cmd.cmdidx = SEND_RELATIVE_ADDR; + cmd.cmdarg = mmc->rca << 16; + cmd.resp_type = MMC_CMD_R6; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + if (IS_SD(mmc)) + mmc->rca = (((uint *)(cmd.response))[0] >> 16) & 0xffff; + + /* Get the Card-Specific Data */ + cmd.cmdidx = SEND_CSD; + cmd.resp_type = MMC_CMD_R2; + cmd.cmdarg = mmc->rca << 16; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + mmc->csd[0] = ((uint *)(cmd.response))[0]; + mmc->csd[1] = ((uint *)(cmd.response))[1]; + mmc->csd[2] = ((uint *)(cmd.response))[2]; + mmc->csd[3] = ((uint *)(cmd.response))[3]; + + if (mmc->version == MMC_VERSION_UNKNOWN) { + int version = (cmd.response[0] >> 2) & 0xf; + + switch (version) { + case 0: + mmc->version = MMC_VERSION_1_2; + break; + case 1: + mmc->version = MMC_VERSION_1_4; + break; + case 2: + mmc->version = MMC_VERSION_2_2; + break; + case 3: + mmc->version = MMC_VERSION_3; + break; + case 4: + mmc->version = MMC_VERSION_4; + break; + default: + mmc->version = MMC_VERSION_1_2; + break; + } + } + + /* divide frequency by 10, since the mults are 10x bigger */ + freq = fbase[(cmd.response[3] & 0x7)]; + mult = multipliers[((cmd.response[3] >> 3) & 0xf)]; + + mmc->tran_speed = freq * mult; + + mmc->read_bl_len = 1 << ((((uint *)(cmd.response))[1] >> 16) & 0xf); + + if (IS_SD(mmc)) + mmc->write_bl_len = mmc->read_bl_len; + else + mmc->write_bl_len = 1 << ((((uint *)(cmd.response))[3] >> 22) & 0xf); + + csize = (mmc->csd[1] & 0x3ff) << 2 | (mmc->csd[2] & 0xc0000000) >> 30; + cmult = (mmc->csd[2] & 0x00038000) >> 15; + + mmc->capacity = (csize + 1) << (cmult + 2); + mmc->capacity *= mmc->read_bl_len; + + if (mmc->read_bl_len > 512) + mmc->read_bl_len = 512; + + if (mmc->write_bl_len > 512) + mmc->write_bl_len = 512; + + /* Select the card, and put it into Transfer Mode */ + cmd.cmdidx = SELECT_CARD; + cmd.resp_type = MMC_CMD_R1b; + cmd.cmdarg = mmc->rca << 16; + cmd.flags = 0; + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + if (IS_SD(mmc)) + err = sd_change_freq(mmc); + else + err = mmc_change_freq(mmc); + + if (err) + return err; + + if (IS_SD(mmc)) { + if (mmc->mode & MMC_MODE_4BIT) { + cmd.cmdidx = APP_CMD; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = mmc->rca << 16; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + return err; + + cmd.cmdidx = SET_BUS_WIDTH; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 2; + cmd.flags = 0; + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + return err; + + regs->proctl |= PROCTL_DTW_4; + } + + if (mmc->mode & MMC_MODE_HS) + set_sysctl(mmc, 50000000); + else + set_sysctl(mmc, 25000000); + } else { + if (mmc->mode & MMC_MODE_4BIT) { + /* Set the card to use 4 bit*/ + cmd.cmdidx = MMC_SWITCH; + cmd.resp_type = MMC_CMD_R1b; + cmd.cmdarg = 0x1b70100; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + regs->proctl |= PROCTL_DTW_4; + } else if (mmc->mode & MMC_MODE_8BIT) { + /* Set the card to use 8 bit*/ + cmd.cmdidx = MMC_SWITCH; + cmd.resp_type = MMC_CMD_R1b; + cmd.cmdarg = 0x1b70200; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + regs->proctl |= PROCTL_DTW_8; + } + + if (mmc->mode & MMC_MODE_HS) { + if (mmc->mode & MMC_MODE_HS_52MHz) + set_sysctl(mmc, 52000000); + else + set_sysctl(mmc, 26000000); + } else + set_sysctl(mmc, 20000000); + } + + /* fill in device description */ + mmc->block_dev.if_type = IF_TYPE_MMC; + mmc->block_dev.part_type = PART_TYPE_DOS; + mmc->block_dev.dev = 0; + mmc->block_dev.lun = 0; + mmc->block_dev.type = 0; + mmc->block_dev.blksz = mmc->read_bl_len; + mmc->block_dev.lba = mmc->capacity/mmc->read_bl_len; + sprintf(mmc->block_dev.vendor,"Man %02x%02x%02x Snr %02x%02x%02x%02x", + mmc->cid[0], mmc->cid[1], mmc->cid[2], + mmc->cid[9], mmc->cid[10], mmc->cid[11], mmc->cid[12]); + sprintf(mmc->block_dev.product,"%c%c%c%c%c", mmc->cid[3], + mmc->cid[4], mmc->cid[5], mmc->cid[6], mmc->cid[7]); + sprintf(mmc->block_dev.revision,"%d.%d", mmc->cid[8] >> 4, + mmc->cid[8] & 0xf); + mmc->block_dev.removable = 1; + mmc->block_dev.block_read = mmc_bread; + + init_part(&mmc->block_dev); + + return 0; +} + +int mmc_send_if_cond(struct mmc *mmc) +{ + struct mmc_cmd cmd; + int err; + + cmd.cmdidx = SEND_IF_COND; + cmd.cmdarg = 0x1aa; + cmd.resp_type = MMC_CMD_R7; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + if (((uint *)(cmd.response))[0] != 0x1aa) + return UNUSABLE_ERR; + else + mmc->version = SD_VERSION_2; + + return 0; +} + +int +mmc_init(int verbose) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + struct fsl_esdhc *regs = (struct fsl_esdhc *)&im->sdhc; + int timeout = 1000; + struct mmc *mmc; + int err; + + mmc = malloc(sizeof(struct mmc)); + + mmc->regs = regs; + + if (mmc_dev) + free(mmc_dev); + + mmc_dev = mmc; + + regs->sysctl = SYSCTL_HCKEN | SYSCTL_IPGEN; + + /* Set the clock speed */ + set_sysctl(mmc, 400000); + + /* Disable the BRR and BWR bits in IRQSTAT */ + regs->irqstaten &= ~(IRQSTATEN_BRR | IRQSTATEN_BWR); + + /* Put the PROCTL reg back to the default */ + regs->proctl = PROCTL_INIT; + + while (!(regs->prsstat & PRSSTAT_CINS) && timeout--) + udelay(1000); + + if (timeout <= 0) + return NO_CARD_ERR; + + /* Reset the Card */ + err = mmc_go_idle(mmc); + + if (err) + return err; + + /* Test for SD version 2 */ + err = mmc_send_if_cond(mmc); + + /* If we got an error other than timeout, we bail */ + if (err && err != TIMEOUT) + return err; + + /* Now try to get the SD card's operating condition */ + err = sd_send_op_cond(mmc); + + /* If the command timed out, we check for an MMC card */ + if (err == TIMEOUT) { + err = mmc_send_op_cond(mmc); + + if (err) { + printf("Card did not respond to voltage select!\n"); + return UNUSABLE_ERR; + } + } + + err = mmc_startup(mmc); + + if (err) + printf("Returning with err %d\n", err); + + return err; +} + +int +mmc2info(ulong addr) +{ + /* Hmm... */ + return 0; +} + +static void print_mmcinfo(struct mmc *mmc) +{ + printf("Manufacturer: %x\n", mmc->cid[0] >> 24); + printf("OEM: %x\n", (mmc->cid[0] >> 8) & 0xffff); + printf("Name: %c%c%c%c%c\n", mmc->cid[0] & 0xff, + (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, + (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff); + + printf("Tran Speed: %d\n", mmc->tran_speed); + printf("Rd Block Len: %d\n", mmc->read_bl_len); + + printf("%s version %d.%d\n", IS_SD(mmc) ? "SD" : "MMC", + (mmc->version >> 4) & 0xf, mmc->version & 0xf); + + printf("High Capacity: %s\n", mmc->high_capacity ? "Yes" : "No"); + printf("Capacity: %d\n", mmc->capacity); + + printf("Bus Width: %d-bit\n", (mmc->mode & MMC_MODE_4BIT) ? 4 : + (mmc->mode & MMC_MODE_8BIT) ? 8 : 1); +} + +int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + if (mmc_dev) + print_mmcinfo(mmc_dev); + else + printf("Call mmcinit first\n"); + + return 0; +} + +U_BOOT_CMD(mmcinfo, 1, 0, do_mmcinfo, "mmcinfo -- display MMC info\n", NULL); + +#endif /* CONFIG_MMC */ diff --git a/drivers/mmc/fsl_esdhc.h b/drivers/mmc/fsl_esdhc.h new file mode 100644 index 0000000..cf5f2d1 --- /dev/null +++ b/drivers/mmc/fsl_esdhc.h @@ -0,0 +1,208 @@ +/* + * FSL SD/MMC Defines + *------------------------------------------------------------------- + * + * Copyright 2007-2008, Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + *------------------------------------------------------------------- + * + */ + +#ifndef __FSL_ESDHC_H__ +#define __FSL_ESDHC_H__ + +#define SD_VERSION_SD 0x20000 +#define SD_VERSION_2 (SD_VERSION_SD | 0x20) +#define SD_VERSION_1_0 (SD_VERSION_SD | 0x10) +#define SD_VERSION_1_10 (SD_VERSION_SD | 0x1a) +#define MMC_VERSION_MMC 0x10000 +#define MMC_VERSION_UNKNOWN (MMC_VERSION_MMC) +#define MMC_VERSION_1_2 (MMC_VERSION_MMC | 0x12) +#define MMC_VERSION_1_4 (MMC_VERSION_MMC | 0x14) +#define MMC_VERSION_2_2 (MMC_VERSION_MMC | 0x22) +#define MMC_VERSION_3 (MMC_VERSION_MMC | 0x30) +#define MMC_VERSION_4 (MMC_VERSION_MMC | 0x40) + +#define MMC_MODE_HS 0x001 +#define MMC_MODE_HS_52MHz 0x010 +#define MMC_MODE_4BIT 0x100 +#define MMC_MODE_8BIT 0x200 + +#define SD_DATA_4BIT 0x00040000 + +#define IS_SD(x) (mmc->version & SD_VERSION_SD) + +#define MMC_DATA_READ 1 +#define MMC_DATA_WRITE 2 + +#define NO_CARD_ERR -16 /* No SD/MMC card inserted */ +#define UNUSABLE_ERR -17 /* Unusable Card */ +#define COMM_ERR -18 /* Communications Error */ +#define TIMEOUT -19 + +#define GO_IDLE_STATE 0x0 +#define SEND_IF_COND (8) + +#define APP_CMD (55) + +#define MMC_SEND_OP_COND (1) + +#define SD_SEND_OP_COND (41) + +#define ALL_SEND_CID (2) + +#define SEND_RELATIVE_ADDR (3) + +#define SELECT_CARD (7) + +#define SEND_SCR (51) + +#define SEND_EXT_CSD (8) + +#define SEND_CSD (9) + +#define SEND_STATUS (13) + +#define SWITCH_FUNC (6) +#define MMC_SWITCH (6) + +#define SET_BUS_WIDTH (6) + +#define STOP_TRANSMISSION (12) + +#define SET_BLOCKLEN (16) + +#define READ_SINGLE_BLOCK (17) +#define READ_MULTIPLE_BLOCKS (18) + +#define SD_HIGHSPEED_BUSY 0x00020000 +#define SD_HIGHSPEED_SUPPORTED 0x00020000 + +#define MMC_HS_TIMING 0x00000100 +#define MMC_HS_52MHZ 0x2 + +#define OCR_BUSY 0x80 +#define OCR_HCS 0x40000000 + +/* FSL eSDHC-specific constants */ +#define SYSCTL 0x0002e02c +#define SYSCTL_INITA 0x08000000 +#define SYSCTL_PEREN 0x00000004 +#define SYSCTL_HCKEN 0x00000002 +#define SYSCTL_IPGEN 0x00000001 + +#define IRQSTAT 0x0002e030 +#define IRQSTAT_DMAE (0x10000000) +#define IRQSTAT_AC12E (0x01000000) +#define IRQSTAT_DEBE (0x00400000) +#define IRQSTAT_DCE (0x00200000) +#define IRQSTAT_DTOE (0x00100000) +#define IRQSTAT_CIE (0x00080000) +#define IRQSTAT_CEBE (0x00040000) +#define IRQSTAT_CCE (0x00020000) +#define IRQSTAT_CTOE (0x00010000) +#define IRQSTAT_CINT (0x00000100) +#define IRQSTAT_CRM (0x00000080) +#define IRQSTAT_CINS (0x00000040) +#define IRQSTAT_BRR (0x00000020) +#define IRQSTAT_BWR (0x00000010) +#define IRQSTAT_DINT (0x00000008) +#define IRQSTAT_BGE (0x00000004) +#define IRQSTAT_TC (0x00000002) +#define IRQSTAT_CC (0x00000001) + +#define CMD_ERR (IRQSTAT_CIE | IRQSTAT_CEBE | IRQSTAT_CCE) +#define DATA_ERR (IRQSTAT_DEBE | IRQSTAT_DCE | IRQSTAT_DTOE) + +#define IRQSTATEN 0x0002e034 +#define IRQSTATEN_DMAE (0x10000000) +#define IRQSTATEN_AC12E (0x01000000) +#define IRQSTATEN_DEBE (0x00400000) +#define IRQSTATEN_DCE (0x00200000) +#define IRQSTATEN_DTOE (0x00100000) +#define IRQSTATEN_CIE (0x00080000) +#define IRQSTATEN_CEBE (0x00040000) +#define IRQSTATEN_CCE (0x00020000) +#define IRQSTATEN_CTOE (0x00010000) +#define IRQSTATEN_CINT (0x00000100) +#define IRQSTATEN_CRM (0x00000080) +#define IRQSTATEN_CINS (0x00000040) +#define IRQSTATEN_BRR (0x00000020) +#define IRQSTATEN_BWR (0x00000010) +#define IRQSTATEN_DINT (0x00000008) +#define IRQSTATEN_BGE (0x00000004) +#define IRQSTATEN_TC (0x00000002) +#define IRQSTATEN_CC (0x00000001) + +#define PRSSTAT 0x0002e024 +#define PRSSTAT_CLSL (0x00800000) +#define PRSSTAT_WPSPL (0x00080000) +#define PRSSTAT_CDPL (0x00040000) +#define PRSSTAT_CINS (0x00010000) +#define PRSSTAT_BREN (0x00000800) +#define PRSSTAT_DLA (0x00000004) +#define PRSSTAT_CICHB (0x00000002) +#define PRSSTAT_CIDHB (0x00000001) + +#define PROCTL 0x0002e028 +#define PROCTL_INIT 0x00000020 +#define PROCTL_DTW_4 0x00000002 +#define PROCTL_DTW_8 0x00000004 + +#define CMDARG 0x0002e008 + +#define XFERTYP 0x0002e00c +#define XFERTYP_CMD(x) ((x & 0x3f) << 24) +#define XFERTYP_CMDTYP_NORMAL 0x0 +#define XFERTYP_CMDTYP_SUSPEND 0x00400000 +#define XFERTYP_CMDTYP_RESUME 0x00800000 +#define XFERTYP_CMDTYP_ABORT 0x00c00000 +#define XFERTYP_DPSEL 0x00200000 +#define XFERTYP_CICEN 0x00100000 +#define XFERTYP_CCCEN 0x00080000 +#define XFERTYP_RSPTYP_NONE 0 +#define XFERTYP_RSPTYP_136 0x00010000 +#define XFERTYP_RSPTYP_48 0x00020000 +#define XFERTYP_RSPTYP_48_BUSY 0x00030000 +#define XFERTYP_MSBSEL 0x00000020 +#define XFERTYP_DTDSEL 0x00000010 +#define XFERTYP_AC12EN 0x00000004 +#define XFERTYP_BCEN 0x00000002 +#define XFERTYP_DMAEN 0x00000001 + +#define CINS_TIMEOUT 1000 + +#define DSADDR 0x2e004 + +#define CMDRSP0 0x2e010 +#define CMDRSP1 0x2e014 +#define CMDRSP2 0x2e018 +#define CMDRSP3 0x2e01c + +#define DATPORT 0x2e020 + +#define WML 0x2e044 +#define WML_WRITE 0x00010000 + +#define BLKATTR 0x2e004 +#define BLKATTR_CNT(x) ((x & 0xffff) << 16) +#define BLKATTR_SIZE(x) (x & 0x1fff) +#define MAX_BLK_CNT 0x7fff /* so malloc will have enough room with 32M */ + + +#endif /* __FSL_ESDHC_H__ */ diff --git a/include/asm-ppc/arch-mpc83xx/mmc.h b/include/asm-ppc/arch-mpc83xx/mmc.h new file mode 100644 index 0000000..d5034f4 --- /dev/null +++ b/include/asm-ppc/arch-mpc83xx/mmc.h @@ -0,0 +1 @@ +/* Stub file to satisfy odd requirement for <arch/mmc.h> */ -- 1.5.4.GIT ^ permalink raw reply related [flat|nested] 39+ messages in thread
* [U-Boot-Users] [PATCH] Add eSDHC driver 2008-04-22 15:07 ` [U-Boot-Users] [PATCH] Add eSDHC driver Andy Fleming @ 2008-04-22 16:53 ` Anton Vorontsov 2008-04-23 19:23 ` Ken.Fuchs at bench.com 1 sibling, 0 replies; 39+ messages in thread From: Anton Vorontsov @ 2008-04-22 16:53 UTC (permalink / raw) To: u-boot On Tue, Apr 22, 2008 at 10:07:46AM -0500, Andy Fleming wrote: > This is the SD/MMC controller on several of Freescale's more recent parts Cool. Is there Linux version pending? Does anybody working on it yet? Thanks. -- Anton Vorontsov email: cbouatmailru at gmail.com irc://irc.freenode.net/bd2 ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] [PATCH] Add eSDHC driver 2008-04-22 15:07 ` [U-Boot-Users] [PATCH] Add eSDHC driver Andy Fleming 2008-04-22 16:53 ` Anton Vorontsov @ 2008-04-23 19:23 ` Ken.Fuchs at bench.com 2008-04-24 6:24 ` Pierre Savary 1 sibling, 1 reply; 39+ messages in thread From: Ken.Fuchs at bench.com @ 2008-04-23 19:23 UTC (permalink / raw) To: u-boot > Pierre Savary wrote: > >Where could we find the driver that works with MMCv4 on at91sam9x? Andy Fleming wrote: > Pierre, I don't have a driver that works on at91sam9x, I'm > afraid. Here's an MMC v2.x AT91SAM9260 patch for Atmel modified u-boot 1.1.5. You will need to define GPIO pins for other AT91SAM9 processors, etc. If you really need an MMC v4.x AT91SAM9 MCI driver for 1.1.5 fast, you probably could cut and paste the v4.x code you need from Andy's MMC driver into the MMC v2.x MCI driver this patch provides. BTW, if anyone knows why MMC 4 bit is disabled for AT91SAM9261 in the MCI Linux driver, I'd like to hear the reasons why. --- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) --- diff -burN u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c --- u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c 2007-08-23 08:37:42.000000000 +0200 @@ -109,6 +109,24 @@ } +#ifdef CONFIG_MMC +#if (CONFIG_COMMANDS & CFG_CMD_MMC) +int AT91F_MMC_Hardware_Init(void) +{ + AT91C_BASE_PIOA->PIO_ASR = (1 << 8 ); /* periph A select register */ + AT91C_BASE_PIOA->PIO_BSR |= 0x3B; /* periph B select register */ + AT91C_BASE_PIOA->PIO_PDR |= 0x13B; /* PIO disable register */ + AT91C_BASE_PIOA->PIO_PPUDR |= 0x13B; /* Pull up disable register */ + + AT91C_BASE_PMC->PMC_PCER = (1 << 9); +} +#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */ +#endif /* CONFIG_MMC */ + + + + + #ifdef CONFIG_DRIVER_ETHER #if (CONFIG_COMMANDS & CFG_CMD_NET) diff -burN u-boot-1.1.5/common/cmd_nvedit.c u-boot-1.1.5.klk/common/cmd_nvedit.c --- u-boot-1.1.5/common/cmd_nvedit.c 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/common/cmd_nvedit.c 2007-08-23 09:26:18.000000000 +0200 @@ -530,6 +530,7 @@ return (-1); } +#ifndef CFG_ENV_IS_NOWHERE #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \ ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \ (CFG_CMD_ENV|CFG_CMD_FLASH)) || \ @@ -544,7 +545,7 @@ return (saveenv() ? 1 : 0); } - +#endif #endif @@ -587,7 +588,7 @@ "setenv name\n" " - delete environment variable 'name'\n" ); - +#ifndef CFG_ENV_IS_NOWHERE #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \ ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \ (CFG_CMD_ENV|CFG_CMD_FLASH)) || \ @@ -600,6 +601,7 @@ ); #endif /* CFG_CMD_ENV */ +#endif #if (CONFIG_COMMANDS & CFG_CMD_ASKENV) diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c 2007-08-23 09:45:46.000000000 +0200 @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> + +#ifdef CONFIG_MMC + +#include <part.h> +#include <mmc.h> + +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/byteorder.h> +//#include <asm/arch/clk.h> +//#include <asm/arch/memory-map.h> +#include <asm/arch/hardware.h> //klk + +#include "atmel_mci.h" +#undef DEBUG +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args) +#else +#define pr_debug(...) do { } while(0) +#endif + +#ifndef CFG_MMC_CLK_OD +#define CFG_MMC_CLK_OD 375000 +#endif + +#ifndef CFG_MMC_CLK_PP +#define CFG_MMC_CLK_PP 20000000 +#endif + +#ifndef CFG_MMC_OP_COND +#define CFG_MMC_OP_COND 0x00100000 +#endif + +#define MMC_DEFAULT_BLKLEN 512 +#define MMC_DEFAULT_RCA 1 + +static unsigned int mmc_rca; +static int mmc_card_is_sd; +static block_dev_desc_t mmc_blkdev; + +block_dev_desc_t *mmc_get_dev(int dev) +{ + return &mmc_blkdev; +} + +static void mci_set_mode(unsigned long hz, unsigned long blklen) +{ + unsigned long bus_hz; + unsigned long clkdiv; + + // bus_hz = get_mci_clk_rate(); + bus_hz = AT91C_MASTER_CLOCK; + clkdiv = (bus_hz / hz) / 2 - 1; + + pr_debug("mmc: setting clock %lu Hz, block size %lu\n", + hz, blklen); + + if (clkdiv & ~255UL) { + clkdiv = 255; + pr_debug("mmc: clock %lu too low; setting CLKDIV to 255\n", + hz); + } + + blklen &= 0xfffc; + mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) + | MMCI_BF(BLKLEN, blklen) + | MMCI_BIT(RDPROOF) + | MMCI_BIT(WRPROOF))); +} + +#define RESP_NO_CRC 1 +#define R1 MMCI_BF(RSPTYP, 1) +#define R2 MMCI_BF(RSPTYP, 2) +#define R3 (R1 | RESP_NO_CRC) +#define R6 R1 +#define NID MMCI_BF(MAXLAT, 0) +#define NCR MMCI_BF(MAXLAT, 1) +#define TRCMD_START MMCI_BF(TRCMD, 1) +#define TRDIR_READ MMCI_BF(TRDIR, 1) +#define TRTYP_BLOCK MMCI_BF(TRTYP, 0) +#define INIT_CMD MMCI_BF(SPCMD, 1) +#define OPEN_DRAIN MMCI_BF(OPDCMD, 1) + +#define ERROR_FLAGS (MMCI_BIT(DTOE) \ + | MMCI_BIT(RDIRE) \ + | MMCI_BIT(RENDE) \ + | MMCI_BIT(RINDE) \ + | MMCI_BIT(RTOE)) + +static int +mmc_cmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long *response = resp; + int i, response_words = 0; + unsigned long error_flags; + u32 status; + + AT91F_MMC_Hardware_Init(); + + pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n", + cmd, arg, flags); + + error_flags = ERROR_FLAGS; + if (!(flags & RESP_NO_CRC)) + error_flags |= MMCI_BIT(RCRCE); + + flags &= ~MMCI_BF(CMDNB, ~0UL); + + if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_48_BIT_RESP) + response_words = 1; + else if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_136_BIT_RESP) + response_words = 4; + + mmci_writel(ARGR, arg); + mmci_writel(CMDR, cmd | flags); + do { + udelay(40); + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(CMDRDY))); + + pr_debug("mmc: status 0x%08lx\n", status); + + if (status & ERROR_FLAGS) { + pr_debug("mmc: command %lu failed (status: 0x%08lx)\n", + cmd, status); + return -EIO; + } + + if (response_words) + pr_debug("mmc: response:"); + + for (i = 0; i < response_words; i++) { + response[i] = mmci_readl(RSPR); + pr_debug(" %08lx", response[i]); + } + pr_debug("\n"); + + return 0; +} + +static int mmc_acmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long aresp[4]; + int ret; + + /* + * Seems like the APP_CMD part of an ACMD has 64 cycles max + * latency even though the ACMD part doesn't. This isn't + * entirely clear in the SD Card spec, but some cards refuse + * to work if we attempt to use 5 cycles max latency here... + */ + ret = mmc_cmd(MMC_CMD_APP_CMD, 0, aresp, + R1 | NCR | (flags & OPEN_DRAIN)); + if (ret) + return ret; + if ((aresp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) != R1_APP_CMD) + return -ENODEV; + + ret = mmc_cmd(cmd, arg, resp, flags); + return ret; +} + +static unsigned long +mmc_bread(int dev, unsigned long start, lbaint_t blkcnt, + unsigned long *buffer) +{ + int ret, i = 0; + unsigned long resp[4]; + unsigned long card_status, data; + unsigned long wordcount; + u32 status; + + if (blkcnt == 0) + return 0; + + pr_debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n", + dev, start, blkcnt); + + /* Put the device into Transfer state */ + ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + if (ret) goto fail; + + /* Set block length */ + ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + if (ret) goto fail; + + pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); + + for (i = 0; i < blkcnt; i++, start++) { + ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, + start * mmc_blkdev.blksz, resp, + (R1 | NCR | TRCMD_START | TRDIR_READ + | TRTYP_BLOCK)); + if (ret) goto fail; + + ret = -EIO; + wordcount = 0; + do { + do { + status = mmci_readl(SR); + if (status & (ERROR_FLAGS | MMCI_BIT(OVRE))) + goto fail; + } while (!(status & MMCI_BIT(RXRDY))); + + if (status & MMCI_BIT(RXRDY)) { + data = mmci_readl(RDR); + /* pr_debug("%x\n", data); */ + *buffer++ = data; + wordcount++; + } + } while(wordcount < (mmc_blkdev.blksz / 4)); + + pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount); + + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(BLKE))); + + putc('.'); + } + +out: + /* Put the device back into Standby state */ + mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + return i; + +fail: + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread failed, card status = %08x\n", card_status); + goto out; +} + +static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = resp[2] >> 24; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 16; + cid->psn = (resp[2] << 16) | (resp[3] >> 16); + cid->mdt = resp[3] >> 8; +} + +static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = 0; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 24; + cid->psn = (resp[2] << 8) | (resp[3] >> 24); + cid->mdt = (resp[3] >> 8) & 0x0fff; +} + +static void mmc_dump_cid(const struct mmc_cid *cid) +{ + printf("Manufacturer ID: %02lX\n", cid->mid); + printf("OEM/Application ID: %04lX\n", cid->oid); + printf("Product name: %s\n", cid->pnm); + printf("Product Revision: %lu.%lu\n", + cid->prv >> 4, cid->prv & 0x0f); + printf("Product Serial Number: %lu\n", cid->psn); + printf("Manufacturing Date: %02lu/%02lu\n", + cid->mdt >> 4, cid->mdt & 0x0f); +} + +static void mmc_dump_csd(const struct mmc_csd *csd) +{ + unsigned long *csd_raw = (unsigned long *)csd; + pr_debug("CSD data: %08lx %08lx %08lx %08lx\n", + csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]); + pr_debug("CSD structure version: 1.%u\n", csd->csd_structure); + pr_debug("MMC System Spec version: %u\n", csd->spec_vers); + pr_debug("Card command classes: %03x\n", csd->ccc); + pr_debug("Read block length: %u\n", 1 << csd->read_bl_len); + if (csd->read_bl_partial) + puts("Supports partial reads\n"); + else + puts("Does not support partial reads\n"); + pr_debug("Write block length: %u\n", 1 << csd->write_bl_len); + if (csd->write_bl_partial) + puts("Supports partial writes\n"); + else + puts("Does not support partial writes\n"); + if (csd->wp_grp_enable) + pr_debug("Supports group WP: %u\n", csd->wp_grp_size + 1); + else + puts("Does not support group WP\n"); + pr_debug("Card capacity: %u bytes\n", + (csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) * + (1 << csd->read_bl_len)); + pr_debug("File format: %u/%u\n", + csd->file_format_grp, csd->file_format); + puts("Write protection: "); + if (csd->perm_write_protect) + puts(" permanent"); + if (csd->tmp_write_protect) + puts(" temporary"); + putc('\n'); +} + +static int mmc_idle_cards(void) +{ + int ret; + + /* Reset and initialize all cards */ + ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0); + + if (ret) + return ret; + pr_debug(" ret: %i\n",ret); + /* Keep the bus idle for 74 clock cycles */ + return mmc_cmd(0, 0, NULL, INIT_CMD); +} + +static int sd_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + for (i = 0; i < 1000; i++) { + ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND, CFG_MMC_OP_COND, + resp, R3 | NID); + if (ret || (resp[0] & 0x80000000)) + break; + ret = -ETIMEDOUT; + } + + if (ret) + return ret; + + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID); + if (ret) + return ret; + sd_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Get RCA of the card that responded */ + ret = mmc_cmd(MMC_CMD_SD_SEND_RELATIVE_ADDR, 0, resp, R6 | NCR); + if (ret) + return ret; + + mmc_rca = resp[0] >> 16; + if (verbose) + pr_debug("SD Card detected (RCA %u)\n", mmc_rca); + mmc_card_is_sd = 1; + return 0; +} + +static int mmc_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + + for (i = 0; i < 1000; i++) { + ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND, resp, + R3 | NID | OPEN_DRAIN); + if (ret || (resp[0] & 0x80000000)) + { + break; + } + ret = -ETIMEDOUT; + } + pr_debug("4\n"); + pr_debug("ret : %i\n",ret); + if (ret) + return ret; + pr_debug("5\n"); + /* Get CID of all cards. FIXME: Support more than one card */ + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID | OPEN_DRAIN); + if (ret) + return ret; + mmc_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Set Relative Address of the card that responded */ + ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp, + R1 | NCR | OPEN_DRAIN); + return ret; +} + +static void mci_set_data_timeout(struct mmc_csd *csd) +{ + static const unsigned int dtomul_to_shift[] = { + 0, 4, 7, 8, 10, 12, 16, 20, + }; + static const unsigned int taac_exp[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, + }; + static const unsigned int taac_mant[] = { + 0, 10, 12, 13, 15, 60, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, + }; + unsigned int timeout_ns, timeout_clks; + unsigned int e, m; + unsigned int dtocyc, dtomul; + unsigned int shift; + u32 dtor; + + e = csd->taac & 0x07; + m = (csd->taac >> 3) & 0x0f; + + timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; + timeout_clks = csd->nsac * 100; + + timeout_clks += (((timeout_ns + 9) / 10) + * ((CFG_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000; + if (!mmc_card_is_sd) + timeout_clks *= 10; + else + timeout_clks *= 100; + + dtocyc = timeout_clks; + dtomul = 0; + while (dtocyc > 15 && dtomul < 8) { + dtomul++; + shift = dtomul_to_shift[dtomul]; + dtocyc = (timeout_clks + (1 << shift) - 1) >> shift; + } + + if (dtomul >= 8) { + dtomul = 7; + dtocyc = 15; + puts("Warning: Using maximum data timeout\n"); + } + + dtor = (MMCI_BF(DTOMUL, dtomul) + | MMCI_BF(DTOCYC, dtocyc)); + mmci_writel(DTOR, dtor); + + pr_debug("mmc: Using %u cycles data timeout (DTOR=0x%x)\n", + dtocyc << shift, dtor); +} + +int mmc_init(int verbose) +{ + struct mmc_cid cid; + struct mmc_csd csd; + unsigned int max_blksz; + int ret,aux; + + AT91F_MMC_Hardware_Init(); + + pr_debug("0\n"); + /* Initialize controller */ + mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, MMCI_BIT(MCIEN)); + mmci_writel(DTOR, 0x5f); + mmci_writel(IDR, ~0UL); + mmci_writel(SDCR, 0x1); + mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); +/* //mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, 0x00000001); + mmci_writel(DTOR, 0x0000007F); + mmci_writel(IDR, 0xFFFFFFFF); + mmci_writel(SDCR, 0x00000001); + //mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); + mmci_writel(MR, 0x02009B4A); */ + + pr_debug("1\n"); + + mmc_card_is_sd = 0; + + ret = sd_init_card(&cid, verbose); + if (ret) { + mmc_rca = MMC_DEFAULT_RCA; + ret = mmc_init_card(&cid, verbose); + } + pr_debug("6\n"); + if (ret) + return ret; + pr_debug("7\n"); + /* Get CSD from the card */ + ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &csd, R2 | NCR); + if (ret) + return ret; + if (verbose) + mmc_dump_csd(&csd); + + mci_set_data_timeout(&csd); + + /* Initialize the blockdev structure */ + mmc_blkdev.if_type = IF_TYPE_MMC; + mmc_blkdev.part_type = PART_TYPE_DOS; + mmc_blkdev.block_read = mmc_bread; + sprintf((char *)mmc_blkdev.vendor, + "Man %02x%04x Snr %08x", + cid.mid, cid.oid, cid.psn); + strncpy((char *)mmc_blkdev.product, cid.pnm, + sizeof(mmc_blkdev.product)); + sprintf((char *)mmc_blkdev.revision, "%x %x", + cid.prv >> 4, cid.prv & 0x0f); + + /* + * If we can't use 512 byte blocks, refuse to deal with the + * card. Tons of code elsewhere seems to depend on this. + */ + max_blksz = 1 << csd.read_bl_len; + // if (max_blksz < 512 || (max_blksz > 512 && !csd.read_bl_partial)) { + // pr_debug("Card does not support 512 byte reads, aborting.\n"); + // return -ENODEV; + // } + mmc_blkdev.blksz = 512; + mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2)); + + mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz); + +#if 0 + if (fat_register_device(&mmc_blkdev, 1)) + pr_debug("Could not register MMC fat device\n"); +#else + init_part(&mmc_blkdev); +#endif + + return 0; +} + +int mmc_read(ulong src, uchar *dst, int size) +{ + return -ENOSYS; +} + +int mmc_write(uchar *src, ulong dst, int size) +{ + return -ENOSYS; +} + +int mmc2info(ulong addr) +{ + return 0; +} + +#endif /* CONFIG_MMC */ diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h 2007-08-17 10:43:17.000000000 +0200 @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __CPU_AT32AP_ATMEL_MCI_H__ +#define __CPU_AT32AP_ATMEL_MCI_H__ + +/* Atmel MultiMedia Card Interface (MCI) registers */ +#define MMCI_CR 0x0000 +#define MMCI_MR 0x0004 +#define MMCI_DTOR 0x0008 +#define MMCI_SDCR 0x000c +#define MMCI_ARGR 0x0010 +#define MMCI_CMDR 0x0014 +#define MMCI_RSPR 0x0020 +#define MMCI_RSPR1 0x0024 +#define MMCI_RSPR2 0x0028 +#define MMCI_RSPR3 0x002c +#define MMCI_RDR 0x0030 +#define MMCI_TDR 0x0034 +#define MMCI_SR 0x0040 +#define MMCI_IER 0x0044 +#define MMCI_IDR 0x0048 +#define MMCI_IMR 0x004c + +/* Bitfields in CR */ +#define MMCI_MCIEN_OFFSET 0 +#define MMCI_MCIEN_SIZE 1 +#define MMCI_MCIDIS_OFFSET 1 +#define MMCI_MCIDIS_SIZE 1 +#define MMCI_PWSEN_OFFSET 2 +#define MMCI_PWSEN_SIZE 1 +#define MMCI_PWSDIS_OFFSET 3 +#define MMCI_PWSDIS_SIZE 1 +#define MMCI_SWRST_OFFSET 7 +#define MMCI_SWRST_SIZE 1 + +/* Bitfields in MR */ +#define MMCI_CLKDIV_OFFSET 0 +#define MMCI_CLKDIV_SIZE 8 +#define MMCI_PWSDIV_OFFSET 8 +#define MMCI_PWSDIV_SIZE 3 +#define MMCI_RDPROOF_OFFSET 11 +#define MMCI_RDPROOF_SIZE 1 +#define MMCI_WRPROOF_OFFSET 12 +#define MMCI_WRPROOF_SIZE 1 +#define MMCI_PDCPADV_OFFSET 14 +#define MMCI_PDCPADV_SIZE 1 +#define MMCI_PDCMODE_OFFSET 15 +#define MMCI_PDCMODE_SIZE 1 +#define MMCI_BLKLEN_OFFSET 16 +#define MMCI_BLKLEN_SIZE 16 + +/* Bitfields in DTOR */ +#define MMCI_DTOCYC_OFFSET 0 +#define MMCI_DTOCYC_SIZE 4 +#define MMCI_DTOMUL_OFFSET 4 +#define MMCI_DTOMUL_SIZE 3 + +/* Bitfields in SDCR */ +#define MMCI_SCDSEL_OFFSET 0 +#define MMCI_SCDSEL_SIZE 4 +#define MMCI_SCDBUS_OFFSET 7 +#define MMCI_SCDBUS_SIZE 1 + +/* Bitfields in ARGR */ +#define MMCI_ARG_OFFSET 0 +#define MMCI_ARG_SIZE 32 + +/* Bitfields in CMDR */ +#define MMCI_CMDNB_OFFSET 0 +#define MMCI_CMDNB_SIZE 6 +#define MMCI_RSPTYP_OFFSET 6 +#define MMCI_RSPTYP_SIZE 2 +#define MMCI_SPCMD_OFFSET 8 +#define MMCI_SPCMD_SIZE 3 +#define MMCI_OPDCMD_OFFSET 11 +#define MMCI_OPDCMD_SIZE 1 +#define MMCI_MAXLAT_OFFSET 12 +#define MMCI_MAXLAT_SIZE 1 +#define MMCI_TRCMD_OFFSET 16 +#define MMCI_TRCMD_SIZE 2 +#define MMCI_TRDIR_OFFSET 18 +#define MMCI_TRDIR_SIZE 1 +#define MMCI_TRTYP_OFFSET 19 +#define MMCI_TRTYP_SIZE 2 + +/* Bitfields in RSPRx */ +#define MMCI_RSP_OFFSET 0 +#define MMCI_RSP_SIZE 32 + +/* Bitfields in SR/IER/IDR/IMR */ +#define MMCI_CMDRDY_OFFSET 0 +#define MMCI_CMDRDY_SIZE 1 +#define MMCI_RXRDY_OFFSET 1 +#define MMCI_RXRDY_SIZE 1 +#define MMCI_TXRDY_OFFSET 2 +#define MMCI_TXRDY_SIZE 1 +#define MMCI_BLKE_OFFSET 3 +#define MMCI_BLKE_SIZE 1 +#define MMCI_DTIP_OFFSET 4 +#define MMCI_DTIP_SIZE 1 +#define MMCI_NOTBUSY_OFFSET 5 +#define MMCI_NOTBUSY_SIZE 1 +#define MMCI_ENDRX_OFFSET 6 +#define MMCI_ENDRX_SIZE 1 +#define MMCI_ENDTX_OFFSET 7 +#define MMCI_ENDTX_SIZE 1 +#define MMCI_RXBUFF_OFFSET 14 +#define MMCI_RXBUFF_SIZE 1 +#define MMCI_TXBUFE_OFFSET 15 +#define MMCI_TXBUFE_SIZE 1 +#define MMCI_RINDE_OFFSET 16 +#define MMCI_RINDE_SIZE 1 +#define MMCI_RDIRE_OFFSET 17 +#define MMCI_RDIRE_SIZE 1 +#define MMCI_RCRCE_OFFSET 18 +#define MMCI_RCRCE_SIZE 1 +#define MMCI_RENDE_OFFSET 19 +#define MMCI_RENDE_SIZE 1 +#define MMCI_RTOE_OFFSET 20 +#define MMCI_RTOE_SIZE 1 +#define MMCI_DCRCE_OFFSET 21 +#define MMCI_DCRCE_SIZE 1 +#define MMCI_DTOE_OFFSET 22 +#define MMCI_DTOE_SIZE 1 +#define MMCI_OVRE_OFFSET 30 +#define MMCI_OVRE_SIZE 1 +#define MMCI_UNRE_OFFSET 31 +#define MMCI_UNRE_SIZE 1 + +/* Constants for DTOMUL */ +#define MMCI_DTOMUL_1_CYCLE 0 +#define MMCI_DTOMUL_16_CYCLES 1 +#define MMCI_DTOMUL_128_CYCLES 2 +#define MMCI_DTOMUL_256_CYCLES 3 +#define MMCI_DTOMUL_1024_CYCLES 4 +#define MMCI_DTOMUL_4096_CYCLES 5 +#define MMCI_DTOMUL_65536_CYCLES 6 +#define MMCI_DTOMUL_1048576_CYCLES 7 + +/* Constants for RSPTYP */ +#define MMCI_RSPTYP_NO_RESP 0 +#define MMCI_RSPTYP_48_BIT_RESP 1 +#define MMCI_RSPTYP_136_BIT_RESP 2 + +/* Constants for SPCMD */ +#define MMCI_SPCMD_NO_SPEC_CMD 0 +#define MMCI_SPCMD_INIT_CMD 1 +#define MMCI_SPCMD_SYNC_CMD 2 +#define MMCI_SPCMD_INT_CMD 4 +#define MMCI_SPCMD_INT_RESP 5 + +/* Constants for TRCMD */ +#define MMCI_TRCMD_NO_TRANS 0 +#define MMCI_TRCMD_START_TRANS 1 +#define MMCI_TRCMD_STOP_TRANS 2 + +/* Constants for TRTYP */ +#define MMCI_TRTYP_BLOCK 0 +#define MMCI_TRTYP_MULTI_BLOCK 1 +#define MMCI_TRTYP_STREAM 2 + +/* Bit manipulation macros */ +#define MMCI_BIT(name) \ + (1 << MMCI_##name##_OFFSET) +#define MMCI_BF(name,value) \ + (((value) & ((1 << MMCI_##name##_SIZE) - 1)) \ + << MMCI_##name##_OFFSET) +#define MMCI_BFEXT(name,value) \ + (((value) >> MMCI_##name##_OFFSET)\ + & ((1 << MMCI_##name##_SIZE) - 1)) +#define MMCI_BFINS(name,value,old) \ + (((old) & ~(((1 << MMCI_##name##_SIZE) - 1) \ + << MMCI_##name##_OFFSET)) \ + | MMCI_BF(name,value)) + +/* Register access macros */ +#define mmci_readl(reg) \ + readl((void *)MMCI_BASE + MMCI_##reg) +#define mmci_writel(reg,value) \ + writel((value), (void *)MMCI_BASE + MMCI_##reg) + +#endif /* __CPU_AT32AP_ATMEL_MCI_H__ */ diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk 2007-08-21 17:06:35.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk 2007-08-16 13:34:14.000000000 +0200 @@ -19,10 +19,10 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA -# +#PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,) PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 -PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,) +PLATFORM_RELFLAGS += $(call cc-option,) PLATFORM_CPPFLAGS += -march=armv5te PLATFORM_CPPFLAGS += $(call cc-option,-mtune=arm926ejs,) diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile 2007-08-23 09:14:21.000000000 +0200 @@ -26,8 +26,8 @@ LIB = lib$(SOC).a -OBJS = serial.o interrupts.o usb_ohci.o lcd.o ether.o spi.o -SOBJS = +OBJS = serial.o interrupts.o usb_ohci.o ether.o spi.o +SOBJS = atmel_mci.o all: .depend $(LIB) diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c 2007-08-21 17:06:35.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c 2007-08-23 10:36:47.000000000 +0200 @@ -184,6 +184,20 @@ { unsigned int timeout; +#ifdef CONFIG_AT91SAM9260EK + /* Configure PIO controllers to periph mode */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, // PIO controller base address + ((unsigned int) AT91C_PA1_SPI0_MOSI) | + ((unsigned int) AT91C_PA3_SPI0_NPCS0) | + ((unsigned int) AT91C_PA0_SPI0_MISO) | + ((unsigned int) AT91C_PA2_SPI0_SPCK), /* Peripheral A */ + 0); /* Peripheral B */ + /* Configure PIO controllers to periph mode */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOC, /* PIO controller base address */ + 0, /* Peripheral A */ + ((unsigned int) AT91C_PC11_SPI0_NPCS1)); /* Peripheral B */ +#endif + pDesc->state = BUSY; /* Disable PDC TX and RX channels */ diff -burN u-boot-1.1.5/cpu/arm926ejs/config.mk u-boot-1.1.5.klk/cpu/arm926ejs/config.mk --- u-boot-1.1.5/cpu/arm926ejs/config.mk 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/config.mk 2007-08-16 13:34:42.000000000 +0200 @@ -20,10 +20,10 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA # - -PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ - -msoft-float - +# +#PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ +# -msoft-float +PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 PLATFORM_CPPFLAGS += -march=armv4 # ======================================================================== = # diff -burN u-boot-1.1.5/disk/part.c u-boot-1.1.5.klk/disk/part.c --- u-boot-1.1.5/disk/part.c 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/disk/part.c 2007-08-23 08:29:56.000000000 +0200 @@ -36,6 +36,7 @@ #if ((CONFIG_COMMANDS & CFG_CMD_IDE) || \ (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ (CONFIG_COMMANDS & CFG_CMD_USB) || \ + (CONFIG_COMMANDS & CFG_CMD_MMC) || \ defined(CONFIG_MMC) || \ defined(CONFIG_SYSTEMACE) ) @@ -126,6 +127,8 @@ #if ((CONFIG_COMMANDS & CFG_CMD_IDE) || \ (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ (CONFIG_COMMANDS & CFG_CMD_USB) || \ + (CONFIG_COMMANDS & CFG_CMD_MMC) || \ + defined(CONFIG_MMC) || \ defined(CONFIG_SYSTEMACE) ) #if defined(CONFIG_MAC_PARTITION) || \ diff -burN u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h --- u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h 2007-08-17 10:44:42.000000000 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __ASM_AVR32_MMC_H +#define __ASM_AVR32_MMC_H + +struct mmc_cid { + unsigned long psn; + unsigned short oid; + unsigned char mid; + unsigned char prv; + unsigned char mdt; + char pnm[7]; +}; + +struct mmc_csd +{ + u8 csd_structure:2, + spec_vers:4, + rsvd1:2; + u8 taac; + u8 nsac; + u8 tran_speed; + u16 ccc:12, + read_bl_len:4; + u64 read_bl_partial:1, + write_blk_misalign:1, + read_blk_misalign:1, + dsr_imp:1, + rsvd2:2, + c_size:12, + vdd_r_curr_min:3, + vdd_r_curr_max:3, + vdd_w_curr_min:3, + vdd_w_curr_max:3, + c_size_mult:3, + sector_size:5, + erase_grp_size:5, + wp_grp_size:5, + wp_grp_enable:1, + default_ecc:2, + r2w_factor:3, + write_bl_len:4, + write_bl_partial:1, + rsvd3:5; + u8 file_format_grp:1, + copy:1, + perm_write_protect:1, + tmp_write_protect:1, + file_format:2, + ecc:2; + u8 crc:7; + u8 one:1; +}; + +/* MMC Command numbers */ +#define MMC_CMD_GO_IDLE_STATE 0 +#define MMC_CMD_SEND_OP_COND 1 +#define MMC_CMD_ALL_SEND_CID 2 +#define MMC_CMD_SET_RELATIVE_ADDR 3 +#define MMC_CMD_SD_SEND_RELATIVE_ADDR 3 +#define MMC_CMD_SET_DSR 4 +#define MMC_CMD_SELECT_CARD 7 +#define MMC_CMD_SEND_CSD 9 +#define MMC_CMD_SEND_CID 10 +#define MMC_CMD_SEND_STATUS 13 +#define MMC_CMD_SET_BLOCKLEN 16 +#define MMC_CMD_READ_SINGLE_BLOCK 17 +#define MMC_CMD_READ_MULTIPLE_BLOCK 18 +#define MMC_CMD_WRITE_BLOCK 24 +#define MMC_CMD_APP_CMD 55 + +#define MMC_ACMD_SD_SEND_OP_COND 41 + +#define R1_ILLEGAL_COMMAND (1 << 22) +#define R1_APP_CMD (1 << 5) + +#endif /* __ASM_AVR32_MMC_H */ diff -burN u-boot-1.1.5/include/configs/at91sam9260ek.h u-boot-1.1.5.klk/include/configs/at91sam9260ek.h --- u-boot-1.1.5/include/configs/at91sam9260ek.h 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/include/configs/at91sam9260ek.h 2007-08-23 10:51:43.000000000 +0200 @@ -88,6 +88,8 @@ CFG_CMD_FLASH | \ CFG_CMD_AUTOSCRIPT | \ CFG_CMD_NAND | \ + CFG_CMD_MMC | \ + CFG_CMD_EXT2 | \ CFG_CMD_FAT ) & \ ~(CFG_CMD_BDI | \ CFG_CMD_IMLS | \ @@ -225,6 +227,7 @@ #undef CFG_ENV_IS_IN_FLASH #define CFG_ENV_IS_IN_DATAFLASH 1 #undef CFG_ENV_IS_IN_NAND +#undef CFG_ENV_IS_NOWHERE /*#define CONFIG_MTD_DEBUG 1 #define CONFIG_MTD_DEBUG_VERBOSE MTD_DEBUG_LEVEL3 @@ -241,6 +244,10 @@ #define CFG_ENV_SIZE 0x4000 /* 0x8000 */ #endif +#ifdef CFG_ENV_IS_NOWHERE +#define CFG_ENV_SIZE 0x4000 +#endif + #ifdef CFG_ENV_IS_IN_FLASH #ifdef CONFIG_BOOTBINFUNC #define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x60000) /* after u-boot.bin */ @@ -257,6 +264,10 @@ #define CONFIG_DOS_PARTITION 1 #define LITTLEENDIAN 1 +/* MMC */ +#define CONFIG_MMC 1 +#define MMCI_BASE 0xFFFA8000 + #define CFG_LOAD_ADDR 0x23f00000 /* default load address */ #ifdef CONFIG_BOOTBINFUNC ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] [PATCH] Add eSDHC driver 2008-04-23 19:23 ` Ken.Fuchs at bench.com @ 2008-04-24 6:24 ` Pierre Savary 2008-04-29 19:45 ` [U-Boot-Users] drivers MMCplus for at91sam9x Ken.Fuchs at bench.com 0 siblings, 1 reply; 39+ messages in thread From: Pierre Savary @ 2008-04-24 6:24 UTC (permalink / raw) To: u-boot Thanks for that... but it's my own patch ;) Pierre -----Message d'origine----- De?: u-boot-users-bounces at lists.sourceforge.net [mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de Ken.Fuchs at bench.com Envoy??: mercredi 23 avril 2008 21:23 ??: pierre.savary at kerlink.fr Cc?: u-boot-users at lists.sourceforge.net; afleming at freescale.com; drzeus-mmc at drzeus.cx Objet?: Re: [U-Boot-Users] [PATCH] Add eSDHC driver > Pierre Savary wrote: > >Where could we find the driver that works with MMCv4 on at91sam9x? Andy Fleming wrote: > Pierre, I don't have a driver that works on at91sam9x, I'm > afraid. Here's an MMC v2.x AT91SAM9260 patch for Atmel modified u-boot 1.1.5. You will need to define GPIO pins for other AT91SAM9 processors, etc. If you really need an MMC v4.x AT91SAM9 MCI driver for 1.1.5 fast, you probably could cut and paste the v4.x code you need from Andy's MMC driver into the MMC v2.x MCI driver this patch provides. BTW, if anyone knows why MMC 4 bit is disabled for AT91SAM9261 in the MCI Linux driver, I'd like to hear the reasons why. --- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) --- diff -burN u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c --- u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c 2007-08-23 08:37:42.000000000 +0200 @@ -109,6 +109,24 @@ } +#ifdef CONFIG_MMC +#if (CONFIG_COMMANDS & CFG_CMD_MMC) +int AT91F_MMC_Hardware_Init(void) +{ + AT91C_BASE_PIOA->PIO_ASR = (1 << 8 ); /* periph A select register */ + AT91C_BASE_PIOA->PIO_BSR |= 0x3B; /* periph B select register */ + AT91C_BASE_PIOA->PIO_PDR |= 0x13B; /* PIO disable register */ + AT91C_BASE_PIOA->PIO_PPUDR |= 0x13B; /* Pull up disable register */ + + AT91C_BASE_PMC->PMC_PCER = (1 << 9); +} +#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */ +#endif /* CONFIG_MMC */ + + + + + #ifdef CONFIG_DRIVER_ETHER #if (CONFIG_COMMANDS & CFG_CMD_NET) diff -burN u-boot-1.1.5/common/cmd_nvedit.c u-boot-1.1.5.klk/common/cmd_nvedit.c --- u-boot-1.1.5/common/cmd_nvedit.c 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/common/cmd_nvedit.c 2007-08-23 09:26:18.000000000 +0200 @@ -530,6 +530,7 @@ return (-1); } +#ifndef CFG_ENV_IS_NOWHERE #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \ ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \ (CFG_CMD_ENV|CFG_CMD_FLASH)) || \ @@ -544,7 +545,7 @@ return (saveenv() ? 1 : 0); } - +#endif #endif @@ -587,7 +588,7 @@ "setenv name\n" " - delete environment variable 'name'\n" ); - +#ifndef CFG_ENV_IS_NOWHERE #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \ ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \ (CFG_CMD_ENV|CFG_CMD_FLASH)) || \ @@ -600,6 +601,7 @@ ); #endif /* CFG_CMD_ENV */ +#endif #if (CONFIG_COMMANDS & CFG_CMD_ASKENV) diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c 2007-08-23 09:45:46.000000000 +0200 @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> + +#ifdef CONFIG_MMC + +#include <part.h> +#include <mmc.h> + +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/byteorder.h> +//#include <asm/arch/clk.h> +//#include <asm/arch/memory-map.h> +#include <asm/arch/hardware.h> //klk + +#include "atmel_mci.h" +#undef DEBUG +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args) +#else +#define pr_debug(...) do { } while(0) +#endif + +#ifndef CFG_MMC_CLK_OD +#define CFG_MMC_CLK_OD 375000 +#endif + +#ifndef CFG_MMC_CLK_PP +#define CFG_MMC_CLK_PP 20000000 +#endif + +#ifndef CFG_MMC_OP_COND +#define CFG_MMC_OP_COND 0x00100000 +#endif + +#define MMC_DEFAULT_BLKLEN 512 +#define MMC_DEFAULT_RCA 1 + +static unsigned int mmc_rca; +static int mmc_card_is_sd; +static block_dev_desc_t mmc_blkdev; + +block_dev_desc_t *mmc_get_dev(int dev) +{ + return &mmc_blkdev; +} + +static void mci_set_mode(unsigned long hz, unsigned long blklen) +{ + unsigned long bus_hz; + unsigned long clkdiv; + + // bus_hz = get_mci_clk_rate(); + bus_hz = AT91C_MASTER_CLOCK; + clkdiv = (bus_hz / hz) / 2 - 1; + + pr_debug("mmc: setting clock %lu Hz, block size %lu\n", + hz, blklen); + + if (clkdiv & ~255UL) { + clkdiv = 255; + pr_debug("mmc: clock %lu too low; setting CLKDIV to 255\n", + hz); + } + + blklen &= 0xfffc; + mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) + | MMCI_BF(BLKLEN, blklen) + | MMCI_BIT(RDPROOF) + | MMCI_BIT(WRPROOF))); +} + +#define RESP_NO_CRC 1 +#define R1 MMCI_BF(RSPTYP, 1) +#define R2 MMCI_BF(RSPTYP, 2) +#define R3 (R1 | RESP_NO_CRC) +#define R6 R1 +#define NID MMCI_BF(MAXLAT, 0) +#define NCR MMCI_BF(MAXLAT, 1) +#define TRCMD_START MMCI_BF(TRCMD, 1) +#define TRDIR_READ MMCI_BF(TRDIR, 1) +#define TRTYP_BLOCK MMCI_BF(TRTYP, 0) +#define INIT_CMD MMCI_BF(SPCMD, 1) +#define OPEN_DRAIN MMCI_BF(OPDCMD, 1) + +#define ERROR_FLAGS (MMCI_BIT(DTOE) \ + | MMCI_BIT(RDIRE) \ + | MMCI_BIT(RENDE) \ + | MMCI_BIT(RINDE) \ + | MMCI_BIT(RTOE)) + +static int +mmc_cmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long *response = resp; + int i, response_words = 0; + unsigned long error_flags; + u32 status; + + AT91F_MMC_Hardware_Init(); + + pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n", + cmd, arg, flags); + + error_flags = ERROR_FLAGS; + if (!(flags & RESP_NO_CRC)) + error_flags |= MMCI_BIT(RCRCE); + + flags &= ~MMCI_BF(CMDNB, ~0UL); + + if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_48_BIT_RESP) + response_words = 1; + else if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_136_BIT_RESP) + response_words = 4; + + mmci_writel(ARGR, arg); + mmci_writel(CMDR, cmd | flags); + do { + udelay(40); + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(CMDRDY))); + + pr_debug("mmc: status 0x%08lx\n", status); + + if (status & ERROR_FLAGS) { + pr_debug("mmc: command %lu failed (status: 0x%08lx)\n", + cmd, status); + return -EIO; + } + + if (response_words) + pr_debug("mmc: response:"); + + for (i = 0; i < response_words; i++) { + response[i] = mmci_readl(RSPR); + pr_debug(" %08lx", response[i]); + } + pr_debug("\n"); + + return 0; +} + +static int mmc_acmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long aresp[4]; + int ret; + + /* + * Seems like the APP_CMD part of an ACMD has 64 cycles max + * latency even though the ACMD part doesn't. This isn't + * entirely clear in the SD Card spec, but some cards refuse + * to work if we attempt to use 5 cycles max latency here... + */ + ret = mmc_cmd(MMC_CMD_APP_CMD, 0, aresp, + R1 | NCR | (flags & OPEN_DRAIN)); + if (ret) + return ret; + if ((aresp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) != R1_APP_CMD) + return -ENODEV; + + ret = mmc_cmd(cmd, arg, resp, flags); + return ret; +} + +static unsigned long +mmc_bread(int dev, unsigned long start, lbaint_t blkcnt, + unsigned long *buffer) +{ + int ret, i = 0; + unsigned long resp[4]; + unsigned long card_status, data; + unsigned long wordcount; + u32 status; + + if (blkcnt == 0) + return 0; + + pr_debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n", + dev, start, blkcnt); + + /* Put the device into Transfer state */ + ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + if (ret) goto fail; + + /* Set block length */ + ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + if (ret) goto fail; + + pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); + + for (i = 0; i < blkcnt; i++, start++) { + ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, + start * mmc_blkdev.blksz, resp, + (R1 | NCR | TRCMD_START | TRDIR_READ + | TRTYP_BLOCK)); + if (ret) goto fail; + + ret = -EIO; + wordcount = 0; + do { + do { + status = mmci_readl(SR); + if (status & (ERROR_FLAGS | MMCI_BIT(OVRE))) + goto fail; + } while (!(status & MMCI_BIT(RXRDY))); + + if (status & MMCI_BIT(RXRDY)) { + data = mmci_readl(RDR); + /* pr_debug("%x\n", data); */ + *buffer++ = data; + wordcount++; + } + } while(wordcount < (mmc_blkdev.blksz / 4)); + + pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount); + + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(BLKE))); + + putc('.'); + } + +out: + /* Put the device back into Standby state */ + mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + return i; + +fail: + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread failed, card status = %08x\n", card_status); + goto out; +} + +static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = resp[2] >> 24; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 16; + cid->psn = (resp[2] << 16) | (resp[3] >> 16); + cid->mdt = resp[3] >> 8; +} + +static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = 0; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 24; + cid->psn = (resp[2] << 8) | (resp[3] >> 24); + cid->mdt = (resp[3] >> 8) & 0x0fff; +} + +static void mmc_dump_cid(const struct mmc_cid *cid) +{ + printf("Manufacturer ID: %02lX\n", cid->mid); + printf("OEM/Application ID: %04lX\n", cid->oid); + printf("Product name: %s\n", cid->pnm); + printf("Product Revision: %lu.%lu\n", + cid->prv >> 4, cid->prv & 0x0f); + printf("Product Serial Number: %lu\n", cid->psn); + printf("Manufacturing Date: %02lu/%02lu\n", + cid->mdt >> 4, cid->mdt & 0x0f); +} + +static void mmc_dump_csd(const struct mmc_csd *csd) +{ + unsigned long *csd_raw = (unsigned long *)csd; + pr_debug("CSD data: %08lx %08lx %08lx %08lx\n", + csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]); + pr_debug("CSD structure version: 1.%u\n", csd->csd_structure); + pr_debug("MMC System Spec version: %u\n", csd->spec_vers); + pr_debug("Card command classes: %03x\n", csd->ccc); + pr_debug("Read block length: %u\n", 1 << csd->read_bl_len); + if (csd->read_bl_partial) + puts("Supports partial reads\n"); + else + puts("Does not support partial reads\n"); + pr_debug("Write block length: %u\n", 1 << csd->write_bl_len); + if (csd->write_bl_partial) + puts("Supports partial writes\n"); + else + puts("Does not support partial writes\n"); + if (csd->wp_grp_enable) + pr_debug("Supports group WP: %u\n", csd->wp_grp_size + 1); + else + puts("Does not support group WP\n"); + pr_debug("Card capacity: %u bytes\n", + (csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) * + (1 << csd->read_bl_len)); + pr_debug("File format: %u/%u\n", + csd->file_format_grp, csd->file_format); + puts("Write protection: "); + if (csd->perm_write_protect) + puts(" permanent"); + if (csd->tmp_write_protect) + puts(" temporary"); + putc('\n'); +} + +static int mmc_idle_cards(void) +{ + int ret; + + /* Reset and initialize all cards */ + ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0); + + if (ret) + return ret; + pr_debug(" ret: %i\n",ret); + /* Keep the bus idle for 74 clock cycles */ + return mmc_cmd(0, 0, NULL, INIT_CMD); +} + +static int sd_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + for (i = 0; i < 1000; i++) { + ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND, CFG_MMC_OP_COND, + resp, R3 | NID); + if (ret || (resp[0] & 0x80000000)) + break; + ret = -ETIMEDOUT; + } + + if (ret) + return ret; + + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID); + if (ret) + return ret; + sd_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Get RCA of the card that responded */ + ret = mmc_cmd(MMC_CMD_SD_SEND_RELATIVE_ADDR, 0, resp, R6 | NCR); + if (ret) + return ret; + + mmc_rca = resp[0] >> 16; + if (verbose) + pr_debug("SD Card detected (RCA %u)\n", mmc_rca); + mmc_card_is_sd = 1; + return 0; +} + +static int mmc_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + + for (i = 0; i < 1000; i++) { + ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND, resp, + R3 | NID | OPEN_DRAIN); + if (ret || (resp[0] & 0x80000000)) + { + break; + } + ret = -ETIMEDOUT; + } + pr_debug("4\n"); + pr_debug("ret : %i\n",ret); + if (ret) + return ret; + pr_debug("5\n"); + /* Get CID of all cards. FIXME: Support more than one card */ + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID | OPEN_DRAIN); + if (ret) + return ret; + mmc_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Set Relative Address of the card that responded */ + ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp, + R1 | NCR | OPEN_DRAIN); + return ret; +} + +static void mci_set_data_timeout(struct mmc_csd *csd) +{ + static const unsigned int dtomul_to_shift[] = { + 0, 4, 7, 8, 10, 12, 16, 20, + }; + static const unsigned int taac_exp[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, + }; + static const unsigned int taac_mant[] = { + 0, 10, 12, 13, 15, 60, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, + }; + unsigned int timeout_ns, timeout_clks; + unsigned int e, m; + unsigned int dtocyc, dtomul; + unsigned int shift; + u32 dtor; + + e = csd->taac & 0x07; + m = (csd->taac >> 3) & 0x0f; + + timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; + timeout_clks = csd->nsac * 100; + + timeout_clks += (((timeout_ns + 9) / 10) + * ((CFG_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000; + if (!mmc_card_is_sd) + timeout_clks *= 10; + else + timeout_clks *= 100; + + dtocyc = timeout_clks; + dtomul = 0; + while (dtocyc > 15 && dtomul < 8) { + dtomul++; + shift = dtomul_to_shift[dtomul]; + dtocyc = (timeout_clks + (1 << shift) - 1) >> shift; + } + + if (dtomul >= 8) { + dtomul = 7; + dtocyc = 15; + puts("Warning: Using maximum data timeout\n"); + } + + dtor = (MMCI_BF(DTOMUL, dtomul) + | MMCI_BF(DTOCYC, dtocyc)); + mmci_writel(DTOR, dtor); + + pr_debug("mmc: Using %u cycles data timeout (DTOR=0x%x)\n", + dtocyc << shift, dtor); +} + +int mmc_init(int verbose) +{ + struct mmc_cid cid; + struct mmc_csd csd; + unsigned int max_blksz; + int ret,aux; + + AT91F_MMC_Hardware_Init(); + + pr_debug("0\n"); + /* Initialize controller */ + mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, MMCI_BIT(MCIEN)); + mmci_writel(DTOR, 0x5f); + mmci_writel(IDR, ~0UL); + mmci_writel(SDCR, 0x1); + mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); +/* //mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, 0x00000001); + mmci_writel(DTOR, 0x0000007F); + mmci_writel(IDR, 0xFFFFFFFF); + mmci_writel(SDCR, 0x00000001); + //mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); + mmci_writel(MR, 0x02009B4A); */ + + pr_debug("1\n"); + + mmc_card_is_sd = 0; + + ret = sd_init_card(&cid, verbose); + if (ret) { + mmc_rca = MMC_DEFAULT_RCA; + ret = mmc_init_card(&cid, verbose); + } + pr_debug("6\n"); + if (ret) + return ret; + pr_debug("7\n"); + /* Get CSD from the card */ + ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &csd, R2 | NCR); + if (ret) + return ret; + if (verbose) + mmc_dump_csd(&csd); + + mci_set_data_timeout(&csd); + + /* Initialize the blockdev structure */ + mmc_blkdev.if_type = IF_TYPE_MMC; + mmc_blkdev.part_type = PART_TYPE_DOS; + mmc_blkdev.block_read = mmc_bread; + sprintf((char *)mmc_blkdev.vendor, + "Man %02x%04x Snr %08x", + cid.mid, cid.oid, cid.psn); + strncpy((char *)mmc_blkdev.product, cid.pnm, + sizeof(mmc_blkdev.product)); + sprintf((char *)mmc_blkdev.revision, "%x %x", + cid.prv >> 4, cid.prv & 0x0f); + + /* + * If we can't use 512 byte blocks, refuse to deal with the + * card. Tons of code elsewhere seems to depend on this. + */ + max_blksz = 1 << csd.read_bl_len; + // if (max_blksz < 512 || (max_blksz > 512 && !csd.read_bl_partial)) { + // pr_debug("Card does not support 512 byte reads, aborting.\n"); + // return -ENODEV; + // } + mmc_blkdev.blksz = 512; + mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2)); + + mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz); + +#if 0 + if (fat_register_device(&mmc_blkdev, 1)) + pr_debug("Could not register MMC fat device\n"); +#else + init_part(&mmc_blkdev); +#endif + + return 0; +} + +int mmc_read(ulong src, uchar *dst, int size) +{ + return -ENOSYS; +} + +int mmc_write(uchar *src, ulong dst, int size) +{ + return -ENOSYS; +} + +int mmc2info(ulong addr) +{ + return 0; +} + +#endif /* CONFIG_MMC */ diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h 2007-08-17 10:43:17.000000000 +0200 @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __CPU_AT32AP_ATMEL_MCI_H__ +#define __CPU_AT32AP_ATMEL_MCI_H__ + +/* Atmel MultiMedia Card Interface (MCI) registers */ +#define MMCI_CR 0x0000 +#define MMCI_MR 0x0004 +#define MMCI_DTOR 0x0008 +#define MMCI_SDCR 0x000c +#define MMCI_ARGR 0x0010 +#define MMCI_CMDR 0x0014 +#define MMCI_RSPR 0x0020 +#define MMCI_RSPR1 0x0024 +#define MMCI_RSPR2 0x0028 +#define MMCI_RSPR3 0x002c +#define MMCI_RDR 0x0030 +#define MMCI_TDR 0x0034 +#define MMCI_SR 0x0040 +#define MMCI_IER 0x0044 +#define MMCI_IDR 0x0048 +#define MMCI_IMR 0x004c + +/* Bitfields in CR */ +#define MMCI_MCIEN_OFFSET 0 +#define MMCI_MCIEN_SIZE 1 +#define MMCI_MCIDIS_OFFSET 1 +#define MMCI_MCIDIS_SIZE 1 +#define MMCI_PWSEN_OFFSET 2 +#define MMCI_PWSEN_SIZE 1 +#define MMCI_PWSDIS_OFFSET 3 +#define MMCI_PWSDIS_SIZE 1 +#define MMCI_SWRST_OFFSET 7 +#define MMCI_SWRST_SIZE 1 + +/* Bitfields in MR */ +#define MMCI_CLKDIV_OFFSET 0 +#define MMCI_CLKDIV_SIZE 8 +#define MMCI_PWSDIV_OFFSET 8 +#define MMCI_PWSDIV_SIZE 3 +#define MMCI_RDPROOF_OFFSET 11 +#define MMCI_RDPROOF_SIZE 1 +#define MMCI_WRPROOF_OFFSET 12 +#define MMCI_WRPROOF_SIZE 1 +#define MMCI_PDCPADV_OFFSET 14 +#define MMCI_PDCPADV_SIZE 1 +#define MMCI_PDCMODE_OFFSET 15 +#define MMCI_PDCMODE_SIZE 1 +#define MMCI_BLKLEN_OFFSET 16 +#define MMCI_BLKLEN_SIZE 16 + +/* Bitfields in DTOR */ +#define MMCI_DTOCYC_OFFSET 0 +#define MMCI_DTOCYC_SIZE 4 +#define MMCI_DTOMUL_OFFSET 4 +#define MMCI_DTOMUL_SIZE 3 + +/* Bitfields in SDCR */ +#define MMCI_SCDSEL_OFFSET 0 +#define MMCI_SCDSEL_SIZE 4 +#define MMCI_SCDBUS_OFFSET 7 +#define MMCI_SCDBUS_SIZE 1 + +/* Bitfields in ARGR */ +#define MMCI_ARG_OFFSET 0 +#define MMCI_ARG_SIZE 32 + +/* Bitfields in CMDR */ +#define MMCI_CMDNB_OFFSET 0 +#define MMCI_CMDNB_SIZE 6 +#define MMCI_RSPTYP_OFFSET 6 +#define MMCI_RSPTYP_SIZE 2 +#define MMCI_SPCMD_OFFSET 8 +#define MMCI_SPCMD_SIZE 3 +#define MMCI_OPDCMD_OFFSET 11 +#define MMCI_OPDCMD_SIZE 1 +#define MMCI_MAXLAT_OFFSET 12 +#define MMCI_MAXLAT_SIZE 1 +#define MMCI_TRCMD_OFFSET 16 +#define MMCI_TRCMD_SIZE 2 +#define MMCI_TRDIR_OFFSET 18 +#define MMCI_TRDIR_SIZE 1 +#define MMCI_TRTYP_OFFSET 19 +#define MMCI_TRTYP_SIZE 2 + +/* Bitfields in RSPRx */ +#define MMCI_RSP_OFFSET 0 +#define MMCI_RSP_SIZE 32 + +/* Bitfields in SR/IER/IDR/IMR */ +#define MMCI_CMDRDY_OFFSET 0 +#define MMCI_CMDRDY_SIZE 1 +#define MMCI_RXRDY_OFFSET 1 +#define MMCI_RXRDY_SIZE 1 +#define MMCI_TXRDY_OFFSET 2 +#define MMCI_TXRDY_SIZE 1 +#define MMCI_BLKE_OFFSET 3 +#define MMCI_BLKE_SIZE 1 +#define MMCI_DTIP_OFFSET 4 +#define MMCI_DTIP_SIZE 1 +#define MMCI_NOTBUSY_OFFSET 5 +#define MMCI_NOTBUSY_SIZE 1 +#define MMCI_ENDRX_OFFSET 6 +#define MMCI_ENDRX_SIZE 1 +#define MMCI_ENDTX_OFFSET 7 +#define MMCI_ENDTX_SIZE 1 +#define MMCI_RXBUFF_OFFSET 14 +#define MMCI_RXBUFF_SIZE 1 +#define MMCI_TXBUFE_OFFSET 15 +#define MMCI_TXBUFE_SIZE 1 +#define MMCI_RINDE_OFFSET 16 +#define MMCI_RINDE_SIZE 1 +#define MMCI_RDIRE_OFFSET 17 +#define MMCI_RDIRE_SIZE 1 +#define MMCI_RCRCE_OFFSET 18 +#define MMCI_RCRCE_SIZE 1 +#define MMCI_RENDE_OFFSET 19 +#define MMCI_RENDE_SIZE 1 +#define MMCI_RTOE_OFFSET 20 +#define MMCI_RTOE_SIZE 1 +#define MMCI_DCRCE_OFFSET 21 +#define MMCI_DCRCE_SIZE 1 +#define MMCI_DTOE_OFFSET 22 +#define MMCI_DTOE_SIZE 1 +#define MMCI_OVRE_OFFSET 30 +#define MMCI_OVRE_SIZE 1 +#define MMCI_UNRE_OFFSET 31 +#define MMCI_UNRE_SIZE 1 + +/* Constants for DTOMUL */ +#define MMCI_DTOMUL_1_CYCLE 0 +#define MMCI_DTOMUL_16_CYCLES 1 +#define MMCI_DTOMUL_128_CYCLES 2 +#define MMCI_DTOMUL_256_CYCLES 3 +#define MMCI_DTOMUL_1024_CYCLES 4 +#define MMCI_DTOMUL_4096_CYCLES 5 +#define MMCI_DTOMUL_65536_CYCLES 6 +#define MMCI_DTOMUL_1048576_CYCLES 7 + +/* Constants for RSPTYP */ +#define MMCI_RSPTYP_NO_RESP 0 +#define MMCI_RSPTYP_48_BIT_RESP 1 +#define MMCI_RSPTYP_136_BIT_RESP 2 + +/* Constants for SPCMD */ +#define MMCI_SPCMD_NO_SPEC_CMD 0 +#define MMCI_SPCMD_INIT_CMD 1 +#define MMCI_SPCMD_SYNC_CMD 2 +#define MMCI_SPCMD_INT_CMD 4 +#define MMCI_SPCMD_INT_RESP 5 + +/* Constants for TRCMD */ +#define MMCI_TRCMD_NO_TRANS 0 +#define MMCI_TRCMD_START_TRANS 1 +#define MMCI_TRCMD_STOP_TRANS 2 + +/* Constants for TRTYP */ +#define MMCI_TRTYP_BLOCK 0 +#define MMCI_TRTYP_MULTI_BLOCK 1 +#define MMCI_TRTYP_STREAM 2 + +/* Bit manipulation macros */ +#define MMCI_BIT(name) \ + (1 << MMCI_##name##_OFFSET) +#define MMCI_BF(name,value) \ + (((value) & ((1 << MMCI_##name##_SIZE) - 1)) \ + << MMCI_##name##_OFFSET) +#define MMCI_BFEXT(name,value) \ + (((value) >> MMCI_##name##_OFFSET)\ + & ((1 << MMCI_##name##_SIZE) - 1)) +#define MMCI_BFINS(name,value,old) \ + (((old) & ~(((1 << MMCI_##name##_SIZE) - 1) \ + << MMCI_##name##_OFFSET)) \ + | MMCI_BF(name,value)) + +/* Register access macros */ +#define mmci_readl(reg) \ + readl((void *)MMCI_BASE + MMCI_##reg) +#define mmci_writel(reg,value) \ + writel((value), (void *)MMCI_BASE + MMCI_##reg) + +#endif /* __CPU_AT32AP_ATMEL_MCI_H__ */ diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk 2007-08-21 17:06:35.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk 2007-08-16 13:34:14.000000000 +0200 @@ -19,10 +19,10 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA -# +#PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,) PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 -PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,) +PLATFORM_RELFLAGS += $(call cc-option,) PLATFORM_CPPFLAGS += -march=armv5te PLATFORM_CPPFLAGS += $(call cc-option,-mtune=arm926ejs,) diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile 2007-08-23 09:14:21.000000000 +0200 @@ -26,8 +26,8 @@ LIB = lib$(SOC).a -OBJS = serial.o interrupts.o usb_ohci.o lcd.o ether.o spi.o -SOBJS = +OBJS = serial.o interrupts.o usb_ohci.o ether.o spi.o +SOBJS = atmel_mci.o all: .depend $(LIB) diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c 2007-08-21 17:06:35.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c 2007-08-23 10:36:47.000000000 +0200 @@ -184,6 +184,20 @@ { unsigned int timeout; +#ifdef CONFIG_AT91SAM9260EK + /* Configure PIO controllers to periph mode */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, // PIO controller base address + ((unsigned int) AT91C_PA1_SPI0_MOSI) | + ((unsigned int) AT91C_PA3_SPI0_NPCS0) | + ((unsigned int) AT91C_PA0_SPI0_MISO) | + ((unsigned int) AT91C_PA2_SPI0_SPCK), /* Peripheral A */ + 0); /* Peripheral B */ + /* Configure PIO controllers to periph mode */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOC, /* PIO controller base address */ + 0, /* Peripheral A */ + ((unsigned int) AT91C_PC11_SPI0_NPCS1)); /* Peripheral B */ +#endif + pDesc->state = BUSY; /* Disable PDC TX and RX channels */ diff -burN u-boot-1.1.5/cpu/arm926ejs/config.mk u-boot-1.1.5.klk/cpu/arm926ejs/config.mk --- u-boot-1.1.5/cpu/arm926ejs/config.mk 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/config.mk 2007-08-16 13:34:42.000000000 +0200 @@ -20,10 +20,10 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA # - -PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ - -msoft-float - +# +#PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ +# -msoft-float +PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 PLATFORM_CPPFLAGS += -march=armv4 # ======================================================================== = # diff -burN u-boot-1.1.5/disk/part.c u-boot-1.1.5.klk/disk/part.c --- u-boot-1.1.5/disk/part.c 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/disk/part.c 2007-08-23 08:29:56.000000000 +0200 @@ -36,6 +36,7 @@ #if ((CONFIG_COMMANDS & CFG_CMD_IDE) || \ (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ (CONFIG_COMMANDS & CFG_CMD_USB) || \ + (CONFIG_COMMANDS & CFG_CMD_MMC) || \ defined(CONFIG_MMC) || \ defined(CONFIG_SYSTEMACE) ) @@ -126,6 +127,8 @@ #if ((CONFIG_COMMANDS & CFG_CMD_IDE) || \ (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ (CONFIG_COMMANDS & CFG_CMD_USB) || \ + (CONFIG_COMMANDS & CFG_CMD_MMC) || \ + defined(CONFIG_MMC) || \ defined(CONFIG_SYSTEMACE) ) #if defined(CONFIG_MAC_PARTITION) || \ diff -burN u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h --- u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h 2007-08-17 10:44:42.000000000 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __ASM_AVR32_MMC_H +#define __ASM_AVR32_MMC_H + +struct mmc_cid { + unsigned long psn; + unsigned short oid; + unsigned char mid; + unsigned char prv; + unsigned char mdt; + char pnm[7]; +}; + +struct mmc_csd +{ + u8 csd_structure:2, + spec_vers:4, + rsvd1:2; + u8 taac; + u8 nsac; + u8 tran_speed; + u16 ccc:12, + read_bl_len:4; + u64 read_bl_partial:1, + write_blk_misalign:1, + read_blk_misalign:1, + dsr_imp:1, + rsvd2:2, + c_size:12, + vdd_r_curr_min:3, + vdd_r_curr_max:3, + vdd_w_curr_min:3, + vdd_w_curr_max:3, + c_size_mult:3, + sector_size:5, + erase_grp_size:5, + wp_grp_size:5, + wp_grp_enable:1, + default_ecc:2, + r2w_factor:3, + write_bl_len:4, + write_bl_partial:1, + rsvd3:5; + u8 file_format_grp:1, + copy:1, + perm_write_protect:1, + tmp_write_protect:1, + file_format:2, + ecc:2; + u8 crc:7; + u8 one:1; +}; + +/* MMC Command numbers */ +#define MMC_CMD_GO_IDLE_STATE 0 +#define MMC_CMD_SEND_OP_COND 1 +#define MMC_CMD_ALL_SEND_CID 2 +#define MMC_CMD_SET_RELATIVE_ADDR 3 +#define MMC_CMD_SD_SEND_RELATIVE_ADDR 3 +#define MMC_CMD_SET_DSR 4 +#define MMC_CMD_SELECT_CARD 7 +#define MMC_CMD_SEND_CSD 9 +#define MMC_CMD_SEND_CID 10 +#define MMC_CMD_SEND_STATUS 13 +#define MMC_CMD_SET_BLOCKLEN 16 +#define MMC_CMD_READ_SINGLE_BLOCK 17 +#define MMC_CMD_READ_MULTIPLE_BLOCK 18 +#define MMC_CMD_WRITE_BLOCK 24 +#define MMC_CMD_APP_CMD 55 + +#define MMC_ACMD_SD_SEND_OP_COND 41 + +#define R1_ILLEGAL_COMMAND (1 << 22) +#define R1_APP_CMD (1 << 5) + +#endif /* __ASM_AVR32_MMC_H */ diff -burN u-boot-1.1.5/include/configs/at91sam9260ek.h u-boot-1.1.5.klk/include/configs/at91sam9260ek.h --- u-boot-1.1.5/include/configs/at91sam9260ek.h 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/include/configs/at91sam9260ek.h 2007-08-23 10:51:43.000000000 +0200 @@ -88,6 +88,8 @@ CFG_CMD_FLASH | \ CFG_CMD_AUTOSCRIPT | \ CFG_CMD_NAND | \ + CFG_CMD_MMC | \ + CFG_CMD_EXT2 | \ CFG_CMD_FAT ) & \ ~(CFG_CMD_BDI | \ CFG_CMD_IMLS | \ @@ -225,6 +227,7 @@ #undef CFG_ENV_IS_IN_FLASH #define CFG_ENV_IS_IN_DATAFLASH 1 #undef CFG_ENV_IS_IN_NAND +#undef CFG_ENV_IS_NOWHERE /*#define CONFIG_MTD_DEBUG 1 #define CONFIG_MTD_DEBUG_VERBOSE MTD_DEBUG_LEVEL3 @@ -241,6 +244,10 @@ #define CFG_ENV_SIZE 0x4000 /* 0x8000 */ #endif +#ifdef CFG_ENV_IS_NOWHERE +#define CFG_ENV_SIZE 0x4000 +#endif + #ifdef CFG_ENV_IS_IN_FLASH #ifdef CONFIG_BOOTBINFUNC #define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x60000) /* after u-boot.bin */ @@ -257,6 +264,10 @@ #define CONFIG_DOS_PARTITION 1 #define LITTLEENDIAN 1 +/* MMC */ +#define CONFIG_MMC 1 +#define MMCI_BASE 0xFFFA8000 + #define CFG_LOAD_ADDR 0x23f00000 /* default load address */ #ifdef CONFIG_BOOTBINFUNC ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao ne _______________________________________________ U-Boot-Users mailing list U-Boot-Users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-24 6:24 ` Pierre Savary @ 2008-04-29 19:45 ` Ken.Fuchs at bench.com 2008-04-29 20:20 ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Adrian Filipi 2008-04-30 14:20 ` [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary 0 siblings, 2 replies; 39+ messages in thread From: Ken.Fuchs at bench.com @ 2008-04-29 19:45 UTC (permalink / raw) To: u-boot I posted the following patch under a different subject line: Re: [U-Boot-Users] [PATCH] Add eSDHC driver > > --- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) --- Pierre Savary wrote: > Thanks for that... but it's my own patch ;) > > Pierre =========================================================== Pierre, I hope you like this patch better. :) The following MMC v4 patch is for u-boot-1.1.5_atmel_1.2. To the AT91SAM9261 MCI device driver it adds support for MMC v4.x chips (MoviNAND in particular). The u-boot_at91sam9260_mmc.patch, previously send to this thread 23 April 2008 must be applied to u-boot-1.1.5_atmel_1.2, prior to applying the patch below. The patch includes lines "/* Ignore */". These are simply place holders for code that was not relevant to the MCI driver or MMC code. The patch is actually of four individual source files. Please let me know of any serious problems applying the patch. It should apply cleanly, but I didn't verify this. The MCI MMC v4 features contained in this patch work perfectly on our AT91SAM9261 board, except that I never got MMC 4 bit bus working (that code is omitted from this patch). Anyone know why the AT91SAM9261-EK doesn't appear to support 4 bit MMC? This patch may not work on AT91SAM9261-EK, since we modified the AT91SAM9261-EK board definitions rather than creating a new configuration and files for our board. Sincerely, Ken Fuchs u-boot-at91sam9261-mmc-v4.patch =============================== svn diff -r21 cpu/arm926ejs/at91sam926x/atmel_mci.c Index: cpu/arm926ejs/at91sam926x/atmel_mci.c =================================================================== --- cpu/arm926ejs/at91sam926x/atmel_mci.c (revision 21) +++ cpu/arm926ejs/at91sam926x/atmel_mci.c (working copy) @@ -1,4 +1,8 @@ /* + * (C) Copyright 2007-2008 + * Benchmark Electronics, Inc. + * Added MMC v4.x (MoviNAND) support + * * Copyright (C) 2004-2006 Atmel Corporation * * See file CREDITS for list of people who contributed to this @@ -34,21 +38,43 @@ #include <asm/arch/hardware.h> //klk #include "atmel_mci.h" -#undef DEBUG + +/* Ignore */ +/* Ignore */ +/* Ignore */ + +#if 0 +#define DEBUG +#else /* 0 */ +#undef DEBUG /* kf - was #undef */ +#endif /* 0 */ + #ifdef DEBUG #define pr_debug(fmt, args...) printf(fmt, ##args) #else #define pr_debug(...) do { } while(0) #endif +#undef CFG_MMC_CLK_OD +#define CFG_MMC_CLK_OD 375000 + #ifndef CFG_MMC_CLK_OD #define CFG_MMC_CLK_OD 375000 #endif +#undef CFG_MMC_CLK_PP +#define CFG_MMC_CLK_PP 20000000 + #ifndef CFG_MMC_CLK_PP #define CFG_MMC_CLK_PP 20000000 #endif +#undef CFG_MMC_OP_COND +#define CFG_MMC_OP_COND 0x80ff8000 +/* 0x80ff8080 works with 30+ sec. power off req */ +/* 0x00800000 works better, but write forever? */ +/* 0x00100000 works with 30+ sec. power off req */ + #ifndef CFG_MMC_OP_COND #define CFG_MMC_OP_COND 0x00100000 #endif @@ -74,8 +100,13 @@ bus_hz = AT91C_MASTER_CLOCK; clkdiv = (bus_hz / hz) / 2 - 1; +#if 1 + printf("mmc: setting clock %lu Hz, block size %lu\n", + hz, blklen); +#else /* 1 */ pr_debug("mmc: setting clock %lu Hz, block size %lu\n", hz, blklen); +#endif /* 1 */ if (clkdiv & ~255UL) { clkdiv = 255; @@ -84,10 +115,17 @@ } blklen &= 0xfffc; + +#if 1 /* AT91SAM9261 does not have RDPROOF and WRPROOF fields. */ mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) + | MMCI_BF(BLKLEN, blklen))); +#else /* 1 */ + mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) | MMCI_BF(BLKLEN, blklen) | MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF))); +#endif /* 1 */ + } #define RESP_NO_CRC 1 @@ -99,6 +137,7 @@ #define NCR MMCI_BF(MAXLAT, 1) #define TRCMD_START MMCI_BF(TRCMD, 1) #define TRDIR_READ MMCI_BF(TRDIR, 1) +#define TRDIR_WRITE MMCI_BF(TRDIR, 0) #define TRTYP_BLOCK MMCI_BF(TRTYP, 0) #define INIT_CMD MMCI_BF(SPCMD, 1) #define OPEN_DRAIN MMCI_BF(OPDCMD, 1) @@ -109,6 +148,20 @@ | MMCI_BIT(RINDE) \ | MMCI_BIT(RTOE)) +#if 0 +#define DEBUG +#else /* 0 */ +#undef DEBUG /* kf - was #undef */ +#endif /* 0 */ + +#undef pr_debug + +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args) +#else +#define pr_debug(...) do { } while(0) +#endif + static int mmc_cmd(unsigned long cmd, unsigned long arg, void *resp, unsigned long flags) @@ -117,7 +170,9 @@ int i, response_words = 0; unsigned long error_flags; u32 status; - +#if 1 + pr_debug("mmc_cmd: entry\n"); +#endif /* 1 */ AT91F_MMC_Hardware_Init(); pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n", @@ -161,12 +216,28 @@ return 0; } +#if 0 +#define DEBUG +#else /* 0 */ +#undef DEBUG /* kf - was #undef */ +#endif /* 0 */ + +#undef pr_debug + +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args) +#else +#define pr_debug(...) do { } while(0) +#endif + static int mmc_acmd(unsigned long cmd, unsigned long arg, void *resp, unsigned long flags) { unsigned long aresp[4]; int ret; + pr_debug("mmc_acmd: entry\n"); + /* * Seems like the APP_CMD part of an ACMD has 64 cycles max * latency even though the ACMD part doesn't. This isn't @@ -184,7 +255,16 @@ return ret; } -static unsigned long +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + +unsigned long mmc_bread(int dev, unsigned long start, lbaint_t blkcnt, unsigned long *buffer) { @@ -193,7 +273,14 @@ unsigned long card_status, data; unsigned long wordcount; u32 status; + unsigned long *bufaddr; + pr_debug("mmc_bread: entry\n"); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread ret = %d, card status = %08x\n", ret, card_status); + + bufaddr = buffer; + if (blkcnt == 0) return 0; @@ -202,10 +289,16 @@ /* Put the device into Transfer state */ ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread ret = %d, card status = %08x\n", + ret, card_status); if (ret) goto fail; /* Set block length */ ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread ret = %d, card status = %08x\n", + ret, card_status); if (ret) goto fail; pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); @@ -228,7 +321,6 @@ if (status & MMCI_BIT(RXRDY)) { data = mmci_readl(RDR); - /* pr_debug("%x\n", data); */ *buffer++ = data; wordcount++; } @@ -240,12 +332,68 @@ status = mmci_readl(SR); } while (!(status & MMCI_BIT(BLKE))); - putc('.'); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, + &card_status, R1 | NCR); + pr_debug("mmc: bread ret = %d, card status = %08x\n", + ret, card_status); + + if (i % 0x800 == 0x7ff) { + putc('.'); /* Display '.', after each MB xfer'ed */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + } + +#if 0 + buffer = bufaddr; + wordcount = 0; + do { + if (wordcount % 8 == 0) { + pr_debug("\n%06lx:", 4 * wordcount); + } + pr_debug(" %08lx", *buffer++); + wordcount++; + } while (4 * wordcount < mmc_blkdev.blksz); + pr_debug("\n"); +#endif /* 0 */ + } out: /* Put the device back into Standby state */ mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread ret = %d, card status = %08x\n", ret, card_status); + if (i >= 0x7ff) { + putc('\n'); + } return i; fail: @@ -254,8 +402,329 @@ goto out; } +unsigned long +mmc_bwrite(int dev, unsigned long start, lbaint_t blkcnt, + unsigned long *buffer) +{ + int ret, i = 0; + unsigned long resp[4]; + unsigned long card_status, data; + unsigned long wordcount; + u32 status; + unsigned long *bufaddr; + + pr_debug("mmc_bwrite: entry\n"); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("en mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + + bufaddr = buffer; + + if (blkcnt == 0) + return 0; + + pr_debug("mmc_bwrite: dev %d, start %lx, blkcnt %lx\n", + dev, start, blkcnt); + + /* Put the device into Transfer state */ + ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("sc mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; + + /* Set block length */ + ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("bl mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; + + pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); + + for (i = 0; i < blkcnt; i++, start++) { + ret = mmc_cmd(MMC_CMD_WRITE_BLOCK, + start * mmc_blkdev.blksz, resp, + (R1 | NCR | TRCMD_START | TRDIR_WRITE + | TRTYP_BLOCK)); + if (ret) goto fail; + + ret = -EIO; + wordcount = 0; + do { + do { + status = mmci_readl(SR); + if (status & (ERROR_FLAGS | MMCI_BIT(UNRE))) + goto fail; + } while (!(status & MMCI_BIT(TXRDY))); + + if (status & MMCI_BIT(TXRDY)) { + data = *buffer++; + mmci_writel(TDR, data); + wordcount++; + } + } while(wordcount < (mmc_blkdev.blksz / 4)); + + pr_debug("mmc: write %u words, waiting for BLKE\n", wordcount); + + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(BLKE))); + + do { + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, + &card_status, R1 | NCR); + if ((card_status & 0x00000100) != 0x00000100) { +#if 0 + printf("lp mmc: bwrite ret = %d, ", ret); + printf("card status = %08x\n", card_status); +#endif /* 0 */ + } else { + pr_debug("lp mmc: bwrite ret = %d, ", ret); + pr_debug("card status = %08x\n", card_status); + } + } while ((card_status & 0x00000100) != 0x00000100); + + if (i % 0x800 == 0x7ff) { + putc('.'); /* Display '.', after each MB xfer'ed */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + } + +#if 0 + ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION, + 0, resp, + R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, + &card_status, R1 | NCR); + pr_debug("st mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; +#endif /* 0 */ + + } + +out: +#if 0 + ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION, + 0, resp, + R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("st mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; +#endif /* 0 */ + + /* Put the device back into Standby state */ + mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("dc mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + if (i >= 0x7ff) { + putc('\n'); + } + return i; + +fail: + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("fa mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + goto out; +} + + /* Hangs - did not attempt to debug */ +/* MMC Multiple Block Write - mmc_mbwrite() */ +unsigned long +mmc_mbwrite(int dev, unsigned long start, lbaint_t blkcnt, + unsigned long *buffer) +{ + int ret, i = 0; + unsigned long resp[4]; + unsigned long card_status, data; + unsigned long wordcount; + u32 status; + unsigned long *bufaddr; + + pr_debug("mmc_bwrite: entry\n"); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("en mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + + bufaddr = buffer; + + if (blkcnt == 0) + return 0; + + if (blkcnt > 0xffff) { /* Exceeds length supported by MoviNAND. */ + return -1; + } + + pr_debug("mmc_mbwrite: dev %d, start %lx, blkcnt %lx\n", + dev, start, blkcnt); + + /* Put the device into Transfer state */ + ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("sc mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; + + /* Set block length */ + ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("bl mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; + + pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); + + ret = mmc_cmd(MMC_CMD_SET_BLOCK_COUNT, + blkcnt, resp, + R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("bc mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; + + ret = mmc_cmd(MMC_CMD_WRITE_MULTIPLE_BLOCK, + start * mmc_blkdev.blksz, resp, + (R1 | NCR | TRCMD_START | TRDIR_WRITE | TRTYP_BLOCK)); + if (ret) goto fail; + + for (i = 0; i < blkcnt; i++, start++) { + + ret = -EIO; + wordcount = 0; + do { + do { + status = mmci_readl(SR); + if (status & (ERROR_FLAGS | MMCI_BIT(UNRE))) + goto fail; + } while (!(status & MMCI_BIT(TXRDY))); + + if (status & MMCI_BIT(TXRDY)) { + data = *buffer++; + mmci_writel(TDR, data); + wordcount++; + } + } while(wordcount < (mmc_blkdev.blksz / 4)); + +#if 1 + pr_debug("mmc: write %u words, waiting for BLKE\n", wordcount); + + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(BLKE))); +#endif /* 0 */ + + do { + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, + &card_status, R1 | NCR); + if ((card_status & 0x00000100) != 0x00000100) { +#if 0 + printf("lp mmc: mbwrite ret = %d, ", ret); + printf("card status = %08x\n", card_status); +#endif /* 0 */ + } else { + pr_debug("lp mmc: mbwrite ret = %d, ", ret); + pr_debug("card status = %08x\n", card_status); + } + } while ((card_status & 0x00000100) != 0x00000100); + + if (i % 0x800 == 0x7ff) { + putc('.'); /* Display '.', after each MB xfer'ed */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + } + } + +out: +#if 0 + ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION, + 0, resp, + R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("st mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; +#endif /* 0 */ + + /* Put the device back into Standby state */ + mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("dc mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + if (i >= 0x7ff) { + putc('\n'); + } + return i; + +fail: + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("fa mmc: mbwrite failed, card status = %08x\n", card_status); + goto out; +} + static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp) { + pr_debug("mmc_parse_cid: entry\n"); + cid->mid = resp[0] >> 24; cid->oid = (resp[0] >> 8) & 0xffff; cid->pnm[0] = resp[0]; @@ -272,6 +741,8 @@ static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp) { + pr_debug("sd_parse_cid: entry\n"); + cid->mid = resp[0] >> 24; cid->oid = (resp[0] >> 8) & 0xffff; cid->pnm[0] = resp[0]; @@ -288,6 +759,8 @@ static void mmc_dump_cid(const struct mmc_cid *cid) { + pr_debug("mmc_dump_cid: entry\n"); + printf("Manufacturer ID: %02lX\n", cid->mid); printf("OEM/Application ID: %04lX\n", cid->oid); printf("Product name: %s\n", cid->pnm); @@ -301,6 +774,9 @@ static void mmc_dump_csd(const struct mmc_csd *csd) { unsigned long *csd_raw = (unsigned long *)csd; + + pr_debug("mmc_dump_csd: entry\n"); + pr_debug("CSD data: %08lx %08lx %08lx %08lx\n", csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]); pr_debug("CSD structure version: 1.%u\n", csd->csd_structure); @@ -337,6 +813,8 @@ { int ret; + pr_debug("mmc_idle_cards: entry\n"); + /* Reset and initialize all cards */ ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0); @@ -352,6 +830,8 @@ unsigned long resp[4]; int i, ret = 0; + pr_debug("sd_init_card: entry\n"); + mmc_idle_cards(); for (i = 0; i < 1000; i++) { ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND, CFG_MMC_OP_COND, @@ -387,10 +867,40 @@ { unsigned long resp[4]; int i, ret = 0; + u32 status; + pr_debug("mmc_init_card: entry\n"); + mmc_idle_cards(); + /* MoviNAND initialization */ for (i = 0; i < 1000; i++) { + mmci_writel(ARGR, 0xFFFFFFFF); + mmci_writel(CMDR, 0x0018113F); + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(CMDRDY))); + } + /* Getting the OCR value seems to prevent marginal chips from */ + /* working@all, whereas they would work fine after waiting */ + /* a full minute or more with the power off prior to booting. */ + /* Our marginal chips have date codes 0716 and 0728. */ +#if 0 + for (i = 0; i < 1000; i++) { + /* Request OCR value to determine chip's supported volt. */ + ret = mmc_cmd(MMC_CMD_SEND_OP_COND, 0, resp, + R3 | NID | OPEN_DRAIN); + if (ret || (resp[0] & 0x80000000)) + { + break; + } + ret = -ETIMEDOUT; + } + if (ret) { + return ret; + } +#endif /* 0 */ + for (i = 0; i < 1000; i++) { ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND, resp, R3 | NID | OPEN_DRAIN); if (ret || (resp[0] & 0x80000000)) @@ -399,13 +909,35 @@ } ret = -ETIMEDOUT; } + pr_debug("Step 4: ret = 0x%lx\n", ret); + pr_debug("MMC_CMD_SEND_OP_COND = 0x%lx\n", MMC_CMD_SEND_OP_COND); + pr_debug("CFG_MMC_OP_COND = 0x%lx\n", CFG_MMC_OP_COND); + pr_debug("resp[0] = 0x%lx\n", resp[0]); + pr_debug("resp[1] = 0x%lx\n", resp[1]); + pr_debug("resp[2] = 0x%lx\n", resp[2]); + pr_debug("resp[3] = 0x%lx\n", resp[3]); + pr_debug("R3 = 0x%lx\n", R3); + pr_debug("NID = 0x%lx\n", NID); + pr_debug("OPEN_DRAIN = 0x%lx\n", OPEN_DRAIN); + pr_debug("4\n"); pr_debug("ret : %i\n",ret); + + pr_debug("MCI_MR = 0x%08lx\n", mmci_readl(MR)); + pr_debug("MCI_DTOR = 0x%08lx\n", mmci_readl(DTOR)); + pr_debug("MCI_SDCR = 0x%08lx\n", mmci_readl(SDCR)); + pr_debug("MCI_ARGR = 0x%08lx\n", mmci_readl(ARGR)); + /* RSPR */ + /* RDR */ + pr_debug("MCI_SR = 0x%08lx\n", mmci_readl(SR)); + pr_debug("MCI_IMR = 0x%08lx\n", mmci_readl(IMR)); + if (ret) return ret; pr_debug("5\n"); /* Get CID of all cards. FIXME: Support more than one card */ ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID | OPEN_DRAIN); + pr_debug("ALL_SEND_CID ret: 0x%08lx\n", ret); if (ret) return ret; mmc_parse_cid(cid, resp); @@ -415,6 +947,7 @@ /* Set Relative Address of the card that responded */ ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp, R1 | NCR | OPEN_DRAIN); + pr_debug("SET_RELATIVE_ADDR ret: 0x%08lx\n", ret); return ret; } @@ -471,23 +1004,42 @@ dtocyc << shift, dtor); } +#define DEFAULT_SECTOR_SIZE 512 + int mmc_init(int verbose) { struct mmc_cid cid; struct mmc_csd csd; unsigned int max_blksz; int ret,aux; + unsigned char buffer[DEFAULT_SECTOR_SIZE]; + pr_debug("mmc_init: entry\n"); + pr_debug("mmc_init: verbose = 0x%08lx\n", verbose); + AT91F_MMC_Hardware_Init(); pr_debug("0\n"); /* Initialize controller */ mmci_writel(CR, MMCI_BIT(SWRST)); mmci_writel(CR, MMCI_BIT(MCIEN)); + + pr_debug("MCI_MR = 0x%08lx\n", mmci_readl(MR)); + pr_debug("MCI_DTOR = 0x%08lx\n", mmci_readl(DTOR)); + pr_debug("MCI_SDCR = 0x%08lx\n", mmci_readl(SDCR)); + pr_debug("MCI_ARGR = 0x%08lx\n", mmci_readl(ARGR)); + /* RSPR */ + /* RDR */ + pr_debug("MCI_SR = 0x%08lx\n", mmci_readl(SR)); + pr_debug("MCI_IMR = 0x%08lx\n", mmci_readl(IMR)); + mmci_writel(DTOR, 0x5f); mmci_writel(IDR, ~0UL); mmci_writel(SDCR, 0x1); mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); +#if 0 + mmci_writel(MR, 0x02009B4A); +#endif /* 0 */ /* //mmci_writel(CR, MMCI_BIT(SWRST)); mmci_writel(CR, 0x00000001); mmci_writel(DTOR, 0x0000007F); @@ -502,6 +1054,7 @@ ret = sd_init_card(&cid, verbose); if (ret) { + pr_debug("Not SDCard, try MMC\n"); mmc_rca = MMC_DEFAULT_RCA; ret = mmc_init_card(&cid, verbose); } @@ -545,6 +1098,20 @@ mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz); #if 0 + mmc_bread(mmc_blkdev.dev, 1024, 1, (ulong *)buffer); + buffer[0] = 0x00; buffer[1] = 0x11; + buffer[2] = 0x22; buffer[3] = 0x33; + buffer[4] = 0x44; buffer[5] = 0x55; + buffer[6] = 0x66; buffer[7] = 0x77; + buffer[504] = 0x88; buffer[505] = 0x99; + buffer[506] = 0xaa; buffer[507] = 0xbb; + buffer[508] = 0xcc; buffer[509] = 0xdd; + buffer[510] = 0xee; buffer[511] = 0xff; + mmc_bwrite(mmc_blkdev.dev, 1024, 1, (ulong *)buffer); + mmc_bread(mmc_blkdev.dev, 1024, 1, (ulong *)buffer); +#endif /* 0 */ + +#if 0 if (fat_register_device(&mmc_blkdev, 1)) pr_debug("Could not register MMC fat device\n"); #else @@ -556,16 +1123,22 @@ int mmc_read(ulong src, uchar *dst, int size) { + pr_debug("mmc_read: entry\n"); + return -ENOSYS; } int mmc_write(uchar *src, ulong dst, int size) { + pr_debug("mmc_write: entry\n"); + return -ENOSYS; } int mmc2info(ulong addr) { + pr_debug("mmc2info: entry\n"); + return 0; } svn diff -r21 include/asm-arm/arch-at91sam926x/mmc.h Index: include/asm-arm/arch-at91sam926x/mmc.h =================================================================== --- include/asm-arm/arch-at91sam926x/mmc.h (revision 0) +++ include/asm-arm/arch-at91sam926x/mmc.h (revision 50) @@ -0,0 +1,103 @@ +/* + * (C) Copyright 2007 + * Benchmark Electronics, Inc. + * Added MMC v4.x (MoviNAND) support + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __ASM_AT91SAM926X_MMC_H +#define __ASM_AT91SAM926X_MMC_H + +struct mmc_cid { + unsigned long psn; + unsigned short oid; + unsigned char mid; + unsigned char prv; + unsigned char mdt; + char pnm[7]; +}; + +struct mmc_csd +{ + u8 csd_structure:2, + spec_vers:4, + rsvd1:2; + u8 taac; + u8 nsac; + u8 tran_speed; + u16 ccc:12, + read_bl_len:4; + u64 read_bl_partial:1, + write_blk_misalign:1, + read_blk_misalign:1, + dsr_imp:1, + rsvd2:2, + c_size:12, + vdd_r_curr_min:3, + vdd_r_curr_max:3, + vdd_w_curr_min:3, + vdd_w_curr_max:3, + c_size_mult:3, + sector_size:5, + erase_grp_size:5, + wp_grp_size:5, + wp_grp_enable:1, + default_ecc:2, + r2w_factor:3, + write_bl_len:4, + write_bl_partial:1, + rsvd3:5; + u8 file_format_grp:1, + copy:1, + perm_write_protect:1, + tmp_write_protect:1, + file_format:2, + ecc:2; + u8 crc:7; + u8 one:1; +}; + +/* MMC Command numbers */ +#define MMC_CMD_GO_IDLE_STATE 0 +#define MMC_CMD_SEND_OP_COND 1 +#define MMC_CMD_ALL_SEND_CID 2 +#define MMC_CMD_SET_RELATIVE_ADDR 3 +#define MMC_CMD_SD_SEND_RELATIVE_ADDR 3 +#define MMC_CMD_SET_DSR 4 +#define MMC_CMD_SELECT_CARD 7 +#define MMC_CMD_SEND_CSD 9 +#define MMC_CMD_SEND_CID 10 +#define MMC_CMD_STOP_TRANSMISSION 12 +#define MMC_CMD_SEND_STATUS 13 +#define MMC_CMD_SET_BLOCKLEN 16 +#define MMC_CMD_READ_SINGLE_BLOCK 17 +#define MMC_CMD_READ_MULTIPLE_BLOCK 18 +#define MMC_CMD_SET_BLOCK_COUNT 23 +#define MMC_CMD_WRITE_BLOCK 24 +#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 +#define MMC_CMD_APP_CMD 55 + +#define MMC_ACMD_SD_SEND_OP_COND 41 + +#define R1_ILLEGAL_COMMAND (1 << 22) +#define R1_APP_CMD (1 << 5) + +#endif /* __ASM_AT91SAM926X_MMC_H */ svn diff -r21 include/configs/at91sam9261ek.h Index: include/configs/at91sam9261ek.h =================================================================== --- include/configs/at91sam9261ek.h (revision 21) +++ include/configs/at91sam9261ek.h (working copy) @@ -1,4 +1,8 @@ /* + * (C) Copyright 2007-2008 + * Benchmark Electronics, Inc. + * Added MMC v4.x (MoviNAND) support + * * (C) Copyright 2005 * M. Amine SAYA ATMEL Rousset, France. * @@ -95,18 +99,24 @@ /* SPI */ #define CONFIG_SPI +/* kf - define hush (from busy box) command line interface & options */ +#define CFG_HUSH_PARSER +#define CFG_PROMPT_HUSH_PS2 "> " +#define CFG_AUTO_COMPLETE +#define CONFIG_CMDLINE_EDITING + #define CONFIG_COMMANDS \ ((CONFIG_CMD_DFL | \ CFG_CMD_NET | \ CFG_CMD_ENV | \ CFG_CMD_USB | \ CFG_CMD_FLASH | \ - CFG_CMD_NAND | \ + CFG_CMD_MMC | \ + CFG_CMD_EXT2 | \ + CFG_CMD_FAT | \ CFG_CMD_AUTOSCRIPT | \ - CFG_CMD_FAT | \ CFG_CMD_NFS | \ CFG_CMD_SPI | \ - CFG_CMD_U | \ CFG_CMD_IMI | \ CFG_CMD_PING ) & \ ~(CFG_CMD_BDI | \ @@ -296,8 +306,12 @@ #define CFG_FLASH_ERASE_TOUT (2*CFG_HZ) /* Timeout for Flash Erase */ #define CFG_FLASH_WRITE_TOUT (2*CFG_HZ) /* Timeout for Flash Write */ +#undef CFG_ENV_IS_IN_FLASH #define CFG_ENV_IS_IN_DATAFLASH 1 -#undef CFG_ENV_IS_IN_FLASH +#if 0 +#undef CFG_ENV_IS_IN_NAND +#endif /* 0 - kf */ +#undef CFG_ENV_IS_NOWHERE #ifdef CFG_ENV_IS_IN_DATAFLASH #define CFG_ENV_OFFSET 0x4000 @@ -305,6 +319,10 @@ #define CFG_ENV_SIZE 0x4000 /* 0x8000 */ #endif +#ifdef CFG_ENV_IS_NOWHERE +#define CFG_ENV_SIZE 0x4000 +#endif + #ifdef CFG_ENV_IS_IN_FLASH #ifdef CONFIG_BOOTBINFUNC #define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x60000) /* after u-boot.bin */ @@ -316,6 +334,9 @@ #endif /* Add LCD stuff */ +/* Ignore */ +/* Ignore */ + #if 0 /* No LCD */ #define CONFIG_LCD /* #undef CONFIG_LCD_LOGO */ @@ -333,8 +354,21 @@ #define CONFIG_DOS_PARTITION 1 #define LITTLEENDIAN 1 -#define CFG_LOAD_ADDR 0x23f00000 /* default load address */ +/* Add FAT filesystem configuration, other than CFG_CMD_FAT */ +#define CONFIG_SUPPORT_VFAT +/* MMC */ +#define CONFIG_MMC 1 +#define MMCI_BASE 0xFFFA8000 /* (void *)AT91C_BASE_MCI */ +/* MMC - kf - slow down speed for debug from 20000000 Hz down to ... */ +/* However, tweaking this value here causes all code to be compiled, */ +/* so we shall change the value only where needed - in atmel_mci.c. */ +#define CFG_MMC_CLK_PP 20000000 + +#define CFG_LOAD_ADDR 0x23f00000 /* default load address */ + +#define CFG_BOOTM_LEN 0x02100000 /* 33MB uncompressed max. */ + #ifdef CONFIG_BOOTBINFUNC #define CFG_BOOT_SIZE 0x00 /* 0 KBytes */ #define CFG_U_BOOT_BASE PHYS_FLASH_1 svn diff -r21 board/at91sam9261ek/at91sam9261ek.c Index: board/at91sam9261ek/at91sam9261ek.c =================================================================== --- board/at91sam9261ek/at91sam9261ek.c (revision 21) +++ board/at91sam9261ek/at91sam9261ek.c (working copy) @@ -1,4 +1,8 @@ /* + * (C) Copyright 2007-2008 + * Benchmark Electronics, Inc. + * Added specific AT91SAM9261 board support + * * (C) Copyright 2005 * M. Amine SAYA ATMEL Rousset, France. * Added AT91SAM9261EK support. @@ -28,12 +32,19 @@ #include <common.h> #include <asm/arch/hardware.h> +#include <asm/arch-at91sam926x/at91sam9261.h> #include <net.h> extern void AT91F_Spi1Init (void); extern void gpio_init(void); +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + /* ------------------------------------------------------------------------ - */ /* * Miscelaneous platform dependent initialisations @@ -107,7 +118,8 @@ *AT91C_PMC_PCER |= 1 << AT91C_ID_US0; /* enable clock */ #endif -#ifdef CONFIG_USART1 +#if 1 + /* #ifdef CONFIG_USART1 */ *AT91C_PIOB_PDR = AT91C_PC12_TXD1 | AT91C_PC13_RXD1; *AT91C_PMC_PCER |= 1 << AT91C_ID_US1; /* enable clock */ #endif @@ -118,6 +130,41 @@ #endif } +#ifdef CONFIG_MMC +#if (CONFIG_COMMANDS & CFG_CMD_MMC) +int AT91F_MMC_Hardware_Init(void) +{ +#if 0 + printf("AT91F_MMC_Hardware_Init: entry\n"); +#endif /* 0 */ + + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, + 0, /* <- Peripheral A */ + (AT91C_PA0_MCDA0 | /* MMC NAND MCDA0 */ + AT91C_PA1_MCCDA | /* MMC NAND MCCDA */ + AT91C_PA2_MCCK | /* MMC NAND MCCK */ + AT91C_PA4_MCDA1 | /* MMC NAND MCDA1 */ + AT91C_PA5_MCDA2 | /* MMC NAND MCDA2 */ + AT91C_PA6_MCDA3 | /* MMC NAND MCDA3 */ + 0)); /* <- Peripheral B */ + +#if 1 + /* Pull up disable register */ + AT91C_BASE_PIOA->PIO_PPUDR |= + AT91C_PA0_MCDA0 | /* MMC NAND MCDA0 */ + AT91C_PA1_MCCDA | /* MMC NAND MCCDA */ + AT91C_PA2_MCCK | /* MMC NAND MCCK */ + AT91C_PA4_MCDA1 | /* MMC NAND MCDA1 */ + AT91C_PA5_MCDA2 | /* MMC NAND MCDA2 */ + AT91C_PA6_MCDA3; /* MMC NAND MCDA3 */ +#endif /* 0 */ + + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_MCI); +} +#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */ +#endif /* CONFIG_MMC */ + + int dram_init (void) { DECLARE_GLOBAL_DATA_PTR; @@ -148,5 +195,35 @@ gpio_init(); +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + return 0; } ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-29 19:45 ` [U-Boot-Users] drivers MMCplus for at91sam9x Ken.Fuchs at bench.com @ 2008-04-29 20:20 ` Adrian Filipi 2008-04-29 20:43 ` Wolfgang Denk 2008-05-08 11:17 ` Haavard Skinnemoen 2008-04-30 14:20 ` [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary 1 sibling, 2 replies; 39+ messages in thread From: Adrian Filipi @ 2008-04-29 20:20 UTC (permalink / raw) To: u-boot hi folks, I've come across a case on one of our PXA250 boards where the flash was getting corrupted when using the 1.3.2 version of cfi_flash.c, while the 1.2.0 version worked just fine. Here's what happens: 1. Reprogram uboot. 2. Compare uboot in flash against uboot in DRAM. 3. Either run "reset" or press the reset button. 4. Compare the flash and DRAM, as well as a new copy of uboot re-read from CF for good measure. At this point the low byte in the word at offset 0x554 has switched from a 0x30 to a 0x10. This is the only change in the flash. The new value is always the same. I narrowed down the source of the problem to the loss of the volatile qualifier on the addr pointer in flash_write_cmd(). Adding the qualifier gets rid of the corruption. In the older 1.2.0 sources, addr was declared as "volatile cfiptr_t addr;". Has anyone else seen this? It seems like the safe thing to do is to restore the qualifier in general. Below is a diff, of the change for the 1.3.2. sources: diff -u -r1.1.1.2.2.2 cfi_flash.c --- cfi_flash.c 23 Apr 2008 17:02:47 -0000 1.1.1.2.2.2 +++ cfi_flash.c 29 Apr 2008 18:55:47 -0000 @@ -464,7 +464,7 @@ uint offset, uchar cmd) { - void *addr; + void *volatile addr; cfiword_t cword; addr = flash_map (info, sect, offset); Adrian -- Linux Software Engineer | EuroTech, Inc. | www.eurotech-inc.com ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-29 20:20 ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Adrian Filipi @ 2008-04-29 20:43 ` Wolfgang Denk 2008-04-29 21:10 ` Adrian Filipi 2008-05-08 11:17 ` Haavard Skinnemoen 1 sibling, 1 reply; 39+ messages in thread From: Wolfgang Denk @ 2008-04-29 20:43 UTC (permalink / raw) To: u-boot In message <alpine.DEB.1.10.0804291604250.32753@pmy.adscville> you wrote: > > I narrowed down the source of the problem to the loss of the > volatile qualifier on the addr pointer in flash_write_cmd(). Adding the > qualifier gets rid of the corruption. In the older 1.2.0 sources, addr was > declared as "volatile cfiptr_t addr;". The volatile should not be needed - the CFI driver should use correct accessor macros instead. See Documentation/volatile-considered-harmful.txt in your Linux kernel source tree... Best regards, Wolfgang Denk -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de No one wants war. -- Kirk, "Errand of Mercy", stardate 3201.7 ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-29 20:43 ` Wolfgang Denk @ 2008-04-29 21:10 ` Adrian Filipi 2008-04-29 21:16 ` Jerry Van Baren 0 siblings, 1 reply; 39+ messages in thread From: Adrian Filipi @ 2008-04-29 21:10 UTC (permalink / raw) To: u-boot Sure, reducing the reliance on volatile is a good idea, but I'm at a loss for anything better to do. I'm seeing a real problem that is only fixed by qualifying the container of the pointer as volatile, i.e. "void *volatile". "volatile void *" has no effect as expected given that the read/write accessors are used now. The old data type was essentially "volatile void *volatile addr" and the new type is simply "void *addr". I seem to need at least "void *volatile addr" for things to work. Note, I'm only seeing this problem on our PXA250 boards. Adrian -- Linux Software Engineer | EuroTech, Inc. | www.eurotech-inc.com On Tue, 29 Apr 2008, Wolfgang Denk wrote: > In message <alpine.DEB.1.10.0804291604250.32753@pmy.adscville> you wrote: >> >> I narrowed down the source of the problem to the loss of the >> volatile qualifier on the addr pointer in flash_write_cmd(). Adding the >> qualifier gets rid of the corruption. In the older 1.2.0 sources, addr was >> declared as "volatile cfiptr_t addr;". > > The volatile should not be needed - the CFI driver should use correct > accessor macros instead. See > Documentation/volatile-considered-harmful.txt in your Linux kernel > source tree... > > Best regards, > > Wolfgang Denk > > ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-29 21:10 ` Adrian Filipi @ 2008-04-29 21:16 ` Jerry Van Baren [not found] ` <alpine.DEB.1.10.0804300949360.13610@pmy.adscville> 0 siblings, 1 reply; 39+ messages in thread From: Jerry Van Baren @ 2008-04-29 21:16 UTC (permalink / raw) To: u-boot Adrian Filipi wrote: > On Tue, 29 Apr 2008, Wolfgang Denk wrote: > >> In message <alpine.DEB.1.10.0804291604250.32753@pmy.adscville> you wrote: >>> I narrowed down the source of the problem to the loss of the >>> volatile qualifier on the addr pointer in flash_write_cmd(). Adding the >>> qualifier gets rid of the corruption. In the older 1.2.0 sources, addr was >>> declared as "volatile cfiptr_t addr;". >> The volatile should not be needed - the CFI driver should use correct >> accessor macros instead. See >> Documentation/volatile-considered-harmful.txt in your Linux kernel >> source tree... >> >> Best regards, >> >> Wolfgang Denk > > Sure, reducing the reliance on volatile is a good idea, but I'm at > a loss for anything better to do. > > I'm seeing a real problem that is only fixed by qualifying the > container of the pointer as volatile, i.e. "void *volatile". "volatile > void *" has no effect as expected given that the read/write accessors are > used now. > > The old data type was essentially "volatile void *volatile addr" > and the new type is simply "void *addr". I seem to need at least "void > *volatile addr" for things to work. > > Note, I'm only seeing this problem on our PXA250 boards. > > Adrian Hi Adrian, Please bottom post. It may be useful to disassemble cfi_flash.o file (objdump -S) and see what the two different configurations of flash_write_cmd() get turned into in assembly. Best regards, gvb ^ permalink raw reply [flat|nested] 39+ messages in thread
[parent not found: <alpine.DEB.1.10.0804300949360.13610@pmy.adscville>]
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier [not found] ` <alpine.DEB.1.10.0804300949360.13610@pmy.adscville> @ 2008-04-30 14:43 ` Jerry Van Baren 2008-04-30 15:11 ` Joakim Tjernlund 2008-04-30 15:38 ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Wolfgang Denk 0 siblings, 2 replies; 39+ messages in thread From: Jerry Van Baren @ 2008-04-30 14:43 UTC (permalink / raw) To: u-boot Adrian Filipi wrote: > On Tue, 29 Apr 2008, Jerry Van Baren wrote: > >> Adrian Filipi wrote: >>> On Tue, 29 Apr 2008, Wolfgang Denk wrote: >>> >>>> In message <alpine.DEB.1.10.0804291604250.32753@pmy.adscville> you >>>> wrote: >>>>> I narrowed down the source of the problem to the loss of the >>>>> volatile qualifier on the addr pointer in flash_write_cmd(). >>>>> Adding the >>>>> qualifier gets rid of the corruption. In the older 1.2.0 sources, >>>>> addr was >>>>> declared as "volatile cfiptr_t addr;". >>>> The volatile should not be needed - the CFI driver should use correct >>>> accessor macros instead. See >>>> Documentation/volatile-considered-harmful.txt in your Linux kernel >>>> source tree... >>>> >>>> Best regards, >>>> >>>> Wolfgang Denk >>> >>> Sure, reducing the reliance on volatile is a good idea, but I'm >>> at a loss for anything better to do. >>> >>> I'm seeing a real problem that is only fixed by qualifying the >>> container of the pointer as volatile, i.e. "void *volatile". >>> "volatile void *" has no effect as expected given that the read/write >>> accessors are used now. >>> >>> The old data type was essentially "volatile void *volatile addr" >>> and the new type is simply "void *addr". I seem to need at least >>> "void *volatile addr" for things to work. >>> >>> Note, I'm only seeing this problem on our PXA250 boards. >>> >>> Adrian >> >> Hi Adrian, >> >> Please bottom post. >> >> It may be useful to disassemble cfi_flash.o file (objdump -S) and see >> what the two different configurations of flash_write_cmd() get turned >> into in assembly. >> >> Best regards, >> gvb >> > > I've attached the assembler output as well as the diff to the > version with volatile added. I don't see anything incriminating. > Instead of using a register, the variable is read from its location on > the stack. > > I'm having a hard time seeing how flash could get corrupted by this > code. It's happening during initialization. > > Adrian I'm not an ARMexpert, but if that were a PowerPC CPU, I would *strongly* suspect that the bus interface unit is rearranging the bus operations going to memory (e.g. moving a read ahead of a write or re-ordering the writes). The result is that the write command/data sequence to the flash gets buggered by the re-ordering. Per my theory, by putting in the "volatile", you force extra reads on the bus which forces the bus interface unit to flush out the flash write sequence in the right order. The fix is totally unrelated the the problem, other than as an unrecognized side effect it "fixes" the problem. The solution in the PowerPC world is to add a "eieio" or "sync" instruction[1] appropriately[2], which prevents the bus interface unit from reordering the memory operations. Your task is to dig into the PXA250 manual to (a) figure out what syncs you need and (b) figure out why the bus interface is doing you in. Alternatively, (c) show that I don't know what I'm talking about. Obviously, (a) gets you the best results, so lets root for that. ;-) HTH, gvb [1] Sync is a big hammer, eieio is a medium size hammer. Don't use both, PPC people will know you don't know what you are doing. ;-) [2] The flash command sequence order is critical (e.g. the 55s and AAs). The actual data sequence is not critical. The observed problem is in flash_write_cmd() that is writing the command sequence. Hmmmmm. ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-30 14:43 ` Jerry Van Baren @ 2008-04-30 15:11 ` Joakim Tjernlund 2008-04-30 15:21 ` Scott Wood 2008-04-30 15:35 ` [U-Boot-Users] PPC sync/eieio (was cfi_flash.c and lost volatile qualifier) Jerry Van Baren 2008-04-30 15:38 ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Wolfgang Denk 1 sibling, 2 replies; 39+ messages in thread From: Joakim Tjernlund @ 2008-04-30 15:11 UTC (permalink / raw) To: u-boot > > [1] Sync is a big hammer, eieio is a medium size hammer. Don't use > both, PPC people will know you don't know what you are doing. ;-) Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all SOC drivers are encouraged to use them. What a waste :( Jocke ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-30 15:11 ` Joakim Tjernlund @ 2008-04-30 15:21 ` Scott Wood 2008-04-30 15:34 ` Joakim Tjernlund 2008-04-30 15:35 ` [U-Boot-Users] PPC sync/eieio (was cfi_flash.c and lost volatile qualifier) Jerry Van Baren 1 sibling, 1 reply; 39+ messages in thread From: Scott Wood @ 2008-04-30 15:21 UTC (permalink / raw) To: u-boot On Wed, Apr 30, 2008 at 05:11:09PM +0200, Joakim Tjernlund wrote: > Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all > SOC drivers are encouraged to use them. What a waste :( sync is needed in some of the cases, to sync I/O accesses with DMA buffer accesses. Ideally, we could trust the driver writers to put synchronization in where needed, but it seems Linux has too much x86 heritage for that. There should at least be raw alternatives, though... -Scott ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-30 15:21 ` Scott Wood @ 2008-04-30 15:34 ` Joakim Tjernlund 2008-04-30 15:41 ` Wolfgang Denk 2008-04-30 16:02 ` Scott Wood 0 siblings, 2 replies; 39+ messages in thread From: Joakim Tjernlund @ 2008-04-30 15:34 UTC (permalink / raw) To: u-boot On Wed, 2008-04-30 at 10:21 -0500, Scott Wood wrote: > On Wed, Apr 30, 2008 at 05:11:09PM +0200, Joakim Tjernlund wrote: > > Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all > > SOC drivers are encouraged to use them. What a waste :( > > sync is needed in some of the cases, to sync I/O accesses with DMA buffer > accesses. Ideally, we could trust the driver writers to put > synchronization in where needed, but it seems Linux has too much x86 > heritage for that. Perhaps, is sync needed in this case for non-smp too? or is eieio enough? Anyway, just have a look at ucc_geth and you will see that most such accesses are just about getting the endian right. > > There should at least be raw alternatives, though... There need be a get-the-endian-right-but-no-sync. After all 2.4 managed well without using the in/out be() functions. Jocke > > -Scott > > ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-30 15:34 ` Joakim Tjernlund @ 2008-04-30 15:41 ` Wolfgang Denk 2008-04-30 16:02 ` Scott Wood 1 sibling, 0 replies; 39+ messages in thread From: Wolfgang Denk @ 2008-04-30 15:41 UTC (permalink / raw) To: u-boot In message <1209569696.16926.53.camel@gentoo-jocke.transmode.se> you wrote: > > There need be a get-the-endian-right-but-no-sync. After all > 2.4 managed well without using the in/out be() functions. Yes, but try building it with a recent version of GCC and run the code on some PPC systems. There may be some nasty surprises. I remember that we had to fix a couple of drivers in our old 2.4.25 kernel. Best regards, Wolfgang Denk -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de As a general rule, the freedom of any people can be judged by the volume of their laughter. ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-30 15:34 ` Joakim Tjernlund 2008-04-30 15:41 ` Wolfgang Denk @ 2008-04-30 16:02 ` Scott Wood 2008-04-30 16:11 ` Joakim Tjernlund 1 sibling, 1 reply; 39+ messages in thread From: Scott Wood @ 2008-04-30 16:02 UTC (permalink / raw) To: u-boot On Wed, Apr 30, 2008 at 05:34:56PM +0200, Joakim Tjernlund wrote: > > On Wed, 2008-04-30 at 10:21 -0500, Scott Wood wrote: > > On Wed, Apr 30, 2008 at 05:11:09PM +0200, Joakim Tjernlund wrote: > > > Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all > > > SOC drivers are encouraged to use them. What a waste :( > > > > sync is needed in some of the cases, to sync I/O accesses with DMA buffer > > accesses. Ideally, we could trust the driver writers to put > > synchronization in where needed, but it seems Linux has too much x86 > > heritage for that. > > Perhaps, is sync needed in this case for non-smp too? or is eieio > enough? Yes, sync is needed -- eieio doesn't order between stores to cacheable memory and stores to cache-inhibited memory. > Anyway, just have a look at ucc_geth Do I have to? :-) > and you will see that most such accesses are just about getting the > endian right. If you mean the descriptor accesses, ordering is relevant there as well. > > There should at least be raw alternatives, though... > > There need be a get-the-endian-right-but-no-sync. Agreed. There's cpu_to_be32, etc., but that doesn't fit well with load/store endian-swapping instructions. > After all 2.4 managed well without using the in/out be() functions. I see in/out_be32() in 2.4... and the significant chunks of code that use volatile pointers instead, I wouldn't consider to be managing "well"; they just happen to work most of the time. -Scott ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-30 16:02 ` Scott Wood @ 2008-04-30 16:11 ` Joakim Tjernlund 0 siblings, 0 replies; 39+ messages in thread From: Joakim Tjernlund @ 2008-04-30 16:11 UTC (permalink / raw) To: u-boot On Wed, 2008-04-30 at 11:02 -0500, Scott Wood wrote: > On Wed, Apr 30, 2008 at 05:34:56PM +0200, Joakim Tjernlund wrote: > > > > On Wed, 2008-04-30 at 10:21 -0500, Scott Wood wrote: > > > On Wed, Apr 30, 2008 at 05:11:09PM +0200, Joakim Tjernlund wrote: > > > > Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all > > > > SOC drivers are encouraged to use them. What a waste :( > > > > > > sync is needed in some of the cases, to sync I/O accesses with DMA buffer > > > accesses. Ideally, we could trust the driver writers to put > > > synchronization in where needed, but it seems Linux has too much x86 > > > heritage for that. > > > > Perhaps, is sync needed in this case for non-smp too? or is eieio > > enough? > > Yes, sync is needed -- eieio doesn't order between stores to cacheable > memory and stores to cache-inhibited memory. OK, thanks > > > Anyway, just have a look at ucc_geth > > Do I have to? :-) Yes, it needs a little love here and there :) Especially Timur, his little "rename the tx/rx clock" trick costed me a few days :) Jocke ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] PPC sync/eieio (was cfi_flash.c and lost volatile qualifier) 2008-04-30 15:11 ` Joakim Tjernlund 2008-04-30 15:21 ` Scott Wood @ 2008-04-30 15:35 ` Jerry Van Baren 1 sibling, 0 replies; 39+ messages in thread From: Jerry Van Baren @ 2008-04-30 15:35 UTC (permalink / raw) To: u-boot Joakim Tjernlund wrote: >> [1] Sync is a big hammer, eieio is a medium size hammer. Don't use >> both, PPC people will know you don't know what you are doing. ;-) > > Yet the in_bex()/out_bex() functions in PowerPC linux uses sync and all > SOC drivers are encouraged to use them. What a waste :( > > Jocke Well, I was a little terse because I was cross-applying PPC instructions in a ARM discussion. Personally, I prefer to use sync vs. eieio. The size of the hammer isn't that different, I don't believe. The advantage of sync is that it flushes the read/write operation out on the bus *now*. When I'm writing to hardware to control the hardware, *now* is what I want. The eieio merely guarantees the preceding operations will go out on the bus before following bus operations. The preceding operations could be hung up in the bus interface unit *indefinitely* if no "following" bus operations occur. This is an unlikely occurrence, but could be the result of running out of cache in a tight loop. For instance, if you do a write to a hardware register, a eieio, and then wait in a tight loop until time goes by (reading the decrementer register) followed by another write, the write1/delay/write2 sequence could actually be delay/write1/write2. Note that the order of the writes on the bus is correct per the eieio, but it isn't what the hardware *needed*. Illustration - what you did in code and intended to occur: write1 (eieio) delay write2 (eieio) What actually may happen on the bus: delay write1 (eieio) write2 (eieio) By using a sync, you guarantee the write isn't delayed: write1 (sync) delay write2 (sync) Disclaimer: the above explanation is from my fertile imagination. It may or may not happen and *will* happen differently on different PPC processors. For instance, the eieio instruction is actually a NOP in the 603e core because it doesn't reorder bus operations, but it *does* have a BIU that can buffer and delay the bus operations, causing the above timing problem. I contend using the "sync" instruction will always work correctly and the "eieio" instruction is at best a false economy and at worst a lot of very difficult, mysterious bugs to find, so I'm in agreement with the linux in_bex/out_bex recommendation. Side note: I don't know if I communicated it properly, but when you see "eieio ; sync" or "sync ; eieio", you know the author of that code doesn't understand sync and eieio. "isync ; sync" is occasionally a valid combination, but I don't believe it is necessary other than when called for by the Users Manual in conjunction with writing to special purpose registers. Best regards, gvb ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-30 14:43 ` Jerry Van Baren 2008-04-30 15:11 ` Joakim Tjernlund @ 2008-04-30 15:38 ` Wolfgang Denk 2008-04-30 15:51 ` Jerry Van Baren 1 sibling, 1 reply; 39+ messages in thread From: Wolfgang Denk @ 2008-04-30 15:38 UTC (permalink / raw) To: u-boot In message <48188584.3060109@ge.com> you wrote: > > The solution in the PowerPC world is to add a "eieio" or "sync" > instruction[1] appropriately[2], which prevents the bus interface unit > from reordering the memory operations. No, the solution for ALL architectures is to use the appropriate accessor macros which take care of such things (and probably contain calls like sync or similar). Best regards, Wolfgang Denk -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de Unix: Some say the learning curve is steep, but you only have to climb it once. - Karl Lehenbauer ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-30 15:38 ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Wolfgang Denk @ 2008-04-30 15:51 ` Jerry Van Baren 0 siblings, 0 replies; 39+ messages in thread From: Jerry Van Baren @ 2008-04-30 15:51 UTC (permalink / raw) To: u-boot Wolfgang Denk wrote: > In message <48188584.3060109@ge.com> you wrote: >> The solution in the PowerPC world is to add a "eieio" or "sync" >> instruction[1] appropriately[2], which prevents the bus interface unit >> from reordering the memory operations. > > No, the solution for ALL architectures is to use the appropriate > accessor macros which take care of such things (and probably contain > calls like sync or similar). > > Best regards, > > Wolfgang Denk Agreed. If my theory is correct, Adrian has turned up a problem with the ARM configuration that apparently only shows up for the PXA250. Or I'm blowing smoke - nothing to see, move along. The hairs on the back of my neck say it is a sync/bus interface unit problem. I don't know if it is significant, not being very intimately familiar with ARM (and, in particular, the PXA250), but my quick grep turns up ./include/asm-arm/io.h and a quick browsing shows no syncs. The hairs on the back of my neck are starting to ache. ;-) static inline void sync(void) { } #define __arch_getb(a) (*(volatile unsigned char *)(a)) gvb ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-04-29 20:20 ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Adrian Filipi 2008-04-29 20:43 ` Wolfgang Denk @ 2008-05-08 11:17 ` Haavard Skinnemoen 2008-05-08 14:05 ` Adrian Filipi 1 sibling, 1 reply; 39+ messages in thread From: Haavard Skinnemoen @ 2008-05-08 11:17 UTC (permalink / raw) To: u-boot Adrian Filipi <adrian.filipi@eurotech.com> wrote: > diff -u -r1.1.1.2.2.2 cfi_flash.c > --- cfi_flash.c 23 Apr 2008 17:02:47 -0000 1.1.1.2.2.2 > +++ cfi_flash.c 29 Apr 2008 18:55:47 -0000 > @@ -464,7 +464,7 @@ > uint offset, uchar cmd) > { > > - void *addr; > + void *volatile addr; That looks bogus. It makes the pointer itself volatile, not whatever it points to. All accesses through addr is performed by appropriate I/O accessors, so no volatile should be needed, and certainly not one that affects the pointer itself. I suspect the change adds a few extra memory accesses (probably to the stack) so that any memory ordering problems just happen to go away. flash_write_cmd() calls sync() after writing the command to the flash, so any memory ordering issues should have been taken care of. However, sync() does nothing on ARM. Maybe it should do something? Haavard ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-05-08 11:17 ` Haavard Skinnemoen @ 2008-05-08 14:05 ` Adrian Filipi 2008-05-08 16:27 ` Haavard Skinnemoen 0 siblings, 1 reply; 39+ messages in thread From: Adrian Filipi @ 2008-05-08 14:05 UTC (permalink / raw) To: u-boot Yeah, I agree it's bogus for the pointer to be volatile. There shouldn't be anything unusual about that. The assembler does show several additional memory accesses, so I think your theory is right. I'm at a loss for what to to on the sync(). Adrian -- Linux Software Engineer | EuroTech, Inc. | www.eurotech-inc.com On Thu, 8 May 2008, Haavard Skinnemoen wrote: > Adrian Filipi <adrian.filipi@eurotech.com> wrote: >> diff -u -r1.1.1.2.2.2 cfi_flash.c >> --- cfi_flash.c 23 Apr 2008 17:02:47 -0000 1.1.1.2.2.2 >> +++ cfi_flash.c 29 Apr 2008 18:55:47 -0000 >> @@ -464,7 +464,7 @@ >> uint offset, uchar cmd) >> { >> >> - void *addr; >> + void *volatile addr; > > That looks bogus. It makes the pointer itself volatile, not whatever it > points to. All accesses through addr is performed by appropriate I/O > accessors, so no volatile should be needed, and certainly not one that > affects the pointer itself. > > I suspect the change adds a few extra memory accesses (probably to the > stack) so that any memory ordering problems just happen to go away. > > flash_write_cmd() calls sync() after writing the command to the flash, > so any memory ordering issues should have been taken care of. However, > sync() does nothing on ARM. Maybe it should do something? > > Haavard > ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] cfi_flash.c and lost volatile qualifier 2008-05-08 14:05 ` Adrian Filipi @ 2008-05-08 16:27 ` Haavard Skinnemoen 0 siblings, 0 replies; 39+ messages in thread From: Haavard Skinnemoen @ 2008-05-08 16:27 UTC (permalink / raw) To: u-boot Adrian Filipi <adrian.filipi@eurotech.com> wrote: > Yeah, I agree it's bogus for the pointer to be volatile. There > shouldn't be anything unusual about that. > > The assembler does show several additional memory accesses, so I > think your theory is right. I'm at a loss for what to to on the sync(). I'm at a loss too, I'm afraid...I don't really know PXA. Linux seems to put an mb() after every write to the flash, so perhaps include/asm-arm/system.h on Linux can provide some hints? In any case, sync() should probably expand to at least a compiler barrier on all architectures...though I'm not sure if it will make a difference in this particular case. Haavard ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-29 19:45 ` [U-Boot-Users] drivers MMCplus for at91sam9x Ken.Fuchs at bench.com 2008-04-29 20:20 ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Adrian Filipi @ 2008-04-30 14:20 ` Pierre Savary 2008-04-30 16:25 ` Ken.Fuchs at bench.com 2008-04-30 20:31 ` Ken.Fuchs at bench.com 1 sibling, 2 replies; 39+ messages in thread From: Pierre Savary @ 2008-04-30 14:20 UTC (permalink / raw) To: u-boot Hi Ken, Thanks a lot for your patch. I will test it next week. Have you ever tested your U-Boot with 4GB or 8GB moviNAND? Thanks in advance Pierre -----Message d'origine----- De?: u-boot-users-bounces at lists.sourceforge.net [mailto:u-boot-users-bounces at lists.sourceforge.net] De la part de Ken.Fuchs at bench.com Envoy??: mardi 29 avril 2008 21:46 ??: pierre.savary at kerlink.fr Cc?: u-boot-users at lists.sourceforge.net; afleming at freescale.com; abo at kerlink.fr; drzeus-mmc at drzeus.cx Objet?: Re: [U-Boot-Users] drivers MMCplus for at91sam9x I posted the following patch under a different subject line: Re: [U-Boot-Users] [PATCH] Add eSDHC driver > > --- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) --- Pierre Savary wrote: > Thanks for that... but it's my own patch ;) > > Pierre =========================================================== Pierre, I hope you like this patch better. :) The following MMC v4 patch is for u-boot-1.1.5_atmel_1.2. To the AT91SAM9261 MCI device driver it adds support for MMC v4.x chips (MoviNAND in particular). The u-boot_at91sam9260_mmc.patch, previously send to this thread 23 April 2008 must be applied to u-boot-1.1.5_atmel_1.2, prior to applying the patch below. The patch includes lines "/* Ignore */". These are simply place holders for code that was not relevant to the MCI driver or MMC code. The patch is actually of four individual source files. Please let me know of any serious problems applying the patch. It should apply cleanly, but I didn't verify this. The MCI MMC v4 features contained in this patch work perfectly on our AT91SAM9261 board, except that I never got MMC 4 bit bus working (that code is omitted from this patch). Anyone know why the AT91SAM9261-EK doesn't appear to support 4 bit MMC? This patch may not work on AT91SAM9261-EK, since we modified the AT91SAM9261-EK board definitions rather than creating a new configuration and files for our board. Sincerely, Ken Fuchs u-boot-at91sam9261-mmc-v4.patch =============================== svn diff -r21 cpu/arm926ejs/at91sam926x/atmel_mci.c Index: cpu/arm926ejs/at91sam926x/atmel_mci.c =================================================================== --- cpu/arm926ejs/at91sam926x/atmel_mci.c (revision 21) +++ cpu/arm926ejs/at91sam926x/atmel_mci.c (working copy) @@ -1,4 +1,8 @@ /* + * (C) Copyright 2007-2008 + * Benchmark Electronics, Inc. + * Added MMC v4.x (MoviNAND) support + * * Copyright (C) 2004-2006 Atmel Corporation * * See file CREDITS for list of people who contributed to this @@ -34,21 +38,43 @@ #include <asm/arch/hardware.h> //klk #include "atmel_mci.h" -#undef DEBUG + +/* Ignore */ +/* Ignore */ +/* Ignore */ + +#if 0 +#define DEBUG +#else /* 0 */ +#undef DEBUG /* kf - was #undef */ +#endif /* 0 */ + #ifdef DEBUG #define pr_debug(fmt, args...) printf(fmt, ##args) #else #define pr_debug(...) do { } while(0) #endif +#undef CFG_MMC_CLK_OD +#define CFG_MMC_CLK_OD 375000 + #ifndef CFG_MMC_CLK_OD #define CFG_MMC_CLK_OD 375000 #endif +#undef CFG_MMC_CLK_PP +#define CFG_MMC_CLK_PP 20000000 + #ifndef CFG_MMC_CLK_PP #define CFG_MMC_CLK_PP 20000000 #endif +#undef CFG_MMC_OP_COND +#define CFG_MMC_OP_COND 0x80ff8000 +/* 0x80ff8080 works with 30+ sec. power off req */ +/* 0x00800000 works better, but write forever? */ +/* 0x00100000 works with 30+ sec. power off req */ + #ifndef CFG_MMC_OP_COND #define CFG_MMC_OP_COND 0x00100000 #endif @@ -74,8 +100,13 @@ bus_hz = AT91C_MASTER_CLOCK; clkdiv = (bus_hz / hz) / 2 - 1; +#if 1 + printf("mmc: setting clock %lu Hz, block size %lu\n", + hz, blklen); +#else /* 1 */ pr_debug("mmc: setting clock %lu Hz, block size %lu\n", hz, blklen); +#endif /* 1 */ if (clkdiv & ~255UL) { clkdiv = 255; @@ -84,10 +115,17 @@ } blklen &= 0xfffc; + +#if 1 /* AT91SAM9261 does not have RDPROOF and WRPROOF fields. */ mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) + | MMCI_BF(BLKLEN, blklen))); +#else /* 1 */ + mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) | MMCI_BF(BLKLEN, blklen) | MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF))); +#endif /* 1 */ + } #define RESP_NO_CRC 1 @@ -99,6 +137,7 @@ #define NCR MMCI_BF(MAXLAT, 1) #define TRCMD_START MMCI_BF(TRCMD, 1) #define TRDIR_READ MMCI_BF(TRDIR, 1) +#define TRDIR_WRITE MMCI_BF(TRDIR, 0) #define TRTYP_BLOCK MMCI_BF(TRTYP, 0) #define INIT_CMD MMCI_BF(SPCMD, 1) #define OPEN_DRAIN MMCI_BF(OPDCMD, 1) @@ -109,6 +148,20 @@ | MMCI_BIT(RINDE) \ | MMCI_BIT(RTOE)) +#if 0 +#define DEBUG +#else /* 0 */ +#undef DEBUG /* kf - was #undef */ +#endif /* 0 */ + +#undef pr_debug + +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args) +#else +#define pr_debug(...) do { } while(0) +#endif + static int mmc_cmd(unsigned long cmd, unsigned long arg, void *resp, unsigned long flags) @@ -117,7 +170,9 @@ int i, response_words = 0; unsigned long error_flags; u32 status; - +#if 1 + pr_debug("mmc_cmd: entry\n"); +#endif /* 1 */ AT91F_MMC_Hardware_Init(); pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n", @@ -161,12 +216,28 @@ return 0; } +#if 0 +#define DEBUG +#else /* 0 */ +#undef DEBUG /* kf - was #undef */ +#endif /* 0 */ + +#undef pr_debug + +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args) +#else +#define pr_debug(...) do { } while(0) +#endif + static int mmc_acmd(unsigned long cmd, unsigned long arg, void *resp, unsigned long flags) { unsigned long aresp[4]; int ret; + pr_debug("mmc_acmd: entry\n"); + /* * Seems like the APP_CMD part of an ACMD has 64 cycles max * latency even though the ACMD part doesn't. This isn't @@ -184,7 +255,16 @@ return ret; } -static unsigned long +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + +unsigned long mmc_bread(int dev, unsigned long start, lbaint_t blkcnt, unsigned long *buffer) { @@ -193,7 +273,14 @@ unsigned long card_status, data; unsigned long wordcount; u32 status; + unsigned long *bufaddr; + pr_debug("mmc_bread: entry\n"); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread ret = %d, card status = %08x\n", ret, card_status); + + bufaddr = buffer; + if (blkcnt == 0) return 0; @@ -202,10 +289,16 @@ /* Put the device into Transfer state */ ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread ret = %d, card status = %08x\n", + ret, card_status); if (ret) goto fail; /* Set block length */ ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread ret = %d, card status = %08x\n", + ret, card_status); if (ret) goto fail; pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); @@ -228,7 +321,6 @@ if (status & MMCI_BIT(RXRDY)) { data = mmci_readl(RDR); - /* pr_debug("%x\n", data); */ *buffer++ = data; wordcount++; } @@ -240,12 +332,68 @@ status = mmci_readl(SR); } while (!(status & MMCI_BIT(BLKE))); - putc('.'); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, + &card_status, R1 | NCR); + pr_debug("mmc: bread ret = %d, card status = %08x\n", + ret, card_status); + + if (i % 0x800 == 0x7ff) { + putc('.'); /* Display '.', after each MB xfer'ed */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + } + +#if 0 + buffer = bufaddr; + wordcount = 0; + do { + if (wordcount % 8 == 0) { + pr_debug("\n%06lx:", 4 * wordcount); + } + pr_debug(" %08lx", *buffer++); + wordcount++; + } while (4 * wordcount < mmc_blkdev.blksz); + pr_debug("\n"); +#endif /* 0 */ + } out: /* Put the device back into Standby state */ mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread ret = %d, card status = %08x\n", ret, card_status); + if (i >= 0x7ff) { + putc('\n'); + } return i; fail: @@ -254,8 +402,329 @@ goto out; } +unsigned long +mmc_bwrite(int dev, unsigned long start, lbaint_t blkcnt, + unsigned long *buffer) +{ + int ret, i = 0; + unsigned long resp[4]; + unsigned long card_status, data; + unsigned long wordcount; + u32 status; + unsigned long *bufaddr; + + pr_debug("mmc_bwrite: entry\n"); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("en mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + + bufaddr = buffer; + + if (blkcnt == 0) + return 0; + + pr_debug("mmc_bwrite: dev %d, start %lx, blkcnt %lx\n", + dev, start, blkcnt); + + /* Put the device into Transfer state */ + ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("sc mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; + + /* Set block length */ + ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("bl mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; + + pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); + + for (i = 0; i < blkcnt; i++, start++) { + ret = mmc_cmd(MMC_CMD_WRITE_BLOCK, + start * mmc_blkdev.blksz, resp, + (R1 | NCR | TRCMD_START | TRDIR_WRITE + | TRTYP_BLOCK)); + if (ret) goto fail; + + ret = -EIO; + wordcount = 0; + do { + do { + status = mmci_readl(SR); + if (status & (ERROR_FLAGS | MMCI_BIT(UNRE))) + goto fail; + } while (!(status & MMCI_BIT(TXRDY))); + + if (status & MMCI_BIT(TXRDY)) { + data = *buffer++; + mmci_writel(TDR, data); + wordcount++; + } + } while(wordcount < (mmc_blkdev.blksz / 4)); + + pr_debug("mmc: write %u words, waiting for BLKE\n", wordcount); + + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(BLKE))); + + do { + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, + &card_status, R1 | NCR); + if ((card_status & 0x00000100) != 0x00000100) { +#if 0 + printf("lp mmc: bwrite ret = %d, ", ret); + printf("card status = %08x\n", card_status); +#endif /* 0 */ + } else { + pr_debug("lp mmc: bwrite ret = %d, ", ret); + pr_debug("card status = %08x\n", card_status); + } + } while ((card_status & 0x00000100) != 0x00000100); + + if (i % 0x800 == 0x7ff) { + putc('.'); /* Display '.', after each MB xfer'ed */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + } + +#if 0 + ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION, + 0, resp, + R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, + &card_status, R1 | NCR); + pr_debug("st mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; +#endif /* 0 */ + + } + +out: +#if 0 + ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION, + 0, resp, + R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("st mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; +#endif /* 0 */ + + /* Put the device back into Standby state */ + mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("dc mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + if (i >= 0x7ff) { + putc('\n'); + } + return i; + +fail: + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("fa mmc: bwrite ret = %d, card status = %08x\n", + ret, card_status); + goto out; +} + + /* Hangs - did not attempt to debug */ +/* MMC Multiple Block Write - mmc_mbwrite() */ +unsigned long +mmc_mbwrite(int dev, unsigned long start, lbaint_t blkcnt, + unsigned long *buffer) +{ + int ret, i = 0; + unsigned long resp[4]; + unsigned long card_status, data; + unsigned long wordcount; + u32 status; + unsigned long *bufaddr; + + pr_debug("mmc_bwrite: entry\n"); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("en mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + + bufaddr = buffer; + + if (blkcnt == 0) + return 0; + + if (blkcnt > 0xffff) { /* Exceeds length supported by MoviNAND. */ + return -1; + } + + pr_debug("mmc_mbwrite: dev %d, start %lx, blkcnt %lx\n", + dev, start, blkcnt); + + /* Put the device into Transfer state */ + ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("sc mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; + + /* Set block length */ + ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("bl mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; + + pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); + + ret = mmc_cmd(MMC_CMD_SET_BLOCK_COUNT, + blkcnt, resp, + R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("bc mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; + + ret = mmc_cmd(MMC_CMD_WRITE_MULTIPLE_BLOCK, + start * mmc_blkdev.blksz, resp, + (R1 | NCR | TRCMD_START | TRDIR_WRITE | TRTYP_BLOCK)); + if (ret) goto fail; + + for (i = 0; i < blkcnt; i++, start++) { + + ret = -EIO; + wordcount = 0; + do { + do { + status = mmci_readl(SR); + if (status & (ERROR_FLAGS | MMCI_BIT(UNRE))) + goto fail; + } while (!(status & MMCI_BIT(TXRDY))); + + if (status & MMCI_BIT(TXRDY)) { + data = *buffer++; + mmci_writel(TDR, data); + wordcount++; + } + } while(wordcount < (mmc_blkdev.blksz / 4)); + +#if 1 + pr_debug("mmc: write %u words, waiting for BLKE\n", wordcount); + + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(BLKE))); +#endif /* 0 */ + + do { + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, + &card_status, R1 | NCR); + if ((card_status & 0x00000100) != 0x00000100) { +#if 0 + printf("lp mmc: mbwrite ret = %d, ", ret); + printf("card status = %08x\n", card_status); +#endif /* 0 */ + } else { + pr_debug("lp mmc: mbwrite ret = %d, ", ret); + pr_debug("card status = %08x\n", card_status); + } + } while ((card_status & 0x00000100) != 0x00000100); + + if (i % 0x800 == 0x7ff) { + putc('.'); /* Display '.', after each MB xfer'ed */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + } + } + +out: +#if 0 + ret = mmc_cmd(MMC_CMD_STOP_TRANSMISSION, + 0, resp, + R1 | NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("st mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + if (ret) goto fail; +#endif /* 0 */ + + /* Put the device back into Standby state */ + mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("dc mmc: mbwrite ret = %d, card status = %08x\n", + ret, card_status); + if (i >= 0x7ff) { + putc('\n'); + } + return i; + +fail: + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("fa mmc: mbwrite failed, card status = %08x\n", card_status); + goto out; +} + static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp) { + pr_debug("mmc_parse_cid: entry\n"); + cid->mid = resp[0] >> 24; cid->oid = (resp[0] >> 8) & 0xffff; cid->pnm[0] = resp[0]; @@ -272,6 +741,8 @@ static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp) { + pr_debug("sd_parse_cid: entry\n"); + cid->mid = resp[0] >> 24; cid->oid = (resp[0] >> 8) & 0xffff; cid->pnm[0] = resp[0]; @@ -288,6 +759,8 @@ static void mmc_dump_cid(const struct mmc_cid *cid) { + pr_debug("mmc_dump_cid: entry\n"); + printf("Manufacturer ID: %02lX\n", cid->mid); printf("OEM/Application ID: %04lX\n", cid->oid); printf("Product name: %s\n", cid->pnm); @@ -301,6 +774,9 @@ static void mmc_dump_csd(const struct mmc_csd *csd) { unsigned long *csd_raw = (unsigned long *)csd; + + pr_debug("mmc_dump_csd: entry\n"); + pr_debug("CSD data: %08lx %08lx %08lx %08lx\n", csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]); pr_debug("CSD structure version: 1.%u\n", csd->csd_structure); @@ -337,6 +813,8 @@ { int ret; + pr_debug("mmc_idle_cards: entry\n"); + /* Reset and initialize all cards */ ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0); @@ -352,6 +830,8 @@ unsigned long resp[4]; int i, ret = 0; + pr_debug("sd_init_card: entry\n"); + mmc_idle_cards(); for (i = 0; i < 1000; i++) { ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND, CFG_MMC_OP_COND, @@ -387,10 +867,40 @@ { unsigned long resp[4]; int i, ret = 0; + u32 status; + pr_debug("mmc_init_card: entry\n"); + mmc_idle_cards(); + /* MoviNAND initialization */ for (i = 0; i < 1000; i++) { + mmci_writel(ARGR, 0xFFFFFFFF); + mmci_writel(CMDR, 0x0018113F); + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(CMDRDY))); + } + /* Getting the OCR value seems to prevent marginal chips from */ + /* working@all, whereas they would work fine after waiting */ + /* a full minute or more with the power off prior to booting. */ + /* Our marginal chips have date codes 0716 and 0728. */ +#if 0 + for (i = 0; i < 1000; i++) { + /* Request OCR value to determine chip's supported volt. */ + ret = mmc_cmd(MMC_CMD_SEND_OP_COND, 0, resp, + R3 | NID | OPEN_DRAIN); + if (ret || (resp[0] & 0x80000000)) + { + break; + } + ret = -ETIMEDOUT; + } + if (ret) { + return ret; + } +#endif /* 0 */ + for (i = 0; i < 1000; i++) { ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND, resp, R3 | NID | OPEN_DRAIN); if (ret || (resp[0] & 0x80000000)) @@ -399,13 +909,35 @@ } ret = -ETIMEDOUT; } + pr_debug("Step 4: ret = 0x%lx\n", ret); + pr_debug("MMC_CMD_SEND_OP_COND = 0x%lx\n", MMC_CMD_SEND_OP_COND); + pr_debug("CFG_MMC_OP_COND = 0x%lx\n", CFG_MMC_OP_COND); + pr_debug("resp[0] = 0x%lx\n", resp[0]); + pr_debug("resp[1] = 0x%lx\n", resp[1]); + pr_debug("resp[2] = 0x%lx\n", resp[2]); + pr_debug("resp[3] = 0x%lx\n", resp[3]); + pr_debug("R3 = 0x%lx\n", R3); + pr_debug("NID = 0x%lx\n", NID); + pr_debug("OPEN_DRAIN = 0x%lx\n", OPEN_DRAIN); + pr_debug("4\n"); pr_debug("ret : %i\n",ret); + + pr_debug("MCI_MR = 0x%08lx\n", mmci_readl(MR)); + pr_debug("MCI_DTOR = 0x%08lx\n", mmci_readl(DTOR)); + pr_debug("MCI_SDCR = 0x%08lx\n", mmci_readl(SDCR)); + pr_debug("MCI_ARGR = 0x%08lx\n", mmci_readl(ARGR)); + /* RSPR */ + /* RDR */ + pr_debug("MCI_SR = 0x%08lx\n", mmci_readl(SR)); + pr_debug("MCI_IMR = 0x%08lx\n", mmci_readl(IMR)); + if (ret) return ret; pr_debug("5\n"); /* Get CID of all cards. FIXME: Support more than one card */ ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID | OPEN_DRAIN); + pr_debug("ALL_SEND_CID ret: 0x%08lx\n", ret); if (ret) return ret; mmc_parse_cid(cid, resp); @@ -415,6 +947,7 @@ /* Set Relative Address of the card that responded */ ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp, R1 | NCR | OPEN_DRAIN); + pr_debug("SET_RELATIVE_ADDR ret: 0x%08lx\n", ret); return ret; } @@ -471,23 +1004,42 @@ dtocyc << shift, dtor); } +#define DEFAULT_SECTOR_SIZE 512 + int mmc_init(int verbose) { struct mmc_cid cid; struct mmc_csd csd; unsigned int max_blksz; int ret,aux; + unsigned char buffer[DEFAULT_SECTOR_SIZE]; + pr_debug("mmc_init: entry\n"); + pr_debug("mmc_init: verbose = 0x%08lx\n", verbose); + AT91F_MMC_Hardware_Init(); pr_debug("0\n"); /* Initialize controller */ mmci_writel(CR, MMCI_BIT(SWRST)); mmci_writel(CR, MMCI_BIT(MCIEN)); + + pr_debug("MCI_MR = 0x%08lx\n", mmci_readl(MR)); + pr_debug("MCI_DTOR = 0x%08lx\n", mmci_readl(DTOR)); + pr_debug("MCI_SDCR = 0x%08lx\n", mmci_readl(SDCR)); + pr_debug("MCI_ARGR = 0x%08lx\n", mmci_readl(ARGR)); + /* RSPR */ + /* RDR */ + pr_debug("MCI_SR = 0x%08lx\n", mmci_readl(SR)); + pr_debug("MCI_IMR = 0x%08lx\n", mmci_readl(IMR)); + mmci_writel(DTOR, 0x5f); mmci_writel(IDR, ~0UL); mmci_writel(SDCR, 0x1); mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); +#if 0 + mmci_writel(MR, 0x02009B4A); +#endif /* 0 */ /* //mmci_writel(CR, MMCI_BIT(SWRST)); mmci_writel(CR, 0x00000001); mmci_writel(DTOR, 0x0000007F); @@ -502,6 +1054,7 @@ ret = sd_init_card(&cid, verbose); if (ret) { + pr_debug("Not SDCard, try MMC\n"); mmc_rca = MMC_DEFAULT_RCA; ret = mmc_init_card(&cid, verbose); } @@ -545,6 +1098,20 @@ mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz); #if 0 + mmc_bread(mmc_blkdev.dev, 1024, 1, (ulong *)buffer); + buffer[0] = 0x00; buffer[1] = 0x11; + buffer[2] = 0x22; buffer[3] = 0x33; + buffer[4] = 0x44; buffer[5] = 0x55; + buffer[6] = 0x66; buffer[7] = 0x77; + buffer[504] = 0x88; buffer[505] = 0x99; + buffer[506] = 0xaa; buffer[507] = 0xbb; + buffer[508] = 0xcc; buffer[509] = 0xdd; + buffer[510] = 0xee; buffer[511] = 0xff; + mmc_bwrite(mmc_blkdev.dev, 1024, 1, (ulong *)buffer); + mmc_bread(mmc_blkdev.dev, 1024, 1, (ulong *)buffer); +#endif /* 0 */ + +#if 0 if (fat_register_device(&mmc_blkdev, 1)) pr_debug("Could not register MMC fat device\n"); #else @@ -556,16 +1123,22 @@ int mmc_read(ulong src, uchar *dst, int size) { + pr_debug("mmc_read: entry\n"); + return -ENOSYS; } int mmc_write(uchar *src, ulong dst, int size) { + pr_debug("mmc_write: entry\n"); + return -ENOSYS; } int mmc2info(ulong addr) { + pr_debug("mmc2info: entry\n"); + return 0; } svn diff -r21 include/asm-arm/arch-at91sam926x/mmc.h Index: include/asm-arm/arch-at91sam926x/mmc.h =================================================================== --- include/asm-arm/arch-at91sam926x/mmc.h (revision 0) +++ include/asm-arm/arch-at91sam926x/mmc.h (revision 50) @@ -0,0 +1,103 @@ +/* + * (C) Copyright 2007 + * Benchmark Electronics, Inc. + * Added MMC v4.x (MoviNAND) support + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __ASM_AT91SAM926X_MMC_H +#define __ASM_AT91SAM926X_MMC_H + +struct mmc_cid { + unsigned long psn; + unsigned short oid; + unsigned char mid; + unsigned char prv; + unsigned char mdt; + char pnm[7]; +}; + +struct mmc_csd +{ + u8 csd_structure:2, + spec_vers:4, + rsvd1:2; + u8 taac; + u8 nsac; + u8 tran_speed; + u16 ccc:12, + read_bl_len:4; + u64 read_bl_partial:1, + write_blk_misalign:1, + read_blk_misalign:1, + dsr_imp:1, + rsvd2:2, + c_size:12, + vdd_r_curr_min:3, + vdd_r_curr_max:3, + vdd_w_curr_min:3, + vdd_w_curr_max:3, + c_size_mult:3, + sector_size:5, + erase_grp_size:5, + wp_grp_size:5, + wp_grp_enable:1, + default_ecc:2, + r2w_factor:3, + write_bl_len:4, + write_bl_partial:1, + rsvd3:5; + u8 file_format_grp:1, + copy:1, + perm_write_protect:1, + tmp_write_protect:1, + file_format:2, + ecc:2; + u8 crc:7; + u8 one:1; +}; + +/* MMC Command numbers */ +#define MMC_CMD_GO_IDLE_STATE 0 +#define MMC_CMD_SEND_OP_COND 1 +#define MMC_CMD_ALL_SEND_CID 2 +#define MMC_CMD_SET_RELATIVE_ADDR 3 +#define MMC_CMD_SD_SEND_RELATIVE_ADDR 3 +#define MMC_CMD_SET_DSR 4 +#define MMC_CMD_SELECT_CARD 7 +#define MMC_CMD_SEND_CSD 9 +#define MMC_CMD_SEND_CID 10 +#define MMC_CMD_STOP_TRANSMISSION 12 +#define MMC_CMD_SEND_STATUS 13 +#define MMC_CMD_SET_BLOCKLEN 16 +#define MMC_CMD_READ_SINGLE_BLOCK 17 +#define MMC_CMD_READ_MULTIPLE_BLOCK 18 +#define MMC_CMD_SET_BLOCK_COUNT 23 +#define MMC_CMD_WRITE_BLOCK 24 +#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 +#define MMC_CMD_APP_CMD 55 + +#define MMC_ACMD_SD_SEND_OP_COND 41 + +#define R1_ILLEGAL_COMMAND (1 << 22) +#define R1_APP_CMD (1 << 5) + +#endif /* __ASM_AT91SAM926X_MMC_H */ svn diff -r21 include/configs/at91sam9261ek.h Index: include/configs/at91sam9261ek.h =================================================================== --- include/configs/at91sam9261ek.h (revision 21) +++ include/configs/at91sam9261ek.h (working copy) @@ -1,4 +1,8 @@ /* + * (C) Copyright 2007-2008 + * Benchmark Electronics, Inc. + * Added MMC v4.x (MoviNAND) support + * * (C) Copyright 2005 * M. Amine SAYA ATMEL Rousset, France. * @@ -95,18 +99,24 @@ /* SPI */ #define CONFIG_SPI +/* kf - define hush (from busy box) command line interface & options */ +#define CFG_HUSH_PARSER +#define CFG_PROMPT_HUSH_PS2 "> " +#define CFG_AUTO_COMPLETE +#define CONFIG_CMDLINE_EDITING + #define CONFIG_COMMANDS \ ((CONFIG_CMD_DFL | \ CFG_CMD_NET | \ CFG_CMD_ENV | \ CFG_CMD_USB | \ CFG_CMD_FLASH | \ - CFG_CMD_NAND | \ + CFG_CMD_MMC | \ + CFG_CMD_EXT2 | \ + CFG_CMD_FAT | \ CFG_CMD_AUTOSCRIPT | \ - CFG_CMD_FAT | \ CFG_CMD_NFS | \ CFG_CMD_SPI | \ - CFG_CMD_U | \ CFG_CMD_IMI | \ CFG_CMD_PING ) & \ ~(CFG_CMD_BDI | \ @@ -296,8 +306,12 @@ #define CFG_FLASH_ERASE_TOUT (2*CFG_HZ) /* Timeout for Flash Erase */ #define CFG_FLASH_WRITE_TOUT (2*CFG_HZ) /* Timeout for Flash Write */ +#undef CFG_ENV_IS_IN_FLASH #define CFG_ENV_IS_IN_DATAFLASH 1 -#undef CFG_ENV_IS_IN_FLASH +#if 0 +#undef CFG_ENV_IS_IN_NAND +#endif /* 0 - kf */ +#undef CFG_ENV_IS_NOWHERE #ifdef CFG_ENV_IS_IN_DATAFLASH #define CFG_ENV_OFFSET 0x4000 @@ -305,6 +319,10 @@ #define CFG_ENV_SIZE 0x4000 /* 0x8000 */ #endif +#ifdef CFG_ENV_IS_NOWHERE +#define CFG_ENV_SIZE 0x4000 +#endif + #ifdef CFG_ENV_IS_IN_FLASH #ifdef CONFIG_BOOTBINFUNC #define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x60000) /* after u-boot.bin */ @@ -316,6 +334,9 @@ #endif /* Add LCD stuff */ +/* Ignore */ +/* Ignore */ + #if 0 /* No LCD */ #define CONFIG_LCD /* #undef CONFIG_LCD_LOGO */ @@ -333,8 +354,21 @@ #define CONFIG_DOS_PARTITION 1 #define LITTLEENDIAN 1 -#define CFG_LOAD_ADDR 0x23f00000 /* default load address */ +/* Add FAT filesystem configuration, other than CFG_CMD_FAT */ +#define CONFIG_SUPPORT_VFAT +/* MMC */ +#define CONFIG_MMC 1 +#define MMCI_BASE 0xFFFA8000 /* (void *)AT91C_BASE_MCI */ +/* MMC - kf - slow down speed for debug from 20000000 Hz down to ... */ +/* However, tweaking this value here causes all code to be compiled, */ +/* so we shall change the value only where needed - in atmel_mci.c. */ +#define CFG_MMC_CLK_PP 20000000 + +#define CFG_LOAD_ADDR 0x23f00000 /* default load address */ + +#define CFG_BOOTM_LEN 0x02100000 /* 33MB uncompressed max. */ + #ifdef CONFIG_BOOTBINFUNC #define CFG_BOOT_SIZE 0x00 /* 0 KBytes */ #define CFG_U_BOOT_BASE PHYS_FLASH_1 svn diff -r21 board/at91sam9261ek/at91sam9261ek.c Index: board/at91sam9261ek/at91sam9261ek.c =================================================================== --- board/at91sam9261ek/at91sam9261ek.c (revision 21) +++ board/at91sam9261ek/at91sam9261ek.c (working copy) @@ -1,4 +1,8 @@ /* + * (C) Copyright 2007-2008 + * Benchmark Electronics, Inc. + * Added specific AT91SAM9261 board support + * * (C) Copyright 2005 * M. Amine SAYA ATMEL Rousset, France. * Added AT91SAM9261EK support. @@ -28,12 +32,19 @@ #include <common.h> #include <asm/arch/hardware.h> +#include <asm/arch-at91sam926x/at91sam9261.h> #include <net.h> extern void AT91F_Spi1Init (void); extern void gpio_init(void); +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + /* ------------------------------------------------------------------------ - */ /* * Miscelaneous platform dependent initialisations @@ -107,7 +118,8 @@ *AT91C_PMC_PCER |= 1 << AT91C_ID_US0; /* enable clock */ #endif -#ifdef CONFIG_USART1 +#if 1 + /* #ifdef CONFIG_USART1 */ *AT91C_PIOB_PDR = AT91C_PC12_TXD1 | AT91C_PC13_RXD1; *AT91C_PMC_PCER |= 1 << AT91C_ID_US1; /* enable clock */ #endif @@ -118,6 +130,41 @@ #endif } +#ifdef CONFIG_MMC +#if (CONFIG_COMMANDS & CFG_CMD_MMC) +int AT91F_MMC_Hardware_Init(void) +{ +#if 0 + printf("AT91F_MMC_Hardware_Init: entry\n"); +#endif /* 0 */ + + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, + 0, /* <- Peripheral A */ + (AT91C_PA0_MCDA0 | /* MMC NAND MCDA0 */ + AT91C_PA1_MCCDA | /* MMC NAND MCCDA */ + AT91C_PA2_MCCK | /* MMC NAND MCCK */ + AT91C_PA4_MCDA1 | /* MMC NAND MCDA1 */ + AT91C_PA5_MCDA2 | /* MMC NAND MCDA2 */ + AT91C_PA6_MCDA3 | /* MMC NAND MCDA3 */ + 0)); /* <- Peripheral B */ + +#if 1 + /* Pull up disable register */ + AT91C_BASE_PIOA->PIO_PPUDR |= + AT91C_PA0_MCDA0 | /* MMC NAND MCDA0 */ + AT91C_PA1_MCCDA | /* MMC NAND MCCDA */ + AT91C_PA2_MCCK | /* MMC NAND MCCK */ + AT91C_PA4_MCDA1 | /* MMC NAND MCDA1 */ + AT91C_PA5_MCDA2 | /* MMC NAND MCDA2 */ + AT91C_PA6_MCDA3; /* MMC NAND MCDA3 */ +#endif /* 0 */ + + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_MCI); +} +#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */ +#endif /* CONFIG_MMC */ + + int dram_init (void) { DECLARE_GLOBAL_DATA_PTR; @@ -148,5 +195,35 @@ gpio_init(); +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ +/* Ignore */ + return 0; } ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao ne _______________________________________________ U-Boot-Users mailing list U-Boot-Users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-30 14:20 ` [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary @ 2008-04-30 16:25 ` Ken.Fuchs at bench.com 2008-04-30 20:31 ` Ken.Fuchs at bench.com 1 sibling, 0 replies; 39+ messages in thread From: Ken.Fuchs at bench.com @ 2008-04-30 16:25 UTC (permalink / raw) To: u-boot Pierre Savary wrote: > Thanks a lot for your patch. I will test it next week. Sorry, that patch was manually constructed. I forgot about include/asm-arm/arch-at91sam926x/at91sam9261.h which includes the pin definitions used by the MCI controller. An ancillary patch for this file is appended below. Of course it is useful only for AT91SAM9261 based boards. Note that Atmel used different conventions for defining AT91SAM9261 and AT91SAM9260/AT91SAM9263 hardware (at least for GPIO pin) definitions. This will cause problems in applying the previously posted u-boot-at91sam9261-mmc-v4.patch for boards not based on the AT91SAM9261 (i.e. AT91SAM9260/AT91SAM9263). Note that I added the MMC v4.x code without access to the spec. All I had was a MoviNAND manual, which assumes access to the MMC v4.x spec. (Note that the final CMD1 arg. is the correct and recommended value for MoviNAND chips by their field eng.) The patch included a lot of commented out (/* */ & '#if 0') code used to help me understand MMC v4.x, at least well enough to get the MoviNAND working reliably. I never did get multi-block read or write working; The code for it is included in the previous sent patch. As I mentioned before, I also didn't get 4 bit MMC working, but the code for that is _not_ included in the patch anyway. The Linux MMC code enables 4 bit for AT91SAM9260/AT91SAM9263 and only 1 bit for AT91SAM9261. Does anyone know why? I'd really like to get 4 bit transfers working on the 9261 via U-Boot. I may try to put together a better patch using an earlier version of my U-Boot code as a basis. I'm not so sure my previously sent patch will apply as cleanly as I had thought. > Have you ever tested your U-Boot with 4GB or 8GB moviNAND? No. Sincerely, Ken Fuchs u-boot-at9261-mci-gpio-pins.patch ================================= svn diff -r21 Index: include/asm-arm/arch-at91sam926x/at91sam9261.h =================================================================== --- include/asm-arm/arch-at91sam926x/at91sam9261.h (revision 21) +++ include/asm-arm/arch-at91sam926x/at91sam9261.h (working copy) @@ -17,6 +17,10 @@ * Generated : AT91 SW Application Group 03/30/2005 (17:05:06) * * ------------------------------------------------------------------------ ---- + * (C) Copyright 2007-2008 + * Benchmark Electronics, Inc. + * Added numerous GPIO pin definitions for custom AT91SAM9261 board. + * */ #ifndef AT91SAM9261_H #define AT91SAM9261_H @@ -1330,8 +1334,10 @@ /* ************************************************************************ ***** */ #define AT91C_PIO_PA0 ((unsigned int) 1 << 0) /* Pin Controlled by PA0 */ #define AT91C_PA0_MISO0 ((unsigned int) AT91C_PIO_PA0) /* SPI0 Master In Slave */ +#define AT91C_PA0_MCDA0 ((unsigned int) AT91C_PIO_PA0) /* MMC NAND MCDA0 */ #define AT91C_PIO_PA1 ((unsigned int) 1 << 1) /* Pin Controlled by PA1 */ #define AT91C_PA1_MOSI0 ((unsigned int) AT91C_PIO_PA1) /* SPI0 Master Out Slave */ +#define AT91C_PA1_MCCDA ((unsigned int) AT91C_PIO_PA1) /* MMC NAND MCCDA */ #define AT91C_PIO_PA10 ((unsigned int) 1 << 10) /* Pin Controlled by PA10 */ #define AT91C_PA10_DTXD ((unsigned int) AT91C_PIO_PA10) /* DBGU Debug Transmit Data */ #define AT91C_PA10_LFON ((unsigned int) AT91C_PIO_PA10) @@ -1346,6 +1352,7 @@ #define AT91C_PA16_NPCS15 ((unsigned int) AT91C_PIO_PA16) /* GPIO: SPI1 CS5 */ #define AT91C_PIO_PA2 ((unsigned int) 1 << 2) /* Pin Controlled by PA2 */ #define AT91C_PA2_SPCK0 ((unsigned int) AT91C_PIO_PA2) /* SPI0 Serial Clock */ +#define AT91C_PA2_MCCK ((unsigned int) AT91C_PIO_PA2) /* MMC NAND MCCK */ #define AT91C_PIO_PA23 ((unsigned int) 1 << 23) /* Pin Controlled by PA23 */ #define AT91C_PA23_NPCS14 ((unsigned int) AT91C_PIO_PA23) /* GPIO: SPI1 CS4 */ #define AT91C_PIO_PA24 ((unsigned int) 1 << 24) /* Pin Controlled by PA24 */ @@ -1358,10 +1365,13 @@ #define AT91C_PA3_NPCS00 ((unsigned int) AT91C_PIO_PA3) /* SPI0 Peripheral Chip Select 0 */ #define AT91C_PIO_PA4 ((unsigned int) 1 << 4) /* Pin Controlled by PA4 */ #define AT91C_PA4_NPCS01 ((unsigned int) AT91C_PIO_PA4) /* SPI0 Peripheral Chip Select 1 */ +#define AT91C_PA4_MCDA1 ((unsigned int) AT91C_PIO_PA4) /* MMC NAND MCDA1 */ #define AT91C_PIO_PA5 ((unsigned int) 1 << 5) /* Pin Controlled by PA5 */ #define AT91C_PA5_NPCS02 ((unsigned int) AT91C_PIO_PA5) /* SPI0 Peripheral Chip Select 2 */ +#define AT91C_PA5_MCDA2 ((unsigned int) AT91C_PIO_PA5) /* MMC NAND MCDA2 */ #define AT91C_PIO_PA6 ((unsigned int) 1 << 6) /* Pin Controlled by PA6 */ #define AT91C_PA6_NPCS03 ((unsigned int) AT91C_PIO_PA6) /* SPI0 Peripheral Chip Select 3 */ +#define AT91C_PA6_MCDA3 ((unsigned int) AT91C_PIO_PA6) /* MMC NAND MCDA3 */ #define AT91C_PIO_PA9 ((unsigned int) 1 << 9) /* Pin Controlled by PA9 */ #define AT91C_PA9_DRXD ((unsigned int) AT91C_PIO_PA9) /* DBGU Debug Receive Data */ #define AT91C_PIO_PB0 ((unsigned int) 1 << 0) /* Pin Controlled by PB0 */ ^ permalink raw reply [flat|nested] 39+ messages in thread
* [U-Boot-Users] drivers MMCplus for at91sam9x 2008-04-30 14:20 ` [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary 2008-04-30 16:25 ` Ken.Fuchs at bench.com @ 2008-04-30 20:31 ` Ken.Fuchs at bench.com 1 sibling, 0 replies; 39+ messages in thread From: Ken.Fuchs at bench.com @ 2008-04-30 20:31 UTC (permalink / raw) To: u-boot Pierre Savary wrote: > Thanks a lot for your patch. I will test it next week. I found it useful to modify common/cmd_mmc.c drastically to facilitate easier testing of the AT91SAM9 MCI driver. It replaces mmcinit with "mmc init" and adds raw read ("mmc read") and write ("mmc write") functions. To use it, just apply the (ancillary) patch below. Sincerely, Ken Fuchs ------ u-boot-at91sam9261-cmd-mmc-for-testing.patch ============================================ svn diff -r21 common/cmd_mmc.c Index: common/cmd_mmc.c =================================================================== --- common/cmd_mmc.c (revision 21) +++ common/cmd_mmc.c (working copy) @@ -1,4 +1,8 @@ /* + * (C) Copyright 2007-2008 + * Benchmark Electronics, Inc. + * Split mmcinit into mmc init, mmc read and mmc write + * * (C) Copyright 2003 * Kyle Harris, kharris at nexus-tech.net * @@ -28,19 +32,100 @@ #include <mmc.h> +static unsigned int subcmd; +static unsigned int bstart; +static unsigned int noblocks; +static unsigned int address; + int do_mmc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { - if (mmc_init (1) != 0) { - printf ("No MMC card found\n"); - return 1; + unsigned int compblocks; + + if ((flag & CMD_FLAG_REPEAT) == 0) { + if (argc >= 2) { + if ((argv[1][0] == 'I' && argv[1][1] == 'N' + && argv[1][2] == 'I' && argv[1][3] == 'T') || + (argv[1][0] == 'i' && argv[1][1] == 'n' + && argv[1][2] == 'i' && argv[1][3] == 't')) { + subcmd = 0; /* init */ + } else if ((argv[1][0] == 'R') || + (argv[1][0] == 'r')) { + subcmd = 1; /* block read */ + } else if ((argv[1][0] == 'W') || + (argv[1][0] == 'w')) { + subcmd = 2; /* block write */ + } else if ((argv[1][0] == 'M') || + (argv[1][0] == 'm')) { + subcmd = 3; /* multiple block write */ + } else { + printf("Subcommand must be "); + printf("init, r[ead] or w[rite]\n"); + return 1; + } + } + if (argc >= 3) { + bstart = simple_strtoul(argv[2], NULL, 16); + } + if (argc >= 4) { + noblocks = simple_strtoul(argv[3], NULL, 16); + } + if (argc >= 5) { + address = simple_strtoul(argv[4], NULL, 16); + } } - return 0; + switch (subcmd) { + case 0: + if (mmc_init(1) != 0) { + printf ("No MMC card found\n"); + return 1; + } + return 0; + break; + case 1: + compblocks = mmc_bread(0, bstart, noblocks, (ulong *)address); + if (compblocks < noblocks) { + printf("Error reading block#: 0x%08lx\n", + bstart + compblocks); + } + break; + case 2: + compblocks = + mmc_bwrite(0, bstart, noblocks, (ulong *)address); + if (compblocks < noblocks) { + printf("Error writing block#: 0x%08lx\n", + bstart + compblocks); + } + break; + case 3: + compblocks = + mmc_mbwrite(0, bstart, noblocks, (ulong *)address); + if (compblocks < noblocks) { + printf("Error writing block#: 0x%08lx\n", + bstart + compblocks); + } + break; + } } U_BOOT_CMD( - mmcinit, 1, 0, do_mmc, - "mmcinit - init mmc card\n", - NULL + mmc, 5, 1, do_mmc, + "mmc - init, read & write to the MMC NAND device\n", + "\n\nmmc init - initialize the MMC NAND device\n" + "\nmmc r <block#> <#blocks> <address> - block read MMC NAND blocks\n" + " <block#> - starting block # (hexidecimal) to read\n" + " <#blocks> - no. of (512) blocks (hexidecimal) to read\n" + " <address> - SDRAM/SRAM address (hex.) for read data\n" + "\nmmc w <block#> <#blocks> <address> - block write MMC NAND blocks\n" + " <block#> - starting block # (hexidecimal) to write\n" + " <#blocks> - no. of (512) blocks (hexidecimal) to write\n" + " <address> - SDRAM/SRAM address (hex.) of data to write\n" +#if 0 /* Not working yet, so documentation is removed. */ + "\nmmc m <block#> <#blocks> <address> - multiple block write mode\n" + " <block#> - starting block # (hexidecimal) to write\n" + " <#blocks> - no. of (512) blocks (hexidecimal) to write\n" + " <address> - SDRAM/SRAM address (hex.) of data to write\n" +#endif /* 0 */ + "\nA period (.) is displayed after each full MB is read or written.\n" ); #endif /* CFG_CMD_MMC */ ^ permalink raw reply [flat|nested] 39+ messages in thread
end of thread, other threads:[~2008-05-08 16:27 UTC | newest]
Thread overview: 39+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-08 14:32 [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary
2008-04-09 17:49 ` Jean-Christophe PLAGNIOL-VILLARD
2008-04-10 10:32 ` Pierre Savary
2008-04-10 22:31 ` Ken.Fuchs at bench.com
2008-04-11 8:26 ` Pierre Savary
2008-04-11 15:48 ` Pierre Ossman
2008-04-11 18:54 ` Ken.Fuchs at bench.com
2008-04-12 9:28 ` Pierre Ossman
2008-04-15 10:18 ` Pierre Savary
2008-04-15 16:51 ` Ken.Fuchs at bench.com
[not found] ` <-6021840981243159212@unknownmsgid>
2008-04-15 19:25 ` Andy Fleming
2008-04-16 8:55 ` Pierre Savary
2008-04-16 23:30 ` Ken.Fuchs at bench.com
2008-04-22 11:55 ` Pierre Savary
2008-04-22 15:07 ` [U-Boot-Users] [PATCH] Add eSDHC driver Andy Fleming
2008-04-22 16:53 ` Anton Vorontsov
2008-04-23 19:23 ` Ken.Fuchs at bench.com
2008-04-24 6:24 ` Pierre Savary
2008-04-29 19:45 ` [U-Boot-Users] drivers MMCplus for at91sam9x Ken.Fuchs at bench.com
2008-04-29 20:20 ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Adrian Filipi
2008-04-29 20:43 ` Wolfgang Denk
2008-04-29 21:10 ` Adrian Filipi
2008-04-29 21:16 ` Jerry Van Baren
[not found] ` <alpine.DEB.1.10.0804300949360.13610@pmy.adscville>
2008-04-30 14:43 ` Jerry Van Baren
2008-04-30 15:11 ` Joakim Tjernlund
2008-04-30 15:21 ` Scott Wood
2008-04-30 15:34 ` Joakim Tjernlund
2008-04-30 15:41 ` Wolfgang Denk
2008-04-30 16:02 ` Scott Wood
2008-04-30 16:11 ` Joakim Tjernlund
2008-04-30 15:35 ` [U-Boot-Users] PPC sync/eieio (was cfi_flash.c and lost volatile qualifier) Jerry Van Baren
2008-04-30 15:38 ` [U-Boot-Users] cfi_flash.c and lost volatile qualifier Wolfgang Denk
2008-04-30 15:51 ` Jerry Van Baren
2008-05-08 11:17 ` Haavard Skinnemoen
2008-05-08 14:05 ` Adrian Filipi
2008-05-08 16:27 ` Haavard Skinnemoen
2008-04-30 14:20 ` [U-Boot-Users] drivers MMCplus for at91sam9x Pierre Savary
2008-04-30 16:25 ` Ken.Fuchs at bench.com
2008-04-30 20:31 ` Ken.Fuchs at bench.com
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox