aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Anderson <sean.anderson@seco.com>2023-10-27 16:57:03 -0400
committerJaehoon Chung <jh80.chung@samsung.com>2023-11-01 10:01:10 +0900
commit21c84bb1112695f9bd49379f7e32c251b55a3cad (patch)
tree2fbe9e0e90b289fe6073799180d31806f9fe6d7f
parentc27c8102e128827c684d8d3da7f0ce03d550b65a (diff)
mmc: sdhci: Rework SDHCI_QUIRK_BROKEN_R1B
As noted in commit 3a6383207be ("mmc: sdhci: add the quirk for broken r1b response"), some MMC controllers don't always set the transfer complete bit with R1b responses. According to the SD Host Controller Simplified Specification v4.20, > In the case of a command pairing with response-with-busy[, Transfer > Complete] is set when busy is de-asserted. Refer to DAT Line Active > and Command Inhibit (DAT) in the Present State register. By polling the DAT Line Active bit in the present state register, we can detect when we are no longer busy, without waiting for a long timeout. This results in much faster reads/writes on buggy controllers. Signed-off-by: Sean Anderson <sean.anderson@seco.com> Tested-by: Henrik Grimler <henrik@grimler.se>
-rw-r--r--drivers/mmc/sdhci.c19
-rw-r--r--include/sdhci.h1
2 files changed, 13 insertions, 7 deletions
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index fc9c6c3799..0178ed8a11 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -306,14 +306,19 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
if (stat & SDHCI_INT_ERROR)
break;
- if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) {
- if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) {
+ if (host->quirks & SDHCI_QUIRK_BROKEN_R1B &&
+ cmd->resp_type & MMC_RSP_BUSY && !data) {
+ unsigned int state =
+ sdhci_readl(host, SDHCI_PRESENT_STATE);
+
+ if (!(state & SDHCI_DAT_ACTIVE))
return 0;
- } else {
- printf("%s: Timeout for status update!\n",
- __func__);
- return -ETIMEDOUT;
- }
+ }
+
+ if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) {
+ printf("%s: Timeout for status update: %08x %08x\n",
+ __func__, stat, mask);
+ return -ETIMEDOUT;
}
} while ((stat & mask) != mask);
diff --git a/include/sdhci.h b/include/sdhci.h
index 70fefca2a9..a1b74e3bd7 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -57,6 +57,7 @@
#define SDHCI_PRESENT_STATE 0x24
#define SDHCI_CMD_INHIBIT BIT(0)
#define SDHCI_DATA_INHIBIT BIT(1)
+#define SDHCI_DAT_ACTIVE BIT(2)
#define SDHCI_DOING_WRITE BIT(8)
#define SDHCI_DOING_READ BIT(9)
#define SDHCI_SPACE_AVAILABLE BIT(10)