Commit a27c75e5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v5.14-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC host fixes from Ulf Hansson:

 - dw_mmc: Fix hang on data CRC error

 - mmci: Fix voltage switch procedure for the stm32 variant

 - sdhci-iproc: Fix some clock issues for BCM2711

 - sdhci-msm: Fixup software timeout value

* tag 'mmc-v5.14-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: sdhci-iproc: Set SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN on BCM2711
  mmc: sdhci-iproc: Cap min clock frequency on BCM2711
  mmc: sdhci-msm: Update the software timeout value for sdhc
  mmc: mmci: stm32: Check when the voltage switch procedure should be done
  mmc: dw_mmc: Fix hang on data CRC error
parents 43a6473e 419dd626
...@@ -2018,8 +2018,8 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t) ...@@ -2018,8 +2018,8 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t)
continue; continue;
} }
dw_mci_stop_dma(host);
send_stop_abort(host, data); send_stop_abort(host, data);
dw_mci_stop_dma(host);
state = STATE_SENDING_STOP; state = STATE_SENDING_STOP;
break; break;
} }
...@@ -2043,10 +2043,10 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t) ...@@ -2043,10 +2043,10 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t)
*/ */
if (test_and_clear_bit(EVENT_DATA_ERROR, if (test_and_clear_bit(EVENT_DATA_ERROR,
&host->pending_events)) { &host->pending_events)) {
dw_mci_stop_dma(host);
if (!(host->data_status & (SDMMC_INT_DRTO | if (!(host->data_status & (SDMMC_INT_DRTO |
SDMMC_INT_EBE))) SDMMC_INT_EBE)))
send_stop_abort(host, data); send_stop_abort(host, data);
dw_mci_stop_dma(host);
state = STATE_DATA_ERROR; state = STATE_DATA_ERROR;
break; break;
} }
...@@ -2079,10 +2079,10 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t) ...@@ -2079,10 +2079,10 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t)
*/ */
if (test_and_clear_bit(EVENT_DATA_ERROR, if (test_and_clear_bit(EVENT_DATA_ERROR,
&host->pending_events)) { &host->pending_events)) {
dw_mci_stop_dma(host);
if (!(host->data_status & (SDMMC_INT_DRTO | if (!(host->data_status & (SDMMC_INT_DRTO |
SDMMC_INT_EBE))) SDMMC_INT_EBE)))
send_stop_abort(host, data); send_stop_abort(host, data);
dw_mci_stop_dma(host);
state = STATE_DATA_ERROR; state = STATE_DATA_ERROR;
break; break;
} }
......
...@@ -479,8 +479,9 @@ static int sdmmc_post_sig_volt_switch(struct mmci_host *host, ...@@ -479,8 +479,9 @@ static int sdmmc_post_sig_volt_switch(struct mmci_host *host,
u32 status; u32 status;
int ret = 0; int ret = 0;
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { spin_lock_irqsave(&host->lock, flags);
spin_lock_irqsave(&host->lock, flags); if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180 &&
host->pwr_reg & MCI_STM32_VSWITCHEN) {
mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCH); mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCH);
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
...@@ -492,9 +493,11 @@ static int sdmmc_post_sig_volt_switch(struct mmci_host *host, ...@@ -492,9 +493,11 @@ static int sdmmc_post_sig_volt_switch(struct mmci_host *host,
writel_relaxed(MCI_STM32_VSWENDC | MCI_STM32_CKSTOPC, writel_relaxed(MCI_STM32_VSWENDC | MCI_STM32_CKSTOPC,
host->base + MMCICLEAR); host->base + MMCICLEAR);
spin_lock_irqsave(&host->lock, flags);
mmci_write_pwrreg(host, host->pwr_reg & mmci_write_pwrreg(host, host->pwr_reg &
~(MCI_STM32_VSWITCHEN | MCI_STM32_VSWITCH)); ~(MCI_STM32_VSWITCHEN | MCI_STM32_VSWITCH));
} }
spin_unlock_irqrestore(&host->lock, flags);
return ret; return ret;
} }
......
...@@ -173,6 +173,23 @@ static unsigned int sdhci_iproc_get_max_clock(struct sdhci_host *host) ...@@ -173,6 +173,23 @@ static unsigned int sdhci_iproc_get_max_clock(struct sdhci_host *host)
return pltfm_host->clock; return pltfm_host->clock;
} }
/*
* There is a known bug on BCM2711's SDHCI core integration where the
* controller will hang when the difference between the core clock and the bus
* clock is too great. Specifically this can be reproduced under the following
* conditions:
*
* - No SD card plugged in, polling thread is running, probing cards at
* 100 kHz.
* - BCM2711's core clock configured at 500MHz or more
*
* So we set 200kHz as the minimum clock frequency available for that SoC.
*/
static unsigned int sdhci_iproc_bcm2711_get_min_clock(struct sdhci_host *host)
{
return 200000;
}
static const struct sdhci_ops sdhci_iproc_ops = { static const struct sdhci_ops sdhci_iproc_ops = {
.set_clock = sdhci_set_clock, .set_clock = sdhci_set_clock,
.get_max_clock = sdhci_iproc_get_max_clock, .get_max_clock = sdhci_iproc_get_max_clock,
...@@ -271,13 +288,15 @@ static const struct sdhci_ops sdhci_iproc_bcm2711_ops = { ...@@ -271,13 +288,15 @@ static const struct sdhci_ops sdhci_iproc_bcm2711_ops = {
.set_clock = sdhci_set_clock, .set_clock = sdhci_set_clock,
.set_power = sdhci_set_power_and_bus_voltage, .set_power = sdhci_set_power_and_bus_voltage,
.get_max_clock = sdhci_iproc_get_max_clock, .get_max_clock = sdhci_iproc_get_max_clock,
.get_min_clock = sdhci_iproc_bcm2711_get_min_clock,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset, .reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static const struct sdhci_pltfm_data sdhci_bcm2711_pltfm_data = { static const struct sdhci_pltfm_data sdhci_bcm2711_pltfm_data = {
.quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.ops = &sdhci_iproc_bcm2711_ops, .ops = &sdhci_iproc_bcm2711_ops,
}; };
......
...@@ -2089,6 +2089,23 @@ static void sdhci_msm_cqe_disable(struct mmc_host *mmc, bool recovery) ...@@ -2089,6 +2089,23 @@ static void sdhci_msm_cqe_disable(struct mmc_host *mmc, bool recovery)
sdhci_cqe_disable(mmc, recovery); sdhci_cqe_disable(mmc, recovery);
} }
static void sdhci_msm_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
{
u32 count, start = 15;
__sdhci_set_timeout(host, cmd);
count = sdhci_readb(host, SDHCI_TIMEOUT_CONTROL);
/*
* Update software timeout value if its value is less than hardware data
* timeout value. Qcom SoC hardware data timeout value was calculated
* using 4 * MCLK * 2^(count + 13). where MCLK = 1 / host->clock.
*/
if (cmd && cmd->data && host->clock > 400000 &&
host->clock <= 50000000 &&
((1 << (count + start)) > (10 * host->clock)))
host->data_timeout = 22LL * NSEC_PER_SEC;
}
static const struct cqhci_host_ops sdhci_msm_cqhci_ops = { static const struct cqhci_host_ops sdhci_msm_cqhci_ops = {
.enable = sdhci_msm_cqe_enable, .enable = sdhci_msm_cqe_enable,
.disable = sdhci_msm_cqe_disable, .disable = sdhci_msm_cqe_disable,
...@@ -2438,6 +2455,7 @@ static const struct sdhci_ops sdhci_msm_ops = { ...@@ -2438,6 +2455,7 @@ static const struct sdhci_ops sdhci_msm_ops = {
.irq = sdhci_msm_cqe_irq, .irq = sdhci_msm_cqe_irq,
.dump_vendor_regs = sdhci_msm_dump_vendor_regs, .dump_vendor_regs = sdhci_msm_dump_vendor_regs,
.set_power = sdhci_set_power_noreg, .set_power = sdhci_set_power_noreg,
.set_timeout = sdhci_msm_set_timeout,
}; };
static const struct sdhci_pltfm_data sdhci_msm_pdata = { static const struct sdhci_pltfm_data sdhci_msm_pdata = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment