summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/mmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core/mmc.c')
-rw-r--r--drivers/mmc/core/mmc.c133
1 files changed, 115 insertions, 18 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 89f7a25b7ac1..995261f7fd70 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -108,23 +108,34 @@ static int mmc_decode_cid(struct mmc_card *card)
return 0;
}
+static void mmc_set_erase_size(struct mmc_card *card)
+{
+ if (card->ext_csd.erase_group_def & 1)
+ card->erase_size = card->ext_csd.hc_erase_size;
+ else
+ card->erase_size = card->csd.erase_size;
+
+ mmc_init_erase(card);
+}
+
/*
* Given a 128-bit response, decode to our card CSD structure.
*/
static int mmc_decode_csd(struct mmc_card *card)
{
struct mmc_csd *csd = &card->csd;
- unsigned int e, m, csd_struct;
+ unsigned int e, m, a, b;
u32 *resp = card->raw_csd;
/*
* We only understand CSD structure v1.1 and v1.2.
* v1.2 has extra information in bits 15, 11 and 10.
+ * We also support eMMC v4.4 & v4.41.
*/
- csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 1 && csd_struct != 2) {
+ csd->structure = UNSTUFF_BITS(resp, 126, 2);
+ if (csd->structure == 0) {
printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
- mmc_hostname(card->host), csd_struct);
+ mmc_hostname(card->host), csd->structure);
return -EINVAL;
}
@@ -151,6 +162,13 @@ static int mmc_decode_csd(struct mmc_card *card)
csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+ if (csd->write_blkbits >= 9) {
+ a = UNSTUFF_BITS(resp, 42, 5);
+ b = UNSTUFF_BITS(resp, 37, 5);
+ csd->erase_size = (a + 1) * (b + 1);
+ csd->erase_size <<= csd->write_blkbits - 9;
+ }
+
return 0;
}
@@ -207,11 +225,22 @@ static int mmc_read_ext_csd(struct mmc_card *card)
goto out;
}
+ /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
+ if (card->csd.structure == 3) {
+ int ext_csd_struct = ext_csd[EXT_CSD_STRUCTURE];
+ if (ext_csd_struct > 2) {
+ printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
+ "version %d\n", mmc_hostname(card->host),
+ ext_csd_struct);
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
if (card->ext_csd.rev > 5) {
- printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
- "version %d\n", mmc_hostname(card->host),
- card->ext_csd.rev);
+ printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
+ mmc_hostname(card->host), card->ext_csd.rev);
err = -EINVAL;
goto out;
}
@@ -222,11 +251,28 @@ static int mmc_read_ext_csd(struct mmc_card *card)
ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
- if (card->ext_csd.sectors)
+
+ /* Cards with density > 2GiB are sector addressed */
+ if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512)
mmc_card_set_blockaddr(card);
}
switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+ case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
+ EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52;
+ break;
+ case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 |
+ EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V;
+ break;
+ case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 |
+ EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V;
+ break;
case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
card->ext_csd.hs_max_dtr = 52000000;
break;
@@ -247,8 +293,30 @@ static int mmc_read_ext_csd(struct mmc_card *card)
if (sa_shift > 0 && sa_shift <= 0x17)
card->ext_csd.sa_timeout =
1 << ext_csd[EXT_CSD_S_A_TIMEOUT];
+ card->ext_csd.erase_group_def =
+ ext_csd[EXT_CSD_ERASE_GROUP_DEF];
+ card->ext_csd.hc_erase_timeout = 300 *
+ ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
+ card->ext_csd.hc_erase_size =
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
+ }
+
+ if (card->ext_csd.rev >= 4) {
+ card->ext_csd.sec_trim_mult =
+ ext_csd[EXT_CSD_SEC_TRIM_MULT];
+ card->ext_csd.sec_erase_mult =
+ ext_csd[EXT_CSD_SEC_ERASE_MULT];
+ card->ext_csd.sec_feature_support =
+ ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
+ card->ext_csd.trim_timeout = 300 *
+ ext_csd[EXT_CSD_TRIM_MULT];
}
+ if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
+ card->erased_byte = 0xFF;
+ else
+ card->erased_byte = 0x0;
+
out:
kfree(ext_csd);
@@ -260,6 +328,8 @@ MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
card->raw_csd[2], card->raw_csd[3]);
MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
+MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
+MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
@@ -271,6 +341,8 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
&dev_attr_csd.attr,
&dev_attr_date.attr,
+ &dev_attr_erase_size.attr,
+ &dev_attr_preferred_erase_size.attr,
&dev_attr_fwrev.attr,
&dev_attr_hwrev.attr,
&dev_attr_manfid.attr,
@@ -303,7 +375,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *oldcard)
{
struct mmc_card *card;
- int err;
+ int err, ddr = MMC_SDR_MODE;
u32 cid[4];
unsigned int max_dtr;
@@ -407,6 +479,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
err = mmc_read_ext_csd(card);
if (err)
goto free_card;
+ /* Erase size depends on CSD and Extended CSD */
+ mmc_set_erase_size(card);
}
/*
@@ -444,17 +518,35 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
mmc_set_clock(host, max_dtr);
/*
- * Activate wide bus (if supported).
+ * Indicate DDR mode (if supported).
+ */
+ if (mmc_card_highspeed(card)) {
+ if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
+ && (host->caps & (MMC_CAP_1_8V_DDR)))
+ ddr = MMC_1_8V_DDR_MODE;
+ else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
+ && (host->caps & (MMC_CAP_1_2V_DDR)))
+ ddr = MMC_1_2V_DDR_MODE;
+ }
+
+ /*
+ * Activate wide bus and DDR (if supported).
*/
if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
unsigned ext_csd_bit, bus_width;
if (host->caps & MMC_CAP_8_BIT_DATA) {
- ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
+ if (ddr)
+ ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_8;
+ else
+ ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
bus_width = MMC_BUS_WIDTH_8;
} else {
- ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
+ if (ddr)
+ ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_4;
+ else
+ ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
bus_width = MMC_BUS_WIDTH_4;
}
@@ -465,12 +557,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
goto free_card;
if (err) {
- printk(KERN_WARNING "%s: switch to bus width %d "
+ printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
"failed\n", mmc_hostname(card->host),
- 1 << bus_width);
+ 1 << bus_width, ddr);
err = 0;
} else {
- mmc_set_bus_width(card->host, bus_width);
+ mmc_card_set_ddr_mode(card);
+ mmc_set_bus_width_ddr(card->host, bus_width, ddr);
}
}
@@ -564,12 +657,16 @@ static int mmc_resume(struct mmc_host *host)
return err;
}
-static void mmc_power_restore(struct mmc_host *host)
+static int mmc_power_restore(struct mmc_host *host)
{
+ int ret;
+
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_claim_host(host);
- mmc_init_card(host, host->ocr, host->card);
+ ret = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
+
+ return ret;
}
static int mmc_sleep(struct mmc_host *host)
@@ -626,7 +723,7 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
{
const struct mmc_bus_ops *bus_ops;
- if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
+ if (!mmc_card_is_removable(host))
bus_ops = &mmc_ops_unsafe;
else
bus_ops = &mmc_ops;