summaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorMårten Lindahl <marten.lindahl@axis.com>2021-11-19 16:53:37 +0100
committerUlf Hansson <ulf.hansson@linaro.org>2021-12-14 21:35:25 +0100
commit6a8c2018e872906dddf34da40ddcac54cd7b967f (patch)
tree0b0b43a2302e0e5b6be8c9bedc04eabc45aad901 /drivers/mmc
parentmmc: core: adjust polling interval for CMD1 (diff)
downloadlinux-6a8c2018e872906dddf34da40ddcac54cd7b967f.tar.xz
linux-6a8c2018e872906dddf34da40ddcac54cd7b967f.zip
mmc: dw_mmc: Allow lower TMOUT value than maximum
The TMOUT register is always set with a full value for every transfer, which (with a 200MHz clock) will give a full DRTO of ~84 milliseconds. This is normally good enough to complete the request, but setting a full value makes it impossible to test shorter timeouts, when for example testing data read times on different SD cards. Add a function to set any value smaller than the maximum of 0xFFFFFF. Signed-off-by: Mårten Lindahl <marten.lindahl@axis.com> Reviewed-by: Douglas Anderson <dianders@chromium.org> Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com> Link: https://lore.kernel.org/r/20211119155337.14341-1-marten.lindahl@axis.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/dw_mmc.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 439080fbd87d..195f2b2434b0 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1284,6 +1284,33 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
mci_writel(host, CTYPE, (slot->ctype << slot->id));
}
+static void dw_mci_set_data_timeout(struct dw_mci *host,
+ unsigned int timeout_ns)
+{
+ u32 clk_div, tmout;
+ u64 tmp;
+
+ clk_div = (mci_readl(host, CLKDIV) & 0xFF) * 2;
+ if (clk_div == 0)
+ clk_div = 1;
+
+ tmp = DIV_ROUND_UP_ULL((u64)timeout_ns * host->bus_hz, NSEC_PER_SEC);
+ tmp = DIV_ROUND_UP_ULL(tmp, clk_div);
+
+ /* TMOUT[7:0] (RESPONSE_TIMEOUT) */
+ tmout = 0xFF; /* Set maximum */
+
+ /* TMOUT[31:8] (DATA_TIMEOUT) */
+ if (!tmp || tmp > 0xFFFFFF)
+ tmout |= (0xFFFFFF << 8);
+ else
+ tmout |= (tmp & 0xFFFFFF) << 8;
+
+ mci_writel(host, TMOUT, tmout);
+ dev_dbg(host->dev, "timeout_ns: %u => TMOUT[31:8]: 0x%#08x",
+ timeout_ns, tmout >> 8);
+}
+
static void __dw_mci_start_request(struct dw_mci *host,
struct dw_mci_slot *slot,
struct mmc_command *cmd)
@@ -1304,7 +1331,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
data = cmd->data;
if (data) {
- mci_writel(host, TMOUT, 0xFFFFFFFF);
+ dw_mci_set_data_timeout(host, data->timeout_ns);
mci_writel(host, BYTCNT, data->blksz*data->blocks);
mci_writel(host, BLKSIZ, data->blksz);
}