Merge linux-3.10.67 into dev-kernel-3.10
[linux-3.10.git] / drivers / mmc / host / sdhci.c
index 836e2ac..7688c3c 100644 (file)
@@ -2,6 +2,7 @@
  *  linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
  *
  *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
+ *  Copyright (C) 2012-2015, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,6 +23,8 @@
 #include <linux/scatterlist.h>
 #include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
 
 #include <linux/leds.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/slot-gpio.h>
 
+#include <linux/sysedp.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/ktime.h>
+#endif
+
+#ifdef CONFIG_EMMC_BLKTRACE
+#include <linux/mmc/emmc-trace.h>
+#include "../card/queue.h"
+#endif
 #include "sdhci.h"
 
 #define DRIVER_NAME "sdhci"
 
 #define DBG(f, x...) \
-       pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
+       pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
+#define MMC_CHECK_CMDQ_MODE(host)                      \
+       (host && host->mmc &&                                   \
+       host->mmc->card &&                                              \
+       host->mmc->card->ext_csd.cmdq_mode_en)
 
 #if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \
        defined(CONFIG_MMC_SDHCI_MODULE))
 
 #define MAX_TUNING_LOOP 40
 
-static unsigned int debug_quirks = 0;
+#ifdef CONFIG_CMD_DUMP
+static volatile unsigned int printk_cpu_test = UINT_MAX;
+struct timeval cur_tv;
+struct timeval prev_tv, curr_tv;
+void mmc_cmd_dump(struct mmc_host *host);
+void dbg_add_host_log(struct mmc_host *host, int type, int cmd, int arg)
+{
+       unsigned long long t;
+       unsigned long long nanosec_rem;
+       unsigned long flags;
+       spin_lock_irqsave(&host->cmd_dump_lock, flags);
+
+       if (host->dbg_run_host_log_dat[host->dbg_host_cnt - 1].type == type &&
+               host->dbg_run_host_log_dat[host->dbg_host_cnt - 1].cmd == cmd &&
+               host->dbg_run_host_log_dat[host->dbg_host_cnt - 1].arg == arg) {
+               spin_unlock_irqrestore(&host->cmd_dump_lock, flags);
+               return;
+       }
+       t = cpu_clock(printk_cpu_test);
+       nanosec_rem = do_div(t, 1000000000)/1000;
+       do_gettimeofday(&cur_tv);
+       host->dbg_run_host_log_dat[host->dbg_host_cnt].time_sec = t;
+       host->dbg_run_host_log_dat[host->dbg_host_cnt].time_usec = nanosec_rem;
+       host->dbg_run_host_log_dat[host->dbg_host_cnt].type = type;
+       host->dbg_run_host_log_dat[host->dbg_host_cnt].cmd = cmd;
+       host->dbg_run_host_log_dat[host->dbg_host_cnt].arg = arg;
+       host->dbg_host_cnt++;
+       if (host->dbg_host_cnt >= dbg_max_cnt)
+               host->dbg_host_cnt = 0;
+       spin_unlock_irqrestore(&host->cmd_dump_lock, flags);
+}
+#endif
+
+/* MMC_RTPM timeout */
+#define MMC_RTPM_MSEC_TMOUT 10
+
+/* SDIO 1msec timeout, but use 10msec timeout for HZ=100 */
+#define SDIO_CLK_GATING_TICK_TMOUT ((HZ >= 1000) ? (HZ / 1000) : 1)
+/* 20msec EMMC delayed clock gate timeout */
+#define EMMC_CLK_GATING_TICK_TMOUT ((HZ >= 50) ? (HZ / 50) : 2)
+
+#define IS_SDIO_CARD(host) \
+               (host->mmc->card && \
+               (host->mmc->card->type == MMC_TYPE_SDIO))
+
+#define IS_EMMC_CARD(host) \
+               (host->mmc->card && \
+               (host->mmc->card->type == MMC_TYPE_MMC))
+
+#define IS_SDIO_CARD_OR_EMMC(host) \
+               (host->mmc->card && \
+               ((host->mmc->card->type == MMC_TYPE_SDIO) || \
+               (host->mmc->card->type == MMC_TYPE_MMC)))
+
+#define IS_DELAYED_CLK_GATE(host) \
+               ((host->quirks2 & SDHCI_QUIRK2_DELAYED_CLK_GATE) && \
+               (IS_SDIO_CARD_OR_EMMC(host)) && \
+               (host->mmc->caps2 & MMC_CAP2_CLOCK_GATING))
+
+#ifdef CONFIG_DEBUG_FS
+
+#define IS_32_BIT(x)   (x < (1ULL << 32))
+
+#define IS_DATA_READ(flags)    ((flags & MMC_DATA_READ) ? true : false)
+
+#define PERF_STAT_COMPARE(stat, blk_size, blk_count, is_read) \
+               ( \
+                       (stat->is_read == is_read) && \
+                       (stat->stat_blk_size == blk_size) && \
+                       (stat->stat_blks_per_transfer == blk_count) \
+               )
+
+#endif
+
+#define MIN_SDMMC_FREQ 400000
+
+static unsigned int debug_quirks;
 static unsigned int debug_quirks2;
 
 static void sdhci_finish_data(struct sdhci_host *);
@@ -52,6 +145,7 @@ static void sdhci_finish_data(struct sdhci_host *);
 static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
 static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
+static int sdhci_validate_sd2_0(struct mmc_host *mmc);
 static void sdhci_tuning_timer(unsigned long data);
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
 
@@ -67,55 +161,66 @@ static inline int sdhci_runtime_pm_put(struct sdhci_host *host)
 {
        return 0;
 }
+static inline int sdhci_runtime_resume_host(struct sdhci_host *host)
+{
+       return 0;
+}
+static inline int sdhci_runtime_suspend_host(struct sdhci_host *host)
+{
+       return 0;
+}
 #endif
 
 static void sdhci_dumpregs(struct sdhci_host *host)
 {
-       pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
+       pr_err(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
                mmc_hostname(host->mmc));
 
-       pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
+       pr_err(DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
                sdhci_readl(host, SDHCI_DMA_ADDRESS),
                sdhci_readw(host, SDHCI_HOST_VERSION));
-       pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
+       pr_err(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
                sdhci_readw(host, SDHCI_BLOCK_SIZE),
                sdhci_readw(host, SDHCI_BLOCK_COUNT));
-       pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
+       pr_err(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
                sdhci_readl(host, SDHCI_ARGUMENT),
                sdhci_readw(host, SDHCI_TRANSFER_MODE));
-       pr_debug(DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
+       pr_err(DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
                sdhci_readl(host, SDHCI_PRESENT_STATE),
                sdhci_readb(host, SDHCI_HOST_CONTROL));
-       pr_debug(DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
+       pr_err(DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
                sdhci_readb(host, SDHCI_POWER_CONTROL),
                sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
-       pr_debug(DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
+       pr_err(DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
                sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
                sdhci_readw(host, SDHCI_CLOCK_CONTROL));
-       pr_debug(DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
+       pr_err(DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
                sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
                sdhci_readl(host, SDHCI_INT_STATUS));
-       pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
+       pr_err(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
                sdhci_readl(host, SDHCI_INT_ENABLE),
                sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
-       pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
+       pr_err(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
                sdhci_readw(host, SDHCI_ACMD12_ERR),
                sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
-       pr_debug(DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n",
+       pr_err(DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n",
                sdhci_readl(host, SDHCI_CAPABILITIES),
                sdhci_readl(host, SDHCI_CAPABILITIES_1));
-       pr_debug(DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
+       pr_err(DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
                sdhci_readw(host, SDHCI_COMMAND),
                sdhci_readl(host, SDHCI_MAX_CURRENT));
-       pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
+       pr_err(DRIVER_NAME ": Host ctl2: 0x%08x\n",
                sdhci_readw(host, SDHCI_HOST_CONTROL2));
 
        if (host->flags & SDHCI_USE_ADMA)
-               pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
+               pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
                       readl(host->ioaddr + SDHCI_ADMA_ERROR),
                       readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
 
-       pr_debug(DRIVER_NAME ": ===========================================\n");
+       if (host->ops->dump_host_cust_regs)
+               host->ops->dump_host_cust_regs(host);
+
+       pr_err(DRIVER_NAME ": ===========================================\n");
 }
 
 /*****************************************************************************\
@@ -126,13 +231,10 @@ static void sdhci_dumpregs(struct sdhci_host *host)
 
 static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
 {
-       u32 ier;
-
-       ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-       ier &= ~clear;
-       ier |= set;
-       sdhci_writel(host, ier, SDHCI_INT_ENABLE);
-       sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+       host->ier &= ~clear;
+       host->ier |= set;
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
 static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs)
@@ -175,8 +277,8 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
 
 static void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
+       u32 ctrl;
        unsigned long timeout;
-       u32 uninitialized_var(ier);
 
        if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
                if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
@@ -184,9 +286,6 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
                        return;
        }
 
-       if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-               ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-
        if (host->ops->platform_reset_enter)
                host->ops->platform_reset_enter(host, mask);
 
@@ -214,12 +313,24 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
                host->ops->platform_reset_exit(host, mask);
 
        if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-               sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
+               sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, host->ier);
 
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
                if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
                        host->ops->enable_dma(host);
        }
+
+       /*
+        * VERSION_4_EN bit and 64BIT_EN bit are cleared after a full reset
+        * need to re-configure them after each full reset
+        */
+       if ((mask & SDHCI_RESET_ALL) && host->version >= SDHCI_SPEC_400) {
+               ctrl = sdhci_readl(host, SDHCI_ACMD12_ERR);
+               ctrl |= SDHCI_HOST_VERSION_4_EN;
+               if (host->quirks2 & SDHCI_QUIRK2_SUPPORT_64BIT_DMA)
+                       ctrl |= SDHCI_ADDRESSING_64BIT_EN;
+               sdhci_writel(host, ctrl, SDHCI_ACMD12_ERR);
+       }
 }
 
 static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
@@ -405,9 +516,6 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
 
        BUG_ON(!host->data);
 
-       if (host->blocks == 0)
-               return;
-
        if (host->data->flags & MMC_DATA_READ)
                mask = SDHCI_DATA_AVAILABLE;
        else
@@ -422,7 +530,13 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
                (host->data->blocks == 1))
                mask = ~0;
 
-       while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
+       /*
+        * Start the transfer if the present state register indicates
+        * SDHCI_DATA_AVAILABLE or SDHCI_SPACE_AVAILABLE. The driver should
+        * transfer one complete block of data and wait for the buffer ready
+        * interrupt to transfer the next block of data.
+        */
+       if (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
                if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY)
                        udelay(100);
 
@@ -430,10 +544,6 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
                        sdhci_read_block_pio(host);
                else
                        sdhci_write_block_pio(host);
-
-               host->blocks--;
-               if (host->blocks == 0)
-                       break;
        }
 
        DBG("PIO transfer complete.\n");
@@ -451,10 +561,13 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
        local_irq_restore(*flags);
 }
 
-static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd)
+static void sdhci_set_adma_desc(struct sdhci_host *host, u8 *desc,
+                               dma_addr_t addr, int len, unsigned cmd)
 {
        __le32 *dataddr = (__le32 __force *)(desc + 4);
+       __le64 *dataddr64 = (__le64 __force *)(desc + 4);
        __le16 *cmdlen = (__le16 __force *)desc;
+       u32 ctrl;
 
        /* SDHCI specification says ADMA descriptors should be 4 byte
         * aligned, so using 16 or 32bit operations should be safe. */
@@ -462,7 +575,11 @@ static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd)
        cmdlen[0] = cpu_to_le16(cmd);
        cmdlen[1] = cpu_to_le16(len);
 
-       dataddr[0] = cpu_to_le32(addr);
+       ctrl = sdhci_readl(host, SDHCI_ACMD12_ERR);
+       if (ctrl & SDHCI_ADDRESSING_64BIT_EN)
+               dataddr64[0] = cpu_to_le64(addr);
+       else
+               dataddr[0] = cpu_to_le32(addr);
 }
 
 static int sdhci_adma_table_pre(struct sdhci_host *host,
@@ -480,6 +597,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
        int i;
        char *buffer;
        unsigned long flags;
+       int next_desc;
+       u32 ctrl;
 
        /*
         * The spec does not specify endianness of descriptor table.
@@ -496,11 +615,13 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
         * need to fill it with data first.
         */
 
-       host->align_addr = dma_map_single(mmc_dev(host->mmc),
-               host->align_buffer, 128 * 4, direction);
-       if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
-               goto fail;
-       BUG_ON(host->align_addr & 0x3);
+       if (!host->use_dma_alloc) {
+               host->align_addr = dma_map_single(mmc_dev(host->mmc),
+                       host->align_buffer, 128 * 8, direction);
+               if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
+                       goto fail;
+               BUG_ON(host->align_addr & 0x3);
+       }
 
        host->sg_count = dma_map_sg(mmc_dev(host->mmc),
                data->sg, data->sg_len, direction);
@@ -512,6 +633,17 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 
        align_addr = host->align_addr;
 
+       ctrl = sdhci_readl(host, SDHCI_ACMD12_ERR);
+       if (ctrl & SDHCI_ADDRESSING_64BIT_EN) {
+               if (ctrl & SDHCI_HOST_VERSION_4_EN)
+                       next_desc = 16;
+               else
+                       next_desc = 12;
+       } else {
+               /* 32 bit DMA mode supported */
+               next_desc = 8;
+       }
+
        for_each_sg(data->sg, sg, host->sg_count, i) {
                addr = sg_dma_address(sg);
                len = sg_dma_len(sg);
@@ -533,14 +665,15 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                        }
 
                        /* tran, valid */
-                       sdhci_set_adma_desc(desc, align_addr, offset, 0x21);
+                       sdhci_set_adma_desc(host, desc, align_addr, offset,
+                                               0x21);
 
                        BUG_ON(offset > 65536);
 
                        align += 4;
                        align_addr += 4;
 
-                       desc += 8;
+                       desc += next_desc;
 
                        addr += offset;
                        len -= offset;
@@ -549,14 +682,16 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                BUG_ON(len > 65536);
 
                /* tran, valid */
-               sdhci_set_adma_desc(desc, addr, len, 0x21);
-               desc += 8;
+               if (len > 0) {
+                       sdhci_set_adma_desc(host, desc, addr, len, 0x21);
+                       desc += next_desc;
+               }
 
                /*
                 * If this triggers then we have a calculation bug
                 * somewhere. :/
                 */
-               WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
+               WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 8);
        }
 
        if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
@@ -564,8 +699,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                * Mark the last descriptor as the terminating descriptor
                */
                if (desc != host->adma_desc) {
-                       desc -= 8;
-                       desc[0] |= 0x2; /* end */
+                       desc -= next_desc;
+                       desc[0] |= 0x3; /* end and valid*/
                }
        } else {
                /*
@@ -573,7 +708,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                */
 
                /* nop, end, valid */
-               sdhci_set_adma_desc(desc, 0, 0, 0x3);
+               sdhci_set_adma_desc(host, desc, 0, 0, 0x3);
        }
 
        /*
@@ -581,14 +716,16 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
         */
        if (data->flags & MMC_DATA_WRITE) {
                dma_sync_single_for_device(mmc_dev(host->mmc),
-                       host->align_addr, 128 * 4, direction);
+                       host->align_addr, 128 * 8, direction);
        }
 
-       host->adma_addr = dma_map_single(mmc_dev(host->mmc),
-               host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
-       if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
-               goto unmap_entries;
-       BUG_ON(host->adma_addr & 0x3);
+       if (!host->use_dma_alloc) {
+               host->adma_addr = dma_map_single(mmc_dev(host->mmc),
+                       host->adma_desc, (128 * 2 + 1) * 8, DMA_TO_DEVICE);
+               if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
+                       goto unmap_entries;
+               BUG_ON(host->adma_addr & 0x3);
+       }
 
        return 0;
 
@@ -596,8 +733,9 @@ unmap_entries:
        dma_unmap_sg(mmc_dev(host->mmc), data->sg,
                data->sg_len, direction);
 unmap_align:
-       dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
-               128 * 4, direction);
+       if (!host->use_dma_alloc)
+               dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
+                               128 * 8, direction);
 fail:
        return -EINVAL;
 }
@@ -618,11 +756,13 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
        else
                direction = DMA_TO_DEVICE;
 
-       dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
-               (128 * 2 + 1) * 4, DMA_TO_DEVICE);
+       if (!host->use_dma_alloc) {
+               dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
+                       (128 * 2 + 1) * 8, DMA_TO_DEVICE);
 
-       dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
-               128 * 4, direction);
+               dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
+                       128 * 8, direction);
+       }
 
        if (data->flags & MMC_DATA_READ) {
                dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
@@ -715,6 +855,22 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
                sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
 }
 
+static void sdhci_determine_transfer_mode(struct sdhci_host *host,
+       unsigned int req_size, unsigned int req_blocks)
+{
+       /* Nothing to do if DMA modes are not supported. */
+       if (!(host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))) {
+               host->flags &= ~SDHCI_REQ_USE_DMA;
+       } else if (!host->max_pio_size || (req_size > host->max_pio_size)) {
+               host->flags |= SDHCI_REQ_USE_DMA;
+       } else if (req_size < host->max_pio_size) {
+               host->flags &= ~SDHCI_REQ_USE_DMA;
+               if (host->max_pio_blocks &&
+                       (req_blocks > host->max_pio_blocks))
+                       host->flags |= SDHCI_REQ_USE_DMA;
+       }
+}
+
 static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
 {
        u8 count;
@@ -722,7 +878,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
        struct mmc_data *data = cmd->data;
        int ret;
 
-       WARN_ON(host->data);
+       if (!MMC_CHECK_CMDQ_MODE(host))
+               WARN_ON(host->data);
 
        if (data || (cmd->flags & MMC_RSP_BUSY)) {
                count = sdhci_calc_timeout(host, cmd);
@@ -741,8 +898,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
        host->data_early = 0;
        host->data->bytes_xfered = 0;
 
-       if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
-               host->flags |= SDHCI_REQ_USE_DMA;
+       /* Select dma or PIO mode for transfer */
+       sdhci_determine_transfer_mode(host, data->blksz * data->blocks,
+               data->blocks);
 
        /*
         * FIXME: This doesn't account for merging when mapping the
@@ -819,8 +977,25 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
                                WARN_ON(1);
                                host->flags &= ~SDHCI_REQ_USE_DMA;
                        } else {
-                               sdhci_writel(host, host->adma_addr,
+                               sdhci_writel(host,
+                                       (host->adma_addr & 0xFFFFFFFF),
                                        SDHCI_ADMA_ADDRESS);
+
+                               if ((host->version >= SDHCI_SPEC_400) &&
+                                   (host->quirks2 &
+                                    SDHCI_QUIRK2_SUPPORT_64BIT_DMA)) {
+                                       if (host->quirks2 &
+                                           SDHCI_QUIRK2_USE_64BIT_ADDR) {
+
+                                               sdhci_writel(host,
+                                               (host->adma_addr >> 32)
+                                                       & 0xFFFFFFFF,
+                                               SDHCI_UPPER_ADMA_ADDRESS);
+                                       } else {
+                                               sdhci_writel(host, 0,
+                                               SDHCI_UPPER_ADMA_ADDRESS);
+                                       }
+                               }
                        }
                } else {
                        int sg_cnt;
@@ -855,7 +1030,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
                ctrl &= ~SDHCI_CTRL_DMA_MASK;
                if ((host->flags & SDHCI_REQ_USE_DMA) &&
                        (host->flags & SDHCI_USE_ADMA))
-                       ctrl |= SDHCI_CTRL_ADMA32;
+                       ctrl |= SDHCI_CTRL_ADMA2;
                else
                        ctrl |= SDHCI_CTRL_SDMA;
                sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
@@ -899,11 +1074,18 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
                 * If we are sending CMD23, CMD12 never gets sent
                 * on successful completion (so no Auto-CMD12).
                 */
-               if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
-                       mode |= SDHCI_TRNS_AUTO_CMD12;
-               else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
-                       mode |= SDHCI_TRNS_AUTO_CMD23;
-                       sdhci_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2);
+               if (!MMC_CHECK_CMDQ_MODE(host)) {
+                       if (!host->mrq_cmd->sbc &&
+                               (host->flags & SDHCI_AUTO_CMD12) &&
+                               mmc_op_multi(cmd->opcode))
+                                       mode |= SDHCI_TRNS_AUTO_CMD12;
+                       else if (host->mrq_cmd->sbc &&
+                               (host->flags & SDHCI_AUTO_CMD23)) {
+                                       mode |= SDHCI_TRNS_AUTO_CMD23;
+                                       sdhci_writel(host,
+                                               host->mrq_cmd->sbc->arg,
+                                               SDHCI_ARGUMENT2);
+                       }
                }
        }
 
@@ -915,11 +1097,253 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
        sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
 }
 
