mmc: host: rk_sdmmc:
authorlin tao <lt@mid-server3.(none)>
Fri, 13 Jun 2014 07:23:50 +0000 (15:23 +0800)
committerlin tao <lt@mid-server3.(none)>
Fri, 13 Jun 2014 07:26:10 +0000 (15:26 +0800)
verid: 270A, Complete H/W Reset programming sequence.

drivers/mmc/host/rk_sdmmc.c

index 06cdc5e8e35f89c8bd93de894efed83d6598c346..9424eb43414c1e68c6c26a71e56a5b457b2012d3 100755 (executable)
@@ -1371,23 +1371,93 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
 
 static void dw_mci_hw_reset(struct mmc_host *mmc)
 {
-    struct dw_mci_slot *slot = mmc_priv(mmc);
+        struct dw_mci_slot *slot = mmc_priv(mmc);
+        struct dw_mci *host = slot->host;
+        u32 cmd_flags, timeout, regs;
+        bool ret = true;
 
-    /* 
-     * According to eMMC spec 
-     * tRstW >= 1us ;   RST_n pulse width
-     * tRSCA >= 200us ; RST_n to Command time
-     * tRSTH >= 1us ;   RST_n high period
-     */
+        /* (1) CMD12 to end any transfer in process */
+        cmd_flags = SDMMC_CMD_STOP | SDMMC_CMD_RESP_CRC
+                       | SDMMC_CMD_RESP_EXP | MMC_STOP_TRANSMISSION;
 
-    mci_writel(slot->host, RST_n, 0x1);
-    dsb();
-    udelay(10); //10us for bad quality eMMc.
+       if(host->mmc->hold_reg_flag)
+               cmd_flags |= SDMMC_CMD_USE_HOLD_REG;
+       mci_writel(host, CMDARG, 0);
+       wmb();
+       mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
+       wmb();
+       timeout = jiffies + msecs_to_jiffies(500);
+       while(ret){
+                ret = time_before(jiffies, timeout);
+                if(!(mci_readl(host, CMD) & SDMMC_CMD_START))
+                        break;
+       }
+       
+       if(false == ret)
+               MMC_DBG_ERR_FUNC(host->mmc,
+                       "%s dw_mci_hw_reset: STOP_TRANSMISSION failed!!! [%s]\n",
+                       __func__, mmc_hostname(host->mmc));
+
+       /* (2) wait DTO, even if no response is sent back by card */
+       ret = true;
+       timeout = jiffies + msecs_to_jiffies(5);
+       while(ret){
+               ret = time_before(jiffies, timeout);
+               if(!(mci_readl(host, MINTSTS) & SDMMC_INT_DATA_OVER)){
+                       mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
+                       break;
+               }
+       }
 
-    mci_writel(slot->host, RST_n, 0x0);
-    dsb();
-    usleep_range(300, 1000); //ay least 300(> 200us)
-    
+       /* (3) Reset following: DONNOT CHANGE RESET ORDER!*/
+
+       /* Software reset - BMOD[0] for IDMA only */
+       regs = mci_readl(host, BMOD);
+       regs |= SDMMC_IDMAC_SWRESET;
+       mci_writel(host, BMOD, regs);
+       udelay(1); /* Auto cleared after 1 cycle, 1us is enough for hclk_mmc */
+       regs = mci_readl(host, BMOD);
+       if(regs & SDMMC_IDMAC_SWRESET)
+               MMC_DBG_WARN_FUNC(host->mmc,
+                       "%s dw_mci_hw_reset: SDMMC_IDMAC_SWRESET failed!!! [%s]\n",
+                       __func__, mmc_hostname(host->mmc));
+
+       /* DMA reset - CTRL[2] */
+       regs = mci_readl(host, CTRL);
+       regs |= SDMMC_CTRL_DMA_RESET;
+       mci_writel(host, CTRL, regs);
+       udelay(1); /* Auto cleared after 2 AHB clocks, 1us is enough plus mci_readl access */
+       regs = mci_readl(host, CTRL);
+       if(regs & SDMMC_CTRL_DMA_RESET)
+               MMC_DBG_WARN_FUNC(host->mmc,
+                       "%s dw_mci_hw_reset: SDMMC_CTRL_DMA_RESET failed!!! [%s]\n",
+                       __func__, mmc_hostname(host->mmc));
+
+       /* FIFO reset - CTRL[1] */
+       regs = mci_readl(host, CTRL);
+       regs |= SDMMC_CTRL_FIFO_RESET;
+       mci_writel(host, CTRL, regs);
+       mdelay(1); /* no timing limited, 1ms is random value */
+       regs = mci_readl(host, CTRL);
+       if(regs & SDMMC_CTRL_FIFO_RESET)
+               MMC_DBG_WARN_FUNC(host->mmc,
+                       "%s dw_mci_hw_reset: SDMMC_CTRL_DMA_RESET failed!!! [%s]\n",
+                       __func__, mmc_hostname(host->mmc));
+
+       /* (4) CARD_RESET
+       According to eMMC spec
+       tRstW >= 1us ;   RST_n pulse width
+       tRSCA >= 200us ; RST_n to Command time
+       tRSTH >= 1us ;   RST_n high period
+       */
+
+       mci_writel(slot->host, RST_n, 0x1);
+       dsb();
+       udelay(10); /* 10us for bad quality eMMc. */
+
+       mci_writel(slot->host, RST_n, 0x0);
+       dsb();
+       usleep_range(500, 1000); /* at least 500(> 200us) */
 }
 
 /*