--- zzzz-none-000/linux-4.4.60/drivers/mmc/host/sdhci.c 2017-04-08 07:53:53.000000000 +0000 +++ honeybee-1240e-714/linux-4.4.60/drivers/mmc/host/sdhci.c 2019-07-03 09:21:34.000000000 +0000 @@ -177,6 +177,7 @@ { unsigned long timeout; +retry_reset: sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); if (mask & SDHCI_RESET_ALL) { @@ -189,17 +190,52 @@ /* Wait max 100 ms */ timeout = 100; + if (host->ops->check_power_status && host->pwr && + (mask & SDHCI_RESET_ALL)) + host->ops->check_power_status(host, REQ_BUS_OFF); + /* hw clears the bit when it's done */ while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { pr_err("%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask); + if ((host->quirks2 & SDHCI_QUIRK2_USE_RESET_WORKAROUND) + && host->ops->reset_workaround) { + if (!host->reset_wa_applied) { + /* + * apply the workaround and issue + * reset again. + */ + host->ops->reset_workaround(host, 1); + host->reset_wa_applied = 1; + host->reset_wa_cnt++; + goto retry_reset; + } else { + pr_err("%s: Reset 0x%x failed with workaround\n", + mmc_hostname(host->mmc), + (int)mask); + /* clear the workaround */ + host->ops->reset_workaround(host, 0); + host->reset_wa_applied = 0; + } + } + sdhci_dumpregs(host); return; } timeout--; mdelay(1); } + + if ((host->quirks2 & SDHCI_QUIRK2_USE_RESET_WORKAROUND) && + host->ops->reset_workaround && host->reset_wa_applied) { + pr_info("%s: Reset 0x%x successful with workaround\n", + mmc_hostname(host->mmc), (int)mask); + /* clear the workaround */ + host->ops->reset_workaround(host, 0); + host->reset_wa_applied = 0; + } + } EXPORT_SYMBOL_GPL(sdhci_reset); @@ -942,8 +978,19 @@ } } - if (data->flags & MMC_DATA_READ) + if (data->flags & MMC_DATA_READ) { mode |= SDHCI_TRNS_READ; + if (host->ops->toggle_cdr) { + if ((cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) || + (cmd->opcode == MMC_SEND_TUNING_BLOCK)) + host->ops->toggle_cdr(host, false); + else + host->ops->toggle_cdr(host, true); + } + } + if (host->ops->toggle_cdr && (data->flags & MMC_DATA_WRITE)) + host->ops->toggle_cdr(host, false); + if (host->flags & SDHCI_REQ_USE_DMA) mode |= SDHCI_TRNS_DMA; @@ -1330,6 +1377,8 @@ if (pwr == 0) { sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + if (host->ops->check_power_status) + host->ops->check_power_status(host, REQ_BUS_OFF); if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) sdhci_runtime_pm_bus_off(host); vdd = 0; @@ -1338,20 +1387,28 @@ * Spec says that we should clear the power reg before setting * a new value. Some controllers don't seem to like this though. */ - if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) + if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) { sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - + if (host->ops->check_power_status) + host->ops->check_power_status(host, + REQ_BUS_OFF); + } /* * At least the Marvell CaFe chip gets confused if we set the * voltage and set turn on power at the same time, so set the * voltage first. */ - if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) + if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) { sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + if (host->ops->check_power_status) + host->ops->check_power_status(host, REQ_BUS_ON); + } pwr |= SDHCI_POWER_ON; sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + if (host->ops->check_power_status) + host->ops->check_power_status(host, REQ_BUS_ON); if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) sdhci_runtime_pm_bus_on(host); @@ -1471,10 +1528,7 @@ u8 ctrl; struct mmc_host *mmc = host->mmc; - spin_lock_irqsave(&host->lock, flags); - if (host->flags & SDHCI_DEVICE_DEAD) { - spin_unlock_irqrestore(&host->lock, flags); if (!IS_ERR(mmc->supply.vmmc) && ios->power_mode == MMC_POWER_OFF) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); @@ -1495,6 +1549,7 @@ !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) sdhci_enable_preset_value(host, false); + spin_lock_irqsave(&host->lock, flags); if (!ios->clock || ios->clock != host->clock) { host->ops->set_clock(host, ios->clock); host->clock = ios->clock; @@ -1511,9 +1566,12 @@ host->mmc->max_busy_timeout /= host->timeout_clk; } } + spin_unlock_irqrestore(&host->lock, flags); sdhci_set_power(host, ios->power_mode, ios->vdd); + spin_lock_irqsave(&host->lock, flags); + if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks(host, ios->power_mode); @@ -1784,6 +1842,8 @@ /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + if (host->ops->check_power_status) + host->ops->check_power_status(host, REQ_IO_HIGH); if (!IS_ERR(mmc->supply.vqmmc)) { ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000, @@ -1823,6 +1883,8 @@ */ ctrl |= SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + if (host->ops->check_power_status) + host->ops->check_power_status(host, REQ_IO_LOW); /* Some controller need to do more when switching */ if (host->ops->voltage_switch) @@ -1922,8 +1984,10 @@ switch (host->timing) { /* HS400 tuning is done in HS200 mode */ case MMC_TIMING_MMC_HS400: - err = -EINVAL; - goto out_unlock; + if (!(mmc->caps2 & MMC_CAP2_HS400_POST_TUNING)) { + err = -EINVAL; + goto out_unlock; + } case MMC_TIMING_MMC_HS200: /*