data->host_cookie = 0;
 }
 
+static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
+{
+#ifdef CONFIG_MMC_DW_IDMAC
+       unsigned int blksz = data->blksz;
+       const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
+       u32 fifo_width = 1 << host->data_shift;
+       u32 blksz_depth = blksz / fifo_width, fifoth_val;
+       u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
+       int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1;
+
+       tx_wmark = (host->fifo_depth) / 2;
+       tx_wmark_invers = host->fifo_depth - tx_wmark;
+
+       /*
+        * MSIZE is '1',
+        * if blksz is not a multiple of the FIFO width
+        */
+       if (blksz % fifo_width) {
+               msize = 0;
+               rx_wmark = 1;
+               goto done;
+       }
+
+       do {
+               if (!((blksz_depth % mszs[idx]) ||
+                    (tx_wmark_invers % mszs[idx]))) {
+                       msize = idx;
+                       rx_wmark = mszs[idx] - 1;
+                       break;
+               }
+       } while (--idx > 0);
+       /*
+        * If idx is '0', it won't be tried
+        * Thus, initial values are uesed
+        */
+done:
+       fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark);
+       mci_writel(host, FIFOTH, fifoth_val);
+#endif
+}
+
 static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
 {
        int sg_len;
                 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
                 sg_len);
 
+       /*
+        * Decide the MSIZE and RX/TX Watermark.
+        * If current block size is same with previous size,
+        * no need to update fifoth.
+        */
+       if (host->prev_blksz != data->blksz)
+               dw_mci_adjust_fifoth(host, data);
+
        /* Enable the DMA interface */
        temp = mci_readl(host, CTRL);
        temp |= SDMMC_CTRL_DMA_ENABLE;
                temp = mci_readl(host, CTRL);
                temp &= ~SDMMC_CTRL_DMA_ENABLE;
                mci_writel(host, CTRL, temp);
+
+               /*
+                * Use the initial fifoth_val for PIO mode.
+                * If next issued data may be transfered by DMA mode,
+                * prev_blksz should be invalidated.
+                */
+               mci_writel(host, FIFOTH, host->fifoth_val);
+               host->prev_blksz = 0;
+       } else {
+               /*
+                * Keep the current block size.
+                * It will be used to decide whether to update
+                * fifoth register next time.
+                */
+               host->prev_blksz = data->blksz;
        }
 }
 
                fifo_size = host->pdata->fifo_depth;
        }
        host->fifo_depth = fifo_size;
-       host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
-                       ((fifo_size/2) << 0));
+       host->fifoth_val =
+               SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2);
        mci_writel(host, FIFOTH, host->fifoth_val);
 
        /* disable clock to CIU */
        if (host->use_dma && host->dma_ops->init)
                host->dma_ops->init(host);
 
-       /* Restore the old value at FIFOTH register */
+       /*
+        * 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;
 
        /* Put in max timeout */
        mci_writel(host, TMOUT, 0xFFFFFFFF);