summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-26 09:31:09 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-26 09:31:09 -0800
commited5dc2372dba46e0ecd08791b1a0399d313e5cff (patch)
tree571319985b59a2963fb7580c24ee2aa1696359e2 /drivers/mmc/core
parent0512c04a2b5d29a33d96d315e1d14c55f5148aa7 (diff)
parent0e786102949d7461859c6ce9f39c2c8d28e42db3 (diff)
downloadblackbird-op-linux-ed5dc2372dba46e0ecd08791b1a0399d313e5cff.tar.gz
blackbird-op-linux-ed5dc2372dba46e0ecd08791b1a0399d313e5cff.zip
Merge tag 'mmc-updates-for-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC update from Chris Ball: "MMC highlights for 3.9: Core: - Support for packed commands in eMMC 4.5. (This requires a host capability to be turned on. It increases write throughput by 20%+, but may also increase average write latency; more testing needed.) - Add DT bindings for capability flags. - Add mmc_of_parse() for shared DT parsing between drivers. Drivers: - android-goldfish: New MMC driver for the Android Goldfish emulator. - mvsdio: Add DT bindings, pinctrl, use slot-gpio for card detection. - omap_hsmmc: Fix boot hangs with RPMB partitions. - sdhci-bcm2835: New driver for controller used by Raspberry Pi. - sdhci-esdhc-imx: Add 8-bit data, auto CMD23 support, use slot-gpio. - sh_mmcif: Add support for eMMC DDR, bundled MMCIF IRQs. - tmio_mmc: Add DT bindings, support for vccq regulator" * tag 'mmc-updates-for-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (92 commits) mmc: tegra: assume CONFIG_OF, remove platform data mmc: add DT bindings for more MMC capability flags mmc: tmio: add support for the VccQ regulator mmc: tmio: remove unused and deprecated symbols mmc: sh_mobile_sdhi: use managed resource allocations mmc: sh_mobile_sdhi: remove unused .pdata field mmc: tmio-mmc: parse device-tree bindings mmc: tmio-mmc: define device-tree bindings mmc: sh_mmcif: use mmc_of_parse() to parse standard MMC DT bindings mmc: (cosmetic) remove "extern" from function declarations mmc: provide a standard MMC device-tree binding parser centrally mmc: detailed definition of CD and WP MMC line polarities in DT mmc: sdhi, tmio: only check flags in tmio-mmc driver proper mmc: sdhci: Fix parameter of sdhci_do_start_signal_voltage_switch() mmc: sdhci: check voltage range only on regulators aware of voltage value mmc: bcm2835: set SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK mmc: support packed write command for eMMC4.5 devices mmc: add packed command feature of eMMC4.5 mmc: rtsx: remove driving adjustment mmc: use regulator_can_change_voltage() instead of regulator_count_voltages ...
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/bus.c1
-rw-r--r--drivers/mmc/core/core.c246
-rw-r--r--drivers/mmc/core/core.h6
-rw-r--r--drivers/mmc/core/host.c123
-rw-r--r--drivers/mmc/core/mmc.c46
-rw-r--r--drivers/mmc/core/mmc_ops.c1
-rw-r--r--drivers/mmc/core/sd.c44
-rw-r--r--drivers/mmc/core/sdio.c54
-rw-r--r--drivers/mmc/core/slot-gpio.c57
9 files changed, 495 insertions, 83 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 420cb6753c1e..e219c97a02a4 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -321,6 +321,7 @@ int mmc_add_card(struct mmc_card *card)
#ifdef CONFIG_DEBUG_FS
mmc_add_card_debugfs(card);
#endif
+ mmc_init_context_info(card->host);
ret = device_add(&card->dev);
if (ret)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index aaed7687cf09..08a3cf2a7610 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -319,11 +319,45 @@ out:
}
EXPORT_SYMBOL(mmc_start_bkops);
+/*
+ * mmc_wait_data_done() - done callback for data request
+ * @mrq: done data request
+ *
+ * Wakes up mmc context, passed as a callback to host controller driver
+ */
+static void mmc_wait_data_done(struct mmc_request *mrq)
+{
+ mrq->host->context_info.is_done_rcv = true;
+ wake_up_interruptible(&mrq->host->context_info.wait);
+}
+
static void mmc_wait_done(struct mmc_request *mrq)
{
complete(&mrq->completion);
}
+/*
+ *__mmc_start_data_req() - starts data request
+ * @host: MMC host to start the request
+ * @mrq: data request to start
+ *
+ * Sets the done callback to be called when request is completed by the card.
+ * Starts data mmc request execution
+ */
+static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ mrq->done = mmc_wait_data_done;
+ mrq->host = host;
+ if (mmc_card_removed(host->card)) {
+ mrq->cmd->error = -ENOMEDIUM;
+ mmc_wait_data_done(mrq);
+ return -ENOMEDIUM;
+ }
+ mmc_start_request(host, mrq);
+
+ return 0;
+}
+
static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
init_completion(&mrq->completion);
@@ -337,6 +371,62 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
return 0;
}
+/*
+ * mmc_wait_for_data_req_done() - wait for request completed
+ * @host: MMC host to prepare the command.
+ * @mrq: MMC request to wait for
+ *
+ * Blocks MMC context till host controller will ack end of data request
+ * execution or new request notification arrives from the block layer.
+ * Handles command retries.
+ *
+ * Returns enum mmc_blk_status after checking errors.
+ */
+static int mmc_wait_for_data_req_done(struct mmc_host *host,
+ struct mmc_request *mrq,
+ struct mmc_async_req *next_req)
+{
+ struct mmc_command *cmd;
+ struct mmc_context_info *context_info = &host->context_info;
+ int err;
+ unsigned long flags;
+
+ while (1) {
+ wait_event_interruptible(context_info->wait,
+ (context_info->is_done_rcv ||
+ context_info->is_new_req));
+ spin_lock_irqsave(&context_info->lock, flags);
+ context_info->is_waiting_last_req = false;
+ spin_unlock_irqrestore(&context_info->lock, flags);
+ if (context_info->is_done_rcv) {
+ context_info->is_done_rcv = false;
+ context_info->is_new_req = false;
+ cmd = mrq->cmd;
+ if (!cmd->error || !cmd->retries ||
+ mmc_card_removed(host->card)) {
+ err = host->areq->err_check(host->card,
+ host->areq);
+ break; /* return err */
+ } else {
+ pr_info("%s: req failed (CMD%u): %d, retrying...\n",
+ mmc_hostname(host),
+ cmd->opcode, cmd->error);
+ cmd->retries--;
+ cmd->error = 0;
+ host->ops->request(host, mrq);
+ continue; /* wait for done/new event again */
+ }
+ } else if (context_info->is_new_req) {
+ context_info->is_new_req = false;
+ if (!next_req) {
+ err = MMC_BLK_NEW_REQUEST;
+ break; /* return err */
+ }
+ }
+ }
+ return err;
+}
+
static void mmc_wait_for_req_done(struct mmc_host *host,
struct mmc_request *mrq)
{
@@ -426,8 +516,16 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
mmc_pre_req(host, areq->mrq, !host->areq);
if (host->areq) {
- mmc_wait_for_req_done(host, host->areq->mrq);
- err = host->areq->err_check(host->card, host->areq);
+ err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
+ if (err == MMC_BLK_NEW_REQUEST) {
+ if (error)
+ *error = err;
+ /*
+ * The previous request was not completed,
+ * nothing to return
+ */
+ return NULL;
+ }
/*
* Check BKOPS urgency for each R1 response
*/
@@ -439,14 +537,14 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
}
if (!err && areq)
- start_err = __mmc_start_req(host, areq->mrq);
+ start_err = __mmc_start_data_req(host, areq->mrq);
if (host->areq)
mmc_post_req(host, host->areq->mrq, 0);
/* Cancel a prepared request if it was not started. */
if ((err || start_err) && areq)
- mmc_post_req(host, areq->mrq, -EINVAL);
+ mmc_post_req(host, areq->mrq, -EINVAL);
if (err)
host->areq = NULL;
@@ -1137,7 +1235,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
*/
voltage = regulator_get_voltage(supply);
- if (regulator_count_voltages(supply) == 1)
+ if (!regulator_can_change_voltage(supply))
min_uV = max_uV = voltage;
if (voltage < 0)
@@ -1219,10 +1317,30 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
return ocr;
}
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11)
+int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
+{
+ int err = 0;
+ int old_signal_voltage = host->ios.signal_voltage;
+
+ host->ios.signal_voltage = signal_voltage;
+ if (host->ops->start_signal_voltage_switch) {
+ mmc_host_clk_hold(host);
+ err = host->ops->start_signal_voltage_switch(host, &host->ios);
+ mmc_host_clk_release(host);
+ }
+
+ if (err)
+ host->ios.signal_voltage = old_signal_voltage;
+
+ return err;
+
+}
+
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
{
struct mmc_command cmd = {0};
int err = 0;
+ u32 clock;
BUG_ON(!host);
@@ -1230,27 +1348,81 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
* Send CMD11 only if the request is to switch the card to
* 1.8V signalling.
*/
- if ((signal_voltage != MMC_SIGNAL_VOLTAGE_330) && cmd11) {
- cmd.opcode = SD_SWITCH_VOLTAGE;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
+ return __mmc_set_signal_voltage(host, signal_voltage);
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err)
- return err;
+ /*
+ * If we cannot switch voltages, return failure so the caller
+ * can continue without UHS mode
+ */
+ if (!host->ops->start_signal_voltage_switch)
+ return -EPERM;
+ if (!host->ops->card_busy)
+ pr_warning("%s: cannot verify signal voltage switch\n",
+ mmc_hostname(host));
+
+ cmd.opcode = SD_SWITCH_VOLTAGE;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
- return -EIO;
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err)
+ return err;
+
+ if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
+ return -EIO;
+
+ mmc_host_clk_hold(host);
+ /*
+ * The card should drive cmd and dat[0:3] low immediately
+ * after the response of cmd11, but wait 1 ms to be sure
+ */
+ mmc_delay(1);
+ if (host->ops->card_busy && !host->ops->card_busy(host)) {
+ err = -EAGAIN;
+ goto power_cycle;
}
+ /*
+ * During a signal voltage level switch, the clock must be gated
+ * for 5 ms according to the SD spec
+ */
+ clock = host->ios.clock;
+ host->ios.clock = 0;
+ mmc_set_ios(host);
- host->ios.signal_voltage = signal_voltage;
+ if (__mmc_set_signal_voltage(host, signal_voltage)) {
+ /*
+ * Voltages may not have been switched, but we've already
+ * sent CMD11, so a power cycle is required anyway
+ */
+ err = -EAGAIN;
+ goto power_cycle;
+ }
- if (host->ops->start_signal_voltage_switch) {
- mmc_host_clk_hold(host);
- err = host->ops->start_signal_voltage_switch(host, &host->ios);
- mmc_host_clk_release(host);
+ /* Keep clock gated for at least 5 ms */
+ mmc_delay(5);
+ host->ios.clock = clock;
+ mmc_set_ios(host);
+
+ /* Wait for at least 1 ms according to spec */
+ mmc_delay(1);
+
+ /*
+ * Failure to switch is indicated by the card holding
+ * dat[0:3] low
+ */
+ if (host->ops->card_busy && host->ops->card_busy(host))
+ err = -EAGAIN;
+
+power_cycle:
+ if (err) {
+ pr_debug("%s: Signal voltage switch failed, "
+ "power cycling card\n", mmc_hostname(host));
+ mmc_power_cycle(host);
}
+ mmc_host_clk_release(host);
+
return err;
}
@@ -1314,7 +1486,7 @@ static void mmc_power_up(struct mmc_host *host)
mmc_set_ios(host);
/* Set signal voltage to 3.3V */
- mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
+ __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
/*
* This delay should be sufficient to allow the power supply
@@ -1372,6 +1544,14 @@ void mmc_power_off(struct mmc_host *host)
mmc_host_clk_release(host);
}
+void mmc_power_cycle(struct mmc_host *host)
+{
+ mmc_power_off(host);
+ /* Wait at least 1 ms according to SD spec */
+ mmc_delay(1);
+ mmc_power_up(host);
+}
+
/*
* Cleanup when the last reference to the bus operator is dropped.
*/
@@ -2388,6 +2568,7 @@ EXPORT_SYMBOL(mmc_flush_cache);
* Turn the cache ON/OFF.
* Turning the cache OFF shall trigger flushing of the data
* to the non-volatile storage.
+ * This function should be called with host claimed
*/
int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
{
@@ -2399,7 +2580,6 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
mmc_card_is_removable(host))
return err;
- mmc_claim_host(host);
if (card && mmc_card_mmc(card) &&
(card->ext_csd.cache_size > 0)) {
enable = !!enable;
@@ -2417,7 +2597,6 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
card->ext_csd.cache_ctrl = enable;
}
}
- mmc_release_host(host);
return err;
}
@@ -2436,10 +2615,6 @@ int mmc_suspend_host(struct mmc_host *host)
cancel_delayed_work(&host->detect);
mmc_flush_scheduled_work();
- err = mmc_cache_ctrl(host, 0);
- if (err)
- goto out;
-
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
if (host->bus_ops->suspend) {
@@ -2581,6 +2756,23 @@ int mmc_pm_notify(struct notifier_block *notify_block,
}
#endif
+/**
+ * mmc_init_context_info() - init synchronization context
+ * @host: mmc host
+ *
+ * Init struct context_info needed to implement asynchronous
+ * request mechanism, used by mmc core, host driver and mmc requests
+ * supplier.
+ */
+void mmc_init_context_info(struct mmc_host *host)
+{
+ spin_lock_init(&host->context_info.lock);
+ host->context_info.is_new_req = false;
+ host->context_info.is_done_rcv = false;
+ host->context_info.is_waiting_last_req = false;
+ init_waitqueue_head(&host->context_info.wait);
+}
+
static int __init mmc_init(void)
{
int ret;
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 3bdafbca354f..b9f18a2a8874 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -40,11 +40,12 @@ void mmc_set_ungated(struct mmc_host *host);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
- bool cmd11);
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
+int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
void mmc_power_off(struct mmc_host *host);
+void mmc_power_cycle(struct mmc_host *host);
static inline void mmc_delay(unsigned int ms)
{
@@ -76,5 +77,6 @@ void mmc_remove_host_debugfs(struct mmc_host *host);
void mmc_add_card_debugfs(struct mmc_card *card);
void mmc_remove_card_debugfs(struct mmc_card *card);
+void mmc_init_context_info(struct mmc_host *host);
#endif
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index ee2e16b17017..821cd8224137 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -15,6 +15,8 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/idr.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/pagemap.h>
#include <linux/export.h>
#include <linux/leds.h>
@@ -23,6 +25,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/slot-gpio.h>
#include "core.h"
#include "host.h"
@@ -295,6 +298,126 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
#endif
/**
+ * mmc_of_parse() - parse host's device-tree node
+ * @host: host whose node should be parsed.
+ *
+ * To keep the rest of the MMC subsystem unaware of whether DT has been
+ * used to to instantiate and configure this host instance or not, we
+ * parse the properties and set respective generic mmc-host flags and
+ * parameters.
+ */
+void mmc_of_parse(struct mmc_host *host)
+{
+ struct device_node *np;
+ u32 bus_width;
+ bool explicit_inv_wp, gpio_inv_wp = false;
+ enum of_gpio_flags flags;
+ int len, ret, gpio;
+
+ if (!host->parent || !host->parent->of_node)
+ return;
+
+ np = host->parent->of_node;
+
+ /* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
+ if (of_property_read_u32(np, "bus-width", &bus_width) < 0) {
+ dev_dbg(host->parent,
+ "\"bus-width\" property is missing, assuming 1 bit.\n");
+ bus_width = 1;
+ }
+
+ switch (bus_width) {
+ case 8:
+ host->caps |= MMC_CAP_8_BIT_DATA;
+ /* Hosts capable of 8-bit transfers can also do 4 bits */
+ case 4:
+ host->caps |= MMC_CAP_4_BIT_DATA;
+ break;
+ case 1:
+ break;
+ default:
+ dev_err(host->parent,
+ "Invalid \"bus-width\" value %ud!\n", bus_width);
+ }
+
+ /* f_max is obtained from the optional "max-frequency" property */
+ of_property_read_u32(np, "max-frequency", &host->f_max);
+
+ /*
+ * Configure CD and WP pins. They are both by default active low to
+ * match the SDHCI spec. If GPIOs are provided for CD and / or WP, the
+ * mmc-gpio helpers are used to attach, configure and use them. If
+ * polarity inversion is specified in DT, one of MMC_CAP2_CD_ACTIVE_HIGH
+ * and MMC_CAP2_RO_ACTIVE_HIGH capability-2 flags is set. If the
+ * "broken-cd" property is provided, the MMC_CAP_NEEDS_POLL capability
+ * is set. If the "non-removable" property is found, the
+ * MMC_CAP_NONREMOVABLE capability is set and no card-detection
+ * configuration is performed.
+ */
+
+ /* Parse Card Detection */
+ if (of_find_property(np, "non-removable", &len)) {
+ host->caps |= MMC_CAP_NONREMOVABLE;
+ } else {
+ bool explicit_inv_cd, gpio_inv_cd = false;
+
+ explicit_inv_cd = of_property_read_bool(np, "cd-inverted");
+
+ if (of_find_property(np, "broken-cd", &len))
+ host->caps |= MMC_CAP_NEEDS_POLL;
+
+ gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
+ if (gpio_is_valid(gpio)) {
+ if (!(flags & OF_GPIO_ACTIVE_LOW))
+ gpio_inv_cd = true;
+
+ ret = mmc_gpio_request_cd(host, gpio);
+ if (ret < 0)
+ dev_err(host->parent,
+ "Failed to request CD GPIO #%d: %d!\n",
+ gpio, ret);
+ else
+ dev_info(host->parent, "Got CD GPIO #%d.\n",
+ gpio);
+ }
+
+ if (explicit_inv_cd ^ gpio_inv_cd)
+ host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
+ }
+
+ /* Parse Write Protection */
+ explicit_inv_wp = of_property_read_bool(np, "wp-inverted");
+
+ gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
+ if (gpio_is_valid(gpio)) {
+ if (!(flags & OF_GPIO_ACTIVE_LOW))
+ gpio_inv_wp = true;
+
+ ret = mmc_gpio_request_ro(host, gpio);
+ if (ret < 0)
+ dev_err(host->parent,
+ "Failed to request WP GPIO: %d!\n", ret);
+ }
+ if (explicit_inv_wp ^ gpio_inv_wp)
+ host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
+
+ if (of_find_property(np, "cap-sd-highspeed", &len))
+ host->caps |= MMC_CAP_SD_HIGHSPEED;
+ if (of_find_property(np, "cap-mmc-highspeed", &len))
+ host->caps |= MMC_CAP_MMC_HIGHSPEED;
+ if (of_find_property(np, "cap-power-off-card", &len))
+ host->caps |= MMC_CAP_POWER_OFF_CARD;
+ if (of_find_property(np, "cap-sdio-irq", &len))
+ host->caps |= MMC_CAP_SDIO_IRQ;
+ if (of_find_property(np, "keep-power-in-suspend", &len))
+ host->pm_caps |= MMC_PM_KEEP_POWER;
+ if (of_find_property(np, "enable-sdio-wakeup", &len))
+ host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+}
+
+EXPORT_SYMBOL(mmc_of_parse);
+
+/**
* mmc_alloc_host - initialise the per-host structure.
* @extra: sizeof private data structure
* @dev: pointer to host device model structure
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e6e39111e05b..c8f3d6e0684e 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -496,7 +496,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
* RPMB regions are defined in multiples of 128K.
*/
card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
- if (ext_csd[EXT_CSD_RPMB_MULT]) {
+ if (ext_csd[EXT_CSD_RPMB_MULT] && mmc_host_cmd23(card->host)) {
mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
EXT_CSD_PART_CONFIG_ACC_RPMB,
"rpmb", 0, false,
@@ -538,6 +538,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
} else {
card->ext_csd.data_tag_unit_size = 0;
}
+
+ card->ext_csd.max_packed_writes =
+ ext_csd[EXT_CSD_MAX_PACKED_WRITES];
+ card->ext_csd.max_packed_reads =
+ ext_csd[EXT_CSD_MAX_PACKED_READS];
} else {
card->ext_csd.data_sector_size = 512;
}
@@ -769,11 +774,11 @@ static int mmc_select_hs200(struct mmc_card *card)
if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0);
+ err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, 0);
+ err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
/* If fails try again during next card power cycle */
if (err)
@@ -1221,8 +1226,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* WARNING: eMMC rules are NOT the same as SD DDR
*/
if (ddr == MMC_1_2V_DDR_MODE) {
- err = mmc_set_signal_voltage(host,
- MMC_SIGNAL_VOLTAGE_120, 0);
+ err = __mmc_set_signal_voltage(host,
+ MMC_SIGNAL_VOLTAGE_120);
if (err)
goto err;
}
@@ -1275,6 +1280,29 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
}
+ /*
+ * The mandatory minimum values are defined for packed command.
+ * read: 5, write: 3
+ */
+ if (card->ext_csd.max_packed_writes >= 3 &&
+ card->ext_csd.max_packed_reads >= 5 &&
+ host->caps2 & MMC_CAP2_PACKED_CMD) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_EXP_EVENTS_CTRL,
+ EXT_CSD_PACKED_EVENT_EN,
+ card->ext_csd.generic_cmd6_time);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ if (err) {
+ pr_warn("%s: Enabling packed event failed\n",
+ mmc_hostname(card->host));
+ card->ext_csd.packed_event_en = 0;
+ err = 0;
+ } else {
+ card->ext_csd.packed_event_en = 1;
+ }
+ }
+
if (!oldcard)
host->card = card;
@@ -1379,6 +1407,11 @@ static int mmc_suspend(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
+
+ err = mmc_cache_ctrl(host, 0);
+ if (err)
+ goto out;
+
if (mmc_can_poweroff_notify(host->card))
err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
else if (mmc_card_can_sleep(host))
@@ -1386,8 +1419,9 @@ static int mmc_suspend(struct mmc_host *host)
else if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
- mmc_release_host(host);
+out:
+ mmc_release_host(host);
return err;
}
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 6d8f7012d73a..49f04bc9d0eb 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -363,6 +363,7 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
ext_csd, 512);
}
+EXPORT_SYMBOL_GPL(mmc_send_ext_csd);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
{
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 74972c241dff..9e645e19cec6 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -444,8 +444,7 @@ static void sd_update_bus_speed_mode(struct mmc_card *card)
* If the host doesn't support any of the UHS-I modes, fallback on
* default speed.
*/
- if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) {
+ if (!mmc_host_uhs(card->host)) {
card->sd_bus_speed = 0;
return;
}
@@ -713,6 +712,14 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
{
int err;
u32 max_current;
+ int retries = 10;
+
+try_again:
+ if (!retries) {
+ ocr &= ~SD_OCR_S18R;
+ pr_warning("%s: Skipping voltage switch\n",
+ mmc_hostname(host));
+ }
/*
* Since we're changing the OCR value, we seem to
@@ -734,10 +741,10 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
/*
* If the host supports one of UHS-I modes, request the card
- * to switch to 1.8V signaling level.
+ * to switch to 1.8V signaling level. If the card has failed
+ * repeatedly to switch however, skip this.
*/
- if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
+ if (retries && mmc_host_uhs(host))
ocr |= SD_OCR_S18R;
/*
@@ -748,7 +755,6 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
if (max_current > 150)
ocr |= SD_OCR_XPC;
-try_again:
err = mmc_send_app_op_cond(host, ocr, rocr);
if (err)
return err;
@@ -759,9 +765,12 @@ try_again:
*/
if (!mmc_host_is_spi(host) && rocr &&
((*rocr & 0x41000000) == 0x41000000)) {
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
- if (err) {
- ocr &= ~SD_OCR_S18R;
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+ if (err == -EAGAIN) {
+ retries--;
+ goto try_again;
+ } else if (err) {
+ retries = 0;
goto try_again;
}
}
@@ -960,16 +969,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
/* Card is an ultra-high-speed card */
mmc_card_set_uhs(card);
-
- /*
- * Since initialization is now complete, enable preset
- * value registers for UHS-I cards.
- */
- if (host->ops->enable_preset_value) {
- mmc_host_clk_hold(card->host);
- host->ops->enable_preset_value(host, true);
- mmc_host_clk_release(card->host);
- }
} else {
/*
* Attempt to change to high-speed (if supported)
@@ -1148,13 +1147,6 @@ int mmc_attach_sd(struct mmc_host *host)
BUG_ON(!host);
WARN_ON(!host->claimed);
- /* Disable preset value enable if already set since last time */
- if (host->ops->enable_preset_value) {
- mmc_host_clk_hold(host);
- host->ops->enable_preset_value(host, false);
- mmc_host_clk_release(host);
- }
-
err = mmc_send_app_op_cond(host, 0, &ocr);
if (err)
return err;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 2273ce6b6c1a..aa0719a4dfd1 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -157,10 +157,7 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
if (ret)
goto out;
- if (card->host->caps &
- (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50)) {
+ if (mmc_host_uhs(card->host)) {
if (data & SDIO_UHS_DDR50)
card->sw_caps.sd3_bus_mode
|= SD_MODE_UHS_DDR50;
@@ -478,8 +475,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
* If the host doesn't support any of the UHS-I modes, fallback on
* default speed.
*/
- if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
+ if (!mmc_host_uhs(card->host))
return 0;
bus_speed = SDIO_SPEED_SDR12;
@@ -489,23 +485,27 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
bus_speed = SDIO_SPEED_SDR104;
timing = MMC_TIMING_UHS_SDR104;
card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
bus_speed = SDIO_SPEED_DDR50;
timing = MMC_TIMING_UHS_DDR50;
card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+ card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR50)) {
bus_speed = SDIO_SPEED_SDR50;
timing = MMC_TIMING_UHS_SDR50;
card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
bus_speed = SDIO_SPEED_SDR25;
timing = MMC_TIMING_UHS_SDR25;
card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
@@ -513,6 +513,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
bus_speed = SDIO_SPEED_SDR12;
timing = MMC_TIMING_UHS_SDR12;
card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
}
err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
@@ -583,10 +584,19 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
{
struct mmc_card *card;
int err;
+ int retries = 10;
BUG_ON(!host);
WARN_ON(!host->claimed);
+try_again:
+ if (!retries) {
+ pr_warning("%s: Skipping voltage switch\n",
+ mmc_hostname(host));
+ ocr &= ~R4_18V_PRESENT;
+ host->ocr &= ~R4_18V_PRESENT;
+ }
+
/*
* Inform the card of the voltage
*/
@@ -645,14 +655,16 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
* systems that claim 1.8v signalling in fact do not support
* it.
*/
- if ((ocr & R4_18V_PRESENT) &&
- (host->caps &
- (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50))) {
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
- true);
- if (err) {
+ if (!powered_resume && (ocr & R4_18V_PRESENT) && mmc_host_uhs(host)) {
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+ if (err == -EAGAIN) {
+ sdio_reset(host);
+ mmc_go_idle(host);
+ mmc_send_if_cond(host, host->ocr_avail);
+ mmc_remove_card(card);
+ retries--;
+ goto try_again;
+ } else if (err) {
ocr &= ~R4_18V_PRESENT;
host->ocr &= ~R4_18V_PRESENT;
}
@@ -937,10 +949,12 @@ static int mmc_sdio_resume(struct mmc_host *host)
mmc_claim_host(host);
/* No need to reinitialize powered-resumed nonremovable cards */
- if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
+ if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
+ sdio_reset(host);
+ mmc_go_idle(host);
err = mmc_sdio_init_card(host, host->ocr, host->card,
mmc_card_keep_power(host));
- else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
+ } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host->card);
if (err > 0) {
@@ -1020,6 +1034,10 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
goto out;
}
+ if (mmc_host_uhs(host))
+ /* to query card if 1.8V signalling is supported */
+ host->ocr |= R4_18V_PRESENT;
+
ret = mmc_sdio_init_card(host, host->ocr, host->card,
mmc_card_keep_power(host));
if (!ret && host->sdio_irqs)
@@ -1085,6 +1103,10 @@ int mmc_attach_sdio(struct mmc_host *host)
/*
* Detect and init the card.
*/
+ if (mmc_host_uhs(host))
+ /* to query card if 1.8V signalling is supported */
+ host->ocr |= R4_18V_PRESENT;
+
err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
if (err) {
if (err == -EAGAIN) {
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 16a1c0b6f264..324235105519 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -92,6 +92,20 @@ int mmc_gpio_get_cd(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_gpio_get_cd);
+/**
+ * mmc_gpio_request_ro - request a gpio for write-protection
+ * @host: mmc host
+ * @gpio: gpio number requested
+ *
+ * As devm_* managed functions are used in mmc_gpio_request_ro(), client
+ * drivers do not need to explicitly call mmc_gpio_free_ro() for freeing up,
+ * if the requesting and freeing are only needed at probing and unbinding time
+ * for once. However, if client drivers do something special like runtime
+ * switching for write-protection, they are responsible for calling
+ * mmc_gpio_request_ro() and mmc_gpio_free_ro() as a pair on their own.
+ *
+ * Returns zero on success, else an error.
+ */
int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
{
struct mmc_gpio *ctx;
@@ -106,7 +120,8 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
ctx = host->slot.handler_priv;
- ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->ro_label);
+ ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN,
+ ctx->ro_label);
if (ret < 0)
return ret;
@@ -116,6 +131,20 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
}
EXPORT_SYMBOL(mmc_gpio_request_ro);
+/**
+ * mmc_gpio_request_cd - request a gpio for card-detection
+ * @host: mmc host
+ * @gpio: gpio number requested
+ *
+ * As devm_* managed functions are used in mmc_gpio_request_cd(), client
+ * drivers do not need to explicitly call mmc_gpio_free_cd() for freeing up,
+ * if the requesting and freeing are only needed at probing and unbinding time
+ * for once. However, if client drivers do something special like runtime
+ * switching for card-detection, they are responsible for calling
+ * mmc_gpio_request_cd() and mmc_gpio_free_cd() as a pair on their own.
+ *
+ * Returns zero on success, else an error.
+ */
int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
{
struct mmc_gpio *ctx;
@@ -128,7 +157,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
ctx = host->slot.handler_priv;
- ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label);
+ ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN,
+ ctx->cd_label);
if (ret < 0)
/*
* don't bother freeing memory. It might still get used by other
@@ -146,7 +176,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
irq = -EINVAL;
if (irq >= 0) {
- ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt,
+ ret = devm_request_threaded_irq(&host->class_dev, irq,
+ NULL, mmc_gpio_cd_irqt,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
ctx->cd_label, host);
if (ret < 0)
@@ -164,6 +195,13 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
}
EXPORT_SYMBOL(mmc_gpio_request_cd);
+/**
+ * mmc_gpio_free_ro - free the write-protection gpio
+ * @host: mmc host
+ *
+ * It's provided only for cases that client drivers need to manually free
+ * up the write-protection gpio requested by mmc_gpio_request_ro().
+ */
void mmc_gpio_free_ro(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
@@ -175,10 +213,17 @@ void mmc_gpio_free_ro(struct mmc_host *host)
gpio = ctx->ro_gpio;
ctx->ro_gpio = -EINVAL;
- gpio_free(gpio);
+ devm_gpio_free(&host->class_dev, gpio);
}
EXPORT_SYMBOL(mmc_gpio_free_ro);
+/**
+ * mmc_gpio_free_cd - free the card-detection gpio
+ * @host: mmc host
+ *
+ * It's provided only for cases that client drivers need to manually free
+ * up the card-detection gpio requested by mmc_gpio_request_cd().
+ */
void mmc_gpio_free_cd(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
@@ -188,13 +233,13 @@ void mmc_gpio_free_cd(struct mmc_host *host)
return;
if (host->slot.cd_irq >= 0) {
- free_irq(host->slot.cd_irq, host);
+ devm_free_irq(&host->class_dev, host->slot.cd_irq, host);
host->slot.cd_irq = -EINVAL;
}
gpio = ctx->cd_gpio;
ctx->cd_gpio = -EINVAL;
- gpio_free(gpio);
+ devm_gpio_free(&host->class_dev, gpio);
}
EXPORT_SYMBOL(mmc_gpio_free_cd);
OpenPOWER on IntegriCloud