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>
This commit is contained in:
parent
ed80c931ba
commit
7798f6dbd5
drivers/mmc
|
@ -868,7 +868,7 @@ static void mmc_set_bus_width(struct mmc *mmc, uint width)
|
||||||
|
|
||||||
static int mmc_startup(struct mmc *mmc)
|
static int mmc_startup(struct mmc *mmc)
|
||||||
{
|
{
|
||||||
int err, width;
|
int err;
|
||||||
uint mult, freq;
|
uint mult, freq;
|
||||||
u64 cmult, csize, capacity;
|
u64 cmult, csize, capacity;
|
||||||
struct mmc_cmd cmd;
|
struct mmc_cmd cmd;
|
||||||
|
@ -1087,21 +1087,44 @@ static int mmc_startup(struct mmc *mmc)
|
||||||
else
|
else
|
||||||
mmc->tran_speed = 25000000;
|
mmc->tran_speed = 25000000;
|
||||||
} else {
|
} else {
|
||||||
width = ((mmc->host_caps & MMC_MODE_MASK_WIDTH_BITS) >>
|
int idx;
|
||||||
MMC_MODE_WIDTH_BITS_SHIFT);
|
|
||||||
for (; width >= 0; width--) {
|
/* An array of possible bus widths in order of preference */
|
||||||
/* Set the card to use 4 bit*/
|
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,
|
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
|
||||||
EXT_CSD_BUS_WIDTH, width);
|
EXT_CSD_BUS_WIDTH, extw);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!width) {
|
mmc_set_bus_width(mmc, widths[idx]);
|
||||||
mmc_set_bus_width(mmc, 1);
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
mmc_set_bus_width(mmc, 4 * width);
|
|
||||||
|
|
||||||
err = mmc_send_ext_csd(mmc, test_csd);
|
err = mmc_send_ext_csd(mmc, test_csd);
|
||||||
if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
|
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], \
|
&& memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
|
||||||
&test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
|
&test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
|
||||||
|
|
||||||
mmc->card_caps |= width;
|
mmc->card_caps |= ext_to_hostcaps[extw];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue