From b0e370b95a3b231d0fb5d1958cce85ef57196fe6 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 11 Jun 2019 22:03:43 +0200 Subject: [PATCH 1/3] mmc: core: complete HS400 before checking status We don't have a reproducible error case, yet our BSP team suggested that the mmc_switch_status() command in mmc_select_hs400() should come after the callback into the driver completing HS400 setup. It makes sense to me because we want the status of a fully setup HS400, so it will increase the reliability of the mmc_switch_status() command. Reported-by: Yoshihiro Shimoda Signed-off-by: Wolfram Sang Fixes: ba6c7ac3a2f4 ("mmc: core: more fine-grained hooks for HS400 tuning") Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3e786ba204c3..671bfcceea6a 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1212,13 +1212,13 @@ static int mmc_select_hs400(struct mmc_card *card) mmc_set_timing(host, MMC_TIMING_MMC_HS400); mmc_set_bus_speed(card); + if (host->ops->hs400_complete) + host->ops->hs400_complete(host); + err = mmc_switch_status(card); if (err) goto out_err; - if (host->ops->hs400_complete) - host->ops->hs400_complete(host); - return 0; out_err: From 8a5df8ac628f4febea1e6cd3044bff2d536dd096 Mon Sep 17 00:00:00 2001 From: jjian zhou Date: Mon, 17 Jun 2019 19:04:07 +0800 Subject: [PATCH 2/3] mmc: mediatek: fix SDIO IRQ interrupt handle flow SDIO IRQ is triggered by low level. It need disable SDIO IRQ detected function. Otherwise the interrupt register can't be cleared. It will process the interrupt more. Signed-off-by: Jjian Zhou Signed-off-by: Chaotian Jing Signed-off-by: Yong Mao Fixes: 5215b2e952f3 ("mmc: mediatek: Add MMC_CAP_SDIO_IRQ support") Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 43 +++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 5a6d885994e6..34860f213adb 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1375,24 +1375,25 @@ static void msdc_request_timeout(struct work_struct *work) } } -static void __msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) +static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb) +{ + if (enb) { + sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); + sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); + } else { + sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); + sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); + } +} + +static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) { unsigned long flags; struct msdc_host *host = mmc_priv(mmc); spin_lock_irqsave(&host->lock, flags); - if (enb) - sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); - else - sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); + __msdc_enable_sdio_irq(host, enb); spin_unlock_irqrestore(&host->lock, flags); -} - -static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) -{ - struct msdc_host *host = mmc_priv(mmc); - - __msdc_enable_sdio_irq(mmc, enb); if (enb) pm_runtime_get_noresume(host->dev); @@ -1414,6 +1415,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) spin_lock_irqsave(&host->lock, flags); events = readl(host->base + MSDC_INT); event_mask = readl(host->base + MSDC_INTEN); + if ((events & event_mask) & MSDC_INT_SDIOIRQ) + __msdc_enable_sdio_irq(host, 0); /* clear interrupts */ writel(events & event_mask, host->base + MSDC_INT); @@ -1422,10 +1425,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) data = host->data; spin_unlock_irqrestore(&host->lock, flags); - if ((events & event_mask) & MSDC_INT_SDIOIRQ) { - __msdc_enable_sdio_irq(host->mmc, 0); + if ((events & event_mask) & MSDC_INT_SDIOIRQ) sdio_signal_irq(host->mmc); - } if ((events & event_mask) & MSDC_INT_CDSC) { if (host->internal_cd) @@ -1564,10 +1565,7 @@ static void msdc_init_hw(struct msdc_host *host) sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO); /* Config SDIO device detect interrupt function */ - if (host->mmc->caps & MMC_CAP_SDIO_IRQ) - sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); - else - sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); + sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); /* Configure to default data timeout */ sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3); @@ -2095,7 +2093,12 @@ static void msdc_hw_reset(struct mmc_host *mmc) static void msdc_ack_sdio_irq(struct mmc_host *mmc) { - __msdc_enable_sdio_irq(mmc, 1); + unsigned long flags; + struct msdc_host *host = mmc_priv(mmc); + + spin_lock_irqsave(&host->lock, flags); + __msdc_enable_sdio_irq(host, 1); + spin_unlock_irqrestore(&host->lock, flags); } static int msdc_get_cd(struct mmc_host *mmc) From 20314ce30af197963b0c239f0952db6aaef73f99 Mon Sep 17 00:00:00 2001 From: jjian zhou Date: Mon, 17 Jun 2019 19:04:08 +0800 Subject: [PATCH 3/3] mmc: mediatek: fix SDIO IRQ detection issue If cmd19 timeout or response crcerr occurs during execute_tuning(), it need invoke msdc_reset_hw(). Otherwise SDIO IRQ can't be detected. Signed-off-by: jjian zhou Signed-off-by: Chaotian Jing Signed-off-by: Yong Mao Fixes: 5215b2e952f3 ("mmc: mediatek: Add MMC_CAP_SDIO_IRQ support") Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 34860f213adb..33f4b6387ef7 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1023,6 +1023,8 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) msdc_track_cmd_data(host, mrq->cmd, mrq->data); if (mrq->data) msdc_unprepare_data(host, mrq); + if (host->error) + msdc_reset_hw(host); mmc_request_done(host->mmc, mrq); }