diff mbox series

mmc: tmio: avoid glitches when resetting

Message ID 20220625131722.1397-1-wsa@kernel.org
State New
Headers show
Series mmc: tmio: avoid glitches when resetting | expand

Commit Message

Wolfram Sang June 25, 2022, 1:17 p.m. UTC
From: Wolfram Sang <wsa+renesas@sang-engineering.com>

If we reset because of an error, we need to preserve values for the
clock frequency. Otherwise, glitches may be seen on the bus.

To achieve that, we introduce a 'preserve' parameter to the reset
function and the IP core specific reset callbacks to handle everything
accordingly.

Reported-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 drivers/mmc/host/renesas_sdhi_core.c | 29 ++++++++++++++--------------
 drivers/mmc/host/tmio_mmc.c          |  2 +-
 drivers/mmc/host/tmio_mmc.h          |  6 +++++-
 drivers/mmc/host/tmio_mmc_core.c     | 28 +++++++++++++++++++++------
 4 files changed, 42 insertions(+), 23 deletions(-)

Comments

Ulf Hansson July 12, 2022, 11:09 a.m. UTC | #1
On Sat, 25 Jun 2022 at 15:17, Wolfram Sang <wsa@kernel.org> wrote:
>
> From: Wolfram Sang <wsa+renesas@sang-engineering.com>
>
> If we reset because of an error, we need to preserve values for the
> clock frequency. Otherwise, glitches may be seen on the bus.
>
> To achieve that, we introduce a 'preserve' parameter to the reset
> function and the IP core specific reset callbacks to handle everything
> accordingly.
>
> Reported-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>

Applied for next, thanks!

Kind regards
Uffe


> ---
>  drivers/mmc/host/renesas_sdhi_core.c | 29 ++++++++++++++--------------
>  drivers/mmc/host/tmio_mmc.c          |  2 +-
>  drivers/mmc/host/tmio_mmc.h          |  6 +++++-
>  drivers/mmc/host/tmio_mmc_core.c     | 28 +++++++++++++++++++++------
>  4 files changed, 42 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
> index 4404ca1f98d8..5fa365d0c7fd 100644
> --- a/drivers/mmc/host/renesas_sdhi_core.c
> +++ b/drivers/mmc/host/renesas_sdhi_core.c
> @@ -49,9 +49,6 @@
>  #define HOST_MODE_GEN3_32BIT   (HOST_MODE_GEN3_WMODE | HOST_MODE_GEN3_BUSWIDTH)
>  #define HOST_MODE_GEN3_64BIT   0
>
> -#define CTL_SDIF_MODE  0xe6
> -#define SDIF_MODE_HS400                BIT(0)
> -
>  #define SDHI_VER_GEN2_SDR50    0x490c
>  #define SDHI_VER_RZ_A1         0x820b
>  /* very old datasheets said 0x490c for SDR104, too. They are wrong! */
> @@ -562,23 +559,25 @@ static void renesas_sdhi_scc_reset(struct tmio_mmc_host *host, struct renesas_sd
>  }
>
>  /* only populated for TMIO_MMC_MIN_RCAR2 */
> -static void renesas_sdhi_reset(struct tmio_mmc_host *host)
> +static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve)
>  {
>         struct renesas_sdhi *priv = host_to_priv(host);
>         int ret;
>         u16 val;
>
> -       if (priv->rstc) {
> -               reset_control_reset(priv->rstc);
> -               /* Unknown why but without polling reset status, it will hang */
> -               read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
> -                                 false, priv->rstc);
> -               /* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */
> -               sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
> -               priv->needs_adjust_hs400 = false;
> -               renesas_sdhi_set_clock(host, host->clk_cache);
> -       } else if (priv->scc_ctl) {
> -               renesas_sdhi_scc_reset(host, priv);
> +       if (!preserve) {
> +               if (priv->rstc) {
> +                       reset_control_reset(priv->rstc);
> +                       /* Unknown why but without polling reset status, it will hang */
> +                       read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
> +                                         false, priv->rstc);
> +                       /* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */
> +                       sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
> +                       priv->needs_adjust_hs400 = false;
> +                       renesas_sdhi_set_clock(host, host->clk_cache);
> +               } else if (priv->scc_ctl) {
> +                       renesas_sdhi_scc_reset(host, priv);
> +               }
>         }
>
>         if (sd_ctrl_read16(host, CTL_VERSION) >= SDHI_VER_GEN3_SD) {
> diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
> index b55a29c53d9c..53a2ad9a24b8 100644
> --- a/drivers/mmc/host/tmio_mmc.c
> +++ b/drivers/mmc/host/tmio_mmc.c
> @@ -75,7 +75,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
>         tmio_mmc_clk_start(host);
>  }
>
> -static void tmio_mmc_reset(struct tmio_mmc_host *host)
> +static void tmio_mmc_reset(struct tmio_mmc_host *host, bool preserve)
>  {
>         sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
>         usleep_range(10000, 11000);
> diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
> index e754bb3f5c32..501613c74406 100644
> --- a/drivers/mmc/host/tmio_mmc.h
> +++ b/drivers/mmc/host/tmio_mmc.h
> @@ -42,6 +42,7 @@
>  #define CTL_DMA_ENABLE 0xd8
>  #define CTL_RESET_SD 0xe0
>  #define CTL_VERSION 0xe2
> +#define CTL_SDIF_MODE 0xe6 /* only known on R-Car 2+ */
>
>  /* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
>  #define TMIO_STOP_STP          BIT(0)
> @@ -98,6 +99,9 @@
>  /* Definitions for values the CTL_DMA_ENABLE register can take */
>  #define DMA_ENABLE_DMASDRW     BIT(1)
>
> +/* Definitions for values the CTL_SDIF_MODE register can take */
> +#define SDIF_MODE_HS400                BIT(0) /* only known on R-Car 2+ */
> +
>  /* Define some IRQ masks */
>  /* This is the mask used at reset by the chip */
>  #define TMIO_MASK_ALL           0x837f031d
> @@ -181,7 +185,7 @@ struct tmio_mmc_host {
>         int (*multi_io_quirk)(struct mmc_card *card,
>                               unsigned int direction, int blk_size);
>         int (*write16_hook)(struct tmio_mmc_host *host, int addr);
> -       void (*reset)(struct tmio_mmc_host *host);
> +       void (*reset)(struct tmio_mmc_host *host, bool preserve);
>         bool (*check_retune)(struct tmio_mmc_host *host, struct mmc_request *mrq);
>         void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq);
>         unsigned int (*get_timeout_cycles)(struct tmio_mmc_host *host);
> diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
> index a5850d83908b..437048bb8027 100644
> --- a/drivers/mmc/host/tmio_mmc_core.c
> +++ b/drivers/mmc/host/tmio_mmc_core.c
> @@ -179,8 +179,17 @@ static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
>         sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, reg);
>  }
>
> -static void tmio_mmc_reset(struct tmio_mmc_host *host)
> +static void tmio_mmc_reset(struct tmio_mmc_host *host, bool preserve)
>  {
> +       u16 card_opt, clk_ctrl, sdif_mode;
> +
> +       if (preserve) {
> +               card_opt = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
> +               clk_ctrl = sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL);
> +               if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
> +                       sdif_mode = sd_ctrl_read16(host, CTL_SDIF_MODE);
> +       }
> +
>         /* FIXME - should we set stop clock reg here */
>         sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
>         usleep_range(10000, 11000);
> @@ -190,7 +199,7 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
>         tmio_mmc_abort_dma(host);
>
>         if (host->reset)
> -               host->reset(host);
> +               host->reset(host, preserve);
>
>         sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask_all);
>         host->sdcard_irq_mask = host->sdcard_irq_mask_all;
> @@ -206,6 +215,13 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
>                 sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
>         }
>
> +       if (preserve) {
> +               sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, card_opt);
> +               sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk_ctrl);
> +               if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
> +                       sd_ctrl_write16(host, CTL_SDIF_MODE, sdif_mode);
> +       }
> +
>         if (host->mmc->card)
>                 mmc_retune_needed(host->mmc);
>  }
> @@ -248,7 +264,7 @@ static void tmio_mmc_reset_work(struct work_struct *work)
>
>         spin_unlock_irqrestore(&host->lock, flags);
>
> -       tmio_mmc_reset(host);
> +       tmio_mmc_reset(host, true);
>
>         /* Ready for new calls */
>         host->mrq = NULL;
> @@ -961,7 +977,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>                 tmio_mmc_power_off(host);
>                 /* For R-Car Gen2+, we need to reset SDHI specific SCC */
>                 if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
> -                       tmio_mmc_reset(host);
> +                       tmio_mmc_reset(host, false);
>
>                 host->set_clock(host, 0);
>                 break;
> @@ -1189,7 +1205,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
>                 _host->sdcard_irq_mask_all = TMIO_MASK_ALL;
>
>         _host->set_clock(_host, 0);
> -       tmio_mmc_reset(_host);
> +       tmio_mmc_reset(_host, false);
>
>         spin_lock_init(&_host->lock);
>         mutex_init(&_host->ios_lock);
> @@ -1285,7 +1301,7 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
>         struct tmio_mmc_host *host = dev_get_drvdata(dev);
>
>         tmio_mmc_clk_enable(host);
> -       tmio_mmc_reset(host);
> +       tmio_mmc_reset(host, false);
>
>         if (host->clk_cache)
>                 host->set_clock(host, host->clk_cache);
> --
> 2.35.1
>
diff mbox series

