mmc: Properly determine maximum supported bus width

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>
master
Andy Fleming 12 years ago
parent ed80c931ba
commit 7798f6dbd5
  1. 47
      drivers/mmc/mmc.c

@ -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;
}
}

Loading…
Cancel
Save