summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2015-10-14 16:11:59 +0200
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2015-10-14 16:11:59 +0200
commit332211ed906a6d3c7ffb0f3cae1865348aadcd14 (patch)
tree319ff3e1d2964a1572ca466beee1b93aa1b71552
parent891f3ac4478238d6ff890a3bd5c8536e7ef91d5e (diff)
mmc: core: Disable HPI for certain Hynix eMMC cards
Certain Hynix eMMC 4.41 cards might get broken when HPI feature is used and hence this patch disables the HPI feature for such buggy cards. As some of the other features like BKOPs/Cache/Sanitize are dependent on HPI feature, those features would also get disabled if HPI is disabled. Change-Id: I6a638ce089cbd977122e47aecb721bc3f0adf7b0 Signed-off-by: Pratibhasagar V <pratibha@codeaurora.org> Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org> Fix ported from the following Android MSM kernel commit: https://www.codeaurora.org/cgit/quic/la/kernel/msm/commit/?id=84af3731019921a28d595dbf6cbf00539706a42c
-rwxr-xr-xdrivers/mmc/core/mmc.c19
-rw-r--r--drivers/mmc/core/mmc_ops.c6
-rw-r--r--include/linux/mmc/card.h9
3 files changed, 32 insertions, 2 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 9af23fe2ae8f..e450fbc66559 100755
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -58,6 +58,16 @@ static const unsigned int tacc_mant[] = {
__res & __mask; \
})
+static const struct mmc_fixup mmc_fixups[] = {
+ /*
+ * Certain Hynix eMMC 4.41 cards might get broken when HPI feature
+ * is used so disable the HPI feature for such buggy cards.
+ */
+ MMC_FIXUP(CID_NAME_ANY, CID_MANFID_HYNIX, 0x014a, add_quirk,
+ MMC_QUIRK_BROKEN_HPI),
+ END_FIXUP
+};
+
/*
* Given the decoded CSD structure, decode the raw CID to our CID structure.
*/
@@ -271,6 +281,9 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
*/
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
+ /* fixup device after ext_csd revision field is updated */
+ mmc_fixup_device(card, mmc_fixups);
+
card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
@@ -414,7 +427,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
if (card->ext_csd.rev >= 5) {
card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
/* check whether the eMMC card supports HPI */
- if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
+ if ((ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) &&
+ !(card->quirks & MMC_QUIRK_BROKEN_HPI)) {
card->ext_csd.hpi = 1;
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
@@ -429,7 +443,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
/* Check whether the eMMC card supports background ops */
- if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)
+ if ((ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) &&
+ card->ext_csd.hpi)
card->ext_csd.bk_ops = 1;
/* Check whether the eMMC card needs proactive refresh */
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index c85c58aca3e2..b9b472796a64 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -555,6 +555,12 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
unsigned int flags;
int err;
+ if (!card->ext_csd.hpi_en) {
+ pr_warning("%s: Card didn't support HPI command\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
opcode = card->ext_csd.hpi_cmd;
flags = MMC_RSP_R1 | MMC_CMD_AC;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index ff194e553634..9eb6c6babd13 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -208,6 +208,8 @@ struct mmc_card {
#define MMC_QUIRK_DISABLE_CD (1<<5) /* disconnect CD/DAT[3] resistor */
#define MMC_QUIRK_INAND_CMD38 (1<<6) /* iNAND devices have broken CMD38 */
#define MMC_QUIRK_BLK_NO_CMD23 (1<<7) /* Avoid CMD23 for regular multiblock */
+#define MMC_QUIRK_BROKEN_HPI (1<<8) /* To avoid eMMC device getting broken permanently */
+ /* due to HPI feature */
unsigned int erase_size; /* erase size in sectors */
unsigned int erase_shift; /* if erase unit is power 2 */
@@ -264,6 +266,13 @@ struct mmc_fixup {
int data;
};
+#define CID_MANFID_SANDISK 0x2
+#define CID_MANFID_TOSHIBA 0x11
+#define CID_MANFID_MICRON 0x13
+#define CID_MANFID_SAMSUNG 0x15
+#define CID_MANFID_KINGSTON 0x70
+#define CID_MANFID_HYNIX 0x90
+
#define CID_MANFID_ANY (-1u)
#define CID_OEMID_ANY ((unsigned short) -1)
#define CID_NAME_ANY (NULL)