summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/sdhci.c
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-05-20 21:25:28 -0700
committerGary King <gking@nvidia.com>2010-05-21 19:34:59 -0700
commit3f5d769df6006af515cd7a77ea56414d83a2e6a6 (patch)
tree49420f4a9f439dc6a7e1e06d080ca3893b6d33c2 /drivers/mmc/host/sdhci.c
parentc7edc161906cbdf0598dcf7f3cc7845c9328baaa (diff)
sdhci: add Tegra 2 quirks
add BROKEN_WRITE_PROTECT quirk which calls a get_ro callback function to detect the card read-only status for hosts which do not detect the write protect flag correctly add ENABLE_INTERRUPT_AT_BLOCK_GAP quick for hosts which do not detect SDIO card interrupts unless INTERRUPT_AT_BLOCK_GAP is enabled add BROKEN_CTRL_HISPD quirk for hosts which should not have CTRL_HISPD bit set after switching to high-speed mode add NO_64KB_ADMA quirk for hosts which need to split a 64KB (max) ADMA transfer into 2 smaller transfers add BROKEN_SPEC_VERSION quirk to bypass reading the HOST_VERSION register for controllers which report incorrect values from this register add NO_SDIO_IRQ quirk, for controllers which should use SDIO IRQs Change-Id: I0f09f5a25c0d4048d8c7139a3d68ee3705f95589
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r--drivers/mmc/host/sdhci.c66
1 files changed, 54 insertions, 12 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 2d47bf53a88c..f81f35d6ee5b 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -465,6 +465,25 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
len -= offset;
}
+ if ((len == 0x10000) &&
+ (host->quirks & SDHCI_QUIRK_NO_64KB_ADMA)) {
+ len = 1 << 15;
+
+ desc[7] = (addr >> 24) & 0xff;
+ desc[6] = (addr >> 16) & 0xff;
+ desc[5] = (addr >> 8) & 0xff;
+ desc[4] = (addr >> 0) & 0xff;
+
+ desc[3] = (len >> 8) & 0xff;
+ desc[2] = (len >> 0) & 0xff;
+
+ desc[1] = 0x00;
+ desc[0] = 0x21; /* tran, valid */
+
+ desc += 8;
+ addr += len;
+ }
+
desc[7] = (addr >> 24) & 0xff;
desc[6] = (addr >> 16) & 0xff;
desc[5] = (addr >> 8) & 0xff;
@@ -1162,10 +1181,15 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
ctrl &= ~SDHCI_CTRL_4BITBUS;
- if (ios->timing == MMC_TIMING_SD_HS)
- ctrl |= SDHCI_CTRL_HISPD;
- else
- ctrl &= ~SDHCI_CTRL_HISPD;
+ /* Tegra controllers often fail to detect high-speed cards when
+ * CTRL_HISPD is programmed
+ */
+ if (!(host->quirks & SDHCI_QUIRK_BROKEN_CTRL_HISPD)) {
+ if (ios->timing == MMC_TIMING_SD_HS)
+ ctrl |= SDHCI_CTRL_HISPD;
+ else
+ ctrl &= ~SDHCI_CTRL_HISPD;
+ }
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
@@ -1194,14 +1218,17 @@ static int sdhci_get_ro(struct mmc_host *mmc)
if (host->flags & SDHCI_DEVICE_DEAD)
present = 0;
- else
+ else if (!(host->quirks & SDHCI_QUIRK_BROKEN_WRITE_PROTECT)) {
present = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ present = !(present & SDHCI_WRITE_PROTECT);
+ } else if (host->ops->get_ro)
+ present = host->ops->get_ro(host);
+ else
+ present = 0;
spin_unlock_irqrestore(&host->lock, flags);
- if (host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT)
- return !!(present & SDHCI_WRITE_PROTECT);
- return !(present & SDHCI_WRITE_PROTECT);
+ return present;
}
static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
@@ -1220,6 +1247,16 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
else
sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
+
+ if (host->quirks & SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP) {
+ u8 gap_ctrl = sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL);
+ if (enable)
+ gap_ctrl |= 0x8;
+ else
+ gap_ctrl &= ~0x8;
+ sdhci_writeb(host, gap_ctrl, SDHCI_BLOCK_GAP_CONTROL);
+ }
+
out:
mmiowb();
@@ -1690,9 +1727,11 @@ int sdhci_add_host(struct sdhci_host *host)
sdhci_reset(host, SDHCI_RESET_ALL);
- host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
- host->version = (host->version & SDHCI_SPEC_VER_MASK)
- >> SDHCI_SPEC_VER_SHIFT;
+ if (!(host->quirks & SDHCI_QUIRK_BROKEN_SPEC_VERSION)) {
+ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+ host->version = (host->version & SDHCI_SPEC_VER_MASK)
+ >> SDHCI_SPEC_VER_SHIFT;
+ }
if (host->version > SDHCI_SPEC_200) {
printk(KERN_ERR "%s: Unknown controller version (%d). "
"You may experience problems.\n", mmc_hostname(mmc),
@@ -1802,11 +1841,14 @@ int sdhci_add_host(struct sdhci_host *host)
else
mmc->f_min = host->max_clk / 256;
mmc->f_max = host->max_clk;
- mmc->caps = MMC_CAP_SDIO_IRQ;
+ mmc->caps = 0;
if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
mmc->caps |= MMC_CAP_4_BIT_DATA;
+ if (!(host->quirks & SDHCI_QUIRK_NO_SDIO_IRQ))
+ mmc->caps |= MMC_CAP_SDIO_IRQ;
+
if (caps & SDHCI_CAN_DO_HISPD)
mmc->caps |= MMC_CAP_SD_HIGHSPEED;