]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/mmc/host/mtk-sd.c
Merge remote-tracking branch 'sound-current/for-linus'
[karo-tx-linux.git] / drivers / mmc / host / mtk-sd.c
index 7153500dd0071bc98da0951299463d2b80d26111..39568cc29a2a18cf752141dcf6233746b4d149e1 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 
 #include <linux/mmc/card.h>
@@ -64,6 +65,7 @@
 #define SDC_RESP2        0x48
 #define SDC_RESP3        0x4c
 #define SDC_BLK_NUM      0x50
+#define EMMC_IOCON       0x7c
 #define SDC_ACMD_RESP    0x80
 #define MSDC_DMA_SA      0x90
 #define MSDC_DMA_CTRL    0x98
@@ -71,6 +73,8 @@
 #define MSDC_PATCH_BIT   0xb0
 #define MSDC_PATCH_BIT1  0xb4
 #define MSDC_PAD_TUNE    0xec
+#define PAD_DS_TUNE      0x188
+#define EMMC50_CFG0      0x208
 
 /*--------------------------------------------------------------------------*/
 /* Register Mask                                                            */
@@ -87,6 +91,7 @@
 #define MSDC_CFG_CKSTB          (0x1 << 7)     /* R  */
 #define MSDC_CFG_CKDIV          (0xff << 8)    /* RW */
 #define MSDC_CFG_CKMOD          (0x3 << 16)    /* RW */
+#define MSDC_CFG_HS400_CK_MODE  (0x1 << 18)    /* RW */
 
 /* MSDC_IOCON mask */
 #define MSDC_IOCON_SDR104CKS    (0x1 << 0)     /* RW */
 #define MSDC_PATCH_BIT_SPCPUSH    (0x1 << 29)  /* RW */
 #define MSDC_PATCH_BIT_DECRCTMO   (0x1 << 30)  /* RW */
 
+#define MSDC_PAD_TUNE_DATRRDLY   (0x1f <<  8)  /* RW */
+#define MSDC_PAD_TUNE_CMDRDLY    (0x1f << 16)  /* RW */
+
+#define PAD_DS_TUNE_DLY1         (0x1f << 2)   /* RW */
+#define PAD_DS_TUNE_DLY2         (0x1f << 7)   /* RW */
+#define PAD_DS_TUNE_DLY3         (0x1f << 12)  /* RW */
+
+#define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0)   /* RW */
+#define EMMC50_CFG_CRCSTS_EDGE    (0x1 << 3)   /* RW */
+#define EMMC50_CFG_CFCSTS_SEL     (0x1 << 4)   /* RW */
+
 #define REQ_CMD_EIO  (0x1 << 0)
 #define REQ_CMD_TMO  (0x1 << 1)
 #define REQ_DAT_ERR  (0x1 << 2)
 #define CMD_TIMEOUT         (HZ/10 * 5)        /* 100ms x5 */
 #define DAT_TIMEOUT         (HZ    * 5)        /* 1000ms x5 */
 
+#define PAD_DELAY_MAX  32 /* PAD delay cells */
 /*--------------------------------------------------------------------------*/
 /* Descriptor Structure                                                     */
 /*--------------------------------------------------------------------------*/
@@ -265,6 +282,14 @@ struct msdc_save_para {
        u32 pad_tune;
        u32 patch_bit0;
        u32 patch_bit1;
+       u32 pad_ds_tune;
+       u32 emmc50_cfg0;
+};
+
+struct msdc_delay_phase {
+       u8 maxlen;
+       u8 start;
+       u8 final_phase;
 };
 
 struct msdc_host {
@@ -297,8 +322,9 @@ struct msdc_host {
        u32 mclk;               /* mmc subsystem clock frequency */
        u32 src_clk_freq;       /* source clock frequency */
        u32 sclk;               /* SD/MS bus clock frequency */
-       bool ddr;
+       unsigned char timing;
        bool vqmmc_enabled;
+       u32 hs400_ds_delay;
        struct msdc_save_para save_para; /* used when gate HCLK */
 };
 
@@ -353,7 +379,10 @@ static void msdc_reset_hw(struct msdc_host *host)
 static void msdc_cmd_next(struct msdc_host *host,
                struct mmc_request *mrq, struct mmc_command *cmd);
 
-static u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO |
+static const u32 cmd_ints_mask = MSDC_INTEN_CMDRDY | MSDC_INTEN_RSPCRCERR |
+                       MSDC_INTEN_CMDTMO | MSDC_INTEN_ACMDRDY |
+                       MSDC_INTEN_ACMDCRCERR | MSDC_INTEN_ACMDTMO;
+static const u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO |
                        MSDC_INTEN_DATCRCERR | MSDC_INTEN_DMA_BDCSERR |
                        MSDC_INTEN_DMA_GPDCSERR | MSDC_INTEN_DMA_PROTECT;
 
@@ -485,7 +514,7 @@ static void msdc_ungate_clock(struct msdc_host *host)
                cpu_relax();
 }
 
-static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
+static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
 {
        u32 mode;
        u32 flags;
@@ -501,8 +530,15 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
 
        flags = readl(host->base + MSDC_INTEN);
        sdr_clr_bits(host->base + MSDC_INTEN, flags);
-       if (ddr) { /* may need to modify later */
-               mode = 0x2; /* ddr mode and use divisor */
+       sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_HS400_CK_MODE);
+       if (timing == MMC_TIMING_UHS_DDR50 ||
+           timing == MMC_TIMING_MMC_DDR52 ||
+           timing == MMC_TIMING_MMC_HS400) {
+               if (timing == MMC_TIMING_MMC_HS400)
+                       mode = 0x3;
+               else
+                       mode = 0x2; /* ddr mode and use divisor */
+
                if (hz >= (host->src_clk_freq >> 2)) {
                        div = 0; /* mean div = 1/4 */
                        sclk = host->src_clk_freq >> 2; /* sclk = clk / 4 */
@@ -511,6 +547,14 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
                        sclk = (host->src_clk_freq >> 2) / div;
                        div = (div >> 1);
                }
+
+               if (timing == MMC_TIMING_MMC_HS400 &&
+                   hz >= (host->src_clk_freq >> 1)) {
+                       sdr_set_bits(host->base + MSDC_CFG,
+                                    MSDC_CFG_HS400_CK_MODE);
+                       sclk = host->src_clk_freq >> 1;
+                       div = 0; /* div is ignore when bit18 is set */
+               }
        } else if (hz >= host->src_clk_freq) {
                mode = 0x1; /* no divisor */
                div = 0;
@@ -532,12 +576,12 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
                cpu_relax();
        host->sclk = sclk;
        host->mclk = hz;
-       host->ddr = ddr;
+       host->timing = timing;
        /* need because clk changed. */
        msdc_set_timeout(host, host->timeout_ns, host->timeout_clks);
        sdr_set_bits(host->base + MSDC_INTEN, flags);
 
-       dev_dbg(host->dev, "sclk: %d, ddr: %d\n", host->sclk, ddr);
+       dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->sclk, timing);
 }
 
 static inline u32 msdc_cmd_find_resp(struct msdc_host *host,
@@ -725,11 +769,7 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
        if (done)
                return true;
 
-       sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY |
-                       MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO |
-                       MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR |
-                       MSDC_INTEN_ACMDTMO);
-       writel(cmd->arg, host->base + SDC_ARG);
+       sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
 
        if (cmd->flags & MMC_RSP_PRESENT) {
                if (cmd->flags & MMC_RSP_136) {
@@ -819,10 +859,7 @@ static void msdc_start_command(struct msdc_host *host,
        rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
        mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
 
-       sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY |
-                       MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO |
-                       MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR |
-                       MSDC_INTEN_ACMDTMO);
+       sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
        writel(cmd->arg, host->base + SDC_ARG);
        writel(rawcmd, host->base + SDC_CMD);
 }
@@ -896,7 +933,7 @@ static void msdc_data_xfer_next(struct msdc_host *host,
                                struct mmc_request *mrq, struct mmc_data *data)
 {
        if (mmc_op_multi(mrq->cmd->opcode) && mrq->stop && !mrq->stop->error &&
-           (!data->bytes_xfered || !mrq->sbc))
+           !mrq->sbc)
                msdc_start_command(host, mrq, mrq->stop);
        else
                msdc_request_done(host, mrq);
@@ -942,6 +979,8 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
 
                        if (events & MSDC_INT_DATTMO)
                                data->error = -ETIMEDOUT;
+                       else if (events & MSDC_INT_DATCRCERR)
+                               data->error = -EILSEQ;
 
                        dev_err(host->dev, "%s: cmd=%d; blocks=%d",
                                __func__, mrq->cmd->opcode, data->blocks);
@@ -1113,10 +1152,12 @@ static void msdc_init_hw(struct msdc_host *host)
 
        writel(0, host->base + MSDC_PAD_TUNE);
        writel(0, host->base + MSDC_IOCON);
-       sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 1);
-       writel(0x403c004f, host->base + MSDC_PATCH_BIT);
+       sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
+       writel(0x403c0046, host->base + MSDC_PATCH_BIT);
        sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL, 1);
        writel(0xffff0089, host->base + MSDC_PATCH_BIT1);
+       sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL);
+
        /* Configure to enable SDIO mode.
         * it's must otherwise sdio cmd5 failed
         */
@@ -1148,11 +1189,14 @@ static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma)
        struct mt_bdma_desc *bd = dma->bd;
        int i;
 
-       memset(gpd, 0, sizeof(struct mt_gpdma_desc));
+       memset(gpd, 0, sizeof(struct mt_gpdma_desc) * 2);
 
        gpd->gpd_info = GPDMA_DESC_BDP; /* hwo, cs, bd pointer */
        gpd->ptr = (u32)dma->bd_addr; /* physical address */
-
+       /* gpd->next is must set for desc DMA
+        * That's why must alloc 2 gpd structure.
+        */
+       gpd->next = (u32)dma->gpd_addr + sizeof(struct mt_gpdma_desc);
        memset(bd, 0, sizeof(struct mt_bdma_desc) * MAX_BD_NUM);
        for (i = 0; i < (MAX_BD_NUM - 1); i++)
                bd[i].next = (u32)dma->bd_addr + sizeof(*bd) * (i + 1);
@@ -1162,20 +1206,16 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct msdc_host *host = mmc_priv(mmc);
        int ret;
-       u32 ddr = 0;
 
        pm_runtime_get_sync(host->dev);
 
-       if (ios->timing == MMC_TIMING_UHS_DDR50 ||
-           ios->timing == MMC_TIMING_MMC_DDR52)
-               ddr = 1;
-
        msdc_set_buswidth(host, ios->bus_width);
 
        /* Suspend/Resume will do power off/on */
        switch (ios->power_mode) {
        case MMC_POWER_UP:
                if (!IS_ERR(mmc->supply.vmmc)) {
+                       msdc_init_hw(host);
                        ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
                                        ios->vdd);
                        if (ret) {
@@ -1206,14 +1246,207 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                break;
        }
 
-       if (host->mclk != ios->clock || host->ddr != ddr)
-               msdc_set_mclk(host, ddr, ios->clock);
+       if (host->mclk != ios->clock || host->timing != ios->timing)
+               msdc_set_mclk(host, ios->timing, ios->clock);
 
 end:
        pm_runtime_mark_last_busy(host->dev);
        pm_runtime_put_autosuspend(host->dev);
 }
 
+static u32 test_delay_bit(u32 delay, u32 bit)
+{
+       bit %= PAD_DELAY_MAX;
+       return delay & (1 << bit);
+}
+
+static int get_delay_len(u32 delay, u32 start_bit)
+{
+       int i;
+
+       for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) {
+               if (test_delay_bit(delay, start_bit + i) == 0)
+                       return i;
+       }
+       return PAD_DELAY_MAX - start_bit;
+}
+
+static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
+{
+       int start = 0, len = 0;
+       int start_final = 0, len_final = 0;
+       u8 final_phase = 0xff;
+       struct msdc_delay_phase delay_phase;
+
+       if (delay == 0) {
+               dev_err(host->dev, "phase error: [map:%x]\n", delay);
+               delay_phase.final_phase = final_phase;
+               return delay_phase;
+       }
+
+       while (start < PAD_DELAY_MAX) {
+               len = get_delay_len(delay, start);
+               if (len_final < len) {
+                       start_final = start;
+                       len_final = len;
+               }
+               start += len ? len : 1;
+               if (len >= 8 && start_final < 4)
+                       break;
+       }
+
+       /* The rule is that to find the smallest delay cell */
+       if (start_final == 0)
+               final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX;
+       else
+               final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX;
+       dev_info(host->dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n",
+                delay, len_final, final_phase);
+
+       delay_phase.maxlen = len_final;
+       delay_phase.start = start_final;
+       delay_phase.final_phase = final_phase;
+       return delay_phase;
+}
+
+static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
+{
+       struct msdc_host *host = mmc_priv(mmc);
+       u32 rise_delay = 0, fall_delay = 0;
+       struct msdc_delay_phase final_rise_delay, final_fall_delay;
+       u8 final_delay, final_maxlen;
+       int cmd_err;
+       int i;
+
+       sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+       for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+               sdr_set_field(host->base + MSDC_PAD_TUNE,
+                             MSDC_PAD_TUNE_CMDRDLY, i);
+               mmc_send_tuning(mmc, opcode, &cmd_err);
+               if (!cmd_err)
+                       rise_delay |= (1 << i);
+       }
+
+       sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+       for (i = 0; i < PAD_DELAY_MAX; i++) {
+               sdr_set_field(host->base + MSDC_PAD_TUNE,
+                             MSDC_PAD_TUNE_CMDRDLY, i);
+               mmc_send_tuning(mmc, opcode, &cmd_err);
+               if (!cmd_err)
+                       fall_delay |= (1 << i);
+       }
+
+       final_rise_delay = get_best_delay(host, rise_delay);
+       final_fall_delay = get_best_delay(host, fall_delay);
+
+       final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
+       if (final_maxlen == final_rise_delay.maxlen) {
+               sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+               sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+                             final_rise_delay.final_phase);
+               final_delay = final_rise_delay.final_phase;
+       } else {
+               sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+               sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+                             final_fall_delay.final_phase);
+               final_delay = final_fall_delay.final_phase;
+       }
+
+       return final_delay == 0xff ? -EIO : 0;
+}
+
+static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
+{
+       struct msdc_host *host = mmc_priv(mmc);
+       u32 rise_delay = 0, fall_delay = 0;
+       struct msdc_delay_phase final_rise_delay, final_fall_delay;
+       u8 final_delay, final_maxlen;
+       int i, ret;
+
+       sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+       sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+       for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+               sdr_set_field(host->base + MSDC_PAD_TUNE,
+                             MSDC_PAD_TUNE_DATRRDLY, i);
+               ret = mmc_send_tuning(mmc, opcode, NULL);
+               if (!ret)
+                       rise_delay |= (1 << i);
+       }
+
+       sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+       sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+       for (i = 0; i < PAD_DELAY_MAX; i++) {
+               sdr_set_field(host->base + MSDC_PAD_TUNE,
+                             MSDC_PAD_TUNE_DATRRDLY, i);
+               ret = mmc_send_tuning(mmc, opcode, NULL);
+               if (!ret)
+                       fall_delay |= (1 << i);
+       }
+
+       final_rise_delay = get_best_delay(host, rise_delay);
+       final_fall_delay = get_best_delay(host, fall_delay);
+
+       final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
+       /* Rising edge is more stable, prefer to use it */
+       if (final_rise_delay.maxlen >= 10)
+               final_maxlen = final_rise_delay.maxlen;
+       if (final_maxlen == final_rise_delay.maxlen) {
+               sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+               sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+               sdr_set_field(host->base + MSDC_PAD_TUNE,
+                             MSDC_PAD_TUNE_DATRRDLY,
+                             final_rise_delay.final_phase);
+               final_delay = final_rise_delay.final_phase;
+       } else {
+               sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+               sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+               sdr_set_field(host->base + MSDC_PAD_TUNE,
+                             MSDC_PAD_TUNE_DATRRDLY,
+                             final_fall_delay.final_phase);
+               final_delay = final_fall_delay.final_phase;
+       }
+
+       return final_delay == 0xff ? -EIO : 0;
+}
+
+static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+       struct msdc_host *host = mmc_priv(mmc);
+       int ret;
+
+       pm_runtime_get_sync(host->dev);
+       ret = msdc_tune_response(mmc, opcode);
+       if (ret == -EIO) {
+               dev_err(host->dev, "Tune response fail!\n");
+               goto out;
+       }
+       ret = msdc_tune_data(mmc, opcode);
+       if (ret == -EIO)
+               dev_err(host->dev, "Tune data fail!\n");
+
+out:
+       pm_runtime_mark_last_busy(host->dev);
+       pm_runtime_put_autosuspend(host->dev);
+       return ret;
+}
+
+static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct msdc_host *host = mmc_priv(mmc);
+
+       writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE);
+       return 0;
+}
+
+static void msdc_hw_reset(struct mmc_host *mmc)
+{
+       struct msdc_host *host = mmc_priv(mmc);
+
+       sdr_set_bits(host->base + EMMC_IOCON, 1);
+       udelay(10); /* 10us is enough */
+       sdr_clr_bits(host->base + EMMC_IOCON, 1);
+}
+
 static struct mmc_host_ops mt_msdc_ops = {
        .post_req = msdc_post_req,
        .pre_req = msdc_pre_req,
@@ -1221,6 +1454,9 @@ static struct mmc_host_ops mt_msdc_ops = {
        .set_ios = msdc_ops_set_ios,
        .start_signal_voltage_switch = msdc_ops_switch_volt,
        .card_busy = msdc_card_busy,
+       .execute_tuning = msdc_execute_tuning,
+       .prepare_hs400_tuning = msdc_prepare_hs400_tuning,
+       .hw_reset = msdc_hw_reset,
 };
 
 static int msdc_drv_probe(struct platform_device *pdev)
@@ -1294,6 +1530,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
                goto host_free;
        }
 
+       if (!of_property_read_u32(pdev->dev.of_node, "hs400-ds-delay",
+                                 &host->hs400_ds_delay))
+               dev_dbg(&pdev->dev, "hs400-ds-delay: %x\n",
+                       host->hs400_ds_delay);
+
        host->dev = &pdev->dev;
        host->mmc = mmc;
        host->src_clk_freq = clk_get_rate(host->src_clk);
@@ -1302,6 +1543,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
        mmc->f_min = host->src_clk_freq / (4 * 255);
 
        mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
+       mmc->caps |= MMC_CAP_RUNTIME_RESUME;
        /* MMC core transfer sizes tunable parameters */
        mmc->max_segs = MAX_BD_NUM;
        mmc->max_seg_size = BDMA_DESC_BUFLEN;
@@ -1313,7 +1555,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
 
        host->timeout_clks = 3 * 1048576;
        host->dma.gpd = dma_alloc_coherent(&pdev->dev,
-                               sizeof(struct mt_gpdma_desc),
+                               2 * sizeof(struct mt_gpdma_desc),
                                &host->dma.gpd_addr, GFP_KERNEL);
        host->dma.bd = dma_alloc_coherent(&pdev->dev,
                                MAX_BD_NUM * sizeof(struct mt_bdma_desc),
@@ -1354,7 +1596,7 @@ release:
 release_mem:
        if (host->dma.gpd)
                dma_free_coherent(&pdev->dev,
-                       sizeof(struct mt_gpdma_desc),
+                       2 * sizeof(struct mt_gpdma_desc),
                        host->dma.gpd, host->dma.gpd_addr);
        if (host->dma.bd)
                dma_free_coherent(&pdev->dev,
@@ -1403,6 +1645,8 @@ static void msdc_save_reg(struct msdc_host *host)
        host->save_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
        host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT);
        host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1);
+       host->save_para.pad_ds_tune = readl(host->base + PAD_DS_TUNE);
+       host->save_para.emmc50_cfg0 = readl(host->base + EMMC50_CFG0);
 }
 
 static void msdc_restore_reg(struct msdc_host *host)
@@ -1413,6 +1657,8 @@ static void msdc_restore_reg(struct msdc_host *host)
        writel(host->save_para.pad_tune, host->base + MSDC_PAD_TUNE);
        writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT);
        writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1);
+       writel(host->save_para.pad_ds_tune, host->base + PAD_DS_TUNE);
+       writel(host->save_para.emmc50_cfg0, host->base + EMMC50_CFG0);
 }
 
 static int msdc_runtime_suspend(struct device *dev)