Skip to content

Commit

Permalink
mmc: tmio: avoid glitches when resetting
Browse files Browse the repository at this point in the history
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>
Link: https://lore.kernel.org/r/20220625131722.1397-1-wsa@kernel.org
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
  • Loading branch information
Wolfram Sang authored and Ulf Hansson committed Jul 12, 2022
1 parent aabf199 commit 2e586f8
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 23 deletions.
29 changes: 14 additions & 15 deletions drivers/mmc/host/renesas_sdhi_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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! */
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/mmc/host/tmio_mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 5 additions & 1 deletion drivers/mmc/host/tmio_mmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
28 changes: 22 additions & 6 deletions drivers/mmc/host/tmio_mmc_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand 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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 2e586f8

Please sign in to comment.