mmc: dw_mmc: Allow lower TMOUT value than maximum
authorMårten Lindahl <marten.lindahl@axis.com>
Fri, 19 Nov 2021 15:53:37 +0000 (16:53 +0100)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 14 Dec 2021 20:35:25 +0000 (21:35 +0100)
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>
drivers/mmc/host/dw_mmc.c

index 439080fbd87d883e6d58e6e77439b9ac1bd72eaa..195f2b2434b0ee6fdb7cd1a805e760171359df77 100644 (file)
@@ -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);
        }