+#ifdef CONFIG_DEBUG_FS
+static void get_kbps_from_size_n_usec_32bit(
+               u32 size_in_bits_x1000, u32 time_usecs,
+               u32 *speed_in_kbps)
+{
+       *speed_in_kbps = DIV_ROUND_CLOSEST(size_in_bits_x1000, time_usecs);
+}
+
+static void get_kbps_from_size_n_usec_64bit(
+               u64 size_in_bits_x1000, u64 time_usecs,
+               u32 *speed_in_kbps)
+{
+       int i;
+
+       /* convert 64 bit into 32 bits */
+       i = 0;
+       while (!(IS_32_BIT(size_in_bits_x1000) && IS_32_BIT(time_usecs))) {
+               /* shift right both the operands bytes and time */
+               size_in_bits_x1000 >>= 1;
+               time_usecs >>= 1;
+               i++;
+       }
+       if (i)
+               pr_debug("%s right shifted operands by %d, size=%lld, time=%lld usec\n",
+                       __func__, i, size_in_bits_x1000, time_usecs);
+       /* check for 32 bit operations first */
+       get_kbps_from_size_n_usec_32bit(
+               (u32)size_in_bits_x1000, (u32)time_usecs,
+               speed_in_kbps);
+       return;
+}
+
+static void free_stats_nodes(struct sdhci_host *host)
+{
+       struct data_stat_entry *ptr, *ptr2;
+
+       ptr = host->sdhci_data_stat.head;
+       while (ptr) {
+               ptr2 = ptr->next;
+               host->sdhci_data_stat.stat_size--;
+               devm_kfree(host->mmc->parent, ptr);
+               ptr = ptr2;
+       }
+       if (host->sdhci_data_stat.stat_size)
+               pr_err("stat_size=%d after free %s\n",
+                       host->sdhci_data_stat.stat_size,
+                       __func__);
+       host->sdhci_data_stat.head = NULL;
+}
+
+static struct data_stat_entry *add_entry_sorted(struct sdhci_host *host,
+       unsigned int blk_size, unsigned int blk_count,
+       unsigned int data_flags)
+{
+       struct data_stat_entry *node, *ptr;
+       bool is_read;
+
+       if (!blk_count) {
+               pr_err("%s %s: call blk_size=%d, blk_count=%d, data_flags=0x%x\n",
+                       mmc_hostname(host->mmc), __func__,
+                       blk_size, blk_count, data_flags);
+               goto end;
+       }
+
+       node = devm_kzalloc(host->mmc->parent, sizeof(struct data_stat_entry),
+               GFP_KERNEL);
+       if (!node) {
+               pr_err("%s, %s, line=%d %s: unable to allocate data_stat_entry\n",
+                       __FILE__, __func__, __LINE__, mmc_hostname(host->mmc));
+               goto end;
+       }
+       node->stat_blk_size = blk_size;
+       node->stat_blks_per_transfer = blk_count;
+       is_read = IS_DATA_READ(data_flags);
+       node->is_read = is_read;
+       host->sdhci_data_stat.stat_size++;
+       /* assume existing list is sorted and try to insert this new node
+        * into the increasing order sorted array
+        */
+       ptr = host->sdhci_data_stat.head;
+       if (!ptr) {
+               /* first element */
+               host->sdhci_data_stat.head = node;
+               return node;
+       }
+       if (ptr && ((ptr->stat_blk_size > blk_size) ||
+               ((ptr->stat_blk_size == blk_size) &&
+               (ptr->stat_blks_per_transfer > blk_count)))) {
+               host->sdhci_data_stat.head = node;
+               /* update new head */
+               node->next = ptr;
+               return node;
+       }
+       while (ptr->next) {
+               if ((ptr->next->stat_blk_size < blk_size) ||
+                       ((ptr->next->stat_blk_size == blk_size) &&
+                       (ptr->next->stat_blks_per_transfer < blk_count)))
+                       ptr = ptr->next;
+               else
+                       break;
+       }
+       /* We are here if -
+        * 1. ptr->next is null or
+        * 2. blk_size of ptr->next is greater than new blk size, so we should
+        *    place the new node between ptr and ptr->next
+        */
+       if (!ptr->next) {
+               ptr->next = node;
+               return node;
+       }
+       if ((ptr->next->stat_blk_size > blk_size) ||
+               ((ptr->next->stat_blk_size == blk_size) &&
+               (ptr->next->stat_blks_per_transfer > blk_count)) ||
+               ((ptr->next->stat_blk_size == blk_size) &&
+               (ptr->next->stat_blks_per_transfer == blk_count) &&
+               (ptr->next->is_read != is_read))) {
+               node->next = ptr->next;
+               ptr->next = node;
+               return node;
+       }
+       pr_err("%s %s: line=%d should be unreachable ptr-next->blk_size=%d, blks_per_xfer=%d, is_read=%d, new blk_size=%d, blks_per_xfer=%d, data_flags=0x%x\n",
+               mmc_hostname(host->mmc), __func__, __LINE__,
+               ptr->next->stat_blk_size, ptr->next->stat_blks_per_transfer,
+               ptr->next->is_read, blk_size, blk_count, data_flags);
+end:
+       return NULL;
+}
+
+static void free_data_entry(struct sdhci_host *host,
+                               unsigned int blk_size, unsigned int blk_count,
+                               unsigned int data_flags)
+{
+       struct data_stat_entry *ptr, *ptr2;
+       bool is_read;
+
+       ptr = host->sdhci_data_stat.head;
+       if (!ptr)
+               return;
+       is_read = IS_DATA_READ(data_flags);
+       if (PERF_STAT_COMPARE(ptr, blk_size, blk_count, is_read)) {
+               host->sdhci_data_stat.head = ptr->next;
+               devm_kfree(host->mmc->parent, ptr);
+               host->sdhci_data_stat.stat_size--;
+               return;
+       }
+       while (ptr->next) {
+               if (PERF_STAT_COMPARE(ptr->next, blk_size, blk_count,
+                       is_read)) {
+                       ptr2 = ptr->next->next;
+                       devm_kfree(host->mmc->parent, ptr->next);
+                       host->sdhci_data_stat.stat_size--;
+                       ptr->next = ptr2;
+                       return;
+               }
+               ptr = ptr->next;
+       }
+       pr_err("Error %s %s: given blk_size=%d not found\n",
+               mmc_hostname(host->mmc), __func__, blk_size);
+       return;
+}
+
+static void update_stat(struct sdhci_host *host, u32 blk_size, u32 blk_count,
+                       bool is_start_stat, bool is_data_error,
+                       unsigned int data_flags)
+{
+       u32 new_kbps;
+       struct data_stat_entry *stat;
+       ktime_t t;
+       bool is_read;
+
+       if (!host->enable_sdhci_perf_stats)
+               goto end;
+
+       if (!blk_count) {
+               pr_err("%s %s error stats case: blk_size=%d, blk_count=0, is_start_stat=%d, is_data_error=%d, data_flags=0x%x\n",
+                       mmc_hostname(host->mmc), __func__, blk_size,
+                       (int)is_start_stat, (int)is_data_error, data_flags);
+               goto end;
+       }
+       stat = host->sdhci_data_stat.head;
+       is_read = IS_DATA_READ(data_flags);
+       while (stat) {
+               if (PERF_STAT_COMPARE(stat, blk_size, blk_count, is_read))
+                       break;
+               stat = stat->next;
+       }
+       /* allocation skipped in finish call */
+       if (!stat) {
+               if (!is_start_stat)
+                       goto end;
+               /* allocate an entry */
+               stat = add_entry_sorted(host, blk_size, blk_count, data_flags);
+               if (!stat) {
+                       pr_err("%s %s line=%d: stat entry not found\n",
+                               mmc_hostname(host->mmc), __func__, __LINE__);
+                       goto end;
+               }
+       }
+
+       if (is_start_stat) {
+               stat->start_ktime = ktime_get();
+       } else {
+               if (is_data_error) {
+                       pr_err("%s %s error stats case: blk_size=%d, blk_count=0, is_start_stat=%d, data Error case ... data_flags=0x%x\n",
+                               mmc_hostname(host->mmc), __func__, blk_size,
+                               (int)is_start_stat, data_flags);
+                       memset(&stat->start_ktime, 0, sizeof(ktime_t));
+                       if (!stat->total_bytes)
+                               free_data_entry(host, blk_size, blk_count,
+                                       data_flags);
+                       goto end;
+               }
+               t = ktime_get();
+               stat->duration_usecs = ktime_us_delta(t, stat->start_ktime);
+               stat->current_transferred_bytes = (blk_size * blk_count);
+               get_kbps_from_size_n_usec_32bit(
+                       (((u32)stat->current_transferred_bytes << 3) * 1000),
+                       stat->duration_usecs,
+                       &new_kbps);
+               if (stat->max_kbps == 0) {
+                       stat->max_kbps = new_kbps;
+                       stat->min_kbps = new_kbps;
+               } else {
+                       if (new_kbps > stat->max_kbps)
+                               stat->max_kbps = new_kbps;
+                       if (new_kbps < stat->min_kbps)
+                               stat->min_kbps = new_kbps;
+               }
+               /* update the total bytes figure for this entry */
+               stat->total_usecs += stat->duration_usecs;
+               stat->total_bytes += stat->current_transferred_bytes;
+               stat->total_transfers++;
+       }
+end:
+       return;
+}
+#endif
+
 static void sdhci_finish_data(struct sdhci_host *host)
 {
        struct mmc_data *data;
 
        BUG_ON(!host->data);
+#ifdef CONFIG_CMD_DUMP
+       if (IS_EMMC_CARD(host))
+               dbg_add_host_log(host->mmc, 9, 9, (int)host->mrq_dat);
+#endif
 
        data = host->data;
        host->data = NULL;
@@ -953,20 +1377,36 @@ static void sdhci_finish_data(struct sdhci_host *host)
         */
        if (data->stop &&
            (data->error ||
-            !host->mrq->sbc)) {
+            (!MMC_CHECK_CMDQ_MODE(host) && !host->mrq_dat->sbc))) {
 
                /*
                 * The controller needs a reset of internal state machines
                 * upon error conditions.
                 */
                if (data->error) {
-                       sdhci_reset(host, SDHCI_RESET_CMD);
-                       sdhci_reset(host, SDHCI_RESET_DATA);
+                       if (!MMC_CHECK_CMDQ_MODE(host))
+                               sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+                       else
+                               sdhci_reset(host, SDHCI_RESET_DATA);
                }
-
                sdhci_send_command(host, data->stop);
-       } else
-               tasklet_schedule(&host->finish_tasklet);
+       } else {
+               if (MMC_CHECK_CMDQ_MODE(host))
+                       tasklet_schedule(&host->finish_dat_tasklet);
+               else
+                       tasklet_schedule(&host->finish_tasklet);
+       }
+#ifdef CONFIG_DEBUG_FS
+       if (data->bytes_xfered) {
+               update_stat(host, data->blksz, data->blocks, false, false,
+                       data->flags);
+       } else {
+               host->no_data_transfer_count++;
+               /* performance stats does not include cases of data error */
+               update_stat(host, data->blksz, data->blocks, false, true,
+                       data->flags);
+       }
+#endif
 }
 
 static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
@@ -980,13 +1420,16 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        /* Wait max 10 ms */
        timeout = 10;
 
+       if (!host->mrq_cmd && host->mrq_dat)
+               host->mrq_cmd = host->mrq_dat;
+
        mask = SDHCI_CMD_INHIBIT;
        if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
                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))
+       if (host->mrq_cmd->data && (cmd == host->mrq_cmd->data->stop))
                mask &= ~SDHCI_DATA_INHIBIT;
 
        while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
@@ -995,14 +1438,24 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                                "inhibit bit(s).\n", mmc_hostname(host->mmc));
                        sdhci_dumpregs(host);
                        cmd->error = -EIO;
-                       tasklet_schedule(&host->finish_tasklet);
+                       if (MMC_CHECK_CMDQ_MODE(host))
+                               tasklet_schedule(&host->finish_cmd_tasklet);
+                       else
+                               tasklet_schedule(&host->finish_tasklet);
                        return;
                }
                timeout--;
                mdelay(1);
        }
 
-       mod_timer(&host->timer, jiffies + 10 * HZ);
+       if ((cmd->opcode == MMC_SWITCH) &&
+               (((cmd->arg >> 16) & EXT_CSD_SANITIZE_START)
+               == EXT_CSD_SANITIZE_START))
+               timeout = 100;
+       else
+               timeout = 10;
+
+       mod_timer(&host->timer, jiffies + timeout * HZ);
 
        host->cmd = cmd;
 
@@ -1016,7 +1469,10 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                pr_err("%s: Unsupported response type!\n",
                        mmc_hostname(host->mmc));
                cmd->error = -EINVAL;
-               tasklet_schedule(&host->finish_tasklet);
+               if (MMC_CHECK_CMDQ_MODE(host))
+                       tasklet_schedule(&host->finish_cmd_tasklet);
+               else
+                       tasklet_schedule(&host->finish_tasklet);
                return;
        }
 
@@ -1034,12 +1490,37 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        if (cmd->flags & MMC_RSP_OPCODE)
                flags |= SDHCI_CMD_INDEX;
 
-       /* CMD19 is special in that the Data Present Select should be set */
+       /* CMD19, CMD21 is special in that the Data Present Select should be set */
        if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
            cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
                flags |= SDHCI_CMD_DATA;
 
-       sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
+#ifdef CONFIG_CMD_DUMP
+       if (MMC_CHECK_CMDQ_MODE(host))
+               dbg_add_host_log(host->mmc, 0, cmd->opcode, cmd->arg);
+#endif
+#ifdef CONFIG_EMMC_BLKTRACE
+       if (!MMC_CHECK_CMDQ_MODE(host)) {
+               if (cmd->opcode == MMC_SET_BLOCK_COUNT)
+                       emmc_trace(MMC_ISSUE, host->mmc->mqrq_cur, host->mmc);
+               else if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+                               cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
+                       emmc_trace(MMC_ISSUE_DONE,
+                               host->mmc->mqrq_cur, host->mmc);
+       } else {
+               if (cmd->opcode == MMC_QUEUED_TASK_ADDRESS)
+                       emmc_trace(MMC_ISSUE,
+                               &host->mmc->mq->mqrq[cmd->mrq->areq->mrq->cmd->arg >> 16],
+                               host->mmc);
+               else if (cmd->opcode == MMC_EXECUTE_READ_TASK ||
+                               cmd->opcode == MMC_EXECUTE_WRITE_TASK)
+                       emmc_trace(MMC_ISSUE_DONE,
+                               &host->mmc->mq->mqrq[cmd->arg >> 16],
+                               host->mmc);
+       }
+#endif
+       host->command = SDHCI_MAKE_CMD(cmd->opcode, flags);
+       sdhci_writew(host, host->command, SDHCI_COMMAND);
 }
 
 static void sdhci_finish_command(struct sdhci_host *host)
@@ -1047,11 +1528,15 @@ static void sdhci_finish_command(struct sdhci_host *host)
        int i;
 
        BUG_ON(host->cmd == NULL);
