summaryrefslogtreecommitdiff
path: root/drivers/mmc/core/core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-06-06 02:11:43 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2018-06-06 02:11:43 +0300
commitf60342fac9fae20ada2cd5faadbc2a1337cae03f (patch)
treefe64b1cb3ea699d819e5e808264903aee2d8dc9a /drivers/mmc/core/core.c
parent5231804cf9e584f3e7e763a0d6d2fffe011c1bce (diff)
parentef5332c10d4f332a2ac79e9ad5452f4e89d1815a (diff)
downloadlinux-f60342fac9fae20ada2cd5faadbc2a1337cae03f.tar.xz
Merge tag 'mmc-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson: "MMC core: - Decrease polling rate for erase/trim/discard - Allow non-sleeping GPIOs for card detect - Improve mmc block removal path - Enable support for mmc_sw_reset() for SDIO cards - Add mmc_sw_reset() to allow users to do a soft reset of the card - Allow power delay to be tunable via DT - Allow card detect debounce delay to be tunable via DT - Enable new quirk to limit clock rate for Marvell 8887 chip - Don't show eMMC RPMB and BOOT areas in /proc/partitions - Add capability to avoid 3.3V signaling for fragile HWs MMC host: - Improve/fixup support for handle highmem pages - Remove depends on HAS_DMA in case of platform dependency - mvsdio: Enable support for erase/trim/discard - rtsx_usb: Enable support for erase/trim/discard - renesas_sdhi: Fix WP logic regressions - renesas_sdhi: Add r8a77965 support - renesas_sdhi: Add R8A77980 to whitelist - meson: Add optional support for device reset - meson: Add support for the Meson-AXG platform - dw_mmc: Add new driver for BlueField DW variant - mediatek: Add support for 64G DRAM DMA - sunxi: Deploy runtime PM support - jz4740: Add support for JZ4780 - jz4740: Enable support for DT based platforms - sdhci: Various improvement to timeout handling - sdhci: Disable support for HS200/HS400/UHS when no 1.8V support - sdhci-omap: Add support for controller in k2g SoC - sdhci-omap: Add workarounds for a couple of Erratas - sdhci-omap: Enable support for generic sdhci DT properties - sdhci-cadence: Re-send tune request to deal with errata - sdhci-pci: Fix 3.3V voltage switch for some BYT-based Intel controllers - sdhci-pci: Avoid 3.3V signaling on some NI 904x - sdhci-esdhc-imx: Use watermark levels for PIO access - sdhci-msm: Improve card detection handling - sdhci-msm: Add support voltage pad switching" * tag 'mmc-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (104 commits) mmc: renesas_sdhi: really fix WP logic regressions mmc: mvsdio: Enable MMC_CAP_ERASE mmc: mvsdio: Respect card busy time out from mmc core mmc: sdhci-msm: Remove NO_CARD_NO_RESET quirk mmc: sunxi: Use ifdef rather than __maybe_unused mmc: mxmmc: Use ifdef rather than __maybe_unused mmc: mxmmc: include linux/highmem.h mmc: sunxi: mark PM functions as __maybe_unused mmc: Throttle calls to MMC_SEND_STATUS during mmc_do_erase() mmc: au1xmmc: handle highmem pages mmc: Allow non-sleeping GPIO cd mmc: sdhci-*: Don't emit error msg if sdhci_add_host() fails mmc: sd: Define name for default speed dtr mmc: core: Move calls to ->prepare_hs400_tuning() closer to mmc code mmc: sdhci-xenon: use match_string() helper mmc: wbsd: handle highmem pages mmc: ushc: handle highmem pages mmc: mxcmmc: handle highmem pages mmc: atmel-mci: use sg_copy_{from,to}_buffer mmc: android-goldfish: use sg_copy_{from,to}_buffer ...
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r--drivers/mmc/core/core.c67
1 files changed, 50 insertions, 17 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 121ce50b6d5e..281826d1fcca 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -50,9 +50,6 @@
#include "sd_ops.h"
#include "sdio_ops.h"
-/* If the device is not responding */
-#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
-
/* The max erase timeout, used when host->max_busy_timeout isn't specified */
#define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */
@@ -1484,6 +1481,17 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
}
+void mmc_set_initial_signal_voltage(struct mmc_host *host)
+{
+ /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
+ if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
+ dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
+ dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
+ dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
+}
+
int mmc_host_set_uhs_voltage(struct mmc_host *host)
{
u32 clock;
@@ -1646,19 +1654,13 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
/* Set initial state and call mmc_set_ios */
mmc_set_initial_state(host);
- /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
- if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
- dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
- else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
- dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
- else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
- dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
+ mmc_set_initial_signal_voltage(host);
/*
* This delay should be sufficient to allow the power supply
* to reach the minimum voltage.
*/
- mmc_delay(10);
+ mmc_delay(host->ios.power_delay_ms);
mmc_pwrseq_post_power_on(host);
@@ -1671,7 +1673,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
* This delay must be at least 74 clock sizes, or 1 ms, or the
* time required to reach a stable voltage.
*/
- mmc_delay(10);
+ mmc_delay(host->ios.power_delay_ms);
}
void mmc_power_off(struct mmc_host *host)
@@ -1967,6 +1969,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
unsigned int qty = 0, busy_timeout = 0;
bool use_r1b_resp = false;
unsigned long timeout;
+ int loop_udelay=64, udelay_max=32768;
int err;
mmc_retune_hold(card->host);
@@ -2091,9 +2094,15 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
err = -EIO;
goto out;
}
+ if ((cmd.resp[0] & R1_READY_FOR_DATA) &&
+ R1_CURRENT_STATE(cmd.resp[0]) != R1_STATE_PRG)
+ break;
+
+ usleep_range(loop_udelay, loop_udelay*2);
+ if (loop_udelay < udelay_max)
+ loop_udelay *= 2;
+ } while (1);
- } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
out:
mmc_retune_release(card->host);
return err;
@@ -2435,22 +2444,46 @@ int mmc_hw_reset(struct mmc_host *host)
return -EINVAL;
mmc_bus_get(host);
- if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) {
+ if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) {
mmc_bus_put(host);
return -EOPNOTSUPP;
}
- ret = host->bus_ops->reset(host);
+ ret = host->bus_ops->hw_reset(host);
mmc_bus_put(host);
if (ret)
- pr_warn("%s: tried to reset card, got error %d\n",
+ pr_warn("%s: tried to HW reset card, got error %d\n",
mmc_hostname(host), ret);
return ret;
}
EXPORT_SYMBOL(mmc_hw_reset);
+int mmc_sw_reset(struct mmc_host *host)
+{
+ int ret;
+
+ if (!host->card)
+ return -EINVAL;
+
+ mmc_bus_get(host);
+ if (!host->bus_ops || host->bus_dead || !host->bus_ops->sw_reset) {
+ mmc_bus_put(host);
+ return -EOPNOTSUPP;
+ }
+
+ ret = host->bus_ops->sw_reset(host);
+ mmc_bus_put(host);
+
+ if (ret)
+ pr_warn("%s: tried to SW reset card, got error %d\n",
+ mmc_hostname(host), ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(mmc_sw_reset);
+
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;