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
@ -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…
Reference in New Issue
Block a user