+#ifdef CONFIG_CMD_DUMP
+       if (IS_EMMC_CARD(host))
+               dbg_add_host_log(host->mmc, 8, 8, (int)host->mrq_cmd);
+#endif
 
        if (host->cmd->flags & MMC_RSP_PRESENT) {
                if (host->cmd->flags & MMC_RSP_136) {
                        /* CRC is stripped so we need to do some shifting. */
-                       for (i = 0;i < 4;i++) {
+                       for (i = 0; i < 4; i++) {
                                host->cmd->resp[i] = sdhci_readl(host,
                                        SDHCI_RESPONSE + (3-i)*4) << 8;
                                if (i != 3)
@@ -1066,20 +1551,44 @@ static void sdhci_finish_command(struct sdhci_host *host)
 
        host->cmd->error = 0;
 
+#ifdef CONFIG_CMD_DUMP
+       if (MMC_CHECK_CMDQ_MODE(host))
+               dbg_add_host_log(host->mmc, 0,
+                       host->cmd->opcode, host->cmd->resp[0]);
+#endif
        /* Finished CMD23, now send actual command. */
-       if (host->cmd == host->mrq->sbc) {
+       if (host->cmd == host->mrq_cmd->sbc) {
                host->cmd = NULL;
-               sdhci_send_command(host, host->mrq->cmd);
+               sdhci_send_command(host, host->mrq_cmd->cmd);
        } else {
 
                /* Processed actual command. */
-               if (host->data && host->data_early)
+               if (host->cmd->data && host->data_early) {
+                       host->cmd = NULL;
+                       host->mrq_dat = host->mrq_cmd;
+                       host->mrq_cmd = NULL;
                        sdhci_finish_data(host);
+               }
 
-               if (!host->cmd->data)
-                       tasklet_schedule(&host->finish_tasklet);
+               if (!MMC_CHECK_CMDQ_MODE(host)) {
+                       if (!host->cmd->data)
 
-               host->cmd = NULL;
+                               tasklet_schedule(&host->finish_tasklet);
+                       else {
+                               host->mrq_dat = host->mrq_cmd;
+                               host->mrq_cmd = NULL;
+                       }
+
+                       host->cmd = NULL;
+               } else if (!host->data_early) {
+                       if (!host->mrq_cmd->cmd->error &&
+                       !host->cmd->error && host->cmd->data) {
+                               host->cmd = NULL;
+                               host->mrq_dat = host->mrq_cmd;
+                               host->mrq_cmd = NULL;
+                       }
+                       tasklet_schedule(&host->finish_cmd_tasklet);
+               }
        }
 }
 
@@ -1120,18 +1629,26 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
        int real_div = div, clk_mul = 1;
        u16 clk = 0;
        unsigned long timeout;
+       u32 caps;
 
        if (clock && clock == host->clock)
                return;
 
        host->mmc->actual_clock = 0;
 
-       if (host->ops->set_clock) {
-               host->ops->set_clock(host, clock);
-               if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
-                       return;
-       }
+       if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
+               return;
 
+       /*
+        * If the entire clock control register is updated with zero, some
+        * controllers might first update clock divisor fields and then update
+        * the INT_CLK_EN and CARD_CLK_EN fields. Disable card clock first
+        * to ensure there is no abnormal clock behavior.
+        */
+       clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+       clk &= ~SDHCI_CLOCK_CARD_EN;
+       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+       clk = 0;
        sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
        if (clock == 0)
@@ -1177,9 +1694,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                        div--;
                } else {
                        /* Version 3.00 divisors must be a multiple of 2. */
-                       if (host->max_clk <= clock)
-                               div = 1;
-                       else {
+                       if (host->max_clk <= clock) {
+                               if (host->mmc->ios.timing ==
+                                       MMC_TIMING_UHS_DDR50)
+                                       div = 2;
+                               else
+                                       div = 1;
+                       } else {
                                for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
                                     div += 2) {
                                        if ((host->max_clk / div) <= clock)
@@ -1209,6 +1730,20 @@ clock_set:
        clk |= SDHCI_CLOCK_INT_EN;
        sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
+       /*
+        * For Tegra3 sdmmc controller, internal clock will not be stable bit
+        * will get set only after some other register write is done. To
+        * handle, do a dummy reg write to the caps reg if
+        * SDHCI_QUIRK2_INT_CLK_STABLE_REQ_DUMMY_REG_WRITE is set.
+        */
+       if (host->quirks2 & SDHCI_QUIRK2_INT_CLK_STABLE_REQ_DUMMY_REG_WRITE) {
+               udelay(5);
+
+               caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+               caps |= 1;
+               sdhci_writel(host, caps, SDHCI_CAPABILITIES);
+       }
+
        /* Wait max 20 ms */
        timeout = 20;
        while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
@@ -1236,6 +1771,8 @@ static inline void sdhci_update_clock(struct sdhci_host *host)
 
        clock = host->clock;
        host->clock = 0;
+       if (host->ops->set_clock)
+               host->ops->set_clock(host, clock);
        sdhci_set_clock(host, clock);
 }
 
@@ -1299,6 +1836,32 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
        return power;
 }
 
+static void sdhci_en_strobe(struct mmc_host *mmc)
+{
+       struct sdhci_host *host;
+
+       host = mmc_priv(mmc);
+
+       sdhci_runtime_pm_get(host);
+       if (host->ops->en_strobe)
+               host->ops->en_strobe(host);
+       sdhci_runtime_pm_put(host);
+}
+/* Execute DLL calibration once for MMC device if it is
+ * enumerated in HS400 mode at 200MHz clock freq before
+ * starting any data transfer.
+ */
+static void sdhci_post_init(struct mmc_host *mmc)
+{
+       struct sdhci_host *host;
+
+       host = mmc_priv(mmc);
+
+       sdhci_runtime_pm_get(host);
+       if (host->ops->post_init)
+               host->ops->post_init(host);
+       sdhci_runtime_pm_put(host);
+}
 /*****************************************************************************\
  *                                                                           *
  * MMC callbacks                                                             *
@@ -1314,13 +1877,19 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        host = mmc_priv(mmc);
 
+#ifdef CONFIG_DEBUG_FS
+       if (mrq->data && mrq->data->blocks)
+               update_stat(host, mrq->data->blksz, mrq->data->blocks,
+                       true, false, mrq->data->flags);
+#endif
+
        sdhci_runtime_pm_get(host);
 
        present = mmc_gpio_get_cd(host->mmc);
 
        spin_lock_irqsave(&host->lock, flags);
 
-       WARN_ON(host->mrq != NULL);
+       WARN_ON(host->mrq_cmd != NULL);
 
 #ifndef SDHCI_USE_LEDS_CLASS
        sdhci_activate_led(host);
@@ -1330,14 +1899,15 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
         * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
         * requests if Auto-CMD12 is enabled.
         */
-       if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
+       if (!MMC_CHECK_CMDQ_MODE(host) && !mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
                if (mrq->stop) {
                        mrq->data->stop = NULL;
                        mrq->stop = NULL;
                }
        }
 
-       host->mrq = mrq;
+       host->mrq_cmd = mrq;
+       host->mrq_cmd->data_early = 0;
 
        /*
         * Firstly check card presence from cd-gpio.  The return could
@@ -1349,15 +1919,21 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        if (present < 0) {
                /* If polling, assume that the card is always present. */
                if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
-                       present = 1;
+                       if (host->ops->get_cd)
+                               present = host->ops->get_cd(host);
+                       else
+                               present = 1;
                else
                        present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
                                        SDHCI_CARD_PRESENT;
        }
 
        if (!present || host->flags & SDHCI_DEVICE_DEAD) {
-               host->mrq->cmd->error = -ENOMEDIUM;
-               tasklet_schedule(&host->finish_tasklet);
+               host->mrq_cmd->cmd->error = -ENOMEDIUM;
+               if (MMC_CHECK_CMDQ_MODE(host))
+                       tasklet_schedule(&host->finish_cmd_tasklet);
+               else
+                       tasklet_schedule(&host->finish_tasklet);
        } else {
                u32 present_state;
 
@@ -1369,25 +1945,45 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
                 */
                if ((host->flags & SDHCI_NEEDS_RETUNING) &&
                    !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
+                       if (!mmc->need_tuning || !mmc->ready_tuning) {
+                               if (!mmc->need_tuning)
+                                       mmc->need_tuning = 1;
+                               goto end_tuning;
+                       }
+
                        if (mmc->card) {
                                /* eMMC uses cmd21 but sd and sdio use cmd19 */
                                tuning_opcode =
                                        mmc->card->type == MMC_TYPE_MMC ?
                                        MMC_SEND_TUNING_BLOCK_HS200 :
                                        MMC_SEND_TUNING_BLOCK;
+                               host->mrq_cmd = NULL;
                                spin_unlock_irqrestore(&host->lock, flags);
                                sdhci_execute_tuning(mmc, tuning_opcode);
+                               mmc->need_tuning = 0;
+                               mmc->ready_tuning = 0;
                                spin_lock_irqsave(&host->lock, flags);
 
+end_tuning:
                                /* Restore original mmc_request structure */
-                               host->mrq = mrq;
+                               host->mrq_cmd = mrq;
                        }
                }
 
-               if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
+               /* For a data cmd, check for plat specific preparation */
+               spin_unlock_irqrestore(&host->lock, flags);
+               if (mrq->data)
+                       host->ops->platform_get_bus(host);
+               spin_lock_irqsave(&host->lock, flags);
+
+               if (!MMC_CHECK_CMDQ_MODE(host) &&
+                       (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)))
+                               sdhci_send_command(host, mrq->sbc);
+               else if (MMC_CHECK_CMDQ_MODE(host) && mrq->sbc)
                        sdhci_send_command(host, mrq->sbc);
-               else
+               else {
                        sdhci_send_command(host, mrq->cmd);
+               }
        }
 
        mmiowb();
@@ -1400,6 +1996,14 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
        int vdd_bit = -1;
        u8 ctrl;
 
+       /* cancel delayed clk gate work */
+       if (host->quirks2 & SDHCI_QUIRK2_DELAYED_CLK_GATE)
+               cancel_delayed_work_sync(&host->delayed_clk_gate_wrk);
+
+       /* Do any required preparations prior to setting ios */
+       if (host->ops->platform_ios_config_enter)
+               host->ops->platform_ios_config_enter(host, ios);
+
        spin_lock_irqsave(&host->lock, flags);
 
        if (host->flags & SDHCI_DEVICE_DEAD) {
@@ -1422,8 +2026,6 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                (ios->power_mode == MMC_POWER_UP))
                sdhci_enable_preset_value(host, false);
 
-       sdhci_set_clock(host, ios->clock);
-
        if (ios->power_mode == MMC_POWER_OFF)
                vdd_bit = sdhci_set_power(host, -1);
        else
@@ -1435,6 +2037,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                spin_lock_irqsave(&host->lock, flags);
        }
 
+       sdhci_set_clock(host, ios->clock);
+
        if (host->ops->platform_send_init_74_clocks)
                host->ops->platform_send_init_74_clocks(host, ios->power_mode);
 
@@ -1475,11 +2079,12 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                u16 clk, ctrl_2;
 
                /* In case of UHS-I modes, set High Speed Enable */
-               if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+               if (((ios->timing == MMC_TIMING_MMC_HS200) ||
                    (ios->timing == MMC_TIMING_UHS_SDR50) ||
                    (ios->timing == MMC_TIMING_UHS_SDR104) ||
                    (ios->timing == MMC_TIMING_UHS_DDR50) ||
                    (ios->timing == MMC_TIMING_UHS_SDR25))
+                   && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
                        ctrl |= SDHCI_CTRL_HISPD;
 
                ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
@@ -1512,7 +2117,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                        sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
                        /* Re-enable SD Clock */
-                       sdhci_update_clock(host);
+                       clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+                       clk |= SDHCI_CLOCK_CARD_EN;
+                       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
                }
 
 
@@ -1557,7 +2164,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                }
 
                /* Re-enable SD Clock */
-               sdhci_update_clock(host);
+               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+               clk |= SDHCI_CLOCK_CARD_EN;
+               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
        } else
                sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
@@ -1566,11 +2175,16 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
         * signalling timeout and CRC errors even on CMD0. Resetting
         * it on each ios seems to solve the problem.
         */
-       if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
+       if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
                sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
+
+       /* Platform specific handling post ios setting */
+       if (host->ops->platform_ios_config_exit)
+               host->ops->platform_ios_config_exit(host, ios);
+
 }
 
 static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -1719,6 +2333,12 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
        if (host->version < SDHCI_SPEC_300)
                return 0;
 
+       if (host->quirks2 & SDHCI_QUIRK2_NON_STD_VOLTAGE_SWITCHING) {
+               if (host->ops->switch_signal_voltage)
+                       return host->ops->switch_signal_voltage(
+                               host, ios->signal_voltage);
+       }
+
        ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 
        switch (ios->signal_voltage) {
@@ -1803,6 +2423,10 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
                return 0;
        sdhci_runtime_pm_get(host);
        err = sdhci_do_start_signal_voltage_switch(host, ios);
+       /* Do any post voltage switch platform specific configuration */
+       if  (host->ops->switch_signal_voltage_exit)
+               host->ops->switch_signal_voltage_exit(host,
+                       ios->signal_voltage);
        sdhci_runtime_pm_put(host);
        return err;
 }
@@ -1820,6 +2444,26 @@ static int sdhci_card_busy(struct mmc_host *mmc)
        return !(present_state & SDHCI_DATA_LVL_MASK);
 }
 
