diff options
author | Benn Pörscke <benn.porscke@stericsson.com> | 2011-10-07 15:31:57 +0200 |
---|---|---|
committer | Benn Pörscke <benn.porscke@stericsson.com> | 2011-10-07 15:31:57 +0200 |
commit | 47a4dbf83a75014d6b3467be18997894f1c617db (patch) | |
tree | 7f5d116db48205309fbc4ae0954f20ab8a651e46 /drivers/mmc/core/mmc.c | |
parent | ea8a52f9f4bcc3420c38ae07f8378a2f18443970 (diff) |
Squashandroid-20111012
Change-Id: If0ae9fa8067740ab2ede33703c79ec134f204a5e
Diffstat (limited to 'drivers/mmc/core/mmc.c')
-rw-r--r-- | drivers/mmc/core/mmc.c | 82 |
1 files changed, 67 insertions, 15 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 89f7a25b7ac..eddba13ced0 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -114,17 +114,18 @@ static int mmc_decode_cid(struct mmc_card *card) 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; 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; } @@ -207,11 +208,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 +234,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; @@ -303,7 +332,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 = 0; u32 cid[4]; unsigned int max_dtr; @@ -444,17 +473,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 +512,17 @@ 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); + if (ddr) + mmc_card_set_ddr_mode(card); + else + ddr = MMC_SDR_MODE; + + mmc_set_bus_width_ddr(card->host, bus_width, ddr); } } |