mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: barebox@lists.infradead.org
Subject: [PATCH 4/5] mci: Fix 8 bit mmc cards
Date: Thu,  9 Feb 2012 14:39:57 +0100	[thread overview]
Message-ID: <1328794798-17699-5-git-send-email-s.hauer@pengutronix.de> (raw)
In-Reply-To: <1328794798-17699-1-git-send-email-s.hauer@pengutronix.de>

Currently we test the cards capabilities for being 8bit capable.
This does not work since noone ever sets this bit. Unfortunately
there is no bit to test 8bit capability, so we introduce a patch
from the kernel which puts the mmc card into 8bit mode and tests
whether it can succesfully read the ext_csd in this mode.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/mci-core.c |  133 ++++++++++++++++++++++++++++++++++++++---------
 include/mci.h          |    1 +
 2 files changed, 108 insertions(+), 26 deletions(-)

diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 2377fef..0bf4449 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -391,10 +391,10 @@ static int mci_switch(struct mci *mci, unsigned set, unsigned index,
  */
 static int mmc_change_freq(struct mci *mci)
 {
-	char *ext_csd = sector_buf;
 	char cardtype;
 	int err;
 
+	mci->ext_csd = xmalloc(512);
 	mci->card_caps = 0;
 
 	/* Only version 4 supports high-speed */
@@ -403,13 +403,13 @@ static int mmc_change_freq(struct mci *mci)
 
 	mci->card_caps |= MMC_MODE_4BIT;
 
-	err = mci_send_ext_csd(mci, ext_csd);
+	err = mci_send_ext_csd(mci, mci->ext_csd);
 	if (err) {
 		dev_dbg(mci->mci_dev, "Preparing for frequency setup failed: %d\n", err);
 		return err;
 	}
 
-	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK;
+	cardtype = mci->ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK;
 
 	err = mci_switch(mci, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
 
@@ -419,7 +419,7 @@ static int mmc_change_freq(struct mci *mci)
 	}
 
 	/* Now check to see that it worked */
-	err = mci_send_ext_csd(mci, ext_csd);
+	err = mci_send_ext_csd(mci, mci->ext_csd);
 
 	if (err) {
 		dev_dbg(mci->mci_dev, "Verifying frequency change failed: %d\n", err);
@@ -427,7 +427,7 @@ static int mmc_change_freq(struct mci *mci)
 	}
 
 	/* No high-speed support */
-	if (!ext_csd[EXT_CSD_HS_TIMING])
+	if (!mci->ext_csd[EXT_CSD_HS_TIMING])
 		return 0;
 
 	/* High Speed is set, there are two types: 52MHz and 26MHz */
@@ -767,6 +767,67 @@ static void mci_extract_card_capacity_from_csd(struct mci *mci)
 	dev_dbg(mci->mci_dev, "Capacity: %u MiB\n", (unsigned)mci->capacity >> 20);
 }
 
+static int mmc_compare_ext_csds(struct mci *mci, unsigned bus_width)
+{
+	u8 *bw_ext_csd;
+	int err;
+
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	bw_ext_csd = xmalloc(512);
+	err = mci_send_ext_csd(mci, bw_ext_csd);
+	if (err) {
+		dev_info(mci->mci_dev, "mci_send_ext_csd failed with %d\n", err);
+		if (bus_width != MMC_BUS_WIDTH_1)
+			err = -EINVAL;
+		goto out;
+	}
+
+	if (bus_width == MMC_BUS_WIDTH_1)
+		goto out;
+	/* only compare read only fields */
+	err = (mci->ext_csd[EXT_CSD_PARTITION_SUPPORT] ==
+			bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
+		(mci->ext_csd[EXT_CSD_ERASED_MEM_CONT] ==
+			bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
+		(mci->ext_csd[EXT_CSD_REV] ==
+			bw_ext_csd[EXT_CSD_REV]) &&
+		(mci->ext_csd[EXT_CSD_STRUCTURE] ==
+			bw_ext_csd[EXT_CSD_STRUCTURE]) &&
+		(mci->ext_csd[EXT_CSD_CARD_TYPE] ==
+			bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
+		(mci->ext_csd[EXT_CSD_S_A_TIMEOUT] ==
+			bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
+		(mci->ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
+			bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
+		(mci->ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] ==
+			bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
+		(mci->ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
+			bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
+		(mci->ext_csd[EXT_CSD_SEC_TRIM_MULT] ==
+			bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
+		(mci->ext_csd[EXT_CSD_SEC_ERASE_MULT] ==
+			bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
+		(mci->ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] ==
+			bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
+		(mci->ext_csd[EXT_CSD_TRIM_MULT] ==
+			bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
+		(mci->ext_csd[EXT_CSD_SEC_CNT + 0] ==
+			bw_ext_csd[EXT_CSD_SEC_CNT + 0]) &&
+		(mci->ext_csd[EXT_CSD_SEC_CNT + 1] ==
+			bw_ext_csd[EXT_CSD_SEC_CNT + 1]) &&
+		(mci->ext_csd[EXT_CSD_SEC_CNT + 2] ==
+			bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
+		(mci->ext_csd[EXT_CSD_SEC_CNT + 3] ==
+			bw_ext_csd[EXT_CSD_SEC_CNT + 3]) ?
+				0 : -EINVAL;
+
+out:
+	free(bw_ext_csd);
+	return err;
+}
+
 static int mci_startup_sd(struct mci *mci)
 {
 	struct mci_cmd cmd;
@@ -802,29 +863,18 @@ static int mci_startup_sd(struct mci *mci)
 
 static int mci_startup_mmc(struct mci *mci)
 {
+	struct mci_host *host = mci->host;
 	int err;
+	int idx = 0;
+	static unsigned ext_csd_bits[] = {
+		EXT_CSD_BUS_WIDTH_4,
+		EXT_CSD_BUS_WIDTH_8,
+	};
+	static unsigned bus_widths[] = {
+		MMC_BUS_WIDTH_4,
+		MMC_BUS_WIDTH_8,
+	};
 
-	if (mci->card_caps & MMC_MODE_4BIT) {
-		dev_dbg(mci->mci_dev, "Set MMC bus width to 4 bit\n");
-		/* Set the card to use 4 bit*/
-		err = mci_switch(mci, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4);
-		if (err) {
-			dev_dbg(mci->mci_dev, "Changing MMC bus width failed: %d\n", err);
-			return err;
-		}
-		mci_set_bus_width(mci, MMC_BUS_WIDTH_4);
-	} else if (mci->card_caps & MMC_MODE_8BIT) {
-		dev_dbg(mci->mci_dev, "Set MMC bus width to 8 bit\n");
-		/* Set the card to use 8 bit*/
-		err = mci_switch(mci, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8);
-		if (err) {
-			dev_dbg(mci->mci_dev, "Changing MMC bus width failed: %d\n", err);
-			return err;
-		}
-		mci_set_bus_width(mci, MMC_BUS_WIDTH_8);
-	}
 	/* if possible, speed up the transfer */
 	if (mci->card_caps & MMC_MODE_HS) {
 		if (mci->card_caps & MMC_MODE_HS_52MHz)
@@ -834,6 +884,37 @@ static int mci_startup_mmc(struct mci *mci)
 	} else
 		mci_set_clock(mci, 20000000);
 
+	/*
+	 * Unlike SD, MMC cards dont have a configuration register to notify
+	 * supported bus width. So bus test command should be run to identify
+	 * the supported bus width or compare the ext csd values of current
+	 * bus width and ext csd values of 1 bit mode read earlier.
+	 */
+	if (host->host_caps & MMC_MODE_8BIT)
+		idx = 1;
+
+	for (; idx >= 0; idx--) {
+
+		/*
+		 * Host is capable of 8bit transfer, then switch
+		 * the device to work in 8bit transfer mode. If the
+		 * mmc switch command returns error then switch to
+		 * 4bit transfer mode. On success set the corresponding
+		 * bus width on the host.
+		 */
+		err = mci_switch(mci, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_BUS_WIDTH,
+				 ext_csd_bits[idx]);
+		if (err)
+			continue;
+
+		mci_set_bus_width(mci, bus_widths[idx]);
+
+		err = mmc_compare_ext_csds(mci, bus_widths[idx]);
+		if (!err)
+			break;
+	}
+
 	return 0;
 }
 
diff --git a/include/mci.h b/include/mci.h
index 7e3b459..97036c3 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -326,6 +326,7 @@ struct mci {
 	unsigned write_bl_len;
 	uint64_t capacity;	/**< Card's data capacity in bytes */
 	int ready_for_use;	/** true if already probed */
+	char *ext_csd;
 };
 
 int mci_register(struct mci_host*);
-- 
1.7.9


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

  parent reply	other threads:[~2012-02-09 13:40 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-02-09 13:39 [PATCH] more mci related stuff Sascha Hauer
2012-02-09 13:39 ` [PATCH 1/5] Add a timeout polling loop convenience wrapper Sascha Hauer
2012-02-09 13:39 ` [PATCH 2/5] mci i.MX esdhc: use timeout loops Sascha Hauer
2012-02-09 13:39 ` [PATCH 3/5] mci: Add a complete list of EXT_CSD_* fields from the kernel Sascha Hauer
2012-02-09 13:39 ` Sascha Hauer [this message]
2012-02-09 13:39 ` [PATCH 5/5] mci i.MX esdhc: make 8bit modes platform dependent Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1328794798-17699-5-git-send-email-s.hauer@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox