summaryrefslogtreecommitdiff
path: root/target/linux/brcm2708/patches-3.10/014-bcm2708-sdhci-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-3.10/014-bcm2708-sdhci-driver.patch')
-rw-r--r--target/linux/brcm2708/patches-3.10/014-bcm2708-sdhci-driver.patch2572
1 files changed, 0 insertions, 2572 deletions
diff --git a/target/linux/brcm2708/patches-3.10/014-bcm2708-sdhci-driver.patch b/target/linux/brcm2708/patches-3.10/014-bcm2708-sdhci-driver.patch
deleted file mode 100644
index 048d6e9269..0000000000
--- a/target/linux/brcm2708/patches-3.10/014-bcm2708-sdhci-driver.patch
+++ /dev/null
@@ -1,2572 +0,0 @@
---- a/drivers/mmc/card/block.c
-+++ b/drivers/mmc/card/block.c
-@@ -1333,7 +1333,7 @@ static void mmc_blk_rw_rq_prep(struct mm
- brq->data.blocks = 1;
- }
-
-- if (brq->data.blocks > 1 || do_rel_wr) {
-+ if (brq->data.blocks > 1 || do_rel_wr || card->host->caps2 & MMC_CAP2_FORCE_MULTIBLOCK) {
- /* SPI multiblock writes terminate using a special
- * token, not a STOP_TRANSMISSION request.
- */
---- a/drivers/mmc/core/sd.c
-+++ b/drivers/mmc/core/sd.c
-@@ -13,6 +13,8 @@
- #include <linux/err.h>
- #include <linux/slab.h>
- #include <linux/stat.h>
-+#include <linux/jiffies.h>
-+#include <linux/nmi.h>
-
- #include <linux/mmc/host.h>
- #include <linux/mmc/card.h>
-@@ -58,6 +60,15 @@ static const unsigned int tacc_mant[] =
- __res & __mask; \
- })
-
-+// timeout for tries
-+static const unsigned long retry_timeout_ms= 10*1000;
-+
-+// try at least 10 times, even if timeout is reached
-+static const int retry_min_tries= 10;
-+
-+// delay between tries
-+static const unsigned long retry_delay_ms= 10;
-+
- /*
- * Given the decoded CSD structure, decode the raw CID to our CID structure.
- */
-@@ -210,12 +221,62 @@ static int mmc_decode_scr(struct mmc_car
- }
-
- /*
-- * Fetch and process SD Status register.
-+ * Fetch and process SD Configuration Register.
-+ */
-+static int mmc_read_scr(struct mmc_card *card)
-+{
-+ unsigned long timeout_at;
-+ int err, tries;
-+
-+ timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms );
-+ tries= 0;
-+
-+ while( tries < retry_min_tries || time_before( jiffies, timeout_at ) )
-+ {
-+ unsigned long delay_at;
-+ tries++;
-+
-+ err = mmc_app_send_scr(card, card->raw_scr);
-+ if( !err )
-+ break; // success!!!
-+
-+ touch_nmi_watchdog(); // we are still alive!
-+
-+ // delay
-+ delay_at= jiffies + msecs_to_jiffies( retry_delay_ms );
-+ while( time_before( jiffies, delay_at ) )
-+ {
-+ mdelay( 1 );
-+ touch_nmi_watchdog(); // we are still alive!
-+ }
-+ }
-+
-+ if( err)
-+ {
-+ pr_err("%s: failed to read SD Configuration register (SCR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err );
-+ return err;
-+ }
-+
-+ if( tries > 1 )
-+ {
-+ pr_info("%s: could read SD Configuration register (SCR) at the %dth attempt\n", mmc_hostname(card->host), tries );
-+ }
-+
-+ err = mmc_decode_scr(card);
-+ if (err)
-+ return err;
-+
-+ return err;
-+}
-+
-+/*
-+ * Fetch and process SD Status Register.
- */
- static int mmc_read_ssr(struct mmc_card *card)
- {
-+ unsigned long timeout_at;
- unsigned int au, es, et, eo;
-- int err, i;
-+ int err, i, tries;
- u32 *ssr;
-
- if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
-@@ -228,14 +289,40 @@ static int mmc_read_ssr(struct mmc_card
- if (!ssr)
- return -ENOMEM;
-
-+ timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms );
-+ tries= 0;
-+
-+ while( tries < retry_min_tries || time_before( jiffies, timeout_at ) )
-+ {
-+ unsigned long delay_at;
-+ tries++;
-+
- err = mmc_app_sd_status(card, ssr);
-- if (err) {
-- pr_warning("%s: problem reading SD Status "
-- "register.\n", mmc_hostname(card->host));
-- err = 0;
-+ if( !err )
-+ break; // sucess!!!
-+
-+ touch_nmi_watchdog(); // we are still alive!
-+
-+ // delay
-+ delay_at= jiffies + msecs_to_jiffies( retry_delay_ms );
-+ while( time_before( jiffies, delay_at ) )
-+ {
-+ mdelay( 1 );
-+ touch_nmi_watchdog(); // we are still alive!
-+ }
-+ }
-+
-+ if( err)
-+ {
-+ pr_err("%s: failed to read SD Status register (SSR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err );
- goto out;
- }
-
-+ if( tries > 1 )
-+ {
-+ pr_info("%s: read SD Status register (SSR) after %d attempts\n", mmc_hostname(card->host), tries );
-+ }
-+
- for (i = 0; i < 16; i++)
- ssr[i] = be32_to_cpu(ssr[i]);
-
-@@ -808,13 +895,9 @@ int mmc_sd_setup_card(struct mmc_host *h
-
- if (!reinit) {
- /*
-- * Fetch SCR from card.
-+ * Fetch and decode SD Configuration register.
- */
-- err = mmc_app_send_scr(card, card->raw_scr);
-- if (err)
-- return err;
--
-- err = mmc_decode_scr(card);
-+ err = mmc_read_scr(card);
- if (err)
- return err;
-
---- a/drivers/mmc/host/Kconfig
-+++ b/drivers/mmc/host/Kconfig
-@@ -249,6 +249,27 @@ config MMC_SDHCI_S3C_DMA
-
- YMMV.
-
-+config MMC_SDHCI_BCM2708
-+ tristate "SDHCI support on BCM2708"
-+ depends on MMC_SDHCI && MACH_BCM2708
-+ select MMC_SDHCI_IO_ACCESSORS
-+ help
-+ This selects the Secure Digital Host Controller Interface (SDHCI)
-+ often referrered to as the eMMC block.
-+
-+ If you have a controller with this interface, say Y or M here.
-+
-+ If unsure, say N.
-+
-+config MMC_SDHCI_BCM2708_DMA
-+ bool "DMA support on BCM2708 Arasan controller"
-+ depends on MMC_SDHCI_BCM2708
-+ help
-+ Enable DMA support on the Arasan SDHCI controller in Broadcom 2708
-+ based chips.
-+
-+ If unsure, say N.
-+
- config MMC_SDHCI_BCM2835
- tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
- depends on ARCH_BCM2835
---- a/drivers/mmc/host/Makefile
-+++ b/drivers/mmc/host/Makefile
-@@ -15,6 +15,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-p
- obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
- obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
- obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
-+obj-$(CONFIG_MMC_SDHCI_BCM2708) += sdhci-bcm2708.o
- obj-$(CONFIG_MMC_WBSD) += wbsd.o
- obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
- obj-$(CONFIG_MMC_OMAP) += omap.o
---- /dev/null
-+++ b/drivers/mmc/host/sdhci-bcm2708.c
-@@ -0,0 +1,1420 @@
-+/*
-+ * sdhci-bcm2708.c Support for SDHCI device on BCM2708
-+ * Copyright (c) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+
-+/* Supports:
-+ * SDHCI platform device - Arasan SD controller in BCM2708
-+ *
-+ * Inspired by sdhci-pci.c, by Pierre Ossman
-+ */
-+
-+#include <linux/delay.h>
-+#include <linux/highmem.h>
-+#include <linux/platform_device.h>
-+#include <linux/module.h>
-+#include <linux/mmc/mmc.h>
-+#include <linux/mmc/host.h>
-+#include <linux/mmc/sd.h>
-+
-+#include <linux/io.h>
-+#include <linux/dma-mapping.h>
-+#include <mach/dma.h>
-+
-+#include "sdhci.h"
-+
-+/*****************************************************************************\
-+ * *
-+ * Configuration *
-+ * *
-+\*****************************************************************************/
-+
-+#define DRIVER_NAME "bcm2708_sdhci"
-+
-+/* for the time being insist on DMA mode - PIO seems not to work */
-+#ifndef CONFIG_MMC_SDHCI_BCM2708_DMA
-+#warning Non-DMA (PIO) version of this driver currently unavailable
-+#endif
-+#undef CONFIG_MMC_SDHCI_BCM2708_DMA
-+#define CONFIG_MMC_SDHCI_BCM2708_DMA y
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+/* #define CHECK_DMA_USE */
-+#endif
-+//#define LOG_REGISTERS
-+
-+#define USE_SCHED_TIME
-+#define USE_SPACED_WRITES_2CLK 1 /* space consecutive register writes */
-+#define USE_SOFTWARE_TIMEOUTS 1 /* not hardware timeouts */
-+#define SOFTWARE_ERASE_TIMEOUT_SEC 30
-+
-+#define SDHCI_BCM_DMA_CHAN 4 /* this default is normally overriden */
-+#define SDHCI_BCM_DMA_WAITS 0 /* delays slowing DMA transfers: 0-31 */
-+/* We are worried that SD card DMA use may be blocking the AXI bus for others */
-+
-+/*! TODO: obtain these from the physical address */
-+#define DMA_SDHCI_BASE 0x7e300000 /* EMMC register block on Videocore */
-+#define DMA_SDHCI_BUFFER (DMA_SDHCI_BASE + SDHCI_BUFFER)
-+
-+#define BCM2708_SDHCI_SLEEP_TIMEOUT 1000 /* msecs */
-+
-+/* Mhz clock that the EMMC core is running at. Should match the platform clockman settings */
-+#define BCM2708_EMMC_CLOCK_FREQ 50000000
-+
-+#define REG_EXRDFIFO_EN 0x80
-+#define REG_EXRDFIFO_CFG 0x84
-+
-+int cycle_delay=2;
-+
-+/*****************************************************************************\
-+ * *
-+ * Debug *
-+ * *
-+\*****************************************************************************/
-+
-+
-+
-+#define DBG(f, x...) \
-+ pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
-+// printk(KERN_INFO DRIVER_NAME " [%s()]: " f, __func__,## x)//GRAYG
-+
-+
-+/*****************************************************************************\
-+ * *
-+ * High Precision Time *
-+ * *
-+\*****************************************************************************/
-+
-+#ifdef USE_SCHED_TIME
-+
-+#include <mach/frc.h>
-+
-+typedef unsigned long hptime_t;
-+
-+#define FMT_HPT "lu"
-+
-+static inline hptime_t hptime(void)
-+{
-+ return frc_clock_ticks32();
-+}
-+
-+#define HPTIME_CLK_NS 1000ul
-+
-+#else
-+
-+typedef unsigned long hptime_t;
-+
-+#define FMT_HPT "lu"
-+
-+static inline hptime_t hptime(void)
-+{
-+ return jiffies;
-+}
-+
-+#define HPTIME_CLK_NS (1000000000ul/HZ)
-+
-+#endif
-+
-+static inline unsigned long int since_ns(hptime_t t)
-+{
-+ return (unsigned long)((hptime() - t) * HPTIME_CLK_NS);
-+}
-+
-+static bool allow_highspeed = 1;
-+static int emmc_clock_freq = BCM2708_EMMC_CLOCK_FREQ;
-+static bool sync_after_dma = 1;
-+static bool missing_status = 1;
-+static bool spurious_crc_acmd51 = 0;
-+bool enable_llm = 1;
-+bool extra_messages = 0;
-+
-+#if 0
-+static void hptime_test(void)
-+{
-+ hptime_t now;
-+ hptime_t later;
-+
-+ now = hptime();
-+ msleep(10);
-+ later = hptime();
-+
-+ printk(KERN_INFO DRIVER_NAME": 10ms = %"FMT_HPT" clks "
-+ "(from %"FMT_HPT" to %"FMT_HPT") = %luns\n",
-+ later-now, now, later,
-+ (unsigned long)(HPTIME_CLK_NS * (later - now)));
-+
-+ now = hptime();
-+ msleep(1000);
-+ later = hptime();
-+
-+ printk(KERN_INFO DRIVER_NAME": 1s = %"FMT_HPT" clks "
-+ "(from %"FMT_HPT" to %"FMT_HPT") = %luns\n",
-+ later-now, now, later,
-+ (unsigned long)(HPTIME_CLK_NS * (later - now)));
-+}
-+#endif
-+
-+/*****************************************************************************\
-+ * *
-+ * SDHCI core callbacks *
-+ * *
-+\*****************************************************************************/
-+
-+
-+#ifdef CHECK_DMA_USE
-+/*#define CHECK_DMA_REG_USE*/
-+#endif
-+
-+#ifdef CHECK_DMA_REG_USE
-+/* we don't expect anything to be using these registers during a
-+ DMA (except the IRQ status) - so check */
-+static void check_dma_reg_use(struct sdhci_host *host, int reg);
-+#else
-+#define check_dma_reg_use(host, reg)
-+#endif
-+
-+
-+static inline u32 sdhci_bcm2708_raw_readl(struct sdhci_host *host, int reg)
-+{
-+ return readl(host->ioaddr + reg);
-+}
-+
-+u32 sdhci_bcm2708_readl(struct sdhci_host *host, int reg)
-+{
-+ u32 l = sdhci_bcm2708_raw_readl(host, reg);
-+
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: readl from 0x%02x, value 0x%08x\n",
-+ mmc_hostname(host->mmc), reg, l);
-+#endif
-+ check_dma_reg_use(host, reg);
-+
-+ return l;
-+}
-+
-+u16 sdhci_bcm2708_readw(struct sdhci_host *host, int reg)
-+{
-+ u32 l = sdhci_bcm2708_raw_readl(host, reg & ~3);
-+ u32 w = l >> (reg << 3 & 0x18) & 0xffff;
-+
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: readw from 0x%02x, value 0x%04x\n",
-+ mmc_hostname(host->mmc), reg, w);
-+#endif
-+ check_dma_reg_use(host, reg);
-+
-+ return (u16)w;
-+}
-+
-+u8 sdhci_bcm2708_readb(struct sdhci_host *host, int reg)
-+{
-+ u32 l = sdhci_bcm2708_raw_readl(host, reg & ~3);
-+ u32 b = l >> (reg << 3 & 0x18) & 0xff;
-+
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: readb from 0x%02x, value 0x%02x\n",
-+ mmc_hostname(host->mmc), reg, b);
-+#endif
-+ check_dma_reg_use(host, reg);
-+
-+ return (u8)b;
-+}
-+
-+
-+static void sdhci_bcm2708_raw_writel(struct sdhci_host *host, u32 val, int reg)
-+{
-+ u32 ier;
-+
-+#if USE_SPACED_WRITES_2CLK
-+ static bool timeout_disabled = false;
-+ unsigned int ns_2clk = 0;
-+
-+ /* The Arasan has a bugette whereby it may lose the content of
-+ * successive writes to registers that are within two SD-card clock
-+ * cycles of each other (a clock domain crossing problem).
-+ * It seems, however, that the data register does not have this problem.
-+ * (Which is just as well - otherwise we'd have to nobble the DMA engine
-+ * too)
-+ */
-+ if (reg != SDHCI_BUFFER && host->clock != 0) {
-+ /* host->clock is the clock freq in Hz */
-+ static hptime_t last_write_hpt;
-+ hptime_t now = hptime();
-+ ns_2clk = cycle_delay*1000000/(host->clock/1000);
-+
-+ if (now == last_write_hpt || now == last_write_hpt+1) {
-+ /* we can't guarantee any significant time has
-+ * passed - we'll have to wait anyway ! */
-+ ndelay(ns_2clk);
-+ } else
-+ {
-+ /* we must have waited at least this many ns: */
-+ unsigned int ns_wait = HPTIME_CLK_NS *
-+ (last_write_hpt - now - 1);
-+ if (ns_wait < ns_2clk)
-+ ndelay(ns_2clk - ns_wait);
-+ }
-+ last_write_hpt = now;
-+ }
-+#if USE_SOFTWARE_TIMEOUTS
-+ /* The Arasan is clocked for timeouts using the SD clock which is too
-+ * fast for ERASE commands and causes issues. So we disable timeouts
-+ * for ERASE */
-+ if (host->cmd != NULL && host->cmd->opcode == MMC_ERASE &&
-+ reg == (SDHCI_COMMAND & ~3)) {
-+ mod_timer(&host->timer,
-+ jiffies + SOFTWARE_ERASE_TIMEOUT_SEC * HZ);
-+ ier = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
-+ ier &= ~SDHCI_INT_DATA_TIMEOUT;
-+ writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-+ timeout_disabled = true;
-+ ndelay(ns_2clk);
-+ } else if (timeout_disabled) {
-+ ier = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
-+ ier |= SDHCI_INT_DATA_TIMEOUT;
-+ writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-+ timeout_disabled = false;
-+ ndelay(ns_2clk);
-+ }
-+#endif
-+ writel(val, host->ioaddr + reg);
-+#else
-+ void __iomem * regaddr = host->ioaddr + reg;
-+
-+ writel(val, regaddr);
-+
-+ if (reg != SDHCI_BUFFER && reg != SDHCI_INT_STATUS && host->clock != 0)
-+ {
-+ int timeout = 100000;
-+ while (val != readl(regaddr) && --timeout > 0)
-+ continue;
-+
-+ if (timeout <= 0)
-+ printk(KERN_ERR "%s: writing 0x%X to reg 0x%X "
-+ "always gives 0x%X\n",
-+ mmc_hostname(host->mmc),
-+ val, reg, readl(regaddr));
-+ BUG_ON(timeout <= 0);
-+ }
-+#endif
-+}
-+
-+
-+void sdhci_bcm2708_writel(struct sdhci_host *host, u32 val, int reg)
-+{
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: writel to 0x%02x, value 0x%08x\n",
-+ mmc_hostname(host->mmc), reg, val);
-+#endif
-+ check_dma_reg_use(host, reg);
-+
-+ sdhci_bcm2708_raw_writel(host, val, reg);
-+}
-+
-+void sdhci_bcm2708_writew(struct sdhci_host *host, u16 val, int reg)
-+{
-+ static u32 shadow = 0;
-+
-+ u32 p = reg == SDHCI_COMMAND ? shadow :
-+ sdhci_bcm2708_raw_readl(host, reg & ~3);
-+ u32 s = reg << 3 & 0x18;
-+ u32 l = val << s;
-+ u32 m = 0xffff << s;
-+
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: writew to 0x%02x, value 0x%04x\n",
-+ mmc_hostname(host->mmc), reg, val);
-+#endif
-+
-+ if (reg == SDHCI_TRANSFER_MODE)
-+ shadow = (p & ~m) | l;
-+ else {
-+ check_dma_reg_use(host, reg);
-+ sdhci_bcm2708_raw_writel(host, (p & ~m) | l, reg & ~3);
-+ }
-+}
-+
-+void sdhci_bcm2708_writeb(struct sdhci_host *host, u8 val, int reg)
-+{
-+ u32 p = sdhci_bcm2708_raw_readl(host, reg & ~3);
-+ u32 s = reg << 3 & 0x18;
-+ u32 l = val << s;
-+ u32 m = 0xff << s;
-+
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: writeb to 0x%02x, value 0x%02x\n",
-+ mmc_hostname(host->mmc), reg, val);
-+#endif
-+
-+ check_dma_reg_use(host, reg);
-+ sdhci_bcm2708_raw_writel(host, (p & ~m) | l, reg & ~3);
-+}
-+
-+static unsigned int sdhci_bcm2708_get_max_clock(struct sdhci_host *host)
-+{
-+ return emmc_clock_freq;
-+}
-+
-+/*****************************************************************************\
-+ * *
-+ * DMA Operation *
-+ * *
-+\*****************************************************************************/
-+
-+struct sdhci_bcm2708_priv {
-+ int dma_chan;
-+ int dma_irq;
-+ void __iomem *dma_chan_base;
-+ struct bcm2708_dma_cb *cb_base; /* DMA control blocks */
-+ dma_addr_t cb_handle;
-+ /* tracking scatter gather progress */
-+ unsigned sg_ix; /* scatter gather list index */
-+ unsigned sg_done; /* bytes in current sg_ix done */
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ unsigned char dma_wanted; /* DMA transfer requested */
-+ unsigned char dma_waits; /* wait states in DMAs */
-+#ifdef CHECK_DMA_USE
-+ unsigned char dmas_pending; /* no of unfinished DMAs */
-+ hptime_t when_started;
-+ hptime_t when_reset;
-+ hptime_t when_stopped;
-+#endif
-+#endif
-+ /* signalling the end of a transfer */
-+ void (*complete)(struct sdhci_host *);
-+};
-+
-+#define SDHCI_HOST_PRIV(host) \
-+ (struct sdhci_bcm2708_priv *)((struct sdhci_host *)(host)+1)
-+
-+
-+
-+#ifdef CHECK_DMA_REG_USE
-+static void check_dma_reg_use(struct sdhci_host *host, int reg)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ if (host_priv->dma_wanted && reg != SDHCI_INT_STATUS) {
-+ printk(KERN_INFO"%s: accessing register 0x%x during DMA\n",
-+ mmc_hostname(host->mmc), reg);
-+ }
-+}
-+#endif
-+
-+
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+
-+static void sdhci_clear_set_irqgen(struct sdhci_host *host, u32 clear, u32 set)
-+{
-+ u32 ier;
-+
-+ ier = sdhci_bcm2708_raw_readl(host, SDHCI_SIGNAL_ENABLE);
-+ ier &= ~clear;
-+ ier |= set;
-+ /* change which requests generate IRQs - makes no difference to
-+ the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */
-+ sdhci_bcm2708_raw_writel(host, ier, SDHCI_SIGNAL_ENABLE);
-+}
-+
-+static void sdhci_signal_irqs(struct sdhci_host *host, u32 irqs)
-+{
-+ sdhci_clear_set_irqgen(host, 0, irqs);
-+}
-+
-+static void sdhci_unsignal_irqs(struct sdhci_host *host, u32 irqs)
-+{
-+ sdhci_clear_set_irqgen(host, irqs, 0);
-+}
-+
-+
-+
-+static void schci_bcm2708_cb_read(struct sdhci_bcm2708_priv *host,
-+ int ix,
-+ dma_addr_t dma_addr, unsigned len,
-+ int /*bool*/ is_last)
-+{
-+ struct bcm2708_dma_cb *cb = &host->cb_base[ix];
-+ unsigned char dmawaits = host->dma_waits;
-+
-+ cb->info = BCM2708_DMA_PER_MAP(BCM2708_DMA_DREQ_EMMC) |
-+ BCM2708_DMA_WAITS(dmawaits) |
-+ BCM2708_DMA_S_DREQ |
-+ BCM2708_DMA_D_WIDTH |
-+ BCM2708_DMA_D_INC;
-+ cb->src = DMA_SDHCI_BUFFER; /* DATA register DMA address */
-+ cb->dst = dma_addr;
-+ cb->length = len;
-+ cb->stride = 0;
-+
-+ if (is_last) {
-+ cb->info |= BCM2708_DMA_INT_EN |
-+ BCM2708_DMA_WAIT_RESP;
-+ cb->next = 0;
-+ } else
-+ cb->next = host->cb_handle +
-+ (ix+1)*sizeof(struct bcm2708_dma_cb);
-+
-+ cb->pad[0] = 0;
-+ cb->pad[1] = 0;
-+}
-+
-+static void schci_bcm2708_cb_write(struct sdhci_bcm2708_priv *host,
-+ int ix,
-+ dma_addr_t dma_addr, unsigned len,
-+ int /*bool*/ is_last)
-+{
-+ struct bcm2708_dma_cb *cb = &host->cb_base[ix];
-+ unsigned char dmawaits = host->dma_waits;
-+
-+ /* We can make arbitrarily large writes as long as we specify DREQ to
-+ pace the delivery of bytes to the Arasan hardware */
-+ cb->info = BCM2708_DMA_PER_MAP(BCM2708_DMA_DREQ_EMMC) |
-+ BCM2708_DMA_WAITS(dmawaits) |
-+ BCM2708_DMA_D_DREQ |
-+ BCM2708_DMA_S_WIDTH |
-+ BCM2708_DMA_S_INC;
-+ cb->src = dma_addr;
-+ cb->dst = DMA_SDHCI_BUFFER; /* DATA register DMA address */
-+ cb->length = len;
-+ cb->stride = 0;
-+
-+ if (is_last) {
-+ cb->info |= BCM2708_DMA_INT_EN |
-+ BCM2708_DMA_WAIT_RESP;
-+ cb->next = 0;
-+ } else
-+ cb->next = host->cb_handle +
-+ (ix+1)*sizeof(struct bcm2708_dma_cb);
-+
-+ cb->pad[0] = 0;
-+ cb->pad[1] = 0;
-+}
-+
-+
-+static void schci_bcm2708_dma_go(struct sdhci_host *host)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ void __iomem *dma_chan_base = host_priv->dma_chan_base;
-+
-+ BUG_ON(host_priv->dma_wanted);
-+#ifdef CHECK_DMA_USE
-+ if (host_priv->dma_wanted)
-+ printk(KERN_ERR "%s: DMA already in progress - "
-+ "now %"FMT_HPT", last started %lu "
-+ "reset %lu stopped %lu\n",
-+ mmc_hostname(host->mmc),
-+ hptime(), since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ else if (host_priv->dmas_pending > 0)
-+ printk(KERN_INFO "%s: note - new DMA when %d reset DMAs "
-+ "already in progress - "
-+ "now %"FMT_HPT", started %lu reset %lu stopped %lu\n",
-+ mmc_hostname(host->mmc),
-+ host_priv->dmas_pending,
-+ hptime(), since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ host_priv->dmas_pending += 1;
-+ host_priv->when_started = hptime();
-+#endif
-+ host_priv->dma_wanted = 1;
-+ DBG("PDMA go - base %p handle %08X\n", dma_chan_base,
-+ host_priv->cb_handle);
-+ bcm_dma_start(dma_chan_base, host_priv->cb_handle);
-+}
-+
-+
-+static void
-+sdhci_platdma_read(struct sdhci_host *host, dma_addr_t dma_addr, size_t len)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+
-+ DBG("PDMA to read %d bytes\n", len);
-+ host_priv->sg_done += len;
-+ schci_bcm2708_cb_read(host_priv, 0, dma_addr, len, 1/*TRUE*/);
-+ schci_bcm2708_dma_go(host);
-+}
-+
-+
-+static void
-+sdhci_platdma_write(struct sdhci_host *host, dma_addr_t dma_addr, size_t len)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+
-+ DBG("PDMA to write %d bytes\n", len);
-+ //BUG_ON(0 != (len & 0x1ff));
-+
-+ host_priv->sg_done += len;
-+ schci_bcm2708_cb_write(host_priv, 0, dma_addr, len, 1/*TRUE*/);
-+ schci_bcm2708_dma_go(host);
-+}
-+
-+/*! space is avaiable to receive into or data is available to write
-+ Platform DMA exported function
-+*/
-+void
-+sdhci_bcm2708_platdma_avail(struct sdhci_host *host, unsigned int *ref_intmask,
-+ void(*completion_callback)(struct sdhci_host *host))
-+{
-+ struct mmc_data *data = host->data;
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ int sg_ix;
-+ size_t bytes;
-+ dma_addr_t addr;
-+
-+ BUG_ON(NULL == data);
-+ BUG_ON(0 == data->blksz);
-+
-+ host_priv->complete = completion_callback;
-+
-+ sg_ix = host_priv->sg_ix;
-+ BUG_ON(sg_ix >= data->sg_len);
-+
-+ /* we can DMA blocks larger than blksz - it may hang the DMA
-+ channel but we are its only user */
-+ bytes = sg_dma_len(&data->sg[sg_ix]) - host_priv->sg_done;
-+ addr = sg_dma_address(&data->sg[sg_ix]) + host_priv->sg_done;
-+
-+ if (bytes > 0) {
-+ /* We're going to poll for read/write available state until
-+ we finish this DMA
-+ */
-+
-+ if (data->flags & MMC_DATA_READ) {
-+ if (*ref_intmask & SDHCI_INT_DATA_AVAIL) {
-+ sdhci_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL |
-+ SDHCI_INT_SPACE_AVAIL);
-+ sdhci_platdma_read(host, addr, bytes);
-+ }
-+ } else {
-+ if (*ref_intmask & SDHCI_INT_SPACE_AVAIL) {
-+ sdhci_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL |
-+ SDHCI_INT_SPACE_AVAIL);
-+ sdhci_platdma_write(host, addr, bytes);
-+ }
-+ }
-+ }
-+ /* else:
-+ we have run out of bytes that need transferring (e.g. we may be in
-+ the middle of the last DMA transfer), or
-+ it is also possible that we've been called when another IRQ is
-+ signalled, even though we've turned off signalling of our own IRQ */
-+
-+ *ref_intmask &= ~SDHCI_INT_DATA_END;
-+ /* don't let the main sdhci driver act on this .. we'll deal with it
-+ when we respond to the DMA - if one is currently in progress */
-+}
-+
-+/* is it possible to DMA the given mmc_data structure?
-+ Platform DMA exported function
-+*/
-+int /*bool*/
-+sdhci_bcm2708_platdma_dmaable(struct sdhci_host *host, struct mmc_data *data)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ int ok = bcm_sg_suitable_for_dma(data->sg, data->sg_len);
-+
-+ if (!ok)
-+ DBG("Reverting to PIO - bad cache alignment\n");
-+
-+ else {
-+ host_priv->sg_ix = 0; /* first SG index */
-+ host_priv->sg_done = 0; /* no bytes done */
-+ }
-+
-+ return ok;
-+}
-+
-+#include <mach/arm_control.h> //GRAYG
-+/*! the current SD transacton has been abandonned
-+ We need to tidy up if we were in the middle of a DMA
-+ Platform DMA exported function
-+*/
-+void
-+sdhci_bcm2708_platdma_reset(struct sdhci_host *host, struct mmc_data *data)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+// unsigned long flags;
-+
-+ BUG_ON(NULL == host);
-+
-+// spin_lock_irqsave(&host->lock, flags);
-+
-+ if (host_priv->dma_wanted) {
-+ if (NULL == data) {
-+ printk(KERN_ERR "%s: ongoing DMA reset - no data!\n",
-+ mmc_hostname(host->mmc));
-+ BUG_ON(NULL == data);
-+ } else {
-+ struct scatterlist *sg;
-+ int sg_len;
-+ int sg_todo;
-+ int rc;
-+ unsigned long cs;
-+
-+ sg = data->sg;
-+ sg_len = data->sg_len;
-+ sg_todo = sg_dma_len(&sg[host_priv->sg_ix]);
-+
-+ cs = readl(host_priv->dma_chan_base + BCM2708_DMA_CS);
-+
-+ if (!(BCM2708_DMA_ACTIVE & cs))
-+ {
-+ if (extra_messages)
-+ printk(KERN_INFO "%s: missed completion of "
-+ "cmd %d DMA (%d/%d [%d]/[%d]) - "
-+ "ignoring it\n",
-+ mmc_hostname(host->mmc),
-+ host->last_cmdop,
-+ host_priv->sg_done, sg_todo,
-+ host_priv->sg_ix+1, sg_len);
-+ }
-+ else
-+ printk(KERN_INFO "%s: resetting ongoing cmd %d"
-+ "DMA before %d/%d [%d]/[%d] complete\n",
-+ mmc_hostname(host->mmc),
-+ host->last_cmdop,
-+ host_priv->sg_done, sg_todo,
-+ host_priv->sg_ix+1, sg_len);
-+#ifdef CHECK_DMA_USE
-+ printk(KERN_INFO "%s: now %"FMT_HPT" started %lu "
-+ "last reset %lu last stopped %lu\n",
-+ mmc_hostname(host->mmc),
-+ hptime(), since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ { unsigned long info, debug;
-+ void __iomem *base;
-+ unsigned long pend0, pend1, pend2;
-+
-+ base = host_priv->dma_chan_base;
-+ cs = readl(base + BCM2708_DMA_CS);
-+ info = readl(base + BCM2708_DMA_INFO);
-+ debug = readl(base + BCM2708_DMA_DEBUG);
-+ printk(KERN_INFO "%s: DMA%d CS=%08lX TI=%08lX "
-+ "DEBUG=%08lX\n",
-+ mmc_hostname(host->mmc),
-+ host_priv->dma_chan,
-+ cs, info, debug);
-+ pend0 = readl(__io_address(ARM_IRQ_PEND0));
-+ pend1 = readl(__io_address(ARM_IRQ_PEND1));
-+ pend2 = readl(__io_address(ARM_IRQ_PEND2));
-+
-+ printk(KERN_INFO "%s: PEND0=%08lX "
-+ "PEND1=%08lX PEND2=%08lX\n",
-+ mmc_hostname(host->mmc),
-+ pend0, pend1, pend2);
-+
-+ //gintsts = readl(__io_address(GINTSTS));
-+ //gintmsk = readl(__io_address(GINTMSK));
-+ //printk(KERN_INFO "%s: USB GINTSTS=%08lX"
-+ // "GINTMSK=%08lX\n",
-+ // mmc_hostname(host->mmc), gintsts, gintmsk);
-+ }
-+#endif
-+ rc = bcm_dma_abort(host_priv->dma_chan_base);
-+ BUG_ON(rc != 0);
-+ }
-+ host_priv->dma_wanted = 0;
-+#ifdef CHECK_DMA_USE
-+ host_priv->when_reset = hptime();
-+#endif
-+ }
-+
-+// spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+
-+static void sdhci_bcm2708_dma_complete_irq(struct sdhci_host *host,
-+ u32 dma_cs)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ struct mmc_data *data;
-+ struct scatterlist *sg;
-+ int sg_len;
-+ int sg_ix;
-+ int sg_todo;
-+// unsigned long flags;
-+
-+ BUG_ON(NULL == host);
-+
-+// spin_lock_irqsave(&host->lock, flags);
-+ data = host->data;
-+
-+#ifdef CHECK_DMA_USE
-+ if (host_priv->dmas_pending <= 0)
-+ DBG("on completion no DMA in progress - "
-+ "now %"FMT_HPT" started %lu reset %lu stopped %lu\n",
-+ hptime(), since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ else if (host_priv->dmas_pending > 1)
-+ DBG("still %d DMA in progress after completion - "
-+ "now %"FMT_HPT" started %lu reset %lu stopped %lu\n",
-+ host_priv->dmas_pending - 1,
-+ hptime(), since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ BUG_ON(host_priv->dmas_pending <= 0);
-+ host_priv->dmas_pending -= 1;
-+ host_priv->when_stopped = hptime();
-+#endif
-+ host_priv->dma_wanted = 0;
-+
-+ if (NULL == data) {
-+ DBG("PDMA unused completion - status 0x%X\n", dma_cs);
-+// spin_unlock_irqrestore(&host->lock, flags);
-+ return;
-+ }
-+ sg = data->sg;
-+ sg_len = data->sg_len;
-+ sg_todo = sg_dma_len(&sg[host_priv->sg_ix]);
-+
-+ DBG("PDMA complete %d/%d [%d]/[%d]..\n",
-+ host_priv->sg_done, sg_todo,
-+ host_priv->sg_ix+1, sg_len);
-+
-+ BUG_ON(host_priv->sg_done > sg_todo);
-+
-+ if (host_priv->sg_done >= sg_todo) {
-+ host_priv->sg_ix++;
-+ host_priv->sg_done = 0;
-+ }
-+
-+ sg_ix = host_priv->sg_ix;
-+ if (sg_ix < sg_len) {
-+ u32 irq_mask;
-+ /* Set off next DMA if we've got the capacity */
-+
-+ if (data->flags & MMC_DATA_READ)
-+ irq_mask = SDHCI_INT_DATA_AVAIL;
-+ else
-+ irq_mask = SDHCI_INT_SPACE_AVAIL;
-+
-+ /* We have to use the interrupt status register on the BCM2708
-+ rather than the SDHCI_PRESENT_STATE register because latency
-+ in the glue logic means that the information retrieved from
-+ the latter is not always up-to-date w.r.t the DMA engine -
-+ it may not indicate that a read or a write is ready yet */
-+ if (sdhci_bcm2708_raw_readl(host, SDHCI_INT_STATUS) &
-+ irq_mask) {
-+ size_t bytes = sg_dma_len(&sg[sg_ix]) -
-+ host_priv->sg_done;
-+ dma_addr_t addr = sg_dma_address(&data->sg[sg_ix]) +
-+ host_priv->sg_done;
-+
-+ /* acknowledge interrupt */
-+ sdhci_bcm2708_raw_writel(host, irq_mask,
-+ SDHCI_INT_STATUS);
-+
-+ BUG_ON(0 == bytes);
-+
-+ if (data->flags & MMC_DATA_READ)
-+ sdhci_platdma_read(host, addr, bytes);
-+ else
-+ sdhci_platdma_write(host, addr, bytes);
-+ } else {
-+ DBG("PDMA - wait avail\n");
-+ /* may generate an IRQ if already present */
-+ sdhci_signal_irqs(host, SDHCI_INT_DATA_AVAIL |
-+ SDHCI_INT_SPACE_AVAIL);
-+ }
-+ } else {
-+ if (sync_after_dma) {
-+ /* On the Arasan controller the stop command (which will be
-+ scheduled after this completes) does not seem to work
-+ properly if we allow it to be issued when we are
-+ transferring data to/from the SD card.
-+ We get CRC and DEND errors unless we wait for
-+ the SD controller to finish reading/writing to the card. */
-+ u32 state_mask;
-+ int timeout=30*5000;
-+
-+ DBG("PDMA over - sync card\n");
-+ if (data->flags & MMC_DATA_READ)
-+ state_mask = SDHCI_DOING_READ;
-+ else
-+ state_mask = SDHCI_DOING_WRITE;
-+
-+ while (0 != (sdhci_bcm2708_raw_readl(host, SDHCI_PRESENT_STATE)
-+ & state_mask) && --timeout > 0)
-+ {
-+ udelay(1);
-+ continue;
-+ }
-+ if (timeout <= 0)
-+ printk(KERN_ERR"%s: final %s to SD card still "
-+ "running\n",
-+ mmc_hostname(host->mmc),
-+ data->flags & MMC_DATA_READ? "read": "write");
-+ }
-+ if (host_priv->complete) {
-+ (*host_priv->complete)(host);
-+ DBG("PDMA %s complete\n",
-+ data->flags & MMC_DATA_READ?"read":"write");
-+ sdhci_signal_irqs(host, SDHCI_INT_DATA_AVAIL |
-+ SDHCI_INT_SPACE_AVAIL);
-+ }
-+ }
-+// spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static irqreturn_t sdhci_bcm2708_dma_irq(int irq, void *dev_id)
-+{
-+ irqreturn_t result = IRQ_NONE;
-+ struct sdhci_host *host = dev_id;
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ u32 dma_cs; /* control and status register */
-+
-+ BUG_ON(NULL == dev_id);
-+ BUG_ON(NULL == host_priv->dma_chan_base);
-+
-+ sdhci_spin_lock(host);
-+
-+ dma_cs = readl(host_priv->dma_chan_base + BCM2708_DMA_CS);
-+
-+ if (dma_cs & BCM2708_DMA_ERR) {
-+ unsigned long debug;
-+ debug = readl(host_priv->dma_chan_base +
-+ BCM2708_DMA_DEBUG);
-+ printk(KERN_ERR "%s: DMA error - CS %lX DEBUG %lX\n",
-+ mmc_hostname(host->mmc), (unsigned long)dma_cs,
-+ (unsigned long)debug);
-+ /* reset error */
-+ writel(debug, host_priv->dma_chan_base +
-+ BCM2708_DMA_DEBUG);
-+ }
-+ if (dma_cs & BCM2708_DMA_INT) {
-+ /* acknowledge interrupt */
-+ writel(BCM2708_DMA_INT,
-+ host_priv->dma_chan_base + BCM2708_DMA_CS);
-+
-+ dsb(); /* ARM data synchronization (push) operation */
-+
-+ if (!host_priv->dma_wanted) {
-+ /* ignore this interrupt - it was reset */
-+ if (extra_messages)
-+ printk(KERN_INFO "%s: DMA IRQ %X ignored - "
-+ "results were reset\n",
-+ mmc_hostname(host->mmc), dma_cs);
-+#ifdef CHECK_DMA_USE
-+ printk(KERN_INFO "%s: now %"FMT_HPT
-+ " started %lu reset %lu stopped %lu\n",
-+ mmc_hostname(host->mmc), hptime(),
-+ since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ host_priv->dmas_pending--;
-+#endif
-+ } else
-+ sdhci_bcm2708_dma_complete_irq(host, dma_cs);
-+
-+ result = IRQ_HANDLED;
-+ }
-+ sdhci_spin_unlock(host);
-+
-+ return result;
-+}
-+#endif /* CONFIG_MMC_SDHCI_BCM2708_DMA */
-+
-+
-+/***************************************************************************** \
-+ * *
-+ * Device Attributes *
-+ * *
-+\*****************************************************************************/
-+
-+
-+/**
-+ * Show the DMA-using status
-+ */
-+static ssize_t attr_dma_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)dev_get_drvdata(_dev);
-+
-+ if (host) {
-+ int use_dma = (host->flags & SDHCI_USE_PLATDMA? 1:0);
-+ return sprintf(buf, "%d\n", use_dma);
-+ } else
-+ return -EINVAL;
-+}
-+
-+/**
-+ * Set the DMA-using status
-+ */
-+static ssize_t attr_dma_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)dev_get_drvdata(_dev);
-+
-+ if (host) {
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ int on = simple_strtol(buf, NULL, 0);
-+ if (on) {
-+ host->flags |= SDHCI_USE_PLATDMA;
-+ sdhci_bcm2708_writel(host, 1, REG_EXRDFIFO_EN);
-+ printk(KERN_INFO "%s: DMA enabled\n",
-+ mmc_hostname(host->mmc));
-+ } else {
-+ host->flags &= ~(SDHCI_USE_PLATDMA | SDHCI_REQ_USE_DMA);
-+ sdhci_bcm2708_writel(host, 0, REG_EXRDFIFO_EN);
-+ printk(KERN_INFO "%s: DMA disabled\n",
-+ mmc_hostname(host->mmc));
-+ }
-+#endif
-+ return count;
-+ } else
-+ return -EINVAL;
-+}
-+
-+static DEVICE_ATTR(use_dma, S_IRUGO | S_IWUGO, attr_dma_show, attr_dma_store);
-+
-+
-+/**
-+ * Show the DMA wait states used
-+ */
-+static ssize_t attr_dmawait_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)dev_get_drvdata(_dev);
-+
-+ if (host) {
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ int dmawait = host_priv->dma_waits;
-+ return sprintf(buf, "%d\n", dmawait);
-+ } else
-+ return -EINVAL;
-+}
-+
-+/**
-+ * Set the DMA wait state used
-+ */
-+static ssize_t attr_dmawait_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)dev_get_drvdata(_dev);
-+
-+ if (host) {
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ int dma_waits = simple_strtol(buf, NULL, 0);
-+ if (dma_waits >= 0 && dma_waits < 32)
-+ host_priv->dma_waits = dma_waits;
-+ else
-+ printk(KERN_ERR "%s: illegal dma_waits value - %d",
-+ mmc_hostname(host->mmc), dma_waits);
-+#endif
-+ return count;
-+ } else
-+ return -EINVAL;
-+}
-+
-+static DEVICE_ATTR(dma_wait, S_IRUGO | S_IWUGO,
-+ attr_dmawait_show, attr_dmawait_store);
-+
-+
-+/**
-+ * Show the DMA-using status
-+ */
-+static ssize_t attr_status_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)dev_get_drvdata(_dev);
-+
-+ if (host) {
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ return sprintf(buf,
-+ "present: yes\n"
-+ "power: %s\n"
-+ "clock: %u Hz\n"
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ "dma: %s (%d waits)\n",
-+#else
-+ "dma: unconfigured\n",
-+#endif
-+ "always on",
-+ host->clock
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ , (host->flags & SDHCI_USE_PLATDMA)? "on": "off"
-+ , host_priv->dma_waits
-+#endif
-+ );
-+ } else
-+ return -EINVAL;
-+}
-+
-+static DEVICE_ATTR(status, S_IRUGO, attr_status_show, NULL);
-+
-+/***************************************************************************** \
-+ * *
-+ * Power Management *
-+ * *
-+\*****************************************************************************/
-+
-+
-+#ifdef CONFIG_PM
-+static int sdhci_bcm2708_suspend(struct platform_device *dev, pm_message_t state)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)
-+ platform_get_drvdata(dev);
-+ int ret = 0;
-+
-+ if (host->mmc) {
-+ ret = mmc_suspend_host(host->mmc);
-+ }
-+
-+ return ret;
-+}
-+
-+static int sdhci_bcm2708_resume(struct platform_device *dev)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)
-+ platform_get_drvdata(dev);
-+ int ret = 0;
-+
-+ if (host->mmc) {
-+ ret = mmc_resume_host(host->mmc);
-+ }
-+
-+ return ret;
-+}
-+#endif
-+
-+
-+/*****************************************************************************\
-+ * *
-+ * Device quirk functions. Implemented as local ops because the flags *
-+ * field is out of space with newer kernels. This implementation can be *
-+ * back ported to older kernels as well. *
-+\****************************************************************************/
-+static unsigned int sdhci_bcm2708_quirk_extra_ints(struct sdhci_host *host)
-+{
-+ return 1;
-+}
-+
-+static unsigned int sdhci_bcm2708_quirk_spurious_crc_acmd51(struct sdhci_host *host)
-+{
-+ return 1;
-+}
-+
-+static unsigned int sdhci_bcm2708_quirk_voltage_broken(struct sdhci_host *host)
-+{
-+ return 1;
-+}
-+
-+static unsigned int sdhci_bcm2708_uhs_broken(struct sdhci_host *host)
-+{
-+ return 1;
-+}
-+
-+static unsigned int sdhci_bcm2708_missing_status(struct sdhci_host *host)
-+{
-+ return 1;
-+}
-+
-+/***************************************************************************** \
-+ * *
-+ * Device ops *
-+ * *
-+\*****************************************************************************/
-+
-+static struct sdhci_ops sdhci_bcm2708_ops = {
-+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-+ .read_l = sdhci_bcm2708_readl,
-+ .read_w = sdhci_bcm2708_readw,
-+ .read_b = sdhci_bcm2708_readb,
-+ .write_l = sdhci_bcm2708_writel,
-+ .write_w = sdhci_bcm2708_writew,
-+ .write_b = sdhci_bcm2708_writeb,
-+#else
-+#error The BCM2708 SDHCI driver needs CONFIG_MMC_SDHCI_IO_ACCESSORS to be set
-+#endif
-+ .get_max_clock = sdhci_bcm2708_get_max_clock,
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ // Platform DMA operations
-+ .pdma_able = sdhci_bcm2708_platdma_dmaable,
-+ .pdma_avail = sdhci_bcm2708_platdma_avail,
-+ .pdma_reset = sdhci_bcm2708_platdma_reset,
-+#endif
-+ .extra_ints = sdhci_bcm2708_quirk_extra_ints,
-+ .voltage_broken = sdhci_bcm2708_quirk_voltage_broken,
-+ .uhs_broken = sdhci_bcm2708_uhs_broken,
-+};
-+
-+/*****************************************************************************\
-+ * *
-+ * Device probing/removal *
-+ * *
-+\*****************************************************************************/
-+
-+static int sdhci_bcm2708_probe(struct platform_device *pdev)
-+{
-+ struct sdhci_host *host;
-+ struct resource *iomem;
-+ struct sdhci_bcm2708_priv *host_priv;
-+ int ret;
-+
-+ BUG_ON(pdev == NULL);
-+
-+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!iomem) {
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+
-+ if (resource_size(iomem) != 0x100)
-+ dev_err(&pdev->dev, "Invalid iomem size. You may "
-+ "experience problems.\n");
-+
-+ if (pdev->dev.parent)
-+ host = sdhci_alloc_host(pdev->dev.parent,
-+ sizeof(struct sdhci_bcm2708_priv));
-+ else
-+ host = sdhci_alloc_host(&pdev->dev,
-+ sizeof(struct sdhci_bcm2708_priv));
-+
-+ if (IS_ERR(host)) {
-+ ret = PTR_ERR(host);
-+ goto err;
-+ }
-+ if (missing_status) {
-+ sdhci_bcm2708_ops.missing_status = sdhci_bcm2708_missing_status;
-+ }
-+
-+ if( spurious_crc_acmd51 ) {
-+ sdhci_bcm2708_ops.spurious_crc_acmd51 = sdhci_bcm2708_quirk_spurious_crc_acmd51;
-+ }
-+
-+
-+ printk("sdhci: %s low-latency mode\n",enable_llm?"Enable":"Disable");
-+
-+ host->hw_name = "BCM2708_Arasan";
-+ host->ops = &sdhci_bcm2708_ops;
-+ host->irq = platform_get_irq(pdev, 0);
-+ host->second_irq = 0;
-+
-+ host->quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
-+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
-+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
-+ SDHCI_QUIRK_MISSING_CAPS |
-+ SDHCI_QUIRK_NO_HISPD_BIT |
-+ (sync_after_dma ? 0:SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12);
-+
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ host->flags = SDHCI_USE_PLATDMA;
-+#endif
-+
-+ if (!request_mem_region(iomem->start, resource_size(iomem),
-+ mmc_hostname(host->mmc))) {
-+ dev_err(&pdev->dev, "cannot request region\n");
-+ ret = -EBUSY;
-+ goto err_request;
-+ }
-+
-+ host->ioaddr = ioremap(iomem->start, resource_size(iomem));
-+ if (!host->ioaddr) {
-+ dev_err(&pdev->dev, "failed to remap registers\n");
-+ ret = -ENOMEM;
-+ goto err_remap;
-+ }
-+
-+ host_priv = SDHCI_HOST_PRIV(host);
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ host_priv->dma_wanted = 0;
-+#ifdef CHECK_DMA_USE
-+ host_priv->dmas_pending = 0;
-+ host_priv->when_started = 0;
-+ host_priv->when_reset = 0;
-+ host_priv->when_stopped = 0;
-+#endif
-+ host_priv->sg_ix = 0;
-+ host_priv->sg_done = 0;
-+ host_priv->complete = NULL;
-+ host_priv->dma_waits = SDHCI_BCM_DMA_WAITS;
-+
-+ host_priv->cb_base = dma_alloc_writecombine(&pdev->dev, SZ_4K,
-+ &host_priv->cb_handle,
-+ GFP_KERNEL);
-+ if (!host_priv->cb_base) {
-+ dev_err(&pdev->dev, "cannot allocate DMA CBs\n");
-+ ret = -ENOMEM;
-+ goto err_alloc_cb;
-+ }
-+
-+ ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_FAST,
-+ &host_priv->dma_chan_base,
-+ &host_priv->dma_irq);
-+ if (ret < 0) {
-+ dev_err(&pdev->dev, "couldn't allocate a DMA channel\n");
-+ goto err_add_dma;
-+ }
-+ host_priv->dma_chan = ret;
-+
-+ ret = request_irq(host_priv->dma_irq, sdhci_bcm2708_dma_irq,0,//IRQF_SHARED,
-+ DRIVER_NAME " (dma)", host);
-+ if (ret) {
-+ dev_err(&pdev->dev, "cannot set DMA IRQ\n");
-+ goto err_add_dma_irq;
-+ }
-+ host->second_irq = host_priv->dma_irq;
-+ DBG("DMA CBs %p handle %08X DMA%d %p DMA IRQ %d\n",
-+ host_priv->cb_base, (unsigned)host_priv->cb_handle,
-+ host_priv->dma_chan, host_priv->dma_chan_base,
-+ host_priv->dma_irq);
-+
-+ if (allow_highspeed)
-+ host->mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-+
-+ /* single block writes cause data loss with some SD cards! */
-+ host->mmc->caps2 |= MMC_CAP2_FORCE_MULTIBLOCK;
-+#endif
-+
-+ ret = sdhci_add_host(host);
-+ if (ret)
-+ goto err_add_host;
-+
-+ platform_set_drvdata(pdev, host);
-+ ret = device_create_file(&pdev->dev, &dev_attr_use_dma);
-+ ret = device_create_file(&pdev->dev, &dev_attr_dma_wait);
-+ ret = device_create_file(&pdev->dev, &dev_attr_status);
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ /* enable extension fifo for paced DMA transfers */
-+ sdhci_bcm2708_writel(host, 1, REG_EXRDFIFO_EN);
-+ sdhci_bcm2708_writel(host, 4, REG_EXRDFIFO_CFG);
-+#endif
-+
-+ printk(KERN_INFO "%s: BCM2708 SDHC host at 0x%08llx DMA %d IRQ %d\n",
-+ mmc_hostname(host->mmc), (unsigned long long)iomem->start,
-+ host_priv->dma_chan, host_priv->dma_irq);
-+
-+ return 0;
-+
-+err_add_host:
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ free_irq(host_priv->dma_irq, host);
-+err_add_dma_irq:
-+ bcm_dma_chan_free(host_priv->dma_chan);
-+err_add_dma:
-+ dma_free_writecombine(&pdev->dev, SZ_4K, host_priv->cb_base,
-+ host_priv->cb_handle);
-+err_alloc_cb:
-+#endif
-+ iounmap(host->ioaddr);
-+err_remap:
-+ release_mem_region(iomem->start, resource_size(iomem));
-+err_request:
-+ sdhci_free_host(host);
-+err:
-+ dev_err(&pdev->dev, "probe failed, err %d\n", ret);
-+ return ret;
-+}
-+
-+static int sdhci_bcm2708_remove(struct platform_device *pdev)
-+{
-+ struct sdhci_host *host = platform_get_drvdata(pdev);
-+ struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ int dead;
-+ u32 scratch;
-+
-+ dead = 0;
-+ scratch = sdhci_bcm2708_readl(host, SDHCI_INT_STATUS);
-+ if (scratch == (u32)-1)
-+ dead = 1;
-+
-+ device_remove_file(&pdev->dev, &dev_attr_status);
-+ device_remove_file(&pdev->dev, &dev_attr_dma_wait);
-+ device_remove_file(&pdev->dev, &dev_attr_use_dma);
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ free_irq(host_priv->dma_irq, host);
-+ dma_free_writecombine(&pdev->dev, SZ_4K, host_priv->cb_base,
-+ host_priv->cb_handle);
-+#endif
-+ sdhci_remove_host(host, dead);
-+ iounmap(host->ioaddr);
-+ release_mem_region(iomem->start, resource_size(iomem));
-+ sdhci_free_host(host);
-+ platform_set_drvdata(pdev, NULL);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver sdhci_bcm2708_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = sdhci_bcm2708_probe,
-+ .remove = sdhci_bcm2708_remove,
-+
-+#ifdef CONFIG_PM
-+ .suspend = sdhci_bcm2708_suspend,
-+ .resume = sdhci_bcm2708_resume,
-+#endif
-+
-+};
-+
-+/*****************************************************************************\
-+ * *
-+ * Driver init/exit *
-+ * *
-+\*****************************************************************************/
-+
-+static int __init sdhci_drv_init(void)
-+{
-+ return platform_driver_register(&sdhci_bcm2708_driver);
-+}
-+
-+static void __exit sdhci_drv_exit(void)
-+{
-+ platform_driver_unregister(&sdhci_bcm2708_driver);
-+}
-+
-+module_init(sdhci_drv_init);
-+module_exit(sdhci_drv_exit);
-+
-+module_param(allow_highspeed, bool, 0444);
-+module_param(emmc_clock_freq, int, 0444);
-+module_param(sync_after_dma, bool, 0444);
-+module_param(missing_status, bool, 0444);
-+module_param(spurious_crc_acmd51, bool, 0444);
-+module_param(enable_llm, bool, 0444);
-+module_param(cycle_delay, int, 0444);
-+module_param(extra_messages, bool, 0444);
-+
-+MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
-+MODULE_AUTHOR("Broadcom <info@broadcom.com>");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:"DRIVER_NAME);
-+
-+MODULE_PARM_DESC(allow_highspeed, "Allow high speed transfers modes");
-+MODULE_PARM_DESC(emmc_clock_freq, "Specify the speed of emmc clock");
-+MODULE_PARM_DESC(sync_after_dma, "Block in driver until dma complete");
-+MODULE_PARM_DESC(missing_status, "Use the missing status quirk");
-+MODULE_PARM_DESC(spurious_crc_acmd51, "Use the spurious crc quirk for reading SCR (ACMD51)");
-+MODULE_PARM_DESC(enable_llm, "Enable low-latency mode");
-+MODULE_PARM_DESC(extra_messages, "Enable more sdcard warning messages");
-+
-+
---- a/drivers/mmc/host/sdhci.c
-+++ b/drivers/mmc/host/sdhci.c
-@@ -28,6 +28,7 @@
- #include <linux/mmc/mmc.h>
- #include <linux/mmc/host.h>
- #include <linux/mmc/card.h>
-+#include <linux/mmc/sd.h>
- #include <linux/mmc/slot-gpio.h>
-
- #include "sdhci.h"
-@@ -123,6 +124,91 @@ static void sdhci_dumpregs(struct sdhci_
- * Low level functions *
- * *
- \*****************************************************************************/
-+extern bool enable_llm;
-+static int sdhci_locked=0;
-+void sdhci_spin_lock(struct sdhci_host *host)
-+{
-+ spin_lock(&host->lock);
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ disable_irq_nosync(host->irq);
-+ if(host->second_irq)
-+ disable_irq_nosync(host->second_irq);
-+ local_irq_enable();
-+ }
-+#endif
-+}
-+
-+void sdhci_spin_unlock(struct sdhci_host *host)
-+{
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ local_irq_disable();
-+ if(host->second_irq)
-+ enable_irq(host->second_irq);
-+ enable_irq(host->irq);
-+ }
-+#endif
-+ spin_unlock(&host->lock);
-+}
-+
-+void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags)
-+{
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ while(sdhci_locked)
-+ {
-+ preempt_schedule();
-+ }
-+ spin_lock_irqsave(&host->lock,*flags);
-+ disable_irq(host->irq);
-+ if(host->second_irq)
-+ disable_irq(host->second_irq);
-+ local_irq_enable();
-+ }
-+ else
-+#endif
-+ spin_lock_irqsave(&host->lock,*flags);
-+}
-+
-+void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags)
-+{
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ local_irq_disable();
-+ if(host->second_irq)
-+ enable_irq(host->second_irq);
-+ enable_irq(host->irq);
-+ }
-+#endif
-+ spin_unlock_irqrestore(&host->lock,flags);
-+}
-+
-+static void sdhci_spin_enable_schedule(struct sdhci_host *host)
-+{
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ sdhci_locked = 1;
-+ preempt_enable();
-+ }
-+#endif
-+}
-+
-+static void sdhci_spin_disable_schedule(struct sdhci_host *host)
-+{
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ preempt_disable();
-+ sdhci_locked = 0;
-+ }
-+#endif
-+}
-
- static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
- {
-@@ -288,7 +374,7 @@ static void sdhci_led_control(struct led
- struct sdhci_host *host = container_of(led, struct sdhci_host, led);
- unsigned long flags;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- if (host->runtime_suspended)
- goto out;
-@@ -298,7 +384,7 @@ static void sdhci_led_control(struct led
- else
- sdhci_activate_led(host);
- out:
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
- #endif
-
-@@ -315,7 +401,7 @@ static void sdhci_read_block_pio(struct
- u32 uninitialized_var(scratch);
- u8 *buf;
-
-- DBG("PIO reading\n");
-+ DBG("PIO reading %db\n", host->data->blksz);
-
- blksize = host->data->blksz;
- chunk = 0;
-@@ -360,7 +446,7 @@ static void sdhci_write_block_pio(struct
- u32 scratch;
- u8 *buf;
-
-- DBG("PIO writing\n");
-+ DBG("PIO writing %db\n", host->data->blksz);
-
- blksize = host->data->blksz;
- chunk = 0;
-@@ -399,19 +485,28 @@ static void sdhci_write_block_pio(struct
- local_irq_restore(flags);
- }
-
--static void sdhci_transfer_pio(struct sdhci_host *host)
-+static void sdhci_transfer_pio(struct sdhci_host *host, u32 intstate)
- {
- u32 mask;
-+ u32 state = 0;
-+ u32 intmask;
-+ int available;
-
- BUG_ON(!host->data);
-
- if (host->blocks == 0)
- return;
-
-- if (host->data->flags & MMC_DATA_READ)
-+ if (host->data->flags & MMC_DATA_READ) {
- mask = SDHCI_DATA_AVAILABLE;
-- else
-+ intmask = SDHCI_INT_DATA_AVAIL;
-+ } else {
- mask = SDHCI_SPACE_AVAILABLE;
-+ intmask = SDHCI_INT_SPACE_AVAIL;
-+ }
-+
-+ /* initially we can see whether we can procede using intstate */
-+ available = (intstate & intmask);
-
- /*
- * Some controllers (JMicron JMB38x) mess up the buffer bits
-@@ -422,7 +517,7 @@ static void sdhci_transfer_pio(struct sd
- (host->data->blocks == 1))
- mask = ~0;
-
-- while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
-+ while (available) {
- if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY)
- udelay(100);
-
-@@ -434,9 +529,11 @@ static void sdhci_transfer_pio(struct sd
- host->blocks--;
- if (host->blocks == 0)
- break;
-+ state = sdhci_readl(host, SDHCI_PRESENT_STATE);
-+ available = state & mask;
- }
-
-- DBG("PIO transfer complete.\n");
-+ DBG("PIO transfer complete - %d blocks left.\n", host->blocks);
- }
-
- static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
-@@ -709,7 +806,9 @@ static void sdhci_set_transfer_irqs(stru
- u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
- u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
-
-- if (host->flags & SDHCI_REQ_USE_DMA)
-+ /* platform DMA will begin on receipt of PIO irqs */
-+ if ((host->flags & SDHCI_REQ_USE_DMA) &&
-+ !(host->flags & SDHCI_USE_PLATDMA))
- sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
- else
- sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
-@@ -741,44 +840,25 @@ static void sdhci_prepare_data(struct sd
- host->data_early = 0;
- host->data->bytes_xfered = 0;
-
-- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
-+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA | SDHCI_USE_PLATDMA))
- host->flags |= SDHCI_REQ_USE_DMA;
-
- /*
- * FIXME: This doesn't account for merging when mapping the
- * scatterlist.
- */
-- if (host->flags & SDHCI_REQ_USE_DMA) {
-- int broken, i;
-- struct scatterlist *sg;
--
-- broken = 0;
-- if (host->flags & SDHCI_USE_ADMA) {
-- if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE)
-- broken = 1;
-- } else {
-- if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE)
-- broken = 1;
-- }
--
-- if (unlikely(broken)) {
-- for_each_sg(data->sg, sg, data->sg_len, i) {
-- if (sg->length & 0x3) {
-- DBG("Reverting to PIO because of "
-- "transfer size (%d)\n",
-- sg->length);
-- host->flags &= ~SDHCI_REQ_USE_DMA;
-- break;
-- }
-- }
-- }
-- }
-
- /*
- * The assumption here being that alignment is the same after
- * translation to device address space.
- */
-- if (host->flags & SDHCI_REQ_USE_DMA) {
-+ if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_PLATDMA)) ==
-+ (SDHCI_REQ_USE_DMA | SDHCI_USE_PLATDMA)) {
-+
-+ if (! sdhci_platdma_dmaable(host, data))
-+ host->flags &= ~SDHCI_REQ_USE_DMA;
-+
-+ } else if (host->flags & SDHCI_REQ_USE_DMA) {
- int broken, i;
- struct scatterlist *sg;
-
-@@ -837,7 +917,8 @@ static void sdhci_prepare_data(struct sd
- */
- WARN_ON(1);
- host->flags &= ~SDHCI_REQ_USE_DMA;
-- } else {
-+ } else
-+ if (!(host->flags & SDHCI_USE_PLATDMA)) {
- WARN_ON(sg_cnt != 1);
- sdhci_writel(host, sg_dma_address(data->sg),
- SDHCI_DMA_ADDRESS);
-@@ -853,11 +934,13 @@ static void sdhci_prepare_data(struct sd
- if (host->version >= SDHCI_SPEC_200) {
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- ctrl &= ~SDHCI_CTRL_DMA_MASK;
-+ if (! (host->flags & SDHCI_USE_PLATDMA)) {
- if ((host->flags & SDHCI_REQ_USE_DMA) &&
- (host->flags & SDHCI_USE_ADMA))
- ctrl |= SDHCI_CTRL_ADMA32;
- else
- ctrl |= SDHCI_CTRL_SDMA;
-+ }
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- }
-
-@@ -909,7 +992,8 @@ static void sdhci_set_transfer_mode(stru
-
- if (data->flags & MMC_DATA_READ)
- mode |= SDHCI_TRNS_READ;
-- if (host->flags & SDHCI_REQ_USE_DMA)
-+ if ((host->flags & SDHCI_REQ_USE_DMA) &&
-+ !(host->flags & SDHCI_USE_PLATDMA))
- mode |= SDHCI_TRNS_DMA;
-
- sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
-@@ -925,13 +1009,16 @@ static void sdhci_finish_data(struct sdh
- host->data = NULL;
-
- if (host->flags & SDHCI_REQ_USE_DMA) {
-- if (host->flags & SDHCI_USE_ADMA)
-- sdhci_adma_table_post(host, data);
-- else {
-+ /* we may have to abandon an ongoing platform DMA */
-+ if (host->flags & SDHCI_USE_PLATDMA)
-+ sdhci_platdma_reset(host, data);
-+
-+ if (host->flags & (SDHCI_USE_PLATDMA | SDHCI_USE_SDMA)) {
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
-- }
-+ } else if (host->flags & SDHCI_USE_ADMA)
-+ sdhci_adma_table_post(host, data);
- }
-
- /*
-@@ -984,6 +1071,12 @@ static void sdhci_send_command(struct sd
- if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
- mask |= SDHCI_DATA_INHIBIT;
-
-+ if(host->ops->missing_status && (cmd->opcode == MMC_SEND_STATUS)) {
-+ timeout = 5000; // Really obscenely large delay to send the status, due to bug in controller
-+ // which might cause the STATUS command to get stuck when a data operation is in flow
-+ mask |= SDHCI_DATA_INHIBIT;
-+ }
-+
- /* We shouldn't wait for data inihibit for stop commands, even
- though they might use busy signaling */
- if (host->mrq->data && (cmd == host->mrq->data->stop))
-@@ -999,12 +1092,20 @@ static void sdhci_send_command(struct sd
- return;
- }
- timeout--;
-+ sdhci_spin_enable_schedule(host);
- mdelay(1);
-+ sdhci_spin_disable_schedule(host);
- }
-+ DBG("send cmd %d - wait 0x%X irq 0x%x\n", cmd->opcode, mask,
-+ sdhci_readl(host, SDHCI_INT_STATUS));
-
- mod_timer(&host->timer, jiffies + 10 * HZ);
-
- host->cmd = cmd;
-+ if (host->last_cmdop == MMC_APP_CMD)
-+ host->last_cmdop = -cmd->opcode;
-+ else
-+ host->last_cmdop = cmd->opcode;
-
- sdhci_prepare_data(host, cmd);
-
-@@ -1220,7 +1321,9 @@ clock_set:
- return;
- }
- timeout--;
-+ sdhci_spin_enable_schedule(host);
- mdelay(1);
-+ sdhci_spin_disable_schedule(host);
- }
-
- clk |= SDHCI_CLOCK_CARD_EN;
-@@ -1316,7 +1419,7 @@ static void sdhci_request(struct mmc_hos
-
- sdhci_runtime_pm_get(host);
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- WARN_ON(host->mrq != NULL);
-
-@@ -1374,9 +1477,9 @@ static void sdhci_request(struct mmc_hos
- mmc->card->type == MMC_TYPE_MMC ?
- MMC_SEND_TUNING_BLOCK_HS200 :
- MMC_SEND_TUNING_BLOCK;
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- sdhci_execute_tuning(mmc, tuning_opcode);
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- /* Restore original mmc_request structure */
- host->mrq = mrq;
-@@ -1390,7 +1493,7 @@ static void sdhci_request(struct mmc_hos
- }
-
- mmiowb();
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
-@@ -1399,10 +1502,10 @@ static void sdhci_do_set_ios(struct sdhc
- int vdd_bit = -1;
- u8 ctrl;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- if (host->flags & SDHCI_DEVICE_DEAD) {
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
- mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
- return;
-@@ -1429,9 +1532,9 @@ static void sdhci_do_set_ios(struct sdhc
- vdd_bit = sdhci_set_power(host, ios->vdd);
-
- if (host->vmmc && vdd_bit != -1) {
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
- }
-
- if (host->ops->platform_send_init_74_clocks)
-@@ -1470,7 +1573,7 @@ static void sdhci_do_set_ios(struct sdhc
- else
- ctrl &= ~SDHCI_CTRL_HISPD;
-
-- if (host->version >= SDHCI_SPEC_300) {
-+ if (host->version >= SDHCI_SPEC_300 && !(host->ops->uhs_broken)) {
- u16 clk, ctrl_2;
-
- /* In case of UHS-I modes, set High Speed Enable */
-@@ -1569,7 +1672,7 @@ static void sdhci_do_set_ios(struct sdhc
- sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
-
- mmiowb();
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-@@ -1617,7 +1720,7 @@ static int sdhci_check_ro(struct sdhci_h
- unsigned long flags;
- int is_readonly;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- if (host->flags & SDHCI_DEVICE_DEAD)
- is_readonly = 0;
-@@ -1627,7 +1730,7 @@ static int sdhci_check_ro(struct sdhci_h
- is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
- & SDHCI_WRITE_PROTECT);
-
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
-
- /* This quirk needs to be replaced by a callback-function later */
- return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
-@@ -1700,9 +1803,9 @@ static void sdhci_enable_sdio_irq(struct
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
- sdhci_enable_sdio_irq_nolock(host, enable);
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
-@@ -2046,7 +2149,7 @@ static void sdhci_card_event(struct mmc_
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- /* Check host->mrq first in case we are runtime suspended */
- if (host->mrq &&
-@@ -2063,7 +2166,7 @@ static void sdhci_card_event(struct mmc_
- tasklet_schedule(&host->finish_tasklet);
- }
-
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- static const struct mmc_host_ops sdhci_ops = {
-@@ -2102,14 +2205,14 @@ static void sdhci_tasklet_finish(unsigne
-
- host = (struct sdhci_host*)param;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- /*
- * If this tasklet gets rescheduled while running, it will
- * be run again afterwards but without any active request.
- */
- if (!host->mrq) {
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- return;
- }
-
-@@ -2147,7 +2250,7 @@ static void sdhci_tasklet_finish(unsigne
- #endif
-
- mmiowb();
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
-
- mmc_request_done(host->mmc, mrq);
- sdhci_runtime_pm_put(host);
-@@ -2160,11 +2263,11 @@ static void sdhci_timeout_timer(unsigned
-
- host = (struct sdhci_host*)data;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- if (host->mrq) {
- pr_err("%s: Timeout waiting for hardware "
-- "interrupt.\n", mmc_hostname(host->mmc));
-+ "interrupt - cmd%d.\n", mmc_hostname(host->mmc), host->last_cmdop);
- sdhci_dumpregs(host);
-
- if (host->data) {
-@@ -2181,7 +2284,7 @@ static void sdhci_timeout_timer(unsigned
- }
-
- mmiowb();
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- static void sdhci_tuning_timer(unsigned long data)
-@@ -2191,11 +2294,11 @@ static void sdhci_tuning_timer(unsigned
-
- host = (struct sdhci_host *)data;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- host->flags |= SDHCI_NEEDS_RETUNING;
-
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- /*****************************************************************************\
-@@ -2209,10 +2312,13 @@ static void sdhci_cmd_irq(struct sdhci_h
- BUG_ON(intmask == 0);
-
- if (!host->cmd) {
-+ if (!(host->ops->extra_ints)) {
- pr_err("%s: Got command interrupt 0x%08x even "
- "though no command operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- sdhci_dumpregs(host);
-+ } else
-+ DBG("cmd irq 0x%08x cmd complete\n", (unsigned)intmask);
- return;
- }
-
-@@ -2282,6 +2388,19 @@ static void sdhci_show_adma_error(struct
- static void sdhci_show_adma_error(struct sdhci_host *host) { }
- #endif
-
-+static void sdhci_data_end(struct sdhci_host *host)
-+{
-+ if (host->cmd) {
-+ /*
-+ * Data managed to finish before the
-+ * command completed. Make sure we do
-+ * things in the proper order.
-+ */
-+ host->data_early = 1;
-+ } else
-+ sdhci_finish_data(host);
-+}
-+
- static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
- {
- u32 command;
-@@ -2311,23 +2430,39 @@ static void sdhci_data_irq(struct sdhci_
- }
- }
-
-+ if (!(host->ops->extra_ints)) {
- pr_err("%s: Got data interrupt 0x%08x even "
- "though no data operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- sdhci_dumpregs(host);
-+ } else
-+ DBG("data irq 0x%08x but no data\n", (unsigned)intmask);
-
- return;
- }
-
- if (intmask & SDHCI_INT_DATA_TIMEOUT)
- host->data->error = -ETIMEDOUT;
-- else if (intmask & SDHCI_INT_DATA_END_BIT)
-+ else if (intmask & SDHCI_INT_DATA_END_BIT) {
-+ DBG("end error in cmd %d\n", host->last_cmdop);
-+ if (host->ops->spurious_crc_acmd51 &&
-+ host->last_cmdop == -SD_APP_SEND_SCR) {
-+ DBG("ignoring spurious data_end_bit error\n");
-+ intmask = SDHCI_INT_DATA_AVAIL|SDHCI_INT_DATA_END;
-+ } else
- host->data->error = -EILSEQ;
-- else if ((intmask & SDHCI_INT_DATA_CRC) &&
-+ } else if ((intmask & SDHCI_INT_DATA_CRC) &&
- SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
-- != MMC_BUS_TEST_R)
-+ != MMC_BUS_TEST_R) {
-+ DBG("crc error in cmd %d\n", host->last_cmdop);
-+ if (host->ops->spurious_crc_acmd51 &&
-+ host->last_cmdop == -SD_APP_SEND_SCR) {
-+ DBG("ignoring spurious data_crc_bit error\n");
-+ intmask = SDHCI_INT_DATA_AVAIL|SDHCI_INT_DATA_END;
-+ } else {
- host->data->error = -EILSEQ;
-- else if (intmask & SDHCI_INT_ADMA_ERROR) {
-+ }
-+ } else if (intmask & SDHCI_INT_ADMA_ERROR) {
- pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
- sdhci_show_adma_error(host);
- host->data->error = -EIO;
-@@ -2335,11 +2470,18 @@ static void sdhci_data_irq(struct sdhci_
- host->ops->adma_workaround(host, intmask);
- }
-
-- if (host->data->error)
-+ if (host->data->error) {
-+ DBG("finish request early on error %d\n", host->data->error);
- sdhci_finish_data(host);
-- else {
-- if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
-- sdhci_transfer_pio(host);
-+ } else {
-+ if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) {
-+ if (host->flags & SDHCI_REQ_USE_DMA) {
-+ /* possible only in PLATDMA mode */
-+ sdhci_platdma_avail(host, &intmask,
-+ &sdhci_data_end);
-+ } else
-+ sdhci_transfer_pio(host, intmask);
-+ }
-
- /*
- * We currently don't do anything fancy with DMA
-@@ -2368,18 +2510,8 @@ static void sdhci_data_irq(struct sdhci_
- sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
- }
-
-- if (intmask & SDHCI_INT_DATA_END) {
-- if (host->cmd) {
-- /*
-- * Data managed to finish before the
-- * command completed. Make sure we do
-- * things in the proper order.
-- */
-- host->data_early = 1;
-- } else {
-- sdhci_finish_data(host);
-- }
-- }
-+ if (intmask & SDHCI_INT_DATA_END)
-+ sdhci_data_end(host);
- }
- }
-
-@@ -2390,10 +2522,10 @@ static irqreturn_t sdhci_irq(int irq, vo
- u32 intmask, unexpected = 0;
- int cardint = 0, max_loops = 16;
-
-- spin_lock(&host->lock);
-+ sdhci_spin_lock(host);
-
- if (host->runtime_suspended) {
-- spin_unlock(&host->lock);
-+ sdhci_spin_unlock(host);
- pr_warning("%s: got irq while runtime suspended\n",
- mmc_hostname(host->mmc));
- return IRQ_HANDLED;
-@@ -2435,6 +2567,22 @@ again:
- tasklet_schedule(&host->card_tasklet);
- }
-
-+ if (intmask & SDHCI_INT_ERROR_MASK & ~SDHCI_INT_ERROR)
-+ DBG("controller reports error 0x%x -"
-+ "%s%s%s%s%s%s%s%s%s%s",
-+ intmask,
-+ intmask & SDHCI_INT_TIMEOUT? " timeout": "",
-+ intmask & SDHCI_INT_CRC ? " crc": "",
-+ intmask & SDHCI_INT_END_BIT? " endbit": "",
-+ intmask & SDHCI_INT_INDEX? " index": "",
-+ intmask & SDHCI_INT_DATA_TIMEOUT? " data_timeout": "",
-+ intmask & SDHCI_INT_DATA_CRC? " data_crc": "",
-+ intmask & SDHCI_INT_DATA_END_BIT? " data_endbit": "",
-+ intmask & SDHCI_INT_BUS_POWER? " buspower": "",
-+ intmask & SDHCI_INT_ACMD12ERR? " acmd12": "",
-+ intmask & SDHCI_INT_ADMA_ERROR? " adma": ""
-+ );
-+
- if (intmask & SDHCI_INT_CMD_MASK) {
- sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
- SDHCI_INT_STATUS);
-@@ -2449,7 +2597,13 @@ again:
-
- intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
-
-- intmask &= ~SDHCI_INT_ERROR;
-+ if (intmask & SDHCI_INT_ERROR_MASK) {
-+ /* collect any uncovered errors */
-+ sdhci_writel(host, intmask & SDHCI_INT_ERROR_MASK,
-+ SDHCI_INT_STATUS);
-+ }
-+
-+ intmask &= ~SDHCI_INT_ERROR_MASK;
-
- if (intmask & SDHCI_INT_BUS_POWER) {
- pr_err("%s: Card is consuming too much power!\n",
-@@ -2475,7 +2629,7 @@ again:
- if (intmask && --max_loops)
- goto again;
- out:
-- spin_unlock(&host->lock);
-+ sdhci_spin_unlock(host);
-
- if (unexpected) {
- pr_err("%s: Unexpected interrupt 0x%08x.\n",
-@@ -2569,7 +2723,8 @@ int sdhci_resume_host(struct sdhci_host
- {
- int ret;
-
-- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
-+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA |
-+ SDHCI_USE_PLATDMA)) {
- if (host->ops->enable_dma)
- host->ops->enable_dma(host);
- }
-@@ -2636,15 +2791,15 @@ int sdhci_runtime_suspend_host(struct sd
- host->flags &= ~SDHCI_NEEDS_RETUNING;
- }
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
-
- synchronize_irq(host->irq);
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
- host->runtime_suspended = true;
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
-
- return ret;
- }
-@@ -2670,16 +2825,16 @@ int sdhci_runtime_resume_host(struct sdh
- sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
- if ((host_flags & SDHCI_PV_ENABLED) &&
- !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
- sdhci_enable_preset_value(host, true);
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- /* Set the re-tuning expiration flag */
- if (host->flags & SDHCI_USING_RETUNING_TIMER)
- host->flags |= SDHCI_NEEDS_RETUNING;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- host->runtime_suspended = false;
-
-@@ -2690,7 +2845,7 @@ int sdhci_runtime_resume_host(struct sdh
- /* Enable Card Detection */
- sdhci_enable_card_detection(host);
-
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
-
- return ret;
- }
-@@ -2785,14 +2940,16 @@ int sdhci_add_host(struct sdhci_host *ho
- host->flags &= ~SDHCI_USE_ADMA;
- }
-
-- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
-+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA |
-+ SDHCI_USE_PLATDMA)) {
- if (host->ops->enable_dma) {
- if (host->ops->enable_dma(host)) {
- pr_warning("%s: No suitable DMA "
- "available. Falling back to PIO.\n",
- mmc_hostname(mmc));
- host->flags &=
-- ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
-+ ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA |
-+ SDHCI_USE_PLATDMA);
- }
- }
- }
-@@ -3080,6 +3237,12 @@ int sdhci_add_host(struct sdhci_host *ho
- SDHCI_MAX_CURRENT_MULTIPLIER;
- }
-
-+ if(host->ops->voltage_broken) {
-+ ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
-+ // Cannot support UHS modes if we are stuck at 3.3V;
-+ mmc->caps &= ~(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50);
-+ }
-+
- mmc->ocr_avail = ocr_avail;
- mmc->ocr_avail_sdio = ocr_avail;
- if (host->ocr_avail_sdio)
-@@ -3174,7 +3337,7 @@ int sdhci_add_host(struct sdhci_host *ho
- host->tuning_timer.function = sdhci_tuning_timer;
- }
-
-- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-+ ret = request_irq(host->irq, sdhci_irq, 0,//IRQF_SHARED,
- mmc_hostname(mmc), host);
- if (ret) {
- pr_err("%s: Failed to request IRQ %d: %d\n",
-@@ -3210,6 +3373,7 @@ int sdhci_add_host(struct sdhci_host *ho
-
- pr_info("%s: SDHCI controller on %s [%s] using %s\n",
- mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
-+ (host->flags & SDHCI_USE_PLATDMA) ? "platform's DMA" :
- (host->flags & SDHCI_USE_ADMA) ? "ADMA" :
- (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
-
-@@ -3237,7 +3401,7 @@ void sdhci_remove_host(struct sdhci_host
- unsigned long flags;
-
- if (dead) {
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- host->flags |= SDHCI_DEVICE_DEAD;
-
-@@ -3249,7 +3413,7 @@ void sdhci_remove_host(struct sdhci_host
- tasklet_schedule(&host->finish_tasklet);
- }
-
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- sdhci_disable_card_detection(host);
---- a/drivers/mmc/host/sdhci.h
-+++ b/drivers/mmc/host/sdhci.h
-@@ -289,6 +289,20 @@ struct sdhci_ops {
- void (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
- void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
- int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
-+
-+ int (*pdma_able)(struct sdhci_host *host,
-+ struct mmc_data *data);
-+ void (*pdma_avail)(struct sdhci_host *host,
-+ unsigned int *ref_intmask,
-+ void(*complete)(struct sdhci_host *));
-+ void (*pdma_reset)(struct sdhci_host *host,
-+ struct mmc_data *data);
-+ unsigned int (*extra_ints)(struct sdhci_host *host);
-+ unsigned int (*spurious_crc_acmd51)(struct sdhci_host *host);
-+ unsigned int (*voltage_broken)(struct sdhci_host *host);
-+ unsigned int (*uhs_broken)(struct sdhci_host *host);
-+ unsigned int (*missing_status)(struct sdhci_host *host);
-+
- void (*hw_reset)(struct sdhci_host *host);
- void (*platform_suspend)(struct sdhci_host *host);
- void (*platform_resume)(struct sdhci_host *host);
-@@ -399,9 +413,38 @@ extern int sdhci_resume_host(struct sdhc
- extern void sdhci_enable_irq_wakeups(struct sdhci_host *host);
- #endif
-
-+static inline int /*bool*/
-+sdhci_platdma_dmaable(struct sdhci_host *host, struct mmc_data *data)
-+{
-+ if (host->ops->pdma_able)
-+ return host->ops->pdma_able(host, data);
-+ else
-+ return 1;
-+}
-+static inline void
-+sdhci_platdma_avail(struct sdhci_host *host, unsigned int *ref_intmask,
-+ void(*completion_callback)(struct sdhci_host *))
-+{
-+ if (host->ops->pdma_avail)
-+ host->ops->pdma_avail(host, ref_intmask, completion_callback);
-+}
-+
-+static inline void
-+sdhci_platdma_reset(struct sdhci_host *host, struct mmc_data *data)
-+{
-+ if (host->ops->pdma_reset)
-+ host->ops->pdma_reset(host, data);
-+}
-+
- #ifdef CONFIG_PM_RUNTIME
- extern int sdhci_runtime_suspend_host(struct sdhci_host *host);
- extern int sdhci_runtime_resume_host(struct sdhci_host *host);
- #endif
-
-+extern void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags);
-+extern void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags);
-+extern void sdhci_spin_lock(struct sdhci_host *host);
-+extern void sdhci_spin_unlock(struct sdhci_host *host);
-+
-+
- #endif /* __SDHCI_HW_H */
---- a/include/linux/mmc/host.h
-+++ b/include/linux/mmc/host.h
-@@ -281,6 +281,7 @@ struct mmc_host {
- #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
- MMC_CAP2_PACKED_WR)
- #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
-+#define MMC_CAP2_FORCE_MULTIBLOCK (1 << 31) /* Always use multiblock transfers */
-
- mmc_pm_flag_t pm_caps; /* supported pm features */
-
---- a/include/linux/mmc/sdhci.h
-+++ b/include/linux/mmc/sdhci.h
-@@ -97,6 +97,7 @@ struct sdhci_host {
- #define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3)
-
- int irq; /* Device IRQ */
-+ int second_irq; /* Additional IRQ to disable/enable in low-latency mode */
- void __iomem *ioaddr; /* Mapped address */
-
- const struct sdhci_ops *ops; /* Low level hw interface */
-@@ -128,6 +129,7 @@ struct sdhci_host {
- #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
- #define SDHCI_HS200_NEEDS_TUNING (1<<10) /* HS200 needs tuning */
- #define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */
-+#define SDHCI_USE_PLATDMA (1<<12) /* Host uses 3rd party DMA */
-
- unsigned int version; /* SDHCI spec. version */
-
-@@ -142,6 +144,7 @@ struct sdhci_host {
-
- struct mmc_request *mrq; /* Current request */
- struct mmc_command *cmd; /* Current command */
-+ int last_cmdop; /* Opcode of last cmd sent */
- struct mmc_data *data; /* Current data request */
- unsigned int data_early:1; /* Data finished before cmd */
-