diff options
author | Marek Vasut <marex@denx.de> | 2019-03-23 03:32:24 +0100 |
---|---|---|
committer | Marek Vasut <marex@denx.de> | 2019-04-29 10:08:56 +0200 |
commit | 4e16f0a67d80b4ce11995b870b5d9c8d11266d0d (patch) | |
tree | 06887e6d5010746adb8382529d5076d6beb74ee6 /drivers/mmc/dw_mmc.c | |
parent | 72c347ced8c09f8a61452c884e992c444f555fe2 (diff) | |
download | u-boot-4e16f0a67d80b4ce11995b870b5d9c8d11266d0d.tar.gz |
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/dw_mmc.c')
-rw-r--r-- | drivers/mmc/dw_mmc.c | 24 |
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. */ |