Re: [RFC PATCH] mmc: dw_mmc: add status check before clock update

Alim Akhtar
2015-02-10T14:54:49Z

Hi Andrzej,

On Tue, Feb 10, 2015 at 7:59 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
> According to specs for version 250A, status register should be
> tested before clock update. Otherwise in case MMC card is missing
> mci_send_cmd timeouts and subsequent CTYPE registry write causes system hang.
> This behavior has been observed on Exynos5422/Odroid-XU3.
>
A similar patch was posted recently[1], did you check that?
[1] http://www.spinics.net/lists/linux-doc/msg28092.html

> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> ---
> Hi,
>
> This version corrects usleep to usleep_range function call.
>
> Regards
> Andrzej
> ---
> drivers/mmc/host/dw_mmc.c | 26 ++++++++++++++++++++++++--
> drivers/mmc/host/dw_mmc.h | 1 +
> 2 files changed, 25 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 67c0451..6619c8a 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -878,6 +878,25 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
> cmd, arg, cmd_status);
> }
>
> +static bool dw_mci_wait_busy(struct dw_mci *host)
> +{
> + unsigned long timeout;
> +
> + if (host->verid < DW_MMC_250A)
> + return true;
> +
I wonder this might be true for 240A as well.

> + timeout = jiffies + msecs_to_jiffies(500);
> + while (time_before(jiffies, timeout)) {
> + if (!(mci_readl(host, STATUS) & SDMMC_STATUS_BUSY))
> + return true;
> +
> + usleep_range(1000, 2000);
> + }
> + dev_err(host->dev, "Busy timeout\n");
Probably you need a controller reset here to bring back controller is
original state.
> +
> + return false;
> +}
> +
> static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
> {
> struct dw_mci *host = slot->host;
> @@ -891,8 +910,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
> sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
>
> if (!clock) {
> - mci_writel(host, CLKENA, 0);
> - mci_send_cmd(slot, sdmmc_cmd_bits, 0);
> + if (dw_mci_wait_busy(host)) {
> + mci_writel(host, CLKENA, 0);
> + mci_send_cmd(slot, sdmmc_cmd_bits, 0);
> + } else
> + return;
> } else if (clock != host->current_speed || force_clkinit) {
> div = host->bus_hz / clock;
> if (host->bus_hz % clock && host->bus_hz > clock)
> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> index 0d0f7a27..ea6d4d1 100644
> --- a/drivers/mmc/host/dw_mmc.h
> +++ b/drivers/mmc/host/dw_mmc.h
> @@ -15,6 +15,7 @@
> #define _DW_MMC_H_
>
> #define DW_MMC_240A 0x240a
> +#define DW_MMC_250A 0x250a
>
> #define SDMMC_CTRL 0x000
> #define SDMMC_PWREN 0x004
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html

--
Regards,
Alim