summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorNitin Kumbhar <nkumbhar@nvidia.com>2011-04-25 14:42:58 +0530
committerNitin Kumbhar <nkumbhar@nvidia.com>2011-04-25 14:42:58 +0530
commited22062df7ae836e674c01f69e8567ad51ba31b1 (patch)
tree32972feea81e770d650a3dc7d36907a7c49f9d4d /drivers/mmc
parent90651aad036485974b99101df66a50e57c19e732 (diff)
parent2e35e1d7b965893e68f2fb1af77129406be5ff05 (diff)
merging android-tegra-2.6.36 into git-master/linux-2.6/android-tegra-2.6.36
Conflicts: arch/arm/mm/proc-v7.S drivers/video/tegra/dc/dc.c Change-Id: I40be0d615f14f1c01305388a706d257f624ba968
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/block.c44
-rw-r--r--drivers/mmc/core/Makefile3
-rw-r--r--drivers/mmc/core/mmc_ops.c11
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/core/quirks.c48
-rw-r--r--drivers/mmc/core/sdio.c1
6 files changed, 105 insertions, 3 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 7054fd5863a0..e6f74718e06f 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -45,6 +45,13 @@
MODULE_ALIAS("mmc:block");
+#define INAND_CMD38_ARG_EXT_CSD 113
+#define INAND_CMD38_ARG_ERASE 0x00
+#define INAND_CMD38_ARG_TRIM 0x01
+#define INAND_CMD38_ARG_SECERASE 0x80
+#define INAND_CMD38_ARG_SECTRIM1 0x81
+#define INAND_CMD38_ARG_SECTRIM2 0x88
+
/*
* max 8 partitions per card
*/
@@ -265,6 +272,15 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
else
arg = MMC_ERASE_ARG;
+ if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ INAND_CMD38_ARG_EXT_CSD,
+ arg == MMC_TRIM_ARG ?
+ INAND_CMD38_ARG_TRIM :
+ INAND_CMD38_ARG_ERASE);
+ if (err)
+ goto out;
+ }
err = mmc_erase(card, from, nr, arg);
out:
spin_lock_irq(&md->lock);
@@ -299,9 +315,26 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
else
arg = MMC_SECURE_ERASE_ARG;
+ if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ INAND_CMD38_ARG_EXT_CSD,
+ arg == MMC_SECURE_TRIM1_ARG ?
+ INAND_CMD38_ARG_SECTRIM1 :
+ INAND_CMD38_ARG_SECERASE);
+ if (err)
+ goto out;
+ }
err = mmc_erase(card, from, nr, arg);
- if (!err && arg == MMC_SECURE_TRIM1_ARG)
+ if (!err && arg == MMC_SECURE_TRIM1_ARG) {
+ if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ INAND_CMD38_ARG_EXT_CSD,
+ INAND_CMD38_ARG_SECTRIM2);
+ if (err)
+ goto out;
+ }
err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
+ }
out:
spin_lock_irq(&md->lock);
__blk_end_request(req, err, blk_rq_bytes(req));
@@ -686,6 +719,13 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
return 0;
}
+static const struct mmc_fixup blk_fixups[] =
+{
+ MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+ MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+ END_FIXUP
+};
+
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md;
@@ -714,6 +754,8 @@ static int mmc_blk_probe(struct mmc_card *card)
cap_str, md->read_only ? "(ro)" : "");
mmc_set_drvdata(card, md);
+ mmc_fixup_device(card, blk_fixups);
+
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
mmc_set_bus_resume_policy(card->host, 1);
#endif
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 889e5f898f6f..f25f6a5d6ddd 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MMC) += mmc_core.o
mmc_core-y := core.o bus.o host.o \
mmc.o mmc_ops.o sd.o sd_ops.o \
sdio.o sdio_ops.o sdio_bus.o \
- sdio_cis.o sdio_io.o sdio_irq.o
+ sdio_cis.o sdio_io.o sdio_irq.o \
+ quirks.o
mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 326447c9ede8..b6d75eec4b36 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -387,6 +387,15 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
return err;
}
+/**
+ * mmc_switch - modify EXT_CSD register
+ * @card: the MMC card associated with the data transfer
+ * @set: cmd set values
+ * @index: EXT_CSD register index
+ * @value: value to program into EXT_CSD register
+ *
+ * Modifies the EXT_CSD register for selected card.
+ */
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
{
int err;
@@ -434,6 +443,8 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
return 0;
}
+EXPORT_SYMBOL(mmc_switch);
+
int mmc_send_status(struct mmc_card *card, u32 *status)
{
int err;
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 653eb8e84178..b1a806fbd396 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
int mmc_set_relative_addr(struct mmc_card *card);
int mmc_send_csd(struct mmc_card *card, u32 *csd);
int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
int mmc_send_status(struct mmc_card *card, u32 *status);
int mmc_send_cid(struct mmc_host *host, u32 *cid);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
new file mode 100644
index 000000000000..981c11343f45
--- /dev/null
+++ b/drivers/mmc/core/quirks.c
@@ -0,0 +1,48 @@
+/*
+ * This file contains work-arounds for many known sdio hardware
+ * bugs.
+ *
+ * Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
+ * Inspired from pci fixup code:
+ * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mmc/card.h>
+
+static const struct mmc_fixup mmc_fixup_methods[] = {
+ END_FIXUP
+};
+
+void mmc_fixup_device(struct mmc_card *card,
+ const struct mmc_fixup *table)
+{
+ const struct mmc_fixup *f;
+ u64 rev = cid_rev_card(card);
+
+ /* Non-core specific workarounds. */
+ if (!table)
+ table = mmc_fixup_methods;
+
+ for (f = table; f->vendor_fixup; f++) {
+ if ((f->manfid == CID_MANFID_ANY
+ || f->manfid == card->cid.manfid) &&
+ (f->oemid == CID_OEMID_ANY
+ || f->oemid == card->cid.oemid) &&
+ (f->name == CID_NAME_ANY
+ || !strcmp(f->name, card->cid.prod_name)) &&
+ (f->cis_vendor == card->cis.vendor
+ || f->cis_vendor == (u16) SDIO_ANY_ID) &&
+ (f->cis_device == card->cis.device
+ || f->cis_device == (u16) SDIO_ANY_ID) &&
+ rev >= f->rev_start &&
+ rev <= f->rev_end) {
+ dev_dbg(&card->dev, "calling %pF\n", f->vendor_fixup);
+ f->vendor_fixup(card, f->data);
+ }
+ }
+}
+EXPORT_SYMBOL(mmc_fixup_device);
+
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 155efb1ac797..d3ec4dc18d14 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -480,6 +480,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
card = oldcard;
return 0;
}
+ mmc_fixup_device(card, NULL);
if (card->type == MMC_TYPE_SD_COMBO) {
err = mmc_sd_setup_card(host, card, oldcard != NULL);