[U-Boot] [RFC] [MMC] Is the HIGH_SPEED_SUPPORT bit checked wrong in mmc.c?

Macpaul Lin macpaul at gmail.com
Tue Nov 8 10:15:48 CET 2011


Hi all,

2011/11/3 馬克泡 <macpaul at gmail.com>:
> Hi all,
>
> I have a problem on reading low speed card on my platform.
> While high speed card were all correct.

I've reported a problem with FTSDC010 controller last week.
The problem is, when I'm using card SD ver 1.10 on the platform, the hardware
will report CRC_FAIL when doing DATA transaction when it reads more
then 1 block (512bytes).

After debugging into the problem, I found that if force the high speed
card (capability) under low speed mode,
the CRC_FAIL problem won't occur.
But, the high speed card which is SD ver 2.0 and later won't have this
kind of problem.

However, after I've got the SD 3.0 specification this week.
I've checked CSD information and SD_SWITCH_SWITCH (STATUS) information
with the card I've read.
The detecting function of high_speed seems no problem at all.
But controller still report CRC_FAIL when the hardware is doing DATA
transaction.
Some cards will even worse, the hardware will report CRC_FAIL on
SD_SWITCH_CHECK Command.

After comparing to the Linux generic mmc stack.
I've found that when the mmc stack is setting ios (clock) of the card,
even if the card reported it has high speed capability
(SW_SWITCH_STATUS >50Mhz), the mmc stack will still check
the tran_speed (CSD) recorded in mmc card.
However, the u-boot's mmc stack will only check if the clock is
smaller than f_max (this should be the capability
of mmc host controller, correct?) but not the actual speed of the card.

The following is the part of Linux code, "drivers/mmc/core/sd.c",
mmc_sd_init_card().
        /*
         * Compute bus speed.
         */
        max_dtr = (unsigned int)-1;

        if (mmc_card_highspeed(card)) {
                if (max_dtr > card->sw_caps.hs_max_dtr) {
                        max_dtr = card->sw_caps.hs_max_dtr;
        printk(KERN_WARNING "%s: sw_caps.hs_max_dtr compute bus speed: %08x\n",
                __func__, card->sw_caps.hs_max_dtr);

                }
        } else if (max_dtr > card->csd.max_dtr) {
                max_dtr = card->csd.max_dtr;
        printk(KERN_WARNING "%s: csd.max_dtr compute bus speed: %08x\n",
                __func__, card->csd.max_dtr);

        }

        mmc_set_clock(host, max_dtr);

The following is the u-boot code, "drivers/mmc/mmc.c", mmc_startup().
        if (IS_SD(mmc)) {

[snip]

                if (mmc->card_caps & MMC_MODE_HS)
                        mmc_set_clock(mmc, 50000000);
                else {
                        mmc_set_clock(mmc, 25000000);

The stack will set 50Mhz as the value of the clock to the driver if
MMC_MODE_HS has been detected.
The MODE_HS detecting function are most the same in both Linux's and
u-boot's code.

In my case, the capability of the platform can support clock up to
33000000MHz, which is depended
to the AHBBUS_CLOCK.

I'm going to add a piece of code to like the behavior in the Linux.
Please help on comments. Thanks!

-- 
Best regards,
Macpaul Lin


More information about the U-Boot mailing list