mmc: tmio: avoid glitches when resetting
[ Upstream commit 2e586f8a5b0ed4a525014a692923ac96f6647816 ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
325da44d08
commit
ef577017cd
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user