Patch

diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 4404ca1f98d8..5fa365d0c7fd 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -49,9 +49,6 @@ 
 #define HOST_MODE_GEN3_32BIT	(HOST_MODE_GEN3_WMODE | HOST_MODE_GEN3_BUSWIDTH)
 #define HOST_MODE_GEN3_64BIT	0
 
-#define CTL_SDIF_MODE	0xe6
-#define SDIF_MODE_HS400		BIT(0)
-
 #define SDHI_VER_GEN2_SDR50	0x490c
 #define SDHI_VER_RZ_A1		0x820b
 /* very old datasheets said 0x490c for SDR104, too. They are wrong! */
@@ -562,23 +559,25 @@  static void renesas_sdhi_scc_reset(struct tmio_mmc_host *host, struct renesas_sd
 }
 
 /* only populated for TMIO_MMC_MIN_RCAR2 */
-static void renesas_sdhi_reset(struct tmio_mmc_host *host)
+static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve)
 {
 	struct renesas_sdhi *priv = host_to_priv(host);
 	int ret;
 	u16 val;
 
-	if (priv->rstc) {
-		reset_control_reset(priv->rstc);
-		/* Unknown why but without polling reset status, it will hang */
-		read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
-				  false, priv->rstc);
-		/* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */
-		sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
-		priv->needs_adjust_hs400 = false;
-		renesas_sdhi_set_clock(host, host->clk_cache);
-	} else if (priv->scc_ctl) {
-		renesas_sdhi_scc_reset(host, priv);
+	if (!preserve) {
+		if (priv->rstc) {
+			reset_control_reset(priv->rstc);
+			/* Unknown why but without polling reset status, it will hang */
+			read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
+					  false, priv->rstc);
+			/* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */
+			sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
+			priv->needs_adjust_hs400 = false;
+			renesas_sdhi_set_clock(host, host->clk_cache);
+		} else if (priv->scc_ctl) {
+			renesas_sdhi_scc_reset(host, priv);
+		}
 	}
 
 	if (sd_ctrl_read16(host, CTL_VERSION) >= SDHI_VER_GEN3_SD) {
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index b55a29c53d9c..53a2ad9a24b8 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -75,7 +75,7 @@  static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
 	tmio_mmc_clk_start(host);
 }
 
