mmc: rk_sdmmc: do more timeout recovery operation
authorShawn Lin <shawn.lin@rock-chips.com>
Fri, 22 May 2015 08:08:48 +0000 (16:08 +0800)
committerShawn Lin <shawn.lin@rock-chips.com>
Fri, 22 May 2015 08:19:59 +0000 (16:19 +0800)
  We stop slaver and rebank our setting for better
compatibility.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Reviewed-by: Roger Hu <roger.hu@rock-chips.com>
Tested-by: Allen Lee <allen.lee@rock-chips.com>
cc: Xiao yao <xiaoyao@rock-chips.com>

drivers/mmc/host/rk_sdmmc.c

index 10e358434072700e043fbba51aec9063b663d2c7..a1faf72ca00dfeb01bdd981ca959d0e85e7d9419 100755 (executable)
@@ -2038,9 +2038,96 @@ static void dw_mci_post_tmo(struct mmc_host *mmc)
 {
        struct dw_mci_slot *slot = mmc_priv(mmc);
        struct dw_mci *host = slot->host;
+       struct mmc_data *data;
+       u32 ret, i, regs, cmd_flags;
+       u32 sdio_int;
+       unsigned long timeout = 0;
+       bool ret_timeout = true;
+
        host->cur_slot->mrq = NULL;
        host->mrq = NULL;
        host->state = STATE_IDLE;
+
+       data = host->data;
+
+       printk("[%s] -- Timeout recovery procedure start --\n",
+               mmc_hostname(host->mmc));
+
+       if (data && (data->stop)) {
+               send_stop_cmd(host, data);
+       } else {
+               mci_writel(host, CMDARG, 0);
+               wmb();
+               cmd_flags = SDMMC_CMD_STOP | SDMMC_CMD_RESP_CRC |
+                       SDMMC_CMD_RESP_EXP | MMC_STOP_TRANSMISSION;
+
+               if (host->mmc->hold_reg_flag)
+                       cmd_flags |= SDMMC_CMD_USE_HOLD_REG;
+
+               mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
+               wmb();
+               timeout = jiffies + msecs_to_jiffies(500);
+
+               while(ret_timeout) {
+                       ret_timeout = time_before(jiffies, timeout);
+                       if(!(mci_readl(host, CMD) & SDMMC_CMD_START))
+                               break;
+               }
+
+               if (false == ret_timeout)
+                       MMC_DBG_ERR_FUNC(host->mmc, "stop recovery failed![%s]",
+                                       mmc_hostname(host->mmc));
+       }
+
+       if (!dw_mci_ctrl_all_reset(host)) {
+               ret = -ENODEV;
+               return ;
+       }
+
+#ifdef CONFIG_MMC_DW_IDMAC
+       if (host->use_dma && host->dma_ops->init)
+               host->dma_ops->init(host);
+#endif
+
+       /*
+       * Restore the initial value at FIFOTH register
+       * And Invalidate the prev_blksz with zero
+       */
+       mci_writel(host, FIFOTH, host->fifoth_val);
+       host->prev_blksz = 0;
+       mci_writel(host, TMOUT, 0xFFFFFFFF);
+       mci_writel(host, RINTSTS, 0xFFFFFFFF);
+       regs = SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | SDMMC_INT_TXDR
+                       | SDMMC_INT_RXDR | SDMMC_INT_VSI | DW_MCI_ERROR_FLAGS;
+       if (!(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO))
+               regs |= SDMMC_INT_CD;
+
+       if ((host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO)) {
+               if (host->verid < DW_MMC_240A)
+                       sdio_int = SDMMC_INT_SDIO(0);
+               else
+                       sdio_int = SDMMC_INT_SDIO(8);
+
+               if (mci_readl(host, INTMASK) & sdio_int)
+                       regs |= sdio_int;
+       }
+
+       mci_writel(host, INTMASK, regs);
+       mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
+       for (i = 0; i < host->num_slots; i++) {
+               struct dw_mci_slot *slot = host->slot[i];
+               if (!slot)
+                       continue;
+               if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
+                       dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
+                       dw_mci_setup_bus(slot, true);
+               }
+       }
+       mci_writel(host, RINTSTS, 0xFFFFFFFF);
+
+       printk("[%s] -- Timeout recovery procedure finished --\n",
+               mmc_hostname(host->mmc));
+
 }
 
 static const struct mmc_host_ops dw_mci_ops = {