+static void sdhci_config_tap(struct mmc_host *mmc, u8 option)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (host->ops->config_tap_delay)
+               host->ops->config_tap_delay(host, option);
+}
+
+static int sdhci_validate_sd2_0(struct mmc_host *mmc)
+{
+       struct sdhci_host *host;
+       int err = 0;
+
+       host = mmc_priv(mmc);
+
+       if (host->ops->validate_sd2_0)
+               err = host->ops->validate_sd2_0(host);
+       return err;
+}
+
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct sdhci_host *host;
@@ -1829,13 +2473,27 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        unsigned long timeout;
        int err = 0;
        bool requires_tuning_nonuhs = false;
+       u16 clk = 0;
 
        host = mmc_priv(mmc);
 
        sdhci_runtime_pm_get(host);
        disable_irq(host->irq);
-       spin_lock(&host->lock);
 
+       if ((host->quirks2 & SDHCI_QUIRK2_NON_STANDARD_TUNING) &&
+               host->ops->execute_freq_tuning) {
+               err = host->ops->execute_freq_tuning(host, opcode);
+               enable_irq(host->irq);
+               sdhci_runtime_pm_put(host);
+               return err;
+       }
+
+       if ((host->quirks2 & SDHCI_QUIRK2_NON_STD_TUNING_LOOP_CNTR) &&
+               (host->ops->get_max_tuning_loop_counter))
+               tuning_loop_counter =
+                       host->ops->get_max_tuning_loop_counter(host);
+
+       spin_lock(&host->lock);
        ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 
        /*
@@ -1872,7 +2530,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
         * to make sure we don't hit a controller bug, we _only_
         * enable Buffer Read Ready interrupt here.
         */
-       ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+       ier = host->ier;
        sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
 
        /*
@@ -1895,12 +2553,21 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                cmd.error = 0;
 
                mrq.cmd = &cmd;
-               host->mrq = &mrq;
+               host->mrq_cmd = &mrq;
+
+               if (host->quirks2 & SDHCI_QUIRK2_NON_STD_TUN_CARD_CLOCK) {
+                       clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+                       clk &= ~SDHCI_CLOCK_CARD_EN;
+                       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+               }
 
                /*
                 * In response to CMD19, the card sends 64 bytes of tuning
                 * block to the Host Controller. So we set the block size
                 * to 64 here.
+                * In response to CMD21, the card sends 128 bytes of tuning
+                * block for MMC_BUS_WIDTH_8 and 64 bytes for MMC_BUS_WIDTH_4
+                * to the Host Controller. So we set the block size to 64 here.
                 */
                if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
                        if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
@@ -1925,11 +2592,19 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                sdhci_send_command(host, &cmd);
 
                host->cmd = NULL;
-               host->mrq = NULL;
+               host->mrq_cmd = NULL;
 
                spin_unlock(&host->lock);
                enable_irq(host->irq);
 
+               if (host->quirks2 & SDHCI_QUIRK2_NON_STD_TUN_CARD_CLOCK) {
+                       udelay(1);
+                       sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
+                       clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+                       clk |= SDHCI_CLOCK_CARD_EN;
+                       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+               }
+
                /* Wait for Buffer Read Ready interrupt */
                wait_event_interruptible_timeout(host->buf_ready_int,
                                        (host->tuning_done == 1),
@@ -1972,6 +2647,13 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                                " failed, falling back to fixed sampling"
                                " clock\n");
                        err = -EIO;
+               } else {
+                       sdhci_config_tap(mmc, SAVE_TUNED_TAP);
+                       pr_info("%s: tap value and tuning window after hw tuning completion ...\n",
+                               mmc_hostname(mmc));
+                       /* log tap, trim and tuning windows */
+                       if (host->ops->dump_host_cust_regs)
+                               host->ops->dump_host_cust_regs(host);
                }
        }
 
@@ -2047,37 +2729,208 @@ static void sdhci_card_event(struct mmc_host *mmc)
        struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
 
+       sdhci_runtime_pm_get(host);
        spin_lock_irqsave(&host->lock, flags);
 
-       /* Check host->mrq first in case we are runtime suspended */
-       if (host->mrq &&
+       /* Check host->mrq_cmd first in case we are runtime suspended */
+       if ((host->mrq_cmd || host->mrq_dat) &&
            !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
                pr_err("%s: Card removed during transfer!\n",
                        mmc_hostname(host->mmc));
                pr_err("%s: Resetting controller.\n",
                        mmc_hostname(host->mmc));
 
-               sdhci_reset(host, SDHCI_RESET_CMD);
-               sdhci_reset(host, SDHCI_RESET_DATA);
+               sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
-               host->mrq->cmd->error = -ENOMEDIUM;
-               tasklet_schedule(&host->finish_tasklet);
+               if (host->mrq_cmd) {
+                       host->mrq_cmd->cmd->error = -ENOMEDIUM;
+                       if (MMC_CHECK_CMDQ_MODE(host))
+                               tasklet_schedule(&host->finish_cmd_tasklet);
+                       else
+                               tasklet_schedule(&host->finish_tasklet);
+               }
+               if (host->mrq_dat) {
+                       host->mrq_dat->cmd->error = -ENOMEDIUM;
+                       if (MMC_CHECK_CMDQ_MODE(host))
+                               tasklet_schedule(&host->finish_dat_tasklet);
+                       else
+                               tasklet_schedule(&host->finish_tasklet);
+               }
        }
 
        spin_unlock_irqrestore(&host->lock, flags);
+       sdhci_runtime_pm_put(host);
+}
+
+int sdhci_enable(struct mmc_host *mmc)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (!mmc->card || !(mmc->caps2 & MMC_CAP2_CLOCK_GATING))
+               return 0;
+
+       /* cancel delayed clk gate work */
+       if (host->quirks2 & SDHCI_QUIRK2_DELAYED_CLK_GATE)
+               cancel_delayed_work_sync(&host->delayed_clk_gate_wrk);
+
+       sysedp_set_state(host->sysedpc, 1);
+
+       if (mmc->ios.clock) {
+               if (host->ops->set_clock)
+                       host->ops->set_clock(host, mmc->ios.clock);
+               sdhci_set_clock(host, mmc->ios.clock);
+       }
+
+       return 0;
+}
+
+static void mmc_host_clk_gate(struct sdhci_host *host)
+{
+       sdhci_set_clock(host, 0);
+       if (host->ops->set_clock)
+               host->ops->set_clock(host, 0);
+
+       sysedp_set_state(host->sysedpc, 0);
+
+       return;
+}
+
+void delayed_clk_gate_cb(struct work_struct *work)
+{
+       struct sdhci_host *host = container_of(work, struct sdhci_host,
+                                             delayed_clk_gate_wrk.work);
+
+       /* power off check */
+       if (host->mmc->ios.power_mode == MMC_POWER_OFF)
+               goto end;
+
+       mmc_host_clk_gate(host);
+end:
+       return;
+}
+EXPORT_SYMBOL_GPL(delayed_clk_gate_cb);
+
+int sdhci_disable(struct mmc_host *mmc)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (!mmc->card || !(mmc->caps2 & MMC_CAP2_CLOCK_GATING))
+               return 0;
+
+       if (IS_DELAYED_CLK_GATE(host)) {
+               if (host->is_clk_on) {
+                       if (IS_SDIO_CARD(host))
+                               host->clk_gate_tmout_ticks =
+                                       SDIO_CLK_GATING_TICK_TMOUT;
+                       else if (IS_EMMC_CARD(host))
+                               host->clk_gate_tmout_ticks =
+                                       EMMC_CLK_GATING_TICK_TMOUT;
+                       if (host->clk_gate_tmout_ticks > 0)
+                               schedule_delayed_work(
+                                       &host->delayed_clk_gate_wrk,
+                                       host->clk_gate_tmout_ticks);
+               }
+               return 0;
+       }
+
+       mmc_host_clk_gate(host);
+
+       return 0;
 }
 
