]> git.sur5r.net Git - u-boot/commitdiff
mmc: Properly determine maximum supported bus width
authorAndy Fleming <afleming@freescale.com>
Wed, 31 Oct 2012 19:02:38 +0000 (19:02 +0000)
committerAndy Fleming <afleming@freescale.com>
Tue, 27 Nov 2012 23:48:46 +0000 (17:48 -0600)
At some point, a confusion arose about the use of the bit
definitions in host_caps for bus widths, and the value
in ext_csd. By coincidence, a simple shift could convert
between one and the other:

MMC_MODE_1BIT = 0, EXT_CSD_BUS_WIDTH_1 = 0
MMC_MODE_4BIT = 0x100, EXT_CSD_BUS_WIDTH_4 = 1
MMC_MODE_8BIT = 0x200, EXT_CSD_BUS_WIDTH_8 = 2

However, as host_caps is a bitmask of supported things,
there is not, in fact, a one-to-one correspondence. host_caps
is capable of containing MODE_4BIT | MODE_8BIT, so nonsensical
things were happening where we would try to set the bus width
to 12.

The new code clarifies the very different namespaces:

host_caps/card_caps = bitmask (MMC_MODE_*)
ext CSD fields are just an index (EXT_CSD_BUS_WIDTH_*)
mmc->bus_width integer number of bits (1, 4, 8)

We create arrays to map between the namespaces, like in Linux.

Signed-off-by: Andy Fleming <afleming@freescale.com>
Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
Tested-by: Stephen Warren <swarren@nvidia.com>
drivers/mmc/mmc.c

index 59dc5894c9604ae6484c2e80013feea48c079613..72e8ce6da423018e8714be88fd4a3722fd49dca6 100644 (file)
@@ -868,7 +868,7 @@ static void mmc_set_bus_width(struct mmc *mmc, uint width)
 
 static int mmc_startup(struct mmc *mmc)
 {
-       int err, width;
+       int err;
        uint mult, freq;
        u64 cmult, csize, capacity;
        struct mmc_cmd cmd;
@@ -1087,21 +1087,44 @@ static int mmc_startup(struct mmc *mmc)
                else
                        mmc->tran_speed = 25000000;
        } else {
-               width = ((mmc->host_caps & MMC_MODE_MASK_WIDTH_BITS) >>
-                        MMC_MODE_WIDTH_BITS_SHIFT);
-               for (; width >= 0; width--) {
-                       /* Set the card to use 4 bit*/
+               int idx;
+
+               /* An array of possible bus widths in order of preference */
+               static unsigned ext_csd_bits[] = {
+                       EXT_CSD_BUS_WIDTH_8,
+                       EXT_CSD_BUS_WIDTH_4,
+                       EXT_CSD_BUS_WIDTH_1,
+               };
+
+               /* An array to map CSD bus widths to host cap bits */
+               static unsigned ext_to_hostcaps[] = {
+                       [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
+                       [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
+               };
+
+               /* An array to map chosen bus width to an integer */
+               static unsigned widths[] = {
+                       8, 4, 1,
+               };
+
+               for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
+                       unsigned int extw = ext_csd_bits[idx];
+
+                       /*
+                        * Check to make sure the controller supports
+                        * this bus width, if it's more than 1
+                        */
+                       if (extw != EXT_CSD_BUS_WIDTH_1 &&
+                                       !(mmc->host_caps & ext_to_hostcaps[extw]))
+                               continue;
+
                        err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
-                                       EXT_CSD_BUS_WIDTH, width);
+                                       EXT_CSD_BUS_WIDTH, extw);
 
                        if (err)
                                continue;
 
-                       if (!width) {
-                               mmc_set_bus_width(mmc, 1);
-                               break;
-                       } else
-                               mmc_set_bus_width(mmc, 4 * width);
+                       mmc_set_bus_width(mmc, widths[idx]);
 
                        err = mmc_send_ext_csd(mmc, test_csd);
                        if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
@@ -1115,7 +1138,7 @@ static int mmc_startup(struct mmc *mmc)
                                 && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
                                        &test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
 
-                               mmc->card_caps |= width;
+                               mmc->card_caps |= ext_to_hostcaps[extw];
                                break;
                        }
                }