@@ -1082,6 +1082,12 @@ static void sdhci_finish_command(struct sdhci_host *host)
}
}
+static inline void sdhci_set_max_discard_to(struct sdhci_host *host)
+{
+ if (host->timeout_clk)
+ host->mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+}
+
static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{
int div = 0; /* Initialized for compiler warning */
@@ -1094,6 +1100,12 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
host->mmc->actual_clock = 0;
+ if ((host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) && clock) {
+ /* The lowest allowed timeout clock frequency is 1Khz */
+ host->timeout_clk = (clock + 999) / 1000;
+ sdhci_set_max_discard_to(host);
+ }
+
if (host->ops->set_clock) {
host->ops->set_clock(host, clock);
if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
@@ -2828,25 +2840,24 @@ int sdhci_add_host(struct sdhci_host *host)
} else
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
- host->timeout_clk =
- (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
- if (host->timeout_clk == 0) {
- if (host->ops->get_timeout_clock) {
- host->timeout_clk = host->ops->get_timeout_clock(host);
- } else if (!(host->quirks &
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
- pr_err("%s: Hardware doesn't specify timeout clock "
- "frequency.\n", mmc_hostname(mmc));
- return -ENODEV;
+ if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
+ host->timeout_clk = (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >>
+ SDHCI_TIMEOUT_CLK_SHIFT;
+ if (host->timeout_clk == 0) {
+ if (host->ops->get_timeout_clock) {
+ host->timeout_clk =
+ host->ops->get_timeout_clock(host);
+ } else {
+ pr_err("%s: Hardware doesn't specify timeout "
+ "clock frequency.\n", mmc_hostname(mmc));
+ return -ENODEV;
+ }
+ } else if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT) {
+ host->timeout_clk *= 1000;
}
+ sdhci_set_max_discard_to(host);
}
- if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
- host->timeout_clk *= 1000;
-
- if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
- host->timeout_clk = mmc->f_max / 1000;
- mmc->max_discard_to = (1 << 27) / host->timeout_clk;
mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
1. If SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK is selected, getting timeout through register or callback function is useless. So skip current redundant code. 2. If SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK is selected, host uses SDCLK instead of TMCLK for data timeouts. So host->timeout_clk and mmc->max_discard_to should be updated accordingly when SDCLK changed. 3. If callback function get_timeout_clock is used, the timeout clock will be returned directly and no need to multiply by the timeout clock unit read from register. Signed-off-by: Kevin Liu <kliu5@marvell.com> --- drivers/mmc/host/sdhci.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-)