summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorpopcornmix <popcornmix@gmail.com>2015-04-13 23:34:50 +0100
committerpopcornmix <popcornmix@gmail.com>2015-05-18 14:12:54 +0100
commitb27d37e07824c16a988460823bc423e2f49f438b (patch)
treee8c589e37f6cfc32c51a20cce89aea798ec3eb2c /drivers
parent5d5b216323ff5dd030965b21983a72a350d6a33d (diff)
downloadlinux-b27d37e07824c16a988460823bc423e2f49f438b.tar.gz
bcm2835-mmc: Add range of debug options for slowing things down
bcm2835-mmc: Add option to disable some delays bcm2835-mmc: Add option to disable MMC_QUIRK_BLK_NO_CMD23 bcm2835-mmc: Default to disabling MMC_QUIRK_BLK_NO_CMD23
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/core/quirks.c2
-rw-r--r--drivers/mmc/host/bcm2835-mmc.c44
2 files changed, 32 insertions, 14 deletions
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index f47208231e34..bc3bbad68991 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -71,6 +71,7 @@ static const struct mmc_fixup mmc_fixup_methods[] = {
void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
{
+ extern unsigned mmc_debug;
const struct mmc_fixup *f;
u64 rev = cid_rev_card(card);
@@ -98,6 +99,7 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
/* SDHCI on BCM2708 - bug causes a certain sequence of CMD23 operations to fail.
* Disable this flag for all cards (fall-back to CMD25/CMD18 multi-block transfers).
*/
+ if (mmc_debug & (1<<13))
card->quirks |= MMC_QUIRK_BLK_NO_CMD23;
}
EXPORT_SYMBOL(mmc_fixup_device);
diff --git a/drivers/mmc/host/bcm2835-mmc.c b/drivers/mmc/host/bcm2835-mmc.c
index 1c34f4769993..68314d599d30 100644
--- a/drivers/mmc/host/bcm2835-mmc.c
+++ b/drivers/mmc/host/bcm2835-mmc.c
@@ -71,6 +71,9 @@ pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
#define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE)
+unsigned mmc_debug;
+unsigned mmc_debug2;
+
struct bcm2835_host {
spinlock_t lock;
@@ -131,17 +134,27 @@ struct bcm2835_host {
};
-static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg)
+static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg, int from)
{
+ unsigned delay;
lockdep_assert_held_once(&host->lock);
writel(val, host->ioaddr + reg);
udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ)));
+
+ delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf);
+ if (delay && !((1<<from) & mmc_debug2))
+ udelay(delay);
}
static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg)
{
+ unsigned delay;
lockdep_assert_held_once(&host->lock);
writel(val, host->ioaddr + reg);
+
+ delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf);
+ if (delay)
+ udelay(delay);
}
static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg)
@@ -162,7 +175,7 @@ static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int re
if (reg == SDHCI_TRANSFER_MODE)
host->shadow = newval;
else
- bcm2835_mmc_writel(host, newval, reg & ~3);
+ bcm2835_mmc_writel(host, newval, reg & ~3, 0);
}
@@ -174,7 +187,7 @@ static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg
u32 mask = 0xff << byte_shift;
u32 newval = (oldval & ~mask) | (val << byte_shift);
- bcm2835_mmc_writel(host, newval, reg & ~3);
+ bcm2835_mmc_writel(host, newval, reg & ~3, 1);
}
@@ -206,7 +219,7 @@ static void bcm2835_mmc_unsignal_irqs(struct bcm2835_host *host, u32 clear)
ier &= ~clear;
/* change which requests generate IRQs - makes no difference to
the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */
- bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+ bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE, 2);
}
@@ -307,8 +320,8 @@ static void bcm2835_mmc_init(struct bcm2835_host *host, int soft)
SDHCI_INT_RESPONSE;
spin_lock_irqsave(&host->lock, flags);
- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE);
- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3);
+ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3);
spin_unlock_irqrestore(&host->lock, flags);
if (soft) {
@@ -534,8 +547,8 @@ static void bcm2835_mmc_set_transfer_irqs(struct bcm2835_host *host)
else
host->ier = (host->ier & ~dma_irqs) | pio_irqs;
- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE);
- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 4);
+ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 4);
}
@@ -617,7 +630,7 @@ static void bcm2835_mmc_set_transfer_mode(struct bcm2835_host *host,
mode |= SDHCI_TRNS_AUTO_CMD12;
else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
mode |= SDHCI_TRNS_AUTO_CMD23;
- bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2);
+ bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2, 5);
}
}
@@ -680,7 +693,7 @@ void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd
bcm2835_mmc_prepare_data(host, cmd);
- bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT);
+ bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT, 6);
bcm2835_mmc_set_transfer_mode(host, cmd);
@@ -837,8 +850,8 @@ static void bcm2835_mmc_enable_sdio_irq_nolock(struct bcm2835_host *host, int en
else
host->ier &= ~SDHCI_INT_CARD_INT;
- bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE);
- bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+ bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 7);
+ bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 7);
mmiowb();
}
}
@@ -985,7 +998,7 @@ static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id)
/* Clear selected interrupts. */
mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
SDHCI_INT_BUS_POWER);
- bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS);
+ bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS, 8);
if (intmask & SDHCI_INT_CMD_MASK)
@@ -1015,7 +1028,7 @@ static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id)
if (intmask) {
unexpected |= intmask;
- bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS);
+ bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS, 9);
}
if (result == IRQ_NONE)
@@ -1303,6 +1316,7 @@ static int bcm2835_mmc_add_host(struct bcm2835_host *host)
host->flags = SDHCI_AUTO_CMD23;
+ dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2);
#ifdef FORCE_PIO
dev_info(dev, "Forcing PIO mode\n");
host->have_dma = false;
@@ -1514,6 +1528,8 @@ static struct platform_driver bcm2835_mmc_driver = {
};
module_platform_driver(bcm2835_mmc_driver);
+module_param(mmc_debug, uint, 0644);
+module_param(mmc_debug2, uint, 0644);
MODULE_ALIAS("platform:mmc-bcm2835");
MODULE_DESCRIPTION("BCM2835 SDHCI driver");
MODULE_LICENSE("GPL v2");