summaryrefslogtreecommitdiff
path: root/drivers/mmc/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/core.c38
-rw-r--r--drivers/mmc/core/core.h3
-rw-r--r--drivers/mmc/core/host.c12
-rw-r--r--drivers/mmc/core/mmc_ops.c6
-rw-r--r--drivers/mmc/core/sd.c6
-rw-r--r--drivers/mmc/core/sdio.c17
6 files changed, 71 insertions, 11 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 8f94c2539508..ca4e640eafb1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -52,6 +52,8 @@
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
+static int __mmc_max_reserved_idx = -1;
+
/*
* Enabling software CRCs on the data blocks can be a significant (30%)
* performance cost, and for other reasons may not always be desired.
@@ -2395,10 +2397,46 @@ void mmc_stop_host(struct mmc_host *host)
mmc_release_host(host);
}
+/*
+ * mmc_first_nonreserved_index() - get the first index that
+ * is not reserved
+ */
+int mmc_first_nonreserved_index(void)
+{
+ return __mmc_max_reserved_idx + 1;
+}
+EXPORT_SYMBOL(mmc_first_nonreserved_index);
+
+/*
+ * mmc_get_reserved_index() - get the index reserved for this host
+ * Return: The index reserved for this host or negative error value
+ * if no index is reserved for this host
+ */
+int mmc_get_reserved_index(struct mmc_host *host)
+{
+ return of_alias_get_id(host->parent->of_node, "mmc");
+}
+EXPORT_SYMBOL(mmc_get_reserved_index);
+
+static void mmc_of_reserve_idx(void)
+{
+ int max;
+
+ max = of_alias_max_index("mmc");
+ if (max < 0)
+ return;
+
+ __mmc_max_reserved_idx = max;
+ pr_debug("MMC: reserving %d slots for of aliases\n",
+ __mmc_max_reserved_idx + 1);
+}
+
static int __init mmc_init(void)
{
int ret;
+ mmc_of_reserve_idx();
+
ret = mmc_register_bus();
if (ret)
return ret;
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index db3c9c68875d..09a11032d635 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -79,7 +79,8 @@ int mmc_detect_card_removed(struct mmc_host *host);
int mmc_attach_mmc(struct mmc_host *host);
int mmc_attach_sd(struct mmc_host *host);
int mmc_attach_sdio(struct mmc_host *host);
-
+int mmc_first_nonreserved_index(void);
+int mmc_get_reserved_index(struct mmc_host *host);
/* Module parameters */
extern bool use_spi_crc;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index f7339590a84c..b077e071505a 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -433,6 +433,7 @@ EXPORT_SYMBOL(mmc_of_parse_voltage);
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
int err;
+ int alias_id;
struct mmc_host *host;
host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
@@ -441,8 +442,16 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
/* scanning will be enabled when we're ready */
host->rescan_disable = 1;
+ host->parent = dev;
- err = ida_simple_get(&mmc_host_ida, 0, 0, GFP_KERNEL);
+ alias_id = mmc_get_reserved_index(host);
+ if (alias_id >= 0)
+ err = ida_simple_get(&mmc_host_ida, alias_id,
+ alias_id + 1, GFP_KERNEL);
+ else
+ err = ida_simple_get(&mmc_host_ida,
+ mmc_first_nonreserved_index(),
+ 0, GFP_KERNEL);
if (err < 0) {
kfree(host);
return NULL;
@@ -452,7 +461,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
dev_set_name(&host->class_dev, "mmc%d", host->index);
- host->parent = dev;
host->class_dev.parent = dev;
host->class_dev.class = &mmc_host_class;
device_initialize(&host->class_dev);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 09311c2bd858..2d9715378b42 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -589,6 +589,12 @@ out_tim:
if (timing)
mmc_set_timing(host, timing);
+ /*
+ * WORKAROUND: for Sandisk eMMC cards, it might need certain delay
+ * before sending CMD13 after CMD6
+ */
+ mdelay(1);
+
if (send_status) {
err = mmc_switch_status(card);
if (err && timing)
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index c6d7a0adde0d..b6fef82a9add 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -504,6 +504,12 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
else {
mmc_set_timing(card->host, timing);
mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
+ /*
+ * FIXME: Sandisk SD3.0 cards DDR50 mode requires such
+ * delay to get stable, without this delay we may encounter
+ * CRC errors after switch to DDR50 mode
+ */
+ mmc_delay(100);
}
return 0;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 0bf33786fc5c..3627c9d6452e 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -158,15 +158,18 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
if (mmc_host_uhs(card->host)) {
if (data & SDIO_UHS_DDR50)
card->sw_caps.sd3_bus_mode
- |= SD_MODE_UHS_DDR50;
+ |= SD_MODE_UHS_DDR50 | SD_MODE_UHS_SDR50
+ | SD_MODE_UHS_SDR25 | SD_MODE_UHS_SDR12;
if (data & SDIO_UHS_SDR50)
card->sw_caps.sd3_bus_mode
- |= SD_MODE_UHS_SDR50;
+ |= SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR25
+ | SD_MODE_UHS_SDR12;
if (data & SDIO_UHS_SDR104)
card->sw_caps.sd3_bus_mode
- |= SD_MODE_UHS_SDR104;
+ |= SD_MODE_UHS_SDR104 | SD_MODE_UHS_SDR50
+ | SD_MODE_UHS_SDR25 | SD_MODE_UHS_SDR12;
}
ret = mmc_io_rw_direct(card, 0, 0,
@@ -500,10 +503,8 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
max_rate = min_not_zero(card->quirk_max_rate,
card->sw_caps.uhs_max_dtr);
- if (bus_speed) {
- mmc_set_timing(card->host, timing);
- mmc_set_clock(card->host, max_rate);
- }
+ mmc_set_timing(card->host, timing);
+ mmc_set_clock(card->host, max_rate);
return 0;
}
@@ -1026,7 +1027,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
wake_up_process(host->sdio_irq_thread);
else if (host->caps & MMC_CAP_SDIO_IRQ)
- queue_delayed_work(system_wq, &host->sdio_irq_work, 0);
+ queue_delayed_work(system_wq, &host->sdio_irq_work, 1);
}
out: