mmc: dw_mmc: Calculate timeout from transfer length

The current 4-minute data transfer timeout is misleading and broken.
Instead of such a long wait, calculate the timeout duration based on
the length of the data transfer. The current formula is the transfer
length in bits, divided by a multiplication of bus frequency in Hz,
bus width, DDR mode and converted the mSec. The value is bounded from
the bottom to 1000 mSec.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Jaehoon Chung <jh80.chung@samsung.com>
Cc: Simon Glass <sjg@chromium.org>
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 93a836e..d4976ac 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -114,22 +114,40 @@
 	return 0;
 }
 
+static unsigned int dwmci_get_timeout(struct mmc *mmc, const unsigned int size)
+{
+	unsigned int timeout;
+
+	timeout = size * 8 * 1000;	/* counting in bits and msec */
+	timeout *= 2;			/* wait twice as long */
+	timeout /= mmc->clock;
+	timeout /= mmc->bus_width;
+	timeout /= mmc->ddr_mode ? 2 : 1;
+	timeout = (timeout < 1000) ? 1000 : timeout;
+
+	return timeout;
+}
+
 static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 {
+	struct mmc *mmc = host->mmc;
 	int ret = 0;
-	u32 timeout = 240000;
-	u32 mask, size, i, len = 0;
+	u32 timeout, mask, size, i, len = 0;
 	u32 *buf = NULL;
 	ulong start = get_timer(0);
 	u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >>
 			    RX_WMARK_SHIFT) + 1) * 2;
 
-	size = data->blocksize * data->blocks / 4;
+	size = data->blocksize * data->blocks;
 	if (data->flags == MMC_DATA_READ)
 		buf = (unsigned int *)data->dest;
 	else
 		buf = (unsigned int *)data->src;
 
+	timeout = dwmci_get_timeout(mmc, size);
+
+	size /= 4;
+
 	for (;;) {
 		mask = dwmci_readl(host, DWMCI_RINTSTS);
 		/* Error during data transfer. */