diff options
| author | Asutosh Das <asutoshd@codeaurora.org> | 2014-10-17 16:36:47 +0530 |
|---|---|---|
| committer | Subhash Jadavani <subhashj@codeaurora.org> | 2016-05-31 15:26:30 -0700 |
| commit | c4dd8dad71e8b77f7585e2b7d74d2ea7dcfcf91d (patch) | |
| tree | cd783e9e2bf6a3c2872d7d56893a4497ac184ea8 | |
| parent | 5434534be02ad105213949532796ffbb717814ea (diff) | |
mmc: sdhci: add command queue support to sdhci
Adds command-queue support to SDHCi compliant drivers.
Change-Id: I1efee7f1c86e102364083e9158e4d45c887dd06e
Signed-off-by: Asutosh Das <asutoshd@codeaurora.org>
Signed-off-by: Konstantin Dorfman <kdorfman@codeaurora.org>
Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
[subhashj@codeaurora.org: fixed trivial merge conflicts and
compilation error]
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 146 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.h | 6 |
2 files changed, 148 insertions, 4 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7cb82926a06b..1522405f5567 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -35,6 +35,7 @@ #include <trace/events/mmc.h> #include "sdhci.h" +#include "cmdq_hci.h" #define DRIVER_NAME "sdhci" @@ -2918,6 +2919,20 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } } +#ifdef CONFIG_MMC_CQ_HCI +static irqreturn_t sdhci_cmdq_irq(struct mmc_host *mmc, u32 intmask) +{ + return cmdq_irq(mmc, intmask); +} + +#else +static irqreturn_t sdhci_cmdq_irq(struct mmc_host *mmc, u32 intmask) +{ + pr_err("%s: rxd cmdq-irq when disabled !!!!\n", mmc_hostname(mmc)); + return IRQ_NONE; +} +#endif + static irqreturn_t sdhci_irq(int irq, void *dev_id) { irqreturn_t result = IRQ_NONE; @@ -2939,6 +2954,15 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) } do { + if (host->mmc->card && mmc_card_cmdq(host->mmc->card) && + !mmc_host_halt(host->mmc)) { + pr_debug("*** %s: cmdq intr: 0x%08x\n", + mmc_hostname(host->mmc), + intmask); + result = sdhci_cmdq_irq(host->mmc, intmask); + goto out; + } + if (intmask & SDHCI_INT_AUTO_CMD_ERR) host->auto_cmd_err_sts = sdhci_readw(host, SDHCI_AUTO_CMD_ERR); @@ -3302,6 +3326,106 @@ static void sdhci_set_pmqos_req_type(struct sdhci_host *host) } #endif +#ifdef CONFIG_MMC_CQ_HCI +static void sdhci_cmdq_clear_set_irqs(struct mmc_host *mmc, bool clear) +{ + struct sdhci_host *host = mmc_priv(mmc); + u32 ier = 0; + + ier &= ~SDHCI_INT_ALL_MASK; + + if (clear) { + ier = SDHCI_INT_CMDQ_EN | SDHCI_INT_ERROR_MASK; + sdhci_writel(host, ier, SDHCI_INT_ENABLE); + sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); + } else { + ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | + SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | + SDHCI_INT_INDEX | SDHCI_INT_END_BIT | + SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | + SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE | + SDHCI_INT_AUTO_CMD_ERR; + sdhci_writel(host, ier, SDHCI_INT_ENABLE); + sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); + } +} + +static void sdhci_cmdq_set_data_timeout(struct mmc_host *mmc, u32 val) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_writeb(host, val, SDHCI_TIMEOUT_CONTROL); +} + +static void sdhci_cmdq_dump_vendor_regs(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_dumpregs(host); +} + +static int sdhci_cmdq_init(struct sdhci_host *host, struct mmc_host *mmc, + bool dma64) +{ + return cmdq_init(host->cq_host, mmc, dma64); +} + +static void sdhci_cmdq_set_block_size(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_set_blk_size_reg(host, 512, 0); +} + +static void sdhci_cmdq_clear_set_dumpregs(struct mmc_host *mmc, bool set) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (host->ops->clear_set_dumpregs) + host->ops->clear_set_dumpregs(host, set); +} +#else +static void sdhci_cmdq_clear_set_irqs(struct mmc_host *mmc, bool clear) +{ + +} + +static void sdhci_cmdq_set_data_timeout(struct mmc_host *mmc, u32 val) +{ + +} + +static void sdhci_cmdq_dump_vendor_regs(struct mmc_host *mmc) +{ + +} + +static int sdhci_cmdq_init(struct sdhci_host *host, struct mmc_host *mmc, + bool dma64) +{ + return -ENOSYS; +} + +static void sdhci_cmdq_set_block_size(struct mmc_host *mmc) +{ + +} + +static void sdhci_cmdq_clear_set_dumpregs(struct mmc_host *mmc, bool set) +{ + +} + +#endif + +static const struct cmdq_host_ops sdhci_cmdq_ops = { + .clear_set_irqs = sdhci_cmdq_clear_set_irqs, + .set_data_timeout = sdhci_cmdq_set_data_timeout, + .dump_vendor_regs = sdhci_cmdq_dump_vendor_regs, + .set_block_size = sdhci_cmdq_set_block_size, + .clear_set_dumpregs = sdhci_cmdq_clear_set_dumpregs, +}; + int sdhci_add_host(struct sdhci_host *host) { struct mmc_host *mmc; @@ -3861,11 +3985,25 @@ int sdhci_add_host(struct sdhci_host *host) sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } - pr_info("%s: SDHCI controller on %s [%s] using %s\n", - mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), + if (mmc->caps2 & MMC_CAP2_CMD_QUEUE) { + bool dma64 = (host->flags & SDHCI_USE_ADMA_64BIT) ? + true : false; + ret = sdhci_cmdq_init(host, mmc, dma64); + if (ret) + pr_err("%s: CMDQ init: failed (%d)\n", + mmc_hostname(host->mmc), ret); + else + host->cq_host->ops = &sdhci_cmdq_ops; + } + + pr_info("%s: SDHCI controller on %s [%s] using %s in %s mode\n", + mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), (host->flags & SDHCI_USE_ADMA) ? - (host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" : - (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); + ((host->flags & SDHCI_USE_ADMA_64BIT) ? + "64-bit ADMA" : "32-bit ADMA") : + ((host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"), + ((mmc->caps2 & MMC_CAP2_CMD_QUEUE) && !ret) ? + "CMDQ" : "legacy"); sdhci_enable_card_detection(host); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 8c033f7b2cf9..5e99cf53e3d2 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -153,6 +153,8 @@ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \ SDHCI_INT_BLK_GAP) + +#define SDHCI_INT_CMDQ_EN (0x1 << 14) #define SDHCI_INT_ALL_MASK ((unsigned int)-1) #define SDHCI_AUTO_CMD_ERR 0x3C @@ -528,6 +530,7 @@ struct sdhci_host { #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ #define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */ #define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ +#define SDHCI_USE_ADMA_64BIT (1<<12) /* Host is 64-bit ADMA capable */ #define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */ unsigned int version; /* SDHCI spec. version */ @@ -610,6 +613,8 @@ struct sdhci_host { u32 auto_cmd_err_sts; struct ratelimit_state dbg_dump_rs; + struct cmdq_host *cq_host; + unsigned long private[0] ____cacheline_aligned; }; @@ -657,6 +662,7 @@ struct sdhci_ops { bool enable, u32 type); int (*enable_controller_clock)(struct sdhci_host *host); + void (*clear_set_dumpregs)(struct sdhci_host *host, bool set); void (*dump_vendor_regs)(struct sdhci_host *host); void (*toggle_cdr)(struct sdhci_host *host, bool enable); void (*voltage_switch)(struct sdhci_host *host); |