+#ifdef CONFIG_MMC_FREQ_SCALING
+/*
+ * Wrapper functions to call any platform specific implementation for
+ * supporting dynamic frequency scaling for SD/MMC devices.
+ */
+static int sdhci_gov_get_target(struct mmc_host *mmc, unsigned long *freq)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (host->ops->dfs_gov_get_target_freq)
+               *freq = host->ops->dfs_gov_get_target_freq(host,
+                       mmc->devfreq_stats);
+
+       return 0;
+}
+
+static int sdhci_gov_init(struct mmc_host *mmc)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (host->ops->dfs_gov_init)
+               return host->ops->dfs_gov_init(host);
+
+       return 0;
+}
+
+static void sdhci_gov_exit(struct mmc_host *mmc)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (host->ops->dfs_gov_exit)
+               host->ops->dfs_gov_exit(host);
+}
+#endif
+
+static int sdhci_select_drive_strength(struct mmc_host *mmc,
+                                      unsigned int max_dtr,
+                                      int host_drv,
+                                      int card_drv)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       unsigned char   drv_type;
+
+       /* return default strength if no handler in driver */
+       if (!host->ops->get_drive_strength)
+               return MMC_SET_DRIVER_TYPE_B;
+
+       drv_type = host->ops->get_drive_strength(host, max_dtr,
+                       host_drv, card_drv);
+
+       if (drv_type > MMC_SET_DRIVER_TYPE_D) {
+               pr_err("%s: Error on getting drive strength. Got drv_type %d\n"
+                       , mmc_hostname(host->mmc), drv_type);
+               return MMC_SET_DRIVER_TYPE_B;
+       }
+
+       return drv_type;
+}
+static void sdhci_init_card(struct mmc_host *mmc, struct mmc_card *card)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       /*
+        * Get the max pio transfer limits if defined. This would be used to
+        * dynamically choose between dma and pio modes depending on the
+        * transfer parameters.
+        */
+       if (host->ops->get_max_pio_transfer_limits)
+               host->ops->get_max_pio_transfer_limits(host);
+}
 static const struct mmc_host_ops sdhci_ops = {
        .request        = sdhci_request,
        .set_ios        = sdhci_set_ios,
        .get_cd         = sdhci_get_cd,
        .get_ro         = sdhci_get_ro,
        .hw_reset       = sdhci_hw_reset,
+       .enable         = sdhci_enable,
+       .disable        = sdhci_disable,
        .enable_sdio_irq = sdhci_enable_sdio_irq,
        .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
        .execute_tuning                 = sdhci_execute_tuning,
+       .validate_sd2_0                 = sdhci_validate_sd2_0,
        .card_event                     = sdhci_card_event,
        .card_busy      = sdhci_card_busy,
+#ifdef CONFIG_MMC_FREQ_SCALING
+       .dfs_governor_init              = sdhci_gov_init,
+       .dfs_governor_exit              = sdhci_gov_exit,
+       .dfs_governor_get_target        = sdhci_gov_get_target,
+#endif
+       .select_drive_strength          = sdhci_select_drive_strength,
+       .post_init      = sdhci_post_init,
+       .en_strobe      = sdhci_en_strobe,
+       .init_card      = sdhci_init_card,
 };
 
 /*****************************************************************************\
@@ -2088,7 +2941,7 @@ static const struct mmc_host_ops sdhci_ops = {
 
 static void sdhci_tasklet_card(unsigned long param)
 {
-       struct sdhci_host *host = (struct sdhci_host*)param;
+       struct sdhci_host *host = (struct sdhci_host *)param;
 
        sdhci_card_event(host->mmc);
 
@@ -2099,24 +2952,93 @@ static void sdhci_tasklet_finish(unsigned long param)
 {
        struct sdhci_host *host;
        unsigned long flags;
+       struct mmc_request *mrq = NULL;
+
+       host = (struct sdhci_host *)param;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       /*
+        * If this tasklet gets rescheduled while running, it will
+        * be run again afterwards but without any active request.
+        */
+       if (!host->mrq_cmd && !host->mrq_dat) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
+       del_timer(&host->timer);
+
+       if (host->mrq_cmd)
+               mrq = host->mrq_cmd;
+       else if (host->mrq_dat)
+               mrq = host->mrq_dat;
+
+       /*
+        * The controller needs a reset of internal state machines
+        * upon error conditions.
+        */
+       if (!(host->flags & SDHCI_DEVICE_DEAD) &&
+           ((mrq->cmd && mrq->cmd->error) ||
+                (mrq->data && (mrq->data->error ||
+                 (mrq->data->stop && mrq->data->stop->error))) ||
+                  (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
+
+               /* Some controllers need this kick or reset won't work here */
+               if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
+                       /* This is to force an update */
+                       sdhci_update_clock(host);
+
+               /* Spec says we should do both at the same time */
+               sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+       }
+
+       host->mrq_cmd = NULL;
+       host->mrq_dat = NULL;
+       host->cmd = NULL;
+       host->data = NULL;
+
+#ifndef SDHCI_USE_LEDS_CLASS
+       sdhci_deactivate_led(host);
+#endif
+
+       mmiowb();
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       mmc_request_done(host->mmc, mrq);
+       sdhci_runtime_pm_put(host);
+}
+
+/*
+ * This tasklet gets scheduled to handle CMD only requests in CQ.
+ */
+static void sdhci_tasklet_cmd_finish(unsigned long param)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
        struct mmc_request *mrq;
 
-       host = (struct sdhci_host*)param;
+       host = (struct sdhci_host *)param;
+
+       if (!host->mrq_cmd && host->mrq_dat) {
+               mmc_handle_queued_request(host->mmc, MMC_HANDLE_CLR_CMD);
+               return;
+       }
 
        spin_lock_irqsave(&host->lock, flags);
 
-        /*
-         * If this tasklet gets rescheduled while running, it will
-         * be run again afterwards but without any active request.
-         */
-       if (!host->mrq) {
+       /*
+        * If this tasklet gets rescheduled while running, it will
+        * be run again afterwards but without any active request.
+        */
+       if (!host->mrq_cmd) {
                spin_unlock_irqrestore(&host->lock, flags);
                return;
        }
 
        del_timer(&host->timer);
 
-       mrq = host->mrq;
+       mrq = host->mrq_cmd;
 
        /*
         * The controller needs a reset of internal state machines
@@ -2133,14 +3055,71 @@ static void sdhci_tasklet_finish(unsigned long param)
                        /* This is to force an update */
                        sdhci_update_clock(host);
 
-               /* Spec says we should do both at the same time, but Ricoh
-                  controllers do not like that. */
                sdhci_reset(host, SDHCI_RESET_CMD);
-               sdhci_reset(host, SDHCI_RESET_DATA);
        }
 
-       host->mrq = NULL;
+       host->mrq_cmd = NULL;
        host->cmd = NULL;
+
+#ifndef SDHCI_USE_LEDS_CLASS
+       sdhci_deactivate_led(host);
+#endif
+
+       mmiowb();
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       mmc_request_done(host->mmc, mrq);
+       sdhci_runtime_pm_put(host);
+}
+
+/*
+ * This tasklet gets scheduled to handle CMD with DATA requests in CQ.
+ */
+static void sdhci_tasklet_dat_finish(unsigned long param)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+       struct mmc_request *mrq;
+
+       host = (struct sdhci_host *)param;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       /*
+        * If this tasklet gets rescheduled while running, it will
+        * be run again afterwards but without any active request.
+        */
+       if (!host->mrq_dat) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
+       del_timer(&host->timer);
+
+       mrq = host->mrq_dat;
+
+       if (host->data_early)
+               mrq->data_early = 1;
+
+       /*
+        * The controller needs a reset of internal state machines
+        * upon error conditions.
+        */
+       if (!(host->flags & SDHCI_DEVICE_DEAD) &&
+           ((mrq->cmd && mrq->cmd->error) ||
+                (mrq->data && (mrq->data->error ||
+                 (mrq->data->stop && mrq->data->stop->error))) ||
+                  (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
+
+               /* Some controllers need this kick or reset won't work here */
+               if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
+                       /* This is to force an update */
+                       sdhci_update_clock(host);
+
+               sdhci_reset(host, SDHCI_RESET_DATA);
+       }
+
+       host->mrq_dat = NULL;
        host->data = NULL;
 
 #ifndef SDHCI_USE_LEDS_CLASS
@@ -2159,11 +3138,11 @@ static void sdhci_timeout_timer(unsigned long data)
        struct sdhci_host *host;
        unsigned long flags;
 
-       host = (struct sdhci_host*)data;
+       host = (struct sdhci_host *)data;
 
        spin_lock_irqsave(&host->lock, flags);
 
-       if (host->mrq) {
+       if (host->mrq_cmd || host->mrq_dat) {
                pr_err("%s: Timeout waiting for hardware "
                        "interrupt.\n", mmc_hostname(host->mmc));
                sdhci_dumpregs(host);
@@ -2174,10 +3153,13 @@ static void sdhci_timeout_timer(unsigned long data)
                } else {
                        if (host->cmd)
                                host->cmd->error = -ETIMEDOUT;
-                       else
-                               host->mrq->cmd->error = -ETIMEDOUT;
+                       else if (host->mrq_dat)
+                               host->mrq_dat->cmd->error = -ETIMEDOUT;
 
-                       tasklet_schedule(&host->finish_tasklet);
+                       if (MMC_CHECK_CMDQ_MODE(host))
+                               tasklet_schedule(&host->finish_cmd_tasklet);
+                       else
+                               tasklet_schedule(&host->finish_tasklet);
                }
        }
 
@@ -2217,14 +3199,25 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
                return;
        }
 
-       if (intmask & SDHCI_INT_TIMEOUT)
+       if (intmask & SDHCI_INT_TIMEOUT) {
                host->cmd->error = -ETIMEDOUT;
-       else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
-                       SDHCI_INT_INDEX))
+       } else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
+                       SDHCI_INT_INDEX)) {
                host->cmd->error = -EILSEQ;
+               sdhci_dumpregs(host);
+               if (intmask & SDHCI_INT_INDEX)
+                       pr_err("%s: Command END bit error, intmask: %x Interface clock = %uHz\n",
+                       mmc_hostname(host->mmc), intmask, host->max_clk);
+               else
+                       pr_err("%s: Command CRC error, intmask: %x Interface clock = %uHz\n",
+                       mmc_hostname(host->mmc), intmask, host->max_clk);
+       }
 
        if (host->cmd->error) {
-               tasklet_schedule(&host->finish_tasklet);
+               if (MMC_CHECK_CMDQ_MODE(host))
+                       tasklet_schedule(&host->finish_cmd_tasklet);
+               else
+                       tasklet_schedule(&host->finish_tasklet);
                return;
        }
 
@@ -2263,6 +3256,19 @@ static void sdhci_show_adma_error(struct sdhci_host *host)
        __le16 *len;
        u8 attr;
 
+       u32 ctrl;
+       int next_desc;
+       ctrl = sdhci_readl(host, SDHCI_ACMD12_ERR);
+       if (ctrl & SDHCI_ADDRESSING_64BIT_EN) {
+               if (ctrl & SDHCI_HOST_VERSION_4_EN)
+                       next_desc = 16;
+               else
+                       next_desc = 12;
+       } else {
+               /* 32 bit DMA mode supported*/
+               next_desc = 8;
+       }
+
        sdhci_dumpregs(host);
 
        while (true) {
@@ -2270,11 +3276,14 @@ static void sdhci_show_adma_error(struct sdhci_host *host)
                len = (__le16 *)(desc + 2);
                attr = *desc;
 
-               DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
-                   name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr);
-
-               desc += 8;
-
+               if (next_desc == 8) {
+                       DBG("%s: %p: DMA-32 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
+                               name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr);
+               } else if (next_desc == 16) {
+                       DBG("%s: %p: DMA-64 0x%16x, LEN 0x%04x, Attr=0x%02x\n",
+                               name, desc, le64_to_cpu(*((__le64 *)dma)), le16_to_cpu(*len), attr);
+               }
+               desc += next_desc;
                if (attr & 2)
                        break;
        }
@@ -2288,7 +3297,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
        u32 command;
        BUG_ON(intmask == 0);
 
-       /* CMD19 generates _only_ Buffer Read Ready interrupt */
+       /* CMD19, CMD21 generates _only_ Buffer Read Ready interrupt */
        if (intmask & SDHCI_INT_DATA_AVAIL) {
                command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
                if (command == MMC_SEND_TUNING_BLOCK ||
@@ -2320,16 +3329,25 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                return;
        }
 
-       if (intmask & SDHCI_INT_DATA_TIMEOUT)
+       if (intmask & SDHCI_INT_DATA_TIMEOUT) {
                host->data->error = -ETIMEDOUT;
-       else if (intmask & SDHCI_INT_DATA_END_BIT)
+               pr_err("%s: Data Timeout error, intmask: %x Interface clock = %uHz\n",
+                       mmc_hostname(host->mmc), intmask, host->max_clk);
+               sdhci_dumpregs(host);
+       } else if (intmask & SDHCI_INT_DATA_END_BIT) {
                host->data->error = -EILSEQ;
-       else if ((intmask & SDHCI_INT_DATA_CRC) &&
+               pr_err("%s: Data END Bit error, intmask: %x Interface clock = %uHz\n",
+                       mmc_hostname(host->mmc), intmask, host->max_clk);
+       } else if ((intmask & SDHCI_INT_DATA_CRC) &&
                SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
-                       != MMC_BUS_TEST_R)
+                       != MMC_BUS_TEST_R) {
                host->data->error = -EILSEQ;
-       else if (intmask & SDHCI_INT_ADMA_ERROR) {
+               pr_err("%s: Data CRC error, intmask: %x Interface clock = %uHz\n",
+                       mmc_hostname(host->mmc), intmask, host->max_clk);
+               sdhci_dumpregs(host);
+       } else if (intmask & SDHCI_INT_ADMA_ERROR) {
                pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
+               sdhci_dumpregs(host);
                sdhci_show_adma_error(host);
                host->data->error = -EIO;
                if (host->ops->adma_workaround)
@@ -2370,16 +3388,17 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                }
 
                if (intmask & SDHCI_INT_DATA_END) {
-                       if (host->cmd) {
+                       if ((!MMC_CHECK_CMDQ_MODE(host) && host->cmd) ||
+                               (MMC_CHECK_CMDQ_MODE(host) && host->cmd && (host->mrq_dat->cmd == host->cmd))) {
+
                                /*
                                 * Data managed to finish before the
                                 * command completed. Make sure we do
                                 * things in the proper order.
                                 */
                                host->data_early = 1;
-                       } else {
+                       } else
                                sdhci_finish_data(host);
-                       }
                }
        }
 }
@@ -2436,6 +3455,11 @@ again:
                tasklet_schedule(&host->card_tasklet);
        }
 
+#ifdef CONFIG_CMD_DUMP
+       if (mmc_hostname(host->mmc)[3] == '0')
+               dbg_add_host_log(host->mmc, 7,  intmask, 0xffffffff);
+#endif
+
        if (intmask & SDHCI_INT_CMD_MASK) {
                sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
                        SDHCI_INT_STATUS);
@@ -2448,6 +3472,13 @@ again:
                sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
        }
 
+       if (intmask & SDHCI_INT_RETUNING_EVENT)
+               host->flags |= SDHCI_NEEDS_RETUNING;
+
+       if ((intmask & SDHCI_INT_DATA_MASK) || (intmask & SDHCI_INT_CMD_MASK))
+               if (host->ops->sd_error_stats)
+                       host->ops->sd_error_stats(host, intmask);
+
        intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
 
        intmask &= ~SDHCI_INT_ERROR;
@@ -2529,6 +3560,9 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
 int sdhci_suspend_host(struct sdhci_host *host)
 {
        int ret;
+       struct mmc_host *mmc = host->mmc;
+
+       host->suspend_task = current;
 
        if (host->ops->platform_suspend)
                host->ops->platform_suspend(host);
@@ -2541,6 +3575,14 @@ int sdhci_suspend_host(struct sdhci_host *host)
                host->flags &= ~SDHCI_NEEDS_RETUNING;
        }
 
