diff options
author | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2016-04-07 16:41:46 +0100 |
---|---|---|
committer | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2016-04-07 20:37:13 +0100 |
commit | 0b186dd99e8c42b7c721997c7ac910f89f8d0615 (patch) | |
tree | fa51024bd2463277050962a90e079fa157597ebb | |
parent | 43e5a9f4428d6eac9177979dd8b942d8bba4d752 (diff) |
WIP: mmc: mmci: add qcom specific program end support
This patch adds support to programend interrupt which is very specific
to QCOM integration. This interrupt is use as busy signal when a command
forces the card to enter into programming state like CMD6 writing to
ext_csd registers.
This also fixes the __mmc_switch timeout issue reproted with latest
versions of the eMMC used on DB600c board.
This is just a WIP patch, will be cleaned up soon.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-rw-r--r-- | drivers/mmc/host/mmci.c | 17 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.h | 11 |
2 files changed, 25 insertions, 3 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 2e6c96845c9a6..05aa2b01d09d9 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -814,7 +814,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) datactrl = MCI_DPSM_ENABLE | blksz_bits << 4; if (data->flags & MMC_DATA_READ) - datactrl |= MCI_DPSM_DIRECTION; + datactrl |= MCI_DPSM_DIRECTION | MCI_QCOM_RX_DATA_PEND; if (host->mmc->card && mmc_card_sdio(host->mmc->card)) { u32 clk; @@ -896,6 +896,11 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) if (/*interrupt*/0) c |= MCI_CPSM_INTERRUPT; + if ((cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) { + c |= MCI_QCOM_CSPM_PROGENA; + host->prog_enable = true; + } + if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) c |= host->variant->data_cmd_enable; @@ -990,9 +995,17 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, busy_resp = host->variant->busy_detect && (cmd->flags & MMC_RSP_BUSY); if (!((status|host->busy_status) & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT| - MCI_CMDSENT|MCI_CMDRESPEND))) + MCI_CMDSENT|MCI_CMDRESPEND | MCI_QCOM_PROGDONE))) return; + if (host->prog_enable) { + if(status & MCI_QCOM_PROGDONE) { + host->prog_enable = false; + } else { + return; + } + } + /* Check if we need to wait for busy completion. */ if (host->busy_status && (status & MCI_ST_CARDBUSY)) return; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index a1f5e4f49e2a3..0c8644ae52373 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -64,6 +64,7 @@ #define MCI_ST_CE_ATACMD (1 << 14) /* Modified on Qualcomm Integrations */ +#define MCI_QCOM_CSPM_PROGENA BIT(11) #define MCI_QCOM_CSPM_DATCMD BIT(12) #define MCI_QCOM_CSPM_MCIABORT BIT(13) #define MCI_QCOM_CSPM_CCSENABLE BIT(14) @@ -95,6 +96,9 @@ #define MCI_ST_DPSM_BUSYMODE (1 << 14) #define MCI_ST_DPSM_DDRMODE (1 << 15) +#define MCI_QCOM_DATA_PEND (1 << 17) +#define MCI_QCOM_RX_DATA_PEND (1 << 20) + #define MMCIDATACNT 0x030 #define MMCISTATUS 0x034 #define MCI_CMDCRCFAIL (1 << 0) @@ -124,6 +128,9 @@ #define MCI_ST_CEATAEND (1 << 23) #define MCI_ST_CARDBUSY (1 << 24) +/* Extended status bits for the QCOM variants */ +#define MCI_QCOM_PROGDONE (1 << 23) + #define MMCICLEAR 0x038 #define MCI_CMDCRCFAILCLR (1 << 0) #define MCI_DATACRCFAILCLR (1 << 1) @@ -169,6 +176,7 @@ #define MCI_ST_CEATAENDMASK (1 << 23) #define MCI_ST_BUSYEND (1 << 24) +#define MCI_QCOM_PROGDONEMASK (1 << 23) #define MMCIMASK1 0x040 #define MMCIFIFOCNT 0x048 #define MMCIFIFO 0x080 /* to 0x0bc */ @@ -176,7 +184,7 @@ #define MCI_IRQENABLE \ (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ - MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_STARTBITERRMASK) + MCI_CMDRESPENDMASK| MCI_QCOM_PROGDONEMASK |MCI_CMDSENTMASK|MCI_STARTBITERRMASK) /* These interrupts are directed to IRQ1 when two IRQ lines are available */ #define MCI_IRQ1MASK \ @@ -204,6 +212,7 @@ struct mmci_host { struct mmc_host *mmc; struct clk *clk; bool singleirq; + bool prog_enable; spinlock_t lock; |