Message ID | 20220625131722.1397-1-wsa@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | mmc: tmio: avoid glitches when resetting | expand |
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 --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);