+       /*
+        * If eMMC cards are put in sleep state, Vccq can be disabled
+        * but Vcc would still be powered on. In resume, we only restore
+        * the controller context. So, set MMC_PM_KEEP_POWER flag.
+        */
+       if (mmc_card_can_sleep(mmc) && !(mmc->caps2 & MMC_CAP2_NO_SLEEP_CMD))
+               mmc->pm_flags |= MMC_PM_KEEP_POWER;
+
        ret = mmc_suspend_host(host->mmc);
        if (ret) {
                if (host->flags & SDHCI_USING_RETUNING_TIMER) {
@@ -2551,16 +3593,50 @@ int sdhci_suspend_host(struct sdhci_host *host)
 
                sdhci_enable_card_detection(host);
 
+               host->suspend_task = NULL;
                return ret;
        }
 
+       /* cancel delayed clk gate work */
+       if (host->quirks2 & SDHCI_QUIRK2_DELAYED_CLK_GATE)
+               cancel_delayed_work_sync(&host->delayed_clk_gate_wrk);
+
+       /*
+        * If host clock is disabled but the register access requires host
+        * clock, then enable the clock, mask the interrupts and disable
+        * the clock.
+        */
+       if (host->quirks2 & SDHCI_QUIRK2_REG_ACCESS_REQ_HOST_CLK)
+               if ((!host->clock && host->ops->set_clock) &&
+                       (host->quirks2 & SDHCI_QUIRK2_DELAYED_CLK_GATE))
+                       host->ops->set_clock(host, max(mmc->ios.clock, mmc->f_min));
+
+       if (mmc->pm_flags & MMC_PM_KEEP_POWER)
+               host->card_int_set = host->ier &
+                       SDHCI_INT_CARD_INT;
+
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
                sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
-               free_irq(host->irq, host);
+
+               if (host->quirks2 & SDHCI_QUIRK2_REG_ACCESS_REQ_HOST_CLK)
+                       if ((!host->clock && host->ops->set_clock) &&
+                       (host->quirks2 & SDHCI_QUIRK2_DELAYED_CLK_GATE))
+                               host->ops->set_clock(host, 0);
+
+               if (host->irq)
+                       disable_irq(host->irq);
        } else {
                sdhci_enable_irq_wakeups(host);
                enable_irq_wake(host->irq);
+
+               if (host->quirks2 & SDHCI_QUIRK2_REG_ACCESS_REQ_HOST_CLK)
+                       if ((!host->clock && host->ops->set_clock) &&
+                       (host->quirks2 & SDHCI_QUIRK2_DELAYED_CLK_GATE))
+                               host->ops->set_clock(host, 0);
        }
+
+       host->suspend_task = NULL;
+
        return ret;
 }
 
@@ -2569,6 +3645,10 @@ EXPORT_SYMBOL_GPL(sdhci_suspend_host);
 int sdhci_resume_host(struct sdhci_host *host)
 {
        int ret;
+       struct mmc_host *mmc = host->mmc;
+
+       host->suspend_task = current;
+
 
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
                if (host->ops->enable_dma)
@@ -2576,10 +3656,8 @@ int sdhci_resume_host(struct sdhci_host *host)
        }
 
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
-               ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-                                 mmc_hostname(host->mmc), host);
-               if (ret)
-                       return ret;
+               if (host->irq)
+                       enable_irq(host->irq);
        } else {
                sdhci_disable_irq_wakeups(host);
                disable_irq_wake(host->irq);
@@ -2598,6 +3676,12 @@ int sdhci_resume_host(struct sdhci_host *host)
        }
 
        ret = mmc_resume_host(host->mmc);
+       /* Enable card interrupt as it is overwritten in sdhci_init */
+       if ((mmc->caps & MMC_CAP_SDIO_IRQ) &&
+               (mmc->pm_flags & MMC_PM_KEEP_POWER))
+                       if (host->card_int_set)
+                               mmc->ops->enable_sdio_irq(mmc, true);
+
        sdhci_enable_card_detection(host);
 
        if (host->ops->platform_resume)
@@ -2607,6 +3691,8 @@ int sdhci_resume_host(struct sdhci_host *host)
        if (host->flags & SDHCI_USING_RETUNING_TIMER)
                host->flags |= SDHCI_NEEDS_RETUNING;
 
+       host->suspend_task = NULL;
+
        return ret;
 }
 
@@ -2617,11 +3703,58 @@ EXPORT_SYMBOL_GPL(sdhci_resume_host);
 
 static int sdhci_runtime_pm_get(struct sdhci_host *host)
 {
+       int present;
+
+       if (!(host->quirks2 & SDHCI_QUIRK2_MMC_RTPM))
+               return 0;
+
+       present = mmc_gpio_get_cd(host->mmc);
+       if (present < 0) {
+               /* If polling, assume that the card is always present. */
+               if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+                       if (host->ops->get_cd)
+                               present = host->ops->get_cd(host);
+                       else
+                               present = 1;
+               else
+                       present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+                                       SDHCI_CARD_PRESENT;
+       }
+
+       if ((present && !host->mmc->card && (host->runtime_suspended == false))
+                                       || host->suspend_task == current) {
+               pm_runtime_get_noresume(host->mmc->parent);
+               return 0;
+       }
+
        return pm_runtime_get_sync(host->mmc->parent);
 }
 
 static int sdhci_runtime_pm_put(struct sdhci_host *host)
 {
+       int present;
+
+       if (!(host->quirks2 & SDHCI_QUIRK2_MMC_RTPM))
+               return 0;
+
+       present = mmc_gpio_get_cd(host->mmc);
+       if (present < 0) {
+               /* If polling, assume that the card is always present. */
+               if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+                       if (host->ops->get_cd)
+                               present = host->ops->get_cd(host);
+                       else
+                               present = 1;
+               else
+                       present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+                                       SDHCI_CARD_PRESENT;
+       }
+       if ((present && !host->mmc->card) || host->suspend_task == current) {
+               pm_runtime_mark_last_busy(host->mmc->parent);
+               pm_runtime_put_noidle(host->mmc->parent);
+               return 0;
+       }
+
        pm_runtime_mark_last_busy(host->mmc->parent);
        return pm_runtime_put_autosuspend(host->mmc->parent);
 }
@@ -2631,12 +3764,33 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
        unsigned long flags;
        int ret = 0;
 
+       if (!(host->quirks2 & SDHCI_QUIRK2_MMC_RTPM))
+               return 0;
+
+       if (host->quirks2 & SDHCI_QUIRK2_NON_STD_RTPM) {
+               spin_lock_irqsave(&host->lock, flags);
+               host->runtime_suspended = true;
+               spin_unlock_irqrestore(&host->lock, flags);
+
+               if (host->mmc->ios.clock) {
+                       sdhci_set_clock(host, 0);
+                       if (host->ops->set_clock)
+                               host->ops->set_clock(host, 0);
+                       sysedp_set_state(host->sysedpc, 0);
+               }
+               goto lbl_end;
+       }
+
        /* Disable tuning since we are suspending */
        if (host->flags & SDHCI_USING_RETUNING_TIMER) {
                del_timer_sync(&host->tuning_timer);
                host->flags &= ~SDHCI_NEEDS_RETUNING;
        }
 
+       if (host->ops->set_clock)
+               host->ops->set_clock(host, host->mmc->f_min);
+       sdhci_set_clock(host, host->mmc->f_min);
+
        spin_lock_irqsave(&host->lock, flags);
        sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
        spin_unlock_irqrestore(&host->lock, flags);
@@ -2647,6 +3801,11 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
        host->runtime_suspended = true;
        spin_unlock_irqrestore(&host->lock, flags);
 
+       sdhci_set_clock(host, 0);
+       if (host->ops->set_clock)
+               host->ops->set_clock(host, 0);
+
+lbl_end:
        return ret;
 }
 EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host);