-static void tmio_mmc_reset(struct tmio_mmc_host *host)
+static void tmio_mmc_reset(struct tmio_mmc_host *host, bool preserve)
 {
 	sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
 	usleep_range(10000, 11000);
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index e754bb3f5c32..501613c74406 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -42,6 +42,7 @@ 
 #define CTL_DMA_ENABLE 0xd8
 #define CTL_RESET_SD 0xe0
 #define CTL_VERSION 0xe2
+#define CTL_SDIF_MODE 0xe6 /* only known on R-Car 2+ */
 
 /* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
 #define TMIO_STOP_STP		BIT(0)
@@ -98,6 +99,9 @@ 
 /* Definitions for values the CTL_DMA_ENABLE register can take */
 #define DMA_ENABLE_DMASDRW	BIT(1)
 
+/* Definitions for values the CTL_SDIF_MODE register can take */
+#define SDIF_MODE_HS400		BIT(0) /* only known on R-Car 2+ */
+
 /* Define some IRQ masks */
 /* This is the mask used at reset by the chip */
 #define TMIO_MASK_ALL           0x837f031d
@@ -181,7 +185,7 @@  struct tmio_mmc_host {
 	int (*multi_io_quirk)(struct mmc_card *card,
 			      unsigned int direction, int blk_size);
 	int (*write16_hook)(struct tmio_mmc_host *host, int addr);
-	void (*reset)(struct tmio_mmc_host *host);
+	void (*reset)(struct tmio_mmc_host *host, bool preserve);
 	bool (*check_retune)(struct tmio_mmc_host *host, struct mmc_request *mrq);
 	void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq);
 	unsigned int (*get_timeout_cycles)(struct tmio_mmc_host *host);
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index a5850d83908b..437048bb8027 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -179,8 +179,17 @@  static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
 	sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, reg);
 }
 
-static void tmio_mmc_reset(struct tmio_mmc_host *host)
+static void tmio_mmc_reset(struct tmio_mmc_host *host, bool preserve)
 {
+	u16 card_opt, clk_ctrl, sdif_mode;
+
+	if (preserve) {
+		card_opt = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
+		clk_ctrl = sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL);
+		if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
+			sdif_mode = sd_ctrl_read16(host, CTL_SDIF_MODE);
+	}
+
 	/* FIXME - should we set stop clock reg here */
 	sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
 	usleep_range(10000, 11000);
@@ -190,7 +199,7 @@  static void tmio_mmc_reset(struct tmio_mmc_host *host)
 	tmio_mmc_abort_dma(host);
 
 	if (host->reset)
-		host->reset(host);
+		host->reset(host, preserve);
 
 	sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask_all);
 	host->sdcard_irq_mask = host->sdcard_irq_mask_all;
@@ -206,6 +215,13 @@  static void tmio_mmc_reset(struct tmio_mmc_host *host)
 		sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
 	}
 
+	if (preserve) {
+		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, card_opt);
+		sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk_ctrl);
+		if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
+			sd_ctrl_write16(host, CTL_SDIF_MODE, sdif_mode);
+	}
+
 	if (host->mmc->card)
 		mmc_retune_needed(host->mmc);
 }
@@ -248,7 +264,7 @@  static void tmio_mmc_reset_work(struct work_struct *work)
 
 	spin_unlock_irqrestore(&host->lock, flags);
 
-	tmio_mmc_reset(host);
+	tmio_mmc_reset(host, true);
 
 	/* Ready for new calls */
 	host->mrq = NULL;
@@ -961,7 +977,7 @@  static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		tmio_mmc_power_off(host);
 		/* For R-Car Gen2+, we need to reset SDHI specific SCC */
 		if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
-			tmio_mmc_reset(host);
+			tmio_mmc_reset(host, false);
 
 		host->set_clock(host, 0);
 		break;
@@ -1189,7 +1205,7 @@  int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
 		_host->sdcard_irq_mask_all = TMIO_MASK_ALL;
 
 	_host->set_clock(_host, 0);
-	tmio_mmc_reset(_host);
+	tmio_mmc_reset(_host, false);
 
 	spin_lock_init(&_host->lock);
 	mutex_init(&_host->ios_lock);
@@ -1285,7 +1301,7 @@  int tmio_mmc_host_runtime_resume(struct device *dev)
 	struct tmio_mmc_host *host = dev_get_drvdata(dev);
 
 	tmio_mmc_clk_enable(host);
-	tmio_mmc_reset(host);
+	tmio_mmc_reset(host, false);
 
 	if (host->clk_cache)
 		host->set_clock(host, host->clk_cache);