mmc: tegra: Disable card clock during tuning cmd on Tegra210
Implement tegra210_sdhci_writew() to disable card clock and issue a reset when the tuning command is sent. This is done to prevent an intermittent hang with around 10 % failure rate during tuning. Add tegra186_sdhci_ops because this workaround is specific to Tegra210. Signed-off-by: Aapo Vienamo <avienamo@nvidia.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
Родитель
f6a447fafa
Коммит
38a284d98c
|
@ -177,6 +177,50 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
|
|||
}
|
||||
}
|
||||
|
||||
static bool tegra_sdhci_configure_card_clk(struct sdhci_host *host, bool enable)
|
||||
{
|
||||
bool status;
|
||||
u32 reg;
|
||||
|
||||
reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||
status = !!(reg & SDHCI_CLOCK_CARD_EN);
|
||||
|
||||
if (status == enable)
|
||||
return status;
|
||||
|
||||
if (enable)
|
||||
reg |= SDHCI_CLOCK_CARD_EN;
|
||||
else
|
||||
reg &= ~SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
|
||||
{
|
||||
bool is_tuning_cmd = 0;
|
||||
bool clk_enabled;
|
||||
u8 cmd;
|
||||
|
||||
if (reg == SDHCI_COMMAND) {
|
||||
cmd = SDHCI_GET_CMD(val);
|
||||
is_tuning_cmd = cmd == MMC_SEND_TUNING_BLOCK ||
|
||||
cmd == MMC_SEND_TUNING_BLOCK_HS200;
|
||||
}
|
||||
|
||||
if (is_tuning_cmd)
|
||||
clk_enabled = tegra_sdhci_configure_card_clk(host, 0);
|
||||
|
||||
writew(val, host->ioaddr + reg);
|
||||
|
||||
if (is_tuning_cmd) {
|
||||
udelay(1);
|
||||
tegra_sdhci_configure_card_clk(host, clk_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
|
||||
{
|
||||
return mmc_gpio_get_ro(host->mmc);
|
||||
|
@ -215,28 +259,6 @@ static bool tegra_sdhci_is_pad_and_regulator_valid(struct sdhci_host *host)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool tegra_sdhci_configure_card_clk(struct sdhci_host *host, bool enable)
|
||||
{
|
||||
bool status;
|
||||
u32 reg;
|
||||
|
||||
reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||
status = !!(reg & SDHCI_CLOCK_CARD_EN);
|
||||
|
||||
if (status == enable)
|
||||
return status;
|
||||
|
||||
if (enable)
|
||||
reg |= SDHCI_CLOCK_CARD_EN;
|
||||
else
|
||||
reg &= ~SDHCI_CLOCK_CARD_EN;
|
||||
|
||||
sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
@ -834,6 +856,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra124 = {
|
|||
static const struct sdhci_ops tegra210_sdhci_ops = {
|
||||
.get_ro = tegra_sdhci_get_ro,
|
||||
.read_w = tegra_sdhci_readw,
|
||||
.write_w = tegra210_sdhci_writew,
|
||||
.write_l = tegra_sdhci_writel,
|
||||
.set_clock = tegra_sdhci_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
|
@ -861,6 +884,18 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
|
|||
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP,
|
||||
};
|
||||
|
||||
static const struct sdhci_ops tegra186_sdhci_ops = {
|
||||
.get_ro = tegra_sdhci_get_ro,
|
||||
.read_w = tegra_sdhci_readw,
|
||||
.write_l = tegra_sdhci_writel,
|
||||
.set_clock = tegra_sdhci_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = tegra_sdhci_reset,
|
||||
.set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
|
||||
.voltage_switch = tegra_sdhci_voltage_switch,
|
||||
.get_max_clock = tegra_sdhci_get_max_clock,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
|
||||
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
|
||||
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
|
||||
|
@ -877,7 +912,7 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
|
|||
* But it is not supported as of now.
|
||||
*/
|
||||
SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
|
||||
.ops = &tegra210_sdhci_ops,
|
||||
.ops = &tegra186_sdhci_ops,
|
||||
};
|
||||
|
||||
static const struct sdhci_tegra_soc_data soc_data_tegra186 = {
|
||||
|
|
Загрузка…
Ссылка в новой задаче