@@ -2655,6 +3814,35 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
 {
        unsigned long flags;
        int ret = 0, host_flags = host->flags;
+       unsigned int freq;
+
+       if (!(host->quirks2 & SDHCI_QUIRK2_MMC_RTPM))
+               return 0;
+
+       if (host->quirks2 & SDHCI_QUIRK2_NON_STD_RTPM) {
+               if (host->mmc->ios.clock) {
+                       freq = host->mmc->ios.clock;
+               } else {
+                       if (!host->mmc->f_min)
+                               host->mmc->f_min = MIN_SDMMC_FREQ;
+                       freq = host->mmc->f_min;
+                       host->clock = freq;
+               }
+
+               if (host->ops->set_clock)
+                       host->ops->set_clock(host, freq);
+               sdhci_set_clock(host, freq);
+
+               sysedp_set_state(host->sysedpc, 1);
+               spin_lock_irqsave(&host->lock, flags);
+               host->runtime_suspended = false;
+               spin_unlock_irqrestore(&host->lock, flags);
+               goto lbl_end;
+       }
+
+       if (host->ops->set_clock)
+               host->ops->set_clock(host, host->mmc->f_min);
+       sdhci_set_clock(host, host->mmc->f_min);
 
        if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
                if (host->ops->enable_dma)
@@ -2668,7 +3856,14 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
        host->clock = 0;
        sdhci_do_set_ios(host, &host->mmc->ios);
 
-       sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
+       if (host->mmc->ios.clock) {
+               sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
+       /* Do any post voltage switch platform specific configuration */
+               if (host->ops->switch_signal_voltage_exit)
+                       host->ops->switch_signal_voltage_exit(host,
+                               host->mmc->ios.signal_voltage);
+       }
+
        if ((host_flags & SDHCI_PV_ENABLED) &&
                !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
                spin_lock_irqsave(&host->lock, flags);
@@ -2693,6 +3888,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
 
        spin_unlock_irqrestore(&host->lock, flags);
 
+lbl_end:
        return ret;
 }
 EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
@@ -2725,6 +3921,166 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
 
 EXPORT_SYMBOL_GPL(sdhci_alloc_host);
 
+#ifdef CONFIG_DEBUG_FS
+static int show_sdhci_perf_stats(struct seq_file *s, void *data)
+{
+       struct sdhci_host *host = s->private;
+       int i;
+       u32 avg_perf2;
+       u32 last_perf_in_class;
+       struct data_stat_entry *stat = NULL;
+       char buf[250];
+       u64 my_total_bytes;
+       u64 my_total_usecs;
+       unsigned int overall_avg_perf2;
+
+       seq_printf(s, "SDHCI(%s): perf statistics stat_size=%d\n",
+               mmc_hostname(host->mmc),
+               host->sdhci_data_stat.stat_size
+               );
+       if (host->sdhci_data_stat.stat_size) {
+               seq_printf(s, "SDHCI(%s): perf statistics:\n",
+                       mmc_hostname(host->mmc));
+               seq_puts(s,
+               "Note: Performance figures in kilo bits per sec(kbps)\n");
+               seq_puts(s,
+               "S.No.    Block       Direction    Num blks/        Total     Total           Total          Last            Last usec          Avg kbps        Last kbps           Min kbps   Max kbps\n");
+               seq_puts(s,
+               "         Size        (R/W)        transfer         Bytes     Transfers       Time(usec)     Bytes           Duration           Perf            Perf                Perf       Perf\n");
+       }
+       my_total_bytes = 0;
+       my_total_usecs = 0;
+       for (i = 0; i < host->sdhci_data_stat.stat_size; i++) {
+               if (!stat)
+                       stat = host->sdhci_data_stat.head;
+               else
+                       stat = stat->next;
+               if (!stat) {
+                       pr_err("%s %s: sdhci data stat head NULL i=%d\n",
+                               mmc_hostname(host->mmc), __func__, i);
+                       break;
+               }
+               get_kbps_from_size_n_usec_64bit(
+                       ((stat->total_bytes << 3) * 1000),
+                       stat->total_usecs, &avg_perf2);
+               get_kbps_from_size_n_usec_32bit(
+                       (((u32)stat->current_transferred_bytes << 3) * 1000),
+                       stat->duration_usecs,
+                       &last_perf_in_class);
+               my_total_bytes += stat->total_bytes;
+               my_total_usecs += stat->total_usecs;
+               snprintf(buf, 250,
+                       "%2d    %4d           %c       %8d    %16lld    %8d        %16lld    %8d            %8d           %8d         %8d         %8d    %8d\n",
+                       (i + 1),
+                       stat->stat_blk_size,
+                       stat->is_read ? 'R' : 'W',
+                       stat->stat_blks_per_transfer,
+                       stat->total_bytes,
+                       stat->total_transfers,
+                       stat->total_usecs,
+                       stat->current_transferred_bytes,
+                       stat->duration_usecs,
+                       avg_perf2,
+                       last_perf_in_class,
+                       stat->min_kbps,
+                       stat->max_kbps
+                       );
+               seq_puts(s, buf);
+       }
+       get_kbps_from_size_n_usec_64bit(
+               ((my_total_bytes << 3) * 1000),
+               my_total_usecs, &overall_avg_perf2);
+       snprintf(buf, 250,
+               "Total_bytes=%lldB, time=%lldusecs, overall kbps=%d\n",
+               my_total_bytes, my_total_usecs,
+               overall_avg_perf2);
+       seq_puts(s, buf);
+
+       return 0;
+}
+
+static int sdhci_perf_stats_dump(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_sdhci_perf_stats, inode->i_private);
+}
+
+static const struct file_operations flush_sdhci_perf_stats_fops = {
+       .open           = sdhci_perf_stats_dump,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int restart_sdhci_perf_stats(struct seq_file *s, void *data)
+{
+       struct sdhci_host *host = s->private;
+
+       free_stats_nodes(host);
+       return 0;
+}
+
+static int sdhci_perf_stats_restart(struct inode *inode, struct file *file)
+{
+       return single_open(file, restart_sdhci_perf_stats, inode->i_private);
+}
+
+static const struct file_operations reset_sdhci_perf_stats_fops = {
+       .open           = sdhci_perf_stats_restart,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void sdhci_debugfs_init(struct sdhci_host *host)
+{
+       struct dentry *root = host->debugfs_root;
+
+       /*
+        * debugfs nodes earlier were created from sdhci-tegra,
+        * In this change root debugfs node is created first-come-first-serve
+        */
+       if (!root) {
+               root = debugfs_create_dir(dev_name(mmc_dev(host->mmc)), NULL);
+               if (IS_ERR_OR_NULL(root))
+                       goto err_root;
+               host->debugfs_root = root;
+       }
+
+       if (!debugfs_create_u32("enable_sdhci_perf_stats", S_IRUGO | S_IWUSR,
+               root, (u32 *)&host->enable_sdhci_perf_stats))
+               goto err_root;
+
+       if (!debugfs_create_file("reset_sdhci_perf_stats", S_IRUGO,
+               root, host, &reset_sdhci_perf_stats_fops))
+               goto err_root;
+
+       if (!debugfs_create_file("sdhci_perf_stats", S_IRUGO,
+               root, host, &flush_sdhci_perf_stats_fops))
+               goto err_root;
+
+       if (!debugfs_create_u32("sdhci_perf_no_data_transfer_count", S_IRUGO,
+               root, (u32 *)&host->no_data_transfer_count))
+               goto err_root;
+
+       if (!debugfs_create_u32("max_pio_size", S_IRUGO | S_IWUSR,
+               root, (u32 *)&host->max_pio_size))
+               goto err_root;
+
+       if (!debugfs_create_u32("max_pio_blocks", S_IRUGO | S_IWUSR,
+               root, (u32 *)&host->max_pio_blocks))
+               goto err_root;
+
+       return;
+
+err_root:
+       debugfs_remove_recursive(root);
+       host->debugfs_root = NULL;
+
+       return;
+}
+#endif
+
+/* runtime pm is not enabled before add host */
 int sdhci_add_host(struct sdhci_host *host)
 {
        struct mmc_host *mmc;
@@ -2749,12 +4105,14 @@ int sdhci_add_host(struct sdhci_host *host)
        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_300) {
+       if (host->version > SDHCI_SPEC_400) {
                pr_err("%s: Unknown controller version (%d). "
                        "You may experience problems.\n", mmc_hostname(mmc),
                        host->version);
        }
 
+       host->mrq_cmd = NULL;
+       host->mrq_dat = NULL;
        caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
                sdhci_readl(host, SDHCI_CAPABILITIES);
 
@@ -2802,10 +4160,39 @@ int sdhci_add_host(struct sdhci_host *host)
                /*
                 * We need to allocate descriptors for all sg entries
                 * (128) and potentially one alignment transfer for
-                * each of those entries.
+                * each of those entries. Simply allocating 128 bits
+                * for each entry
                 */
-               host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
-               host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
+               if (mmc_dev(host->mmc)->dma_mask &&
+                               mmc_dev(host->mmc)->coherent_dma_mask) {
+                       host->adma_desc = dma_alloc_coherent(
+                                       mmc_dev(host->mmc), (128 * 2 + 1) * 8,
+                                       &host->adma_addr, GFP_KERNEL);
+                       if (!host->adma_desc)
+                               goto err_dma_alloc;
+
+                       host->align_buffer = dma_alloc_coherent(
+                                       mmc_dev(host->mmc), 128 * 8,
+                                       &host->align_addr, GFP_KERNEL);
+                       if (!host->align_buffer) {
+                               dma_free_coherent(mmc_dev(host->mmc),
+                                               (128 * 2 + 1) * 8,
+                                               host->adma_desc,
+                                               host->adma_addr);
+                               host->adma_desc = NULL;
+                               goto err_dma_alloc;
+                       }
+
+                       host->use_dma_alloc = true;
+
+                       BUG_ON(host->adma_addr & 0x3);
+                       BUG_ON(host->align_addr & 0x3);
+                       goto out_dma_alloc;
+               }
+err_dma_alloc:
+
+               host->adma_desc = kmalloc((128 * 2 + 1) * 8, GFP_KERNEL);
+               host->align_buffer = kmalloc(128 * 8, GFP_KERNEL);
                if (!host->adma_desc || !host->align_buffer) {
                        kfree(host->adma_desc);
                        kfree(host->align_buffer);
@@ -2815,6 +4202,7 @@ int sdhci_add_host(struct sdhci_host *host)
                        host->flags &= ~SDHCI_USE_ADMA;
                }
        }
+out_dma_alloc:
 
        /*
         * If we use DMA, then it's up to the caller to set the DMA
@@ -2834,6 +4222,10 @@ int sdhci_add_host(struct sdhci_host *host)
                        >> SDHCI_CLOCK_BASE_SHIFT;
 
        host->max_clk *= 1000000;
+
+       if (mmc->caps2 & MMC_CAP2_HS533)
+               host->max_clk = MMC_HS533_MAX_DTR;
+
        if (host->max_clk == 0 || host->quirks &
                        SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
                if (!host->ops->get_max_clock) {
@@ -2894,9 +4286,8 @@ int sdhci_add_host(struct sdhci_host *host)
        if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
                host->timeout_clk = mmc->f_max / 1000;
 
-       mmc->max_discard_to = (1 << 27) / host->timeout_clk;
-
-       mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
+       if (!(host->quirks2 & SDHCI_QUIRK2_NO_CALC_MAX_DISCARD_TO))
+               mmc->max_discard_to = (1 << 27) / host->timeout_clk;
 
        if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
                host->flags |= SDHCI_AUTO_CMD12;
@@ -2928,7 +4319,7 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
-           !(host->mmc->caps & MMC_CAP_NONREMOVABLE))
+           !(host->mmc->caps & MMC_CAP_NONREMOVABLE) && !(host->ops->get_cd))
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
@@ -2990,6 +4381,18 @@ int sdhci_add_host(struct sdhci_host *host)
        /* Initial value for re-tuning timer count */
        host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
                              SDHCI_RETUNING_TIMER_COUNT_SHIFT;
+       /*
+        * If the re-tuning timer count value is 0xF, the timer count
+        * information should be obtained in a non-standard way.
+        */
+       if (host->tuning_count == 0xF) {
+               if (host->ops->get_tuning_counter) {
+                       host->tuning_count =
+                               host->ops->get_tuning_counter(host);
+               } else {
+                       host->tuning_count = 0;
+               }
+       }
 
        /*
         * In case Re-tuning Timer is not disabled, the actual value of
@@ -3143,7 +4546,7 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >>
                                SDHCI_MAX_BLOCK_SHIFT;
                if (mmc->max_blk_size >= 3) {
-                       pr_warning("%s: Invalid maximum block size, "
+                       pr_info("%s: Invalid maximum block size, "
                                "assuming 512 bytes\n", mmc_hostname(mmc));
                        mmc->max_blk_size = 0;
                }
@@ -3155,6 +4558,9 @@ int sdhci_add_host(struct sdhci_host *host)
         * Maximum block count.
         */
        mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535;
+#ifdef CONFIG_CMD_DUMP
+       mmc->dbg_host_cnt = 0;
+#endif
 
        /*
         * Init tasklets.
@@ -3163,6 +4569,10 @@ int sdhci_add_host(struct sdhci_host *host)
                sdhci_tasklet_card, (unsigned long)host);
        tasklet_init(&host->finish_tasklet,
                sdhci_tasklet_finish, (unsigned long)host);
+       tasklet_init(&host->finish_cmd_tasklet,
+               sdhci_tasklet_cmd_finish, (unsigned long)host);
+       tasklet_init(&host->finish_dat_tasklet,
+               sdhci_tasklet_dat_finish, (unsigned long)host);
 
        setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
 
@@ -3185,6 +4595,9 @@ int sdhci_add_host(struct sdhci_host *host)
 
        sdhci_init(host, 0);
 
+       host->sysedpc = sysedp_create_consumer(dev_name(mmc_dev(mmc)),
+                                              dev_name(mmc_dev(mmc)));
+
 #ifdef CONFIG_MMC_DEBUG
        sdhci_dumpregs(host);
 #endif
@@ -3216,6 +4629,23 @@ int sdhci_add_host(struct sdhci_host *host)
 
        sdhci_enable_card_detection(host);
 
+       pm_runtime_enable(mmc_dev(mmc));
+       pm_runtime_use_autosuspend(mmc_dev(mmc));
+       if (host->quirks2 & SDHCI_QUIRK2_MMC_RTPM) {
+               /*
+                * Below Autosuspend delay can be increased/decreased based on
+                * power and perf data
+                */
+               pm_runtime_set_autosuspend_delay(mmc_dev(mmc),
+                       MMC_RTPM_MSEC_TMOUT);
+       }
+       host->runtime_pm_init_done = true;
+
+#ifdef CONFIG_DEBUG_FS
+       /* Add debugfs nodes */
+       sdhci_debugfs_init(host);
+#endif
+
        return 0;
 
 #ifdef SDHCI_USE_LEDS_CLASS
@@ -3227,27 +4657,48 @@ reset:
 untasklet:
        tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
+       tasklet_kill(&host->finish_cmd_tasklet);
+       tasklet_kill(&host->finish_dat_tasklet);
 
        return ret;
 }
 
 EXPORT_SYMBOL_GPL(sdhci_add_host);
 
+void sdhci_runtime_forbid(struct sdhci_host *host)
+{
+       pm_runtime_forbid(mmc_dev(host->mmc));
+}
+EXPORT_SYMBOL_GPL(sdhci_runtime_forbid);
+
 void sdhci_remove_host(struct sdhci_host *host, int dead)
 {
        unsigned long flags;
 
+       sdhci_runtime_pm_get(host);
        if (dead) {
                spin_lock_irqsave(&host->lock, flags);
 
                host->flags |= SDHCI_DEVICE_DEAD;
 
-               if (host->mrq) {
+               if (host->mrq_cmd || host->mrq_dat) {
                        pr_err("%s: Controller removed during "
                                " transfer!\n", mmc_hostname(host->mmc));
 
-                       host->mrq->cmd->error = -ENOMEDIUM;
-                       tasklet_schedule(&host->finish_tasklet);
+                       if (host->mrq_cmd) {
+                               host->mrq_cmd->cmd->error = -ENOMEDIUM;
+                               if (MMC_CHECK_CMDQ_MODE(host))
+                                       tasklet_schedule(&host->finish_cmd_tasklet);
+                               else
+                                       tasklet_schedule(&host->finish_tasklet);
+                       }
+                       if (host->mrq_dat) {
+                               host->mrq_dat->cmd->error = -ENOMEDIUM;
+                               if (MMC_CHECK_CMDQ_MODE(host))
+                                       tasklet_schedule(&host->finish_dat_tasklet);
+                               else
+                                       tasklet_schedule(&host->finish_tasklet);
+                       }
                }
 
                spin_unlock_irqrestore(&host->lock, flags);
@@ -3271,6 +4722,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 
        tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
+       tasklet_kill(&host->finish_cmd_tasklet);
+       tasklet_kill(&host->finish_dat_tasklet);
 
        if (host->vmmc) {
                regulator_disable(host->vmmc);
@@ -3282,11 +4735,22 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
                regulator_put(host->vqmmc);
        }
 
-       kfree(host->adma_desc);
-       kfree(host->align_buffer);
+       if (host->use_dma_alloc) {
+               dma_free_coherent(mmc_dev(host->mmc), (128 * 2 + 1) * 8,
+                               host->adma_desc, host->adma_addr);
+               dma_free_coherent(mmc_dev(host->mmc), 128 * 8,
+                               host->align_buffer, host->align_addr);
+       } else {
+               kfree(host->adma_desc);
+               kfree(host->align_buffer);
+       }
 
        host->adma_desc = NULL;
        host->align_buffer = NULL;
+
+       sdhci_runtime_pm_put(host);
+       sysedp_free_consumer(host->sysedpc);
+       host->sysedpc = NULL;
 }
 
 EXPORT_SYMBOL_GPL(sdhci_remove_host);