summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2019-03-23 03:32:24 +0100
committerMarek Vasut <marex@denx.de>2019-04-29 10:08:56 +0200
commit4e16f0a67d80b4ce11995b870b5d9c8d11266d0d (patch)
tree06887e6d5010746adb8382529d5076d6beb74ee6 /drivers/mmc
parent72c347ced8c09f8a61452c884e992c444f555fe2 (diff)
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>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/dw_mmc.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 93a836eac3..d4976ac879 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -114,22 +114,40 @@ static int dwmci_fifo_ready(struct dwmci_host *host, u32 bit, u32 *